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