codec-amr
AMRWB.h
1 #pragma once
2 
3 #include <string.h>
4 
5 #include "AMRCodec.h"
6 extern "C" {
7 #include "wb/dec_if.h"
8 #include "wb/enc_if.h"
9 }
10 
14 class AMRWB : public AMRCodec {
15  public:
19  enum class Mode {
20  WB_6_60 = 0, // 6.60 kbit/s
21  WB_8_85, // 8.85 kbit/s
22  WB_12_65, // 12.65 kbit/s
23  WB_14_25, // 14.25 kbit/s
24  WB_15_85, // 15.85 kbit/s
25  WB_18_25, // 18.25 kbit/s
26  WB_19_85, // 19.85 kbit/s
27  WB_23_05, // 23.05 kbit/s
28  WB_23_85 // 23.85 kbit/s
29  };
30 
31  AMRWB() = default;
32 
36  inline ~AMRWB() override {
37  if (encoderState) {
38  E_IF_exit(encoderState);
39  encoderState = nullptr;
40  }
41 
42  if (decoderState) {
43  D_IF_exit(decoderState);
44  decoderState = nullptr;
45  }
46  }
47 
52  inline void setMode(Mode mode) { currentMode = mode; }
53 
58  inline Mode getMode() const { return currentMode; }
59 
68  inline int encode(const int16_t* pcmSamples, size_t sampleCount,
69  uint8_t* amrData, size_t amrBufferSize) override {
70  if (encoderState == nullptr) encoderState = E_IF_init();
71 
72  if (encoderState == nullptr || !amrData || amrBufferSize == 0) {
73  return 0;
74  }
75 
76  // AMR-WB works with 320 samples per frame (20ms at 16kHz)
77  const size_t samplesPerFrame = 320;
78  size_t bytesWritten = 0;
79 
80  for (size_t i = 0; i < sampleCount && bytesWritten < amrBufferSize;
81  i += samplesPerFrame) {
82  // Make sure we have a full frame
83  if (i + samplesPerFrame > sampleCount) {
84  break;
85  }
86 
87  // Check if we have enough space for worst-case frame size (64 bytes)
88  if (bytesWritten + 64 > amrBufferSize) {
89  break;
90  }
91 
92  // Encode the frame
93  int frameBytes = E_IF_encode(encoderState, static_cast<int>(currentMode),
94  const_cast<short*>(pcmSamples + i),
95  amrData + bytesWritten,
96  0 // forceSpeech
97  );
98 
99  bytesWritten += frameBytes;
100  }
101 
102  return bytesWritten;
103  }
104 
113  inline int decode(const uint8_t* amrData, size_t amrSize, int16_t* pcmSamples,
114  size_t maxSampleCount) override {
115  if (decoderState == nullptr) decoderState = D_IF_init();
116 
117  if (decoderState == nullptr || !amrData || amrSize == 0 || !pcmSamples ||
118  maxSampleCount == 0) {
119  return 0;
120  }
121 
122  // AMR-WB produces 320 samples per frame (20ms at 16kHz)
123  const size_t samplesPerFrame = getFrameSizeSamples();
124  size_t totalSamplesDecoded = 0;
125  size_t offset = 0;
126 
127  // Process the input buffer frame by frame
128  while (offset < amrSize &&
129  totalSamplesDecoded + samplesPerFrame <= maxSampleCount) {
130  // Extract frame type from the frame header
131  uint8_t frameType = (amrData[offset] >> 3) & 0x0F;
132 
133  // Find frame size based on frame type
134  size_t frameSize = 1;
135  if (frameSize <= 8) {
136  frameSize = getEncodedFrameSizeBytes(frameType);
137  }
138 
139  if (offset + frameSize > amrSize) {
140  break; // Not enough data for another frame
141  }
142 
143  // Decode this frame
144  D_IF_decode(decoderState, const_cast<unsigned char*>(amrData + offset),
145  pcmSamples + totalSamplesDecoded,
146  0 // BFI (bad frame indicator)
147  );
148 
149  offset += frameSize;
150  totalSamplesDecoded += samplesPerFrame;
151  }
152 
153  return totalSamplesDecoded;
154  }
155 
160  inline int getSampleRate() const override { return 16000; }
161 
166  int getFrameSizeSamples() override { return 320; }
167 
172  int getEncodedFrameSizeBytes() override {
173  return getEncodedFrameSizeBytes(static_cast<int>(currentMode));
174  }
175 
176  private:
177  void* encoderState = nullptr;
178  void* decoderState = nullptr;
179  Mode currentMode = Mode::WB_23_85;
180 
181  int getEncodedFrameSizeBytes(int mode) {
182  // Bytes per encoded frame for each mode
183  const uint8_t frameSizes[] = {
184  18, // WB_6_60 (6.60 kbps)
185  24, // WB_8_85 (8.85 kbps)
186  33, // WB_12_65 (12.65 kbps)
187  37, // WB_14_25 (14.25 kbps)
188  41, // WB_15_85 (15.85 kbps)
189  47, // WB_18_25 (18.25 kbps)
190  51, // WB_19_85 (19.85 kbps)
191  59, // WB_23_05 (23.05 kbps)
192  61 // WB_23_85 (23.85 kbps)
193  };
194  return frameSizes[mode];
195  }
196 };
Base class for AMR codec implementations.
Definition: AMRCodec.h:9
AMR Wideband codec implementation.
Definition: AMRWB.h:14
int decode(const uint8_t *amrData, size_t amrSize, int16_t *pcmSamples, size_t maxSampleCount) override
Decode AMR-WB data to PCM samples.
Definition: AMRWB.h:113
int getEncodedFrameSizeBytes() override
Get the size in bytes for one encoded frame in current mode.
Definition: AMRWB.h:172
Mode
Available encoding modes for AMR-WB.
Definition: AMRWB.h:19
int getSampleRate() const override
Get sample rate (16000 Hz for AMR-WB)
Definition: AMRWB.h:160
void setMode(Mode mode)
Set encoding mode.
Definition: AMRWB.h:52
~AMRWB() override
Destructor.
Definition: AMRWB.h:36
Mode getMode() const
Get current encoding mode.
Definition: AMRWB.h:58
int encode(const int16_t *pcmSamples, size_t sampleCount, uint8_t *amrData, size_t amrBufferSize) override
Encode PCM samples to AMR-WB format.
Definition: AMRWB.h:68
int getFrameSizeSamples() override
Get frame size in samples (320 for AMR-WB)
Definition: AMRWB.h:166