Merge "RTP: support payloads with larger packetization interval."
diff --git a/jni/rtp/AmrCodec.cpp b/jni/rtp/AmrCodec.cpp
index 84c7166..e2d820e 100644
--- a/jni/rtp/AmrCodec.cpp
+++ b/jni/rtp/AmrCodec.cpp
@@ -52,7 +52,7 @@
 
     int set(int sampleRate, const char *fmtp);
     int encode(void *payload, int16_t *samples);
-    int decode(int16_t *samples, void *payload, int length);
+    int decode(int16_t *samples, int count, void *payload, int length);
 
 private:
     void *mEncoder;
@@ -128,7 +128,7 @@
     return length;
 }
 
-int AmrCodec::decode(int16_t *samples, void *payload, int length)
+int AmrCodec::decode(int16_t *samples, int count, void *payload, int length)
 {
     unsigned char *bytes = (unsigned char *)payload;
     Frame_Type_3GPP type;
@@ -213,7 +213,7 @@
     }
 
     int encode(void *payload, int16_t *samples);
-    int decode(int16_t *samples, void *payload, int length);
+    int decode(int16_t *samples, int count, void *payload, int length);
 
 private:
     void *mEncoder;
@@ -239,20 +239,24 @@
     return -1;
 }
 
-int GsmEfrCodec::decode(int16_t *samples, void *payload, int length)
+int GsmEfrCodec::decode(int16_t *samples, int count, void *payload, int length)
 {
     unsigned char *bytes = (unsigned char *)payload;
-    if (length == 31 && (bytes[0] >> 4) == 0x0C) {
+    int n = 0;
+    while (n + 160 <= count && length >= 31 && (bytes[0] >> 4) == 0x0C) {
         for (int i = 0; i < 30; ++i) {
             bytes[i] = (bytes[i] << 4) | (bytes[i + 1] >> 4);
         }
         bytes[30] <<= 4;
 
-        if (AMRDecode(mDecoder, AMR_122, bytes, samples, MIME_IETF) == 31) {
-            return 160;
+        if (AMRDecode(mDecoder, AMR_122, bytes, &samples[n], MIME_IETF) != 31) {
+            break;
         }
+        n += 160;
+        length -= 31;
+        bytes += 31;
     }
-    return -1;
+    return n;
 }
 
 } // namespace
diff --git a/jni/rtp/AudioCodec.h b/jni/rtp/AudioCodec.h
index e389255..741730b 100644
--- a/jni/rtp/AudioCodec.h
+++ b/jni/rtp/AudioCodec.h
@@ -30,7 +30,7 @@
     // 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;
+    virtual int decode(int16_t *samples, int count, void *payload, int length) = 0;
 };
 
 AudioCodec *newAudioCodec(const char *codecName);
diff --git a/jni/rtp/AudioGroup.cpp b/jni/rtp/AudioGroup.cpp
index 5f07bb5..93c809e 100644
--- a/jni/rtp/AudioGroup.cpp
+++ b/jni/rtp/AudioGroup.cpp
@@ -395,7 +395,8 @@
         mLatencyTimer = tick;
     }
 
-    if (mBufferTail - mBufferHead > BUFFER_SIZE - mInterval) {
+    int count = (BUFFER_SIZE - (mBufferTail - mBufferHead)) * mSampleRate;
+    if (count < mSampleCount) {
         // Buffer overflow. Drop the packet.
         LOGV("stream[%d] buffer overflow", mSocket);
         recv(mSocket, &c, 1, MSG_DONTWAIT);
@@ -403,19 +404,18 @@
     }
 
     // Receive the packet and decode it.
-    int16_t samples[mSampleCount];
-    int length = 0;
+    int16_t samples[count];
     if (!mCodec) {
         // Special case for device stream.
-        length = recv(mSocket, samples, sizeof(samples),
+        count = recv(mSocket, samples, sizeof(samples),
             MSG_TRUNC | MSG_DONTWAIT) >> 1;
     } else {
         __attribute__((aligned(4))) uint8_t buffer[2048];
         sockaddr_storage remote;
-        socklen_t len = sizeof(remote);
+        socklen_t addrlen = sizeof(remote);
 
-        length = recvfrom(mSocket, buffer, sizeof(buffer),
-            MSG_TRUNC | MSG_DONTWAIT, (sockaddr *)&remote, &len);
+        int length = recvfrom(mSocket, buffer, sizeof(buffer),
+            MSG_TRUNC | MSG_DONTWAIT, (sockaddr *)&remote, &addrlen);
 
         // Do we need to check SSRC, sequence, and timestamp? They are not
         // reliable but at least they can be used to identify duplicates?
@@ -433,14 +433,15 @@
         }
         length -= offset;
         if (length >= 0) {
-            length = mCodec->decode(samples, &buffer[offset], length);
+            length = mCodec->decode(samples, count, &buffer[offset], length);
         }
         if (length > 0 && mFixRemote) {
             mRemote = remote;
             mFixRemote = false;
         }
+        count = length;
     }
-    if (length <= 0) {
+    if (count <= 0) {
         LOGV("stream[%d] decoder error", mSocket);
         return;
     }
@@ -462,7 +463,7 @@
 
     // Append to the jitter buffer.
     int tail = mBufferTail * mSampleRate;
-    for (int i = 0; i < mSampleCount; ++i) {
+    for (int i = 0; i < count; ++i) {
         mBuffer[tail & mBufferMask] = samples[i];
         ++tail;
     }
diff --git a/jni/rtp/G711Codec.cpp b/jni/rtp/G711Codec.cpp
index a467acf..ef54863 100644
--- a/jni/rtp/G711Codec.cpp
+++ b/jni/rtp/G711Codec.cpp
@@ -39,7 +39,7 @@
         return mSampleCount;
     }
     int encode(void *payload, int16_t *samples);
-    int decode(int16_t *samples, void *payload, int length);
+    int decode(int16_t *samples, int count, void *payload, int length);
 private:
     int mSampleCount;
 };
@@ -64,9 +64,12 @@
     return mSampleCount;
 }
 
-int UlawCodec::decode(int16_t *samples, void *payload, int length)
+int UlawCodec::decode(int16_t *samples, int count, void *payload, int length)
 {
     int8_t *ulaws = (int8_t *)payload;
+    if (length > count) {
+        length = count;
+    }
     for (int i = 0; i < length; ++i) {
         int ulaw = ~ulaws[i];
         int exponent = (ulaw >> 4) & 0x07;
@@ -87,7 +90,7 @@
         return mSampleCount;
     }
     int encode(void *payload, int16_t *samples);
-    int decode(int16_t *samples, void *payload, int length);
+    int decode(int16_t *samples, int count, void *payload, int length);
 private:
     int mSampleCount;
 };
@@ -111,9 +114,12 @@
     return mSampleCount;
 }
 
-int AlawCodec::decode(int16_t *samples, void *payload, int length)
+int AlawCodec::decode(int16_t *samples, int count, void *payload, int length)
 {
     int8_t *alaws = (int8_t *)payload;
+    if (length > count) {
+        length = count;
+    }
     for (int i = 0; i < length; ++i) {
         int alaw = alaws[i] ^ 0x55;
         int exponent = (alaw >> 4) & 0x07;
diff --git a/jni/rtp/GsmCodec.cpp b/jni/rtp/GsmCodec.cpp
index 8d2286e..61dfdc9 100644
--- a/jni/rtp/GsmCodec.cpp
+++ b/jni/rtp/GsmCodec.cpp
@@ -44,7 +44,7 @@
     }
 
     int encode(void *payload, int16_t *samples);
-    int decode(int16_t *samples, void *payload, int length);
+    int decode(int16_t *samples, int count, void *payload, int length);
 
 private:
     gsm mEncode;
@@ -57,13 +57,17 @@
     return 33;
 }
 
-int GsmCodec::decode(int16_t *samples, void *payload, int length)
+int GsmCodec::decode(int16_t *samples, int count, void *payload, int length)
 {
-    if (length == 33 &&
-        gsm_decode(mDecode, (unsigned char *)payload, samples) == 0) {
-        return 160;
+    unsigned char *bytes = (unsigned char *)payload;
+    int n = 0;
+    while (n + 160 <= count && length >= 33 &&
+        gsm_decode(mDecode, bytes, &samples[n]) == 0) {
+        n += 160;
+        length -= 33;
+        bytes += 33;
     }
-    return -1;
+    return n;
 }
 
 } // namespace