blob: 84c7166477b4c2aec62197d74d664c25ca65b4e4 [file] [log] [blame]
Chia-chi Yehf4ae9422010-09-30 03:04:06 +08001/*
2 * Copyrightm (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Chia-chi Yehf88fc1f2010-09-30 08:51:59 +080017#include <string.h>
18
Chia-chi Yehf4ae9422010-09-30 03:04:06 +080019#include "AudioCodec.h"
20
21#include "gsmamr_dec.h"
22#include "gsmamr_enc.h"
23
24namespace {
25
Chia-chi Yehf88fc1f2010-09-30 08:51:59 +080026const int gFrameBits[8] = {95, 103, 118, 134, 148, 159, 204, 244};
27
28//------------------------------------------------------------------------------
29
30// See RFC 4867 for the encoding details.
31
32class AmrCodec : public AudioCodec
33{
34public:
35 AmrCodec() {
36 if (AMREncodeInit(&mEncoder, &mSidSync, false)) {
37 mEncoder = NULL;
38 }
39 if (GSMInitDecode(&mDecoder, (Word8 *)"RTP")) {
40 mDecoder = NULL;
41 }
42 }
43
44 ~AmrCodec() {
45 if (mEncoder) {
46 AMREncodeExit(&mEncoder, &mSidSync);
47 }
48 if (mDecoder) {
49 GSMDecodeFrameExit(&mDecoder);
50 }
51 }
52
53 int set(int sampleRate, const char *fmtp);
54 int encode(void *payload, int16_t *samples);
55 int decode(int16_t *samples, void *payload, int length);
56
57private:
58 void *mEncoder;
59 void *mSidSync;
60 void *mDecoder;
61
62 int mMode;
63 int mModeSet;
64 bool mOctetAligned;
65};
66
67int AmrCodec::set(int sampleRate, const char *fmtp)
68{
69 // These parameters are not supported.
70 if (strcasestr(fmtp, "crc=1") || strcasestr(fmtp, "robust-sorting=1") ||
71 strcasestr(fmtp, "interleaving=")) {
72 return -1;
73 }
74
75 // Handle mode-set and octet-align.
Chia-chi Yeh53aa6ef2010-11-30 13:10:31 +080076 const char *modes = strcasestr(fmtp, "mode-set=");
Chia-chi Yehf88fc1f2010-09-30 08:51:59 +080077 if (modes) {
78 mMode = 0;
79 mModeSet = 0;
80 for (char c = *modes; c && c != ' '; c = *++modes) {
81 if (c >= '0' && c <= '7') {
82 int mode = c - '0';
83 if (mode > mMode) {
84 mMode = mode;
85 }
86 mModeSet |= 1 << mode;
87 }
88 }
89 } else {
90 mMode = 7;
91 mModeSet = 0xFF;
92 }
93 mOctetAligned = (strcasestr(fmtp, "octet-align=1") != NULL);
94
95 // TODO: handle mode-change-*.
96
97 return (sampleRate == 8000 && mEncoder && mDecoder) ? 160 : -1;
98}
99
100int AmrCodec::encode(void *payload, int16_t *samples)
101{
102 unsigned char *bytes = (unsigned char *)payload;
103 Frame_Type_3GPP type;
104
105 int length = AMREncode(mEncoder, mSidSync, (Mode)mMode,
106 samples, bytes + 1, &type, AMR_TX_WMF);
107
108 if (type != mMode || length != (8 + gFrameBits[mMode] + 7) >> 3) {
109 return -1;
110 }
111
112 if (mOctetAligned) {
113 bytes[0] = 0xF0;
114 bytes[1] = (mMode << 3) | 0x04;
115 ++length;
116 } else {
117 // CMR = 15 (4-bit), F = 0 (1-bit), FT = mMode (4-bit), Q = 1 (1-bit).
118 bytes[0] = 0xFF;
119 bytes[1] = 0xC0 | (mMode << 1) | 1;
120
121 // Shift left 6 bits and update the length.
122 bytes[length + 1] = 0;
123 for (int i = 0; i <= length; ++i) {
124 bytes[i] = (bytes[i] << 6) | (bytes[i + 1] >> 2);
125 }
126 length = (10 + gFrameBits[mMode] + 7) >> 3;
127 }
128 return length;
129}
130
131int AmrCodec::decode(int16_t *samples, void *payload, int length)
132{
133 unsigned char *bytes = (unsigned char *)payload;
134 Frame_Type_3GPP type;
135 if (length < 2) {
136 return -1;
137 }
138 int request = bytes[0] >> 4;
139
140 if (mOctetAligned) {
141 if ((bytes[1] & 0xC4) != 0x04) {
142 return -1;
143 }
144 type = (Frame_Type_3GPP)(bytes[1] >> 3);
145 if (length != (16 + gFrameBits[type] + 7) >> 3) {
146 return -1;
147 }
148 length -= 2;
149 bytes += 2;
150 } else {
151 if ((bytes[0] & 0x0C) || !(bytes[1] & 0x40)) {
152 return -1;
153 }
154 type = (Frame_Type_3GPP)((bytes[0] << 1 | bytes[1] >> 7) & 0x07);
155 if (length != (10 + gFrameBits[type] + 7) >> 3) {
156 return -1;
157 }
158
159 // Shift left 2 bits and update the length.
160 --length;
161 for (int i = 1; i < length; ++i) {
162 bytes[i] = (bytes[i] << 2) | (bytes[i + 1] >> 6);
163 }
164 bytes[length] <<= 2;
165 length = (gFrameBits[type] + 7) >> 3;
166 ++bytes;
167 }
168
169 if (AMRDecode(mDecoder, type, bytes, samples, MIME_IETF) != length) {
170 return -1;
171 }
172
173 // Handle CMR
174 if (request < 8 && request != mMode) {
175 for (int i = request; i >= 0; --i) {
176 if (mModeSet & (1 << i)) {
177 mMode = request;
178 break;
179 }
180 }
181 }
182
183 return 160;
184}
185
186//------------------------------------------------------------------------------
187
188// See RFC 3551 for the encoding details.
189
Chia-chi Yehf4ae9422010-09-30 03:04:06 +0800190class GsmEfrCodec : public AudioCodec
191{
192public:
193 GsmEfrCodec() {
194 if (AMREncodeInit(&mEncoder, &mSidSync, false)) {
195 mEncoder = NULL;
196 }
197 if (GSMInitDecode(&mDecoder, (Word8 *)"RTP")) {
198 mDecoder = NULL;
199 }
200 }
201
202 ~GsmEfrCodec() {
203 if (mEncoder) {
204 AMREncodeExit(&mEncoder, &mSidSync);
205 }
206 if (mDecoder) {
207 GSMDecodeFrameExit(&mDecoder);
208 }
209 }
210
211 int set(int sampleRate, const char *fmtp) {
212 return (sampleRate == 8000 && mEncoder && mDecoder) ? 160 : -1;
213 }
214
215 int encode(void *payload, int16_t *samples);
216 int decode(int16_t *samples, void *payload, int length);
217
218private:
219 void *mEncoder;
220 void *mSidSync;
221 void *mDecoder;
222};
223
224int GsmEfrCodec::encode(void *payload, int16_t *samples)
225{
226 unsigned char *bytes = (unsigned char *)payload;
227 Frame_Type_3GPP type;
228
229 int length = AMREncode(mEncoder, mSidSync, MR122,
230 samples, bytes, &type, AMR_TX_WMF);
231
232 if (type == AMR_122 && length == 32) {
233 bytes[0] = 0xC0 | (bytes[1] >> 4);
234 for (int i = 1; i < 31; ++i) {
235 bytes[i] = (bytes[i] << 4) | (bytes[i + 1] >> 4);
236 }
237 return 31;
238 }
239 return -1;
240}
241
242int GsmEfrCodec::decode(int16_t *samples, void *payload, int length)
243{
244 unsigned char *bytes = (unsigned char *)payload;
245 if (length == 31 && (bytes[0] >> 4) == 0x0C) {
246 for (int i = 0; i < 30; ++i) {
247 bytes[i] = (bytes[i] << 4) | (bytes[i + 1] >> 4);
248 }
249 bytes[30] <<= 4;
250
251 if (AMRDecode(mDecoder, AMR_122, bytes, samples, MIME_IETF) == 31) {
252 return 160;
253 }
254 }
255 return -1;
256}
257
258} // namespace
259
Chia-chi Yehf88fc1f2010-09-30 08:51:59 +0800260AudioCodec *newAmrCodec()
261{
262 return new AmrCodec;
263}
264
Chia-chi Yehf4ae9422010-09-30 03:04:06 +0800265AudioCodec *newGsmEfrCodec()
266{
267 return new GsmEfrCodec;
268}