1ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh/*
2ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh * Copyrightm (C) 2010 The Android Open Source Project
3ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh *
4ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh * Licensed under the Apache License, Version 2.0 (the "License");
5ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh * you may not use this file except in compliance with the License.
6ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh * You may obtain a copy of the License at
7ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh *
8ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh *      http://www.apache.org/licenses/LICENSE-2.0
9ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh *
10ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh * Unless required by applicable law or agreed to in writing, software
11ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh * distributed under the License is distributed on an "AS IS" BASIS,
12ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh * See the License for the specific language governing permissions and
14ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh * limitations under the License.
15ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh */
16ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh
172437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh#include <string.h>
182437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
19ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh#include "AudioCodec.h"
20ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh
21ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh#include "gsmamr_dec.h"
22ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh#include "gsmamr_enc.h"
23ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh
24ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yehnamespace {
25ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh
262437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yehconst int gFrameBits[8] = {95, 103, 118, 134, 148, 159, 204, 244};
272437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
282437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh//------------------------------------------------------------------------------
292437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
302437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh// See RFC 4867 for the encoding details.
312437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
322437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yehclass AmrCodec : public AudioCodec
332437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh{
342437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yehpublic:
352437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    AmrCodec() {
362437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        if (AMREncodeInit(&mEncoder, &mSidSync, false)) {
372437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh            mEncoder = NULL;
382437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        }
392437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        if (GSMInitDecode(&mDecoder, (Word8 *)"RTP")) {
402437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh            mDecoder = NULL;
412437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        }
422437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    }
432437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
442437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    ~AmrCodec() {
452437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        if (mEncoder) {
462437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh            AMREncodeExit(&mEncoder, &mSidSync);
472437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        }
482437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        if (mDecoder) {
492437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh            GSMDecodeFrameExit(&mDecoder);
502437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        }
512437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    }
522437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
532437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    int set(int sampleRate, const char *fmtp);
542437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    int encode(void *payload, int16_t *samples);
55418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yeh    int decode(int16_t *samples, int count, void *payload, int length);
562437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
572437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yehprivate:
582437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    void *mEncoder;
592437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    void *mSidSync;
602437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    void *mDecoder;
612437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
622437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    int mMode;
632437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    int mModeSet;
642437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    bool mOctetAligned;
652437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh};
662437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
672437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yehint AmrCodec::set(int sampleRate, const char *fmtp)
682437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh{
692437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    // These parameters are not supported.
702437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    if (strcasestr(fmtp, "crc=1") || strcasestr(fmtp, "robust-sorting=1") ||
712437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        strcasestr(fmtp, "interleaving=")) {
722437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        return -1;
732437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    }
742437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
752437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    // Handle mode-set and octet-align.
76a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh    const char *modes = strcasestr(fmtp, "mode-set=");
772437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    if (modes) {
782437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        mMode = 0;
792437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        mModeSet = 0;
802437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        for (char c = *modes; c && c != ' '; c = *++modes) {
812437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh            if (c >= '0' && c <= '7') {
822437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh                int mode = c - '0';
832437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh                if (mode > mMode) {
842437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh                    mMode = mode;
852437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh                }
862437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh                mModeSet |= 1 << mode;
872437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh            }
882437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        }
892437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    } else {
902437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        mMode = 7;
912437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        mModeSet = 0xFF;
922437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    }
932437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    mOctetAligned = (strcasestr(fmtp, "octet-align=1") != NULL);
942437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
952437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    // TODO: handle mode-change-*.
962437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
972437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    return (sampleRate == 8000 && mEncoder && mDecoder) ? 160 : -1;
982437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh}
992437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
1002437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yehint AmrCodec::encode(void *payload, int16_t *samples)
1012437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh{
1022437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    unsigned char *bytes = (unsigned char *)payload;
1032437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    Frame_Type_3GPP type;
1042437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
1052437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    int length = AMREncode(mEncoder, mSidSync, (Mode)mMode,
1062437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        samples, bytes + 1, &type, AMR_TX_WMF);
1072437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
1082437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    if (type != mMode || length != (8 + gFrameBits[mMode] + 7) >> 3) {
1092437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        return -1;
1102437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    }
1112437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
1122437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    if (mOctetAligned) {
1132437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        bytes[0] = 0xF0;
1142437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        bytes[1] = (mMode << 3) | 0x04;
1152437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        ++length;
1162437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    } else {
1172437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        // CMR = 15 (4-bit), F = 0 (1-bit), FT = mMode (4-bit), Q = 1 (1-bit).
1182437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        bytes[0] = 0xFF;
1192437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        bytes[1] = 0xC0 | (mMode << 1) | 1;
1202437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
1212437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        // Shift left 6 bits and update the length.
1222437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        bytes[length + 1] = 0;
1232437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        for (int i = 0; i <= length; ++i) {
1242437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh            bytes[i] = (bytes[i] << 6) | (bytes[i + 1] >> 2);
1252437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        }
1262437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        length = (10 + gFrameBits[mMode] + 7) >> 3;
1272437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    }
1282437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    return length;
1292437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh}
1302437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
131418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yehint AmrCodec::decode(int16_t *samples, int count, void *payload, int length)
1322437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh{
1332437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    unsigned char *bytes = (unsigned char *)payload;
1342437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    Frame_Type_3GPP type;
1352437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    if (length < 2) {
1362437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        return -1;
1372437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    }
1382437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    int request = bytes[0] >> 4;
1392437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
1402437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    if (mOctetAligned) {
1412437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        if ((bytes[1] & 0xC4) != 0x04) {
1422437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh            return -1;
1432437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        }
1442437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        type = (Frame_Type_3GPP)(bytes[1] >> 3);
1452437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        if (length != (16 + gFrameBits[type] + 7) >> 3) {
1462437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh            return -1;
1472437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        }
1482437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        length -= 2;
1492437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        bytes += 2;
1502437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    } else {
1512437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        if ((bytes[0] & 0x0C) || !(bytes[1] & 0x40)) {
1522437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh            return -1;
1532437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        }
1542437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        type = (Frame_Type_3GPP)((bytes[0] << 1 | bytes[1] >> 7) & 0x07);
1552437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        if (length != (10 + gFrameBits[type] + 7) >> 3) {
1562437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh            return -1;
1572437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        }
1582437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
1592437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        // Shift left 2 bits and update the length.
1602437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        --length;
1612437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        for (int i = 1; i < length; ++i) {
1622437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh            bytes[i] = (bytes[i] << 2) | (bytes[i + 1] >> 6);
1632437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        }
1642437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        bytes[length] <<= 2;
1652437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        length = (gFrameBits[type] + 7) >> 3;
1662437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        ++bytes;
1672437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    }
1682437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
1692437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    if (AMRDecode(mDecoder, type, bytes, samples, MIME_IETF) != length) {
1702437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        return -1;
1712437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    }
1722437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
1732437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    // Handle CMR
1742437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    if (request < 8 && request != mMode) {
1752437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        for (int i = request; i >= 0; --i) {
1762437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh            if (mModeSet & (1 << i)) {
1772437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh                mMode = request;
1782437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh                break;
1792437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh            }
1802437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh        }
1812437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    }
1822437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
1832437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    return 160;
1842437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh}
1852437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
1862437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh//------------------------------------------------------------------------------
1872437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
1882437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh// See RFC 3551 for the encoding details.
1892437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
190ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yehclass GsmEfrCodec : public AudioCodec
191ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh{
192ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yehpublic:
193ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh    GsmEfrCodec() {
194ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh        if (AMREncodeInit(&mEncoder, &mSidSync, false)) {
195ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh            mEncoder = NULL;
196ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh        }
197ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh        if (GSMInitDecode(&mDecoder, (Word8 *)"RTP")) {
198ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh            mDecoder = NULL;
199ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh        }
200ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh    }
201ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh
202ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh    ~GsmEfrCodec() {
203ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh        if (mEncoder) {
204ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh            AMREncodeExit(&mEncoder, &mSidSync);
205ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh        }
206ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh        if (mDecoder) {
207ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh            GSMDecodeFrameExit(&mDecoder);
208ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh        }
209ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh    }
210ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh
211ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh    int set(int sampleRate, const char *fmtp) {
212ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh        return (sampleRate == 8000 && mEncoder && mDecoder) ? 160 : -1;
213ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh    }
214ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh
215ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh    int encode(void *payload, int16_t *samples);
216418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yeh    int decode(int16_t *samples, int count, void *payload, int length);
217ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh
218ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yehprivate:
219ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh    void *mEncoder;
220ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh    void *mSidSync;
221ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh    void *mDecoder;
222ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh};
223ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh
224ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yehint GsmEfrCodec::encode(void *payload, int16_t *samples)
225ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh{
226ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh    unsigned char *bytes = (unsigned char *)payload;
227ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh    Frame_Type_3GPP type;
228ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh
229ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh    int length = AMREncode(mEncoder, mSidSync, MR122,
230ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh        samples, bytes, &type, AMR_TX_WMF);
231ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh
232ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh    if (type == AMR_122 && length == 32) {
233ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh        bytes[0] = 0xC0 | (bytes[1] >> 4);
234ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh        for (int i = 1; i < 31; ++i) {
235ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh            bytes[i] = (bytes[i] << 4) | (bytes[i + 1] >> 4);
236ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh        }
237ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh        return 31;
238ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh    }
239ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh    return -1;
240ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh}
241ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh
242418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yehint GsmEfrCodec::decode(int16_t *samples, int count, void *payload, int length)
243ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh{
244ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh    unsigned char *bytes = (unsigned char *)payload;
245418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yeh    int n = 0;
246418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yeh    while (n + 160 <= count && length >= 31 && (bytes[0] >> 4) == 0x0C) {
247ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh        for (int i = 0; i < 30; ++i) {
248ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh            bytes[i] = (bytes[i] << 4) | (bytes[i + 1] >> 4);
249ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh        }
250ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh        bytes[30] <<= 4;
251ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh
252418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yeh        if (AMRDecode(mDecoder, AMR_122, bytes, &samples[n], MIME_IETF) != 31) {
253418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yeh            break;
254ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh        }
255418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yeh        n += 160;
256418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yeh        length -= 31;
257418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yeh        bytes += 31;
258ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh    }
259418b5f04c2eb3ceff046328ba23a16b89a5a3306Chia-chi Yeh    return n;
260ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh}
261ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh
262ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh} // namespace
263ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh
2642437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi YehAudioCodec *newAmrCodec()
2652437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh{
2662437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh    return new AmrCodec;
2672437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh}
2682437b7d03ce3c0c63ffe04e15a53174d15ee8479Chia-chi Yeh
269ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi YehAudioCodec *newGsmEfrCodec()
270ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh{
271ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh    return new GsmEfrCodec;
272ac8b0e5a92e1a9abdaa543656fba0cf52ca8d786Chia-chi Yeh}
273