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
0 commit comments