am 0a537b78: Merge "RTP: Enable AMR codec." into gingerbread

Merge commit '0a537b78d3fb4db86411d745b2696459d6b98ef6' into gingerbread-plus-aosp

* commit '0a537b78d3fb4db86411d745b2696459d6b98ef6':
  RTP: Enable AMR codec.
This commit is contained in:
Chia-chi Yeh
2010-09-30 10:10:02 -07:00
committed by Android Git Automerger
3 changed files with 174 additions and 2 deletions

View File

@ -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;

View File

@ -14,6 +14,8 @@
* limitations under the License.
*/
#include <string.h>
#include "AudioCodec.h"
#include "gsmamr_dec.h"
@ -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:
@ -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;

View File

@ -21,6 +21,7 @@
extern AudioCodec *newAlawCodec();
extern AudioCodec *newUlawCodec();
extern AudioCodec *newGsmCodec();
extern AudioCodec *newAmrCodec();
extern AudioCodec *newGsmEfrCodec();
struct AudioCodecType {
@ -30,6 +31,7 @@ struct AudioCodecType {
{"PCMA", newAlawCodec},
{"PCMU", newUlawCodec},
{"GSM", newGsmCodec},
{"AMR", newAmrCodec},
{"GSM-EFR", newGsmEfrCodec},
{NULL, NULL},
};