Skip to content

Commit c1fee43

Browse files
committed
CodecAMR
1 parent f5f2404 commit c1fee43

File tree

2 files changed

+335
-0
lines changed

2 files changed

+335
-0
lines changed
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
#pragma once
2+
#include "AMRNB.h" // https://github.com/pschatzmann/codec-amr
3+
#include "AudioTools/AudioCodecs/AudioCodecsBase.h"
4+
5+
namespace audio_tools {
6+
7+
/**
8+
* @brief AMR Narrowband Decoder
9+
* See https://github.com/pschatzmann/codec-amr
10+
* @ingroup codecs
11+
* @ingroup decoder
12+
* @author Phil Schatzmann
13+
* @copyright GPLv3
14+
*/
15+
16+
class AMRNBDecoder : public AudioDecoder {
17+
public:
18+
AMRNBDecoder(AMRNB::Mode mode) {
19+
setMode(mode);
20+
info.channels = 1;
21+
info.sample_rate = 8000;
22+
}
23+
24+
~AMRNBDecoder() override = default;
25+
26+
void setMode(AMRNB::Mode mode) {
27+
this->mode = mode;
28+
amr.setMode(mode);
29+
}
30+
31+
bool begin() {
32+
notifyAudioChange(audioInfo());
33+
buffer.resize(amr.getEncodedFrameSizeBytes());
34+
return getOutput() != nullptr;
35+
}
36+
37+
void setAudioInfo(AudioInfo from) {
38+
if (from.bits_per_sample != 16) {
39+
LOGE("Invalid bits per sample: %d", from.bits_per_sample);
40+
}
41+
if (from.sample_rate != 8000) {
42+
LOGE("Invalid sample rate: %d", from.sample_rate);
43+
}
44+
if (from.channels != 1) {
45+
LOGE("Invalid channels: %d", from.channels);
46+
}
47+
}
48+
49+
size_t write(const uint8_t *data, size_t len) override {
50+
for (size_t j = 0; j < len; j++) {
51+
buffer.write(data[j]);
52+
if (buffer.isFull()) {
53+
int result_samples = amr.getFrameSizeSamples();
54+
int16_t result[result_samples];
55+
int size =
56+
amr.decode(buffer.data(), buffer.size(), result, result_samples);
57+
if (size > 0) {
58+
if (getOutput() != nullptr) {
59+
getOutput()->write((uint8_t *)result, size * sizeof(int16_t));
60+
}
61+
}
62+
buffer.clear();
63+
}
64+
}
65+
return len;
66+
}
67+
68+
/// Provides the block size (size of encoded frame)
69+
int blockSize() {
70+
amr.setMode(mode);
71+
return amr.getEncodedFrameSizeBytes();
72+
}
73+
74+
/// Provides the frame size (size of decoded frame)
75+
int frameSize() { return amr.getFrameSizeSamples() * sizeof(int16_t); }
76+
77+
protected:
78+
AMRNB amr;
79+
AMRNB::Mode mode;
80+
SingleBuffer<uint8_t> buffer{0};
81+
};
82+
83+
/**
84+
* @brief AMR NB Encoder
85+
* See https://github.com/pschatzmann/codec-amr
86+
* @ingroup codecs
87+
* @ingroup decoder
88+
* @author Phil Schatzmann
89+
* @copyright GPLv3
90+
*/
91+
92+
class AMRNBEncoder : public AudioEncoder {
93+
public:
94+
AMRNBEncoder(AMRNB::Mode mode) {
95+
setMode(mode);
96+
info.channels = 1;
97+
info.sample_rate = 8000;
98+
}
99+
100+
~AMRNBEncoder() override = default;
101+
102+
void setMode(AMRNB::Mode mode) {
103+
this->mode = mode;
104+
amr.setMode(mode);
105+
}
106+
107+
bool begin() {
108+
buffer.resize(frameSize());
109+
return getOutput() != nullptr;
110+
}
111+
112+
void setAudioInfo(AudioInfo from) {
113+
if (from.bits_per_sample != 16) {
114+
LOGE("Invalid bits per sample: %d", from.bits_per_sample);
115+
}
116+
if (from.sample_rate != 8000) {
117+
LOGE("Invalid sample rate: %d", from.sample_rate);
118+
}
119+
if (from.channels != 1) {
120+
LOGE("Invalid channels: %d", from.channels);
121+
}
122+
}
123+
124+
size_t write(const uint8_t *data, size_t len) override {
125+
for (size_t j = 0; j < len; j++) {
126+
buffer.write(data[j]);
127+
if (buffer.isFull()) {
128+
int result_bytes = blockSize();
129+
uint8_t result[result_bytes];
130+
int size =
131+
amr.encode((int16_t *)buffer.data(),
132+
buffer.size() / sizeof(int16_t), result, result_bytes);
133+
if (size > 0) {
134+
if (getOutput() != nullptr) {
135+
getOutput()->write(result, size);
136+
}
137+
}
138+
buffer.clear();
139+
}
140+
}
141+
return len;
142+
}
143+
144+
/// Provides the block size (size of encoded frame)
145+
int blockSize() {
146+
amr.setMode(mode);
147+
return amr.getEncodedFrameSizeBytes();
148+
}
149+
150+
/// Provides the frame size (size of decoded frame)
151+
int frameSize() { return amr.getFrameSizeSamples() * sizeof(int16_t); }
152+
153+
const char *mime() { return "audio/amr"; }
154+
155+
void setOutput(Print &out_stream) override { p_print = &out_stream; }
156+
157+
Print *getOutput() { return p_print; }
158+
159+
protected:
160+
AMRNB amr;
161+
AMRNB::Mode mode;
162+
SingleBuffer<uint8_t> buffer{0};
163+
Print *p_print = nullptr;
164+
};
165+
166+
} // namespace audio_tools
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
#pragma once
2+
#include "AMRWB.h" // https://github.com/pschatzmann/codec-amr
3+
#include "AudioTools/AudioCodecs/AudioCodecsBase.h"
4+
5+
namespace audio_tools {
6+
7+
/**
8+
* @brief AMR Wideband Decoder
9+
* See https://github.com/pschatzmann/codec-amr
10+
* @ingroup codecs
11+
* @ingroup decoder
12+
* @author Phil Schatzmann
13+
* @copyright GPLv3
14+
*/
15+
16+
class AMRWBDecoder : public AudioDecoder {
17+
public:
18+
AMRWBDecoder(AMRWB::Mode mode) {
19+
setMode(mode);
20+
info.channels = 1;
21+
info.sample_rate = 16000;
22+
}
23+
24+
~AMRWBDecoder() override = default;
25+
26+
bool begin() {
27+
notifyAudioChange(audioInfo());
28+
buffer.resize(amr.getEncodedFrameSizeBytes());
29+
return getOutput() != nullptr;
30+
}
31+
32+
void setAudioInfo(AudioInfo from) {
33+
if (from.bits_per_sample != 16) {
34+
LOGE("Invalid bits per sample: %d", from.bits_per_sample);
35+
}
36+
if (from.sample_rate != 8000) {
37+
LOGE("Invalid sample rate: %d", from.sample_rate);
38+
}
39+
if (from.channels != 1) {
40+
LOGE("Invalid channels: %d", from.channels);
41+
}
42+
}
43+
44+
size_t write(const uint8_t *data, size_t len) override {
45+
for (size_t j = 0; j < len; j++) {
46+
buffer.write(data[j]);
47+
if (buffer.isFull()) {
48+
int result_samples = amr.getFrameSizeSamples();
49+
int16_t result[result_samples];
50+
int size = amr.decode(buffer.data(), buffer.size(), result,
51+
result_samples);
52+
if (size > 0) {
53+
if (getOutput() != nullptr) {
54+
getOutput()->write((uint8_t *)result, size * sizeof(int16_t));
55+
}
56+
}
57+
buffer.clear();
58+
}
59+
}
60+
return len;
61+
}
62+
63+
/// Provides the block size (size of encoded frame)
64+
int blickSize() {
65+
return amr.getEncodedFrameSizeBytes();
66+
}
67+
68+
/// Provides the frame size (size of decoded frame)
69+
int frameSize() {
70+
return amr.getFrameSizeSamples() * sizeof(int16_t);
71+
}
72+
73+
void setMode(AMRWB::Mode mode) {
74+
this->mode = mode;
75+
amr.setMode(mode);
76+
}
77+
78+
protected:
79+
AMRWB amr;
80+
AMRWB::Mode mode;
81+
SingleBuffer<uint8_t> buffer{0};
82+
};
83+
84+
/**
85+
* @brief AMR Wideband Encoder
86+
* See https://github.com/pschatzmann/codec-amr
87+
* @ingroup codecs
88+
* @ingroup decoder
89+
* @author Phil Schatzmann
90+
* @copyright GPLv3
91+
*/
92+
93+
class AMRWBEncoder : public AudioEncoder {
94+
public:
95+
AMRWBEncoder(AMRWB::Mode mode) {
96+
setMode(mode);
97+
info.channels = 1;
98+
info.sample_rate = 16000;
99+
}
100+
101+
~AMRWBEncoder() override = default;
102+
103+
void setMode(AMRWB::Mode mode) {
104+
this->mode = mode;
105+
amr.setMode(mode);
106+
}
107+
108+
bool begin() {
109+
buffer.resize(frameSize());
110+
return getOutput() != nullptr;
111+
}
112+
113+
void setAudioInfo(AudioInfo from) {
114+
if (from.bits_per_sample != 16) {
115+
LOGE("Invalid bits per sample: %d", from.bits_per_sample);
116+
}
117+
if (from.sample_rate != 8000) {
118+
LOGE("Invalid sample rate: %d", from.sample_rate);
119+
}
120+
if (from.channels != 1) {
121+
LOGE("Invalid channels: %d", from.channels);
122+
}
123+
}
124+
125+
size_t write(const uint8_t *data, size_t len) override {
126+
for (size_t j = 0; j < len; j++) {
127+
buffer.write(data[j]);
128+
if (buffer.isFull()) {
129+
int result_bytes = blockSize();
130+
uint8_t result[result_bytes];
131+
int size = amr.encode((int16_t *)buffer.data(),
132+
buffer.size() / sizeof(int16_t), result,
133+
result_bytes);
134+
if (size > 0) {
135+
if (getOutput() != nullptr) {
136+
getOutput()->write(result, size);
137+
}
138+
}
139+
buffer.clear();
140+
}
141+
}
142+
return len;
143+
}
144+
145+
/// Provides the block size (size of encoded frame)
146+
int blockSize() {
147+
amr.setMode(mode);
148+
return amr.getEncodedFrameSizeBytes();
149+
}
150+
151+
/// Provides the frame size (size of decoded frame)
152+
int frameSize() {
153+
return amr.getFrameSizeSamples() * sizeof(int16_t);
154+
}
155+
156+
const char *mime() { return "audio/amr"; }
157+
158+
void setOutput(Print &out_stream) override { p_print = &out_stream; }
159+
160+
Print *getOutput() { return p_print; }
161+
162+
protected:
163+
AMRWB amr;
164+
AMRWB::Mode mode;
165+
SingleBuffer<uint8_t> buffer{0};
166+
Print *p_print = nullptr;
167+
};
168+
169+
} // namespace audio_tools

0 commit comments

Comments
 (0)