Loading voip/java/android/net/rtp/AudioCodec.java +1 −2 Original line number Diff line number Diff line Loading @@ -80,8 +80,7 @@ public class AudioCodec { */ public static final AudioCodec AMR = new AudioCodec(97, "AMR/8000", null); // TODO: add rest of the codecs when the native part is done. private static final AudioCodec[] sCodecs = {GSM_EFR, GSM, PCMU, PCMA}; private static final AudioCodec[] sCodecs = {GSM_EFR, AMR, GSM, PCMU, PCMA}; private AudioCodec(int type, String rtpmap, String fmtp) { this.type = type; Loading voip/jni/rtp/AmrCodec.cpp +171 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ * limitations under the License. */ #include <string.h> #include "AudioCodec.h" #include "gsmamr_dec.h" Loading @@ -21,6 +23,170 @@ namespace { const int gFrameBits[8] = {95, 103, 118, 134, 148, 159, 204, 244}; //------------------------------------------------------------------------------ // See RFC 4867 for the encoding details. class AmrCodec : public AudioCodec { public: AmrCodec() { if (AMREncodeInit(&mEncoder, &mSidSync, false)) { mEncoder = NULL; } if (GSMInitDecode(&mDecoder, (Word8 *)"RTP")) { mDecoder = NULL; } } ~AmrCodec() { if (mEncoder) { AMREncodeExit(&mEncoder, &mSidSync); } if (mDecoder) { GSMDecodeFrameExit(&mDecoder); } } int set(int sampleRate, const char *fmtp); int encode(void *payload, int16_t *samples); int decode(int16_t *samples, void *payload, int length); private: void *mEncoder; void *mSidSync; void *mDecoder; int mMode; int mModeSet; bool mOctetAligned; }; int AmrCodec::set(int sampleRate, const char *fmtp) { // These parameters are not supported. if (strcasestr(fmtp, "crc=1") || strcasestr(fmtp, "robust-sorting=1") || strcasestr(fmtp, "interleaving=")) { return -1; } // Handle mode-set and octet-align. char *modes = strcasestr(fmtp, "mode-set="); if (modes) { mMode = 0; mModeSet = 0; for (char c = *modes; c && c != ' '; c = *++modes) { if (c >= '0' && c <= '7') { int mode = c - '0'; if (mode > mMode) { mMode = mode; } mModeSet |= 1 << mode; } } } else { mMode = 7; mModeSet = 0xFF; } mOctetAligned = (strcasestr(fmtp, "octet-align=1") != NULL); // TODO: handle mode-change-*. return (sampleRate == 8000 && mEncoder && mDecoder) ? 160 : -1; } int AmrCodec::encode(void *payload, int16_t *samples) { unsigned char *bytes = (unsigned char *)payload; Frame_Type_3GPP type; int length = AMREncode(mEncoder, mSidSync, (Mode)mMode, samples, bytes + 1, &type, AMR_TX_WMF); if (type != mMode || length != (8 + gFrameBits[mMode] + 7) >> 3) { return -1; } if (mOctetAligned) { bytes[0] = 0xF0; bytes[1] = (mMode << 3) | 0x04; ++length; } else { // CMR = 15 (4-bit), F = 0 (1-bit), FT = mMode (4-bit), Q = 1 (1-bit). bytes[0] = 0xFF; bytes[1] = 0xC0 | (mMode << 1) | 1; // Shift left 6 bits and update the length. bytes[length + 1] = 0; for (int i = 0; i <= length; ++i) { bytes[i] = (bytes[i] << 6) | (bytes[i + 1] >> 2); } length = (10 + gFrameBits[mMode] + 7) >> 3; } return length; } int AmrCodec::decode(int16_t *samples, void *payload, int length) { unsigned char *bytes = (unsigned char *)payload; Frame_Type_3GPP type; if (length < 2) { return -1; } int request = bytes[0] >> 4; if (mOctetAligned) { if ((bytes[1] & 0xC4) != 0x04) { return -1; } type = (Frame_Type_3GPP)(bytes[1] >> 3); if (length != (16 + gFrameBits[type] + 7) >> 3) { return -1; } length -= 2; bytes += 2; } else { if ((bytes[0] & 0x0C) || !(bytes[1] & 0x40)) { return -1; } type = (Frame_Type_3GPP)((bytes[0] << 1 | bytes[1] >> 7) & 0x07); if (length != (10 + gFrameBits[type] + 7) >> 3) { return -1; } // Shift left 2 bits and update the length. --length; for (int i = 1; i < length; ++i) { bytes[i] = (bytes[i] << 2) | (bytes[i + 1] >> 6); } bytes[length] <<= 2; length = (gFrameBits[type] + 7) >> 3; ++bytes; } if (AMRDecode(mDecoder, type, bytes, samples, MIME_IETF) != length) { return -1; } // Handle CMR if (request < 8 && request != mMode) { for (int i = request; i >= 0; --i) { if (mModeSet & (1 << i)) { mMode = request; break; } } } return 160; } //------------------------------------------------------------------------------ // See RFC 3551 for the encoding details. class GsmEfrCodec : public AudioCodec { public: Loading Loading @@ -91,6 +257,11 @@ int GsmEfrCodec::decode(int16_t *samples, void *payload, int length) } // namespace AudioCodec *newAmrCodec() { return new AmrCodec; } AudioCodec *newGsmEfrCodec() { return new GsmEfrCodec; Loading voip/jni/rtp/AudioCodec.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ extern AudioCodec *newAlawCodec(); extern AudioCodec *newUlawCodec(); extern AudioCodec *newGsmCodec(); extern AudioCodec *newAmrCodec(); extern AudioCodec *newGsmEfrCodec(); struct AudioCodecType { Loading @@ -30,6 +31,7 @@ struct AudioCodecType { {"PCMA", newAlawCodec}, {"PCMU", newUlawCodec}, {"GSM", newGsmCodec}, {"AMR", newAmrCodec}, {"GSM-EFR", newGsmEfrCodec}, {NULL, NULL}, }; Loading Loading
voip/java/android/net/rtp/AudioCodec.java +1 −2 Original line number Diff line number Diff line Loading @@ -80,8 +80,7 @@ public class AudioCodec { */ public static final AudioCodec AMR = new AudioCodec(97, "AMR/8000", null); // TODO: add rest of the codecs when the native part is done. private static final AudioCodec[] sCodecs = {GSM_EFR, GSM, PCMU, PCMA}; private static final AudioCodec[] sCodecs = {GSM_EFR, AMR, GSM, PCMU, PCMA}; private AudioCodec(int type, String rtpmap, String fmtp) { this.type = type; Loading
voip/jni/rtp/AmrCodec.cpp +171 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ * limitations under the License. */ #include <string.h> #include "AudioCodec.h" #include "gsmamr_dec.h" Loading @@ -21,6 +23,170 @@ namespace { const int gFrameBits[8] = {95, 103, 118, 134, 148, 159, 204, 244}; //------------------------------------------------------------------------------ // See RFC 4867 for the encoding details. class AmrCodec : public AudioCodec { public: AmrCodec() { if (AMREncodeInit(&mEncoder, &mSidSync, false)) { mEncoder = NULL; } if (GSMInitDecode(&mDecoder, (Word8 *)"RTP")) { mDecoder = NULL; } } ~AmrCodec() { if (mEncoder) { AMREncodeExit(&mEncoder, &mSidSync); } if (mDecoder) { GSMDecodeFrameExit(&mDecoder); } } int set(int sampleRate, const char *fmtp); int encode(void *payload, int16_t *samples); int decode(int16_t *samples, void *payload, int length); private: void *mEncoder; void *mSidSync; void *mDecoder; int mMode; int mModeSet; bool mOctetAligned; }; int AmrCodec::set(int sampleRate, const char *fmtp) { // These parameters are not supported. if (strcasestr(fmtp, "crc=1") || strcasestr(fmtp, "robust-sorting=1") || strcasestr(fmtp, "interleaving=")) { return -1; } // Handle mode-set and octet-align. char *modes = strcasestr(fmtp, "mode-set="); if (modes) { mMode = 0; mModeSet = 0; for (char c = *modes; c && c != ' '; c = *++modes) { if (c >= '0' && c <= '7') { int mode = c - '0'; if (mode > mMode) { mMode = mode; } mModeSet |= 1 << mode; } } } else { mMode = 7; mModeSet = 0xFF; } mOctetAligned = (strcasestr(fmtp, "octet-align=1") != NULL); // TODO: handle mode-change-*. return (sampleRate == 8000 && mEncoder && mDecoder) ? 160 : -1; } int AmrCodec::encode(void *payload, int16_t *samples) { unsigned char *bytes = (unsigned char *)payload; Frame_Type_3GPP type; int length = AMREncode(mEncoder, mSidSync, (Mode)mMode, samples, bytes + 1, &type, AMR_TX_WMF); if (type != mMode || length != (8 + gFrameBits[mMode] + 7) >> 3) { return -1; } if (mOctetAligned) { bytes[0] = 0xF0; bytes[1] = (mMode << 3) | 0x04; ++length; } else { // CMR = 15 (4-bit), F = 0 (1-bit), FT = mMode (4-bit), Q = 1 (1-bit). bytes[0] = 0xFF; bytes[1] = 0xC0 | (mMode << 1) | 1; // Shift left 6 bits and update the length. bytes[length + 1] = 0; for (int i = 0; i <= length; ++i) { bytes[i] = (bytes[i] << 6) | (bytes[i + 1] >> 2); } length = (10 + gFrameBits[mMode] + 7) >> 3; } return length; } int AmrCodec::decode(int16_t *samples, void *payload, int length) { unsigned char *bytes = (unsigned char *)payload; Frame_Type_3GPP type; if (length < 2) { return -1; } int request = bytes[0] >> 4; if (mOctetAligned) { if ((bytes[1] & 0xC4) != 0x04) { return -1; } type = (Frame_Type_3GPP)(bytes[1] >> 3); if (length != (16 + gFrameBits[type] + 7) >> 3) { return -1; } length -= 2; bytes += 2; } else { if ((bytes[0] & 0x0C) || !(bytes[1] & 0x40)) { return -1; } type = (Frame_Type_3GPP)((bytes[0] << 1 | bytes[1] >> 7) & 0x07); if (length != (10 + gFrameBits[type] + 7) >> 3) { return -1; } // Shift left 2 bits and update the length. --length; for (int i = 1; i < length; ++i) { bytes[i] = (bytes[i] << 2) | (bytes[i + 1] >> 6); } bytes[length] <<= 2; length = (gFrameBits[type] + 7) >> 3; ++bytes; } if (AMRDecode(mDecoder, type, bytes, samples, MIME_IETF) != length) { return -1; } // Handle CMR if (request < 8 && request != mMode) { for (int i = request; i >= 0; --i) { if (mModeSet & (1 << i)) { mMode = request; break; } } } return 160; } //------------------------------------------------------------------------------ // See RFC 3551 for the encoding details. class GsmEfrCodec : public AudioCodec { public: Loading Loading @@ -91,6 +257,11 @@ int GsmEfrCodec::decode(int16_t *samples, void *payload, int length) } // namespace AudioCodec *newAmrCodec() { return new AmrCodec; } AudioCodec *newGsmEfrCodec() { return new GsmEfrCodec; Loading
voip/jni/rtp/AudioCodec.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ extern AudioCodec *newAlawCodec(); extern AudioCodec *newUlawCodec(); extern AudioCodec *newGsmCodec(); extern AudioCodec *newAmrCodec(); extern AudioCodec *newGsmEfrCodec(); struct AudioCodecType { Loading @@ -30,6 +31,7 @@ struct AudioCodecType { {"PCMA", newAlawCodec}, {"PCMU", newUlawCodec}, {"GSM", newGsmCodec}, {"AMR", newAmrCodec}, {"GSM-EFR", newGsmEfrCodec}, {NULL, NULL}, }; Loading