RTP: refactor native audio codec.

Change-Id: Ie4e09e221c71e3b7d7ec48fbb897335f8048181c
diff --git a/src/jni/rtp_jni/AudioCodec.cpp b/src/jni/rtp_jni/AudioCodec.cpp
new file mode 100644
index 0000000..ddd07fc
--- /dev/null
+++ b/src/jni/rtp_jni/AudioCodec.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyrightm (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string.h>
+
+#include "AudioCodec.h"
+
+namespace {
+
+int8_t gExponents[128] = {
+    0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+};
+
+//------------------------------------------------------------------------------
+
+class UlawCodec : public AudioCodec
+{
+public:
+    bool set(int sampleRate, int sampleCount) {
+        mSampleCount = sampleCount;
+        return sampleCount > 0;
+    }
+    int encode(void *payload, int16_t *samples);
+    int decode(int16_t *samples, void *payload, int length);
+private:
+    int mSampleCount;
+};
+
+int UlawCodec::encode(void *payload, int16_t *samples)
+{
+    int8_t *ulaws = (int8_t *)payload;
+    for (int i = 0; i < mSampleCount; ++i) {
+        int sample = samples[i];
+        int sign = (sample >> 8) & 0x80;
+        if (sample < 0) {
+            sample = -sample;
+        }
+        sample += 132;
+        if (sample > 32767) {
+            sample = 32767;
+        }
+        int exponent = gExponents[sample >> 8];
+        int mantissa = (sample >> (exponent + 3)) & 0x0F;
+        ulaws[i] = ~(sign | (exponent << 4) | mantissa);
+    }
+    return mSampleCount;
+}
+
+int UlawCodec::decode(int16_t *samples, void *payload, int length)
+{
+    int8_t *ulaws = (int8_t *)payload;
+    for (int i = 0; i < length; ++i) {
+        int ulaw = ~ulaws[i];
+        int exponent = (ulaw >> 4) & 0x07;
+        int mantissa = ulaw & 0x0F;
+        int sample = (((mantissa << 3) + 132) << exponent) - 132;
+        samples[i] = (ulaw < 0 ? -sample : sample);
+    }
+    return length;
+}
+
+AudioCodec *newUlawCodec()
+{
+    return new UlawCodec;
+}
+
+//------------------------------------------------------------------------------
+
+class AlawCodec : public AudioCodec
+{
+public:
+    bool set(int sampleRate, int sampleCount) {
+        mSampleCount = sampleCount;
+        return sampleCount > 0;
+    }
+    int encode(void *payload, int16_t *samples);
+    int decode(int16_t *samples, void *payload, int length);
+private:
+    int mSampleCount;
+};
+
+int AlawCodec::encode(void *payload, int16_t *samples)
+{
+    int8_t *alaws = (int8_t *)payload;
+    for (int i = 0; i < mSampleCount; ++i) {
+        int sample = samples[i];
+        int sign = (sample >> 8) & 0x80;
+        if (sample < 0) {
+            sample = -sample;
+        }
+        if (sample > 32767) {
+            sample = 32767;
+        }
+        int exponent = gExponents[sample >> 8];
+        int mantissa = (sample >> (exponent == 0 ? 4 : exponent + 3)) & 0x0F;
+        alaws[i] = (sign | (exponent << 4) | mantissa) ^ 0xD5;
+    }
+    return mSampleCount;
+}
+
+int AlawCodec::decode(int16_t *samples, void *payload, int length)
+{
+    int8_t *alaws = (int8_t *)payload;
+    for (int i = 0; i < length; ++i) {
+        int alaw = alaws[i] ^ 0x55;
+        int exponent = (alaw >> 4) & 0x07;
+        int mantissa = alaw & 0x0F;
+        int sample = (exponent == 0 ? (mantissa << 4) + 8 :
+            ((mantissa << 3) + 132) << exponent);
+        samples[i] = (alaw < 0 ? sample : -sample);
+    }
+    return length;
+}
+
+AudioCodec *newAlawCodec()
+{
+    return new AlawCodec;
+}
+
+struct AudioCodecType {
+    const char *name;
+    AudioCodec *(*create)();
+} gAudioCodecTypes[] = {
+    {"PCMA", newAlawCodec},
+    {"PCMU", newUlawCodec},
+    {NULL, NULL},
+};
+
+} // namespace
+
+AudioCodec *newAudioCodec(const char *codecName)
+{
+    AudioCodecType *type = gAudioCodecTypes;
+    while (type->name != NULL) {
+        if (strcmp(codecName, type->name) == 0) {
+            return type->create();
+        }
+        ++type;
+    }
+    return NULL;
+}
diff --git a/src/jni/rtp_jni/AudioCodec.h b/src/jni/rtp_jni/AudioCodec.h
new file mode 100644
index 0000000..797494c
--- /dev/null
+++ b/src/jni/rtp_jni/AudioCodec.h
@@ -0,0 +1,36 @@
+/*
+ * Copyrightm (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#ifndef __AUDIO_CODEC_H__
+#define __AUDIO_CODEC_H__
+
+class AudioCodec
+{
+public:
+    virtual ~AudioCodec() {}
+    // Returns true if initialization succeeds.
+    virtual bool set(int sampleRate, int sampleCount) = 0;
+    // Returns the length of payload in bytes.
+    virtual int encode(void *payload, int16_t *samples) = 0;
+    // Returns the number of decoded samples.
+    virtual int decode(int16_t *samples, void *payload, int length) = 0;
+};
+
+AudioCodec *newAudioCodec(const char *codecName);
+
+#endif