Merge "RTP: Adjust the jitter buffer to 512ms." into gingerbread

This commit is contained in:
Chia-chi Yeh
2010-09-29 23:24:32 -07:00
committed by Android (Google) Code Review

View File

@@ -57,9 +57,9 @@ int gRandom = -1;
// a modulo operation on the index while accessing the array. However modulo can // a modulo operation on the index while accessing the array. However modulo can
// be expensive on some platforms, such as ARM. Thus we round up the size of the // be expensive on some platforms, such as ARM. Thus we round up the size of the
// array to the nearest power of 2 and then use bitwise-and instead of modulo. // array to the nearest power of 2 and then use bitwise-and instead of modulo.
// Currently we make it 256ms long and assume packet interval is 32ms or less. // Currently we make it 512ms long and assume packet interval is 40ms or less.
// The first 64ms is the place where samples get mixed. The rest 192ms is the // The first 80ms is the place where samples get mixed. The rest 432ms is the
// real jitter buffer. For a stream at 8000Hz it takes 4096 bytes. These numbers // real jitter buffer. For a stream at 8000Hz it takes 8192 bytes. These numbers
// are chosen by experiments and each of them can be adjusted as needed. // are chosen by experiments and each of them can be adjusted as needed.
// Other notes: // Other notes:
@@ -69,7 +69,11 @@ int gRandom = -1;
// milliseconds. No floating points. // milliseconds. No floating points.
// + If we cannot get enough CPU, we drop samples and simulate packet loss. // + If we cannot get enough CPU, we drop samples and simulate packet loss.
// + Resampling is not done yet, so streams in one group must use the same rate. // + Resampling is not done yet, so streams in one group must use the same rate.
// For the first release we might only support 8kHz and 16kHz. // For the first release only 8000Hz is supported.
#define BUFFER_SIZE 512
#define HISTORY_SIZE 80
#define MEASURE_PERIOD 2000
class AudioStream class AudioStream
{ {
@@ -111,6 +115,7 @@ private:
int mBufferMask; int mBufferMask;
int mBufferHead; int mBufferHead;
int mBufferTail; int mBufferTail;
int mLatencyTimer;
int mLatencyScore; int mLatencyScore;
uint16_t mSequence; uint16_t mSequence;
@@ -159,12 +164,13 @@ bool AudioStream::set(int mode, int socket, sockaddr_storage *remote,
mInterval = mSampleCount / mSampleRate; mInterval = mSampleCount / mSampleRate;
// Allocate jitter buffer. // Allocate jitter buffer.
for (mBufferMask = 8192; mBufferMask < sampleRate; mBufferMask <<= 1); for (mBufferMask = 8; mBufferMask < mSampleRate; mBufferMask <<= 1);
mBufferMask >>= 2; mBufferMask *= BUFFER_SIZE;
mBuffer = new int16_t[mBufferMask]; mBuffer = new int16_t[mBufferMask];
--mBufferMask; --mBufferMask;
mBufferHead = 0; mBufferHead = 0;
mBufferTail = 0; mBufferTail = 0;
mLatencyTimer = 0;
mLatencyScore = 0; mLatencyScore = 0;
// Initialize random bits. // Initialize random bits.
@@ -340,29 +346,35 @@ void AudioStream::decode(int tick)
} }
// Make sure mBufferHead and mBufferTail are reasonable. // Make sure mBufferHead and mBufferTail are reasonable.
if ((unsigned int)(tick + 256 - mBufferHead) > 1024) { if ((unsigned int)(tick + BUFFER_SIZE - mBufferHead) > BUFFER_SIZE * 2) {
mBufferHead = tick - 64; mBufferHead = tick - HISTORY_SIZE;
mBufferTail = mBufferHead; mBufferTail = mBufferHead;
} }
if (tick - mBufferHead > 64) { if (tick - mBufferHead > HISTORY_SIZE) {
// Throw away outdated samples. // Throw away outdated samples.
mBufferHead = tick - 64; mBufferHead = tick - HISTORY_SIZE;
if (mBufferTail - mBufferHead < 0) { if (mBufferTail - mBufferHead < 0) {
mBufferTail = mBufferHead; mBufferTail = mBufferHead;
} }
} }
if (mBufferTail - tick <= 80) { // Adjust the jitter buffer if the latency keeps larger than two times of the
mLatencyScore = tick; // packet interval in the past two seconds.
} else if (tick - mLatencyScore >= 5000) { int score = mBufferTail - tick - mInterval * 2;
// Reset the jitter buffer to 40ms if the latency keeps larger than 80ms if (mLatencyScore > score) {
// in the past 5s. This rarely happens, so let us just keep it simple. mLatencyScore = score;
LOGD("stream[%d] latency control", mSocket); }
mBufferTail = tick + 40; if (mLatencyScore <= 0) {
mLatencyTimer = tick;
mLatencyScore = score;
} else if (tick - mLatencyTimer >= MEASURE_PERIOD) {
LOGD("stream[%d] reduces latency of %dms", mSocket, mLatencyScore);
mBufferTail -= mLatencyScore;
mLatencyTimer = tick;
} }
if (mBufferTail - mBufferHead > 256 - mInterval) { if (mBufferTail - mBufferHead > BUFFER_SIZE - mInterval) {
// Buffer overflow. Drop the packet. // Buffer overflow. Drop the packet.
LOGD("stream[%d] buffer overflow", mSocket); LOGD("stream[%d] buffer overflow", mSocket);
recv(mSocket, &c, 1, MSG_DONTWAIT); recv(mSocket, &c, 1, MSG_DONTWAIT);
@@ -413,17 +425,17 @@ void AudioStream::decode(int tick)
} }
if (tick - mBufferTail > 0) { if (tick - mBufferTail > 0) {
// Buffer underrun. Reset the jitter buffer to 40ms. // Buffer underrun. Reset the jitter buffer.
LOGD("stream[%d] buffer underrun", mSocket); LOGD("stream[%d] buffer underrun", mSocket);
if (mBufferTail - mBufferHead <= 0) { if (mBufferTail - mBufferHead <= 0) {
mBufferHead = tick + 40; mBufferHead = tick + mInterval;
mBufferTail = mBufferHead; mBufferTail = mBufferHead;
} else { } else {
int tail = (tick + 40) * mSampleRate; int tail = (tick + mInterval) * mSampleRate;
for (int i = mBufferTail * mSampleRate; i - tail < 0; ++i) { for (int i = mBufferTail * mSampleRate; i - tail < 0; ++i) {
mBuffer[i & mBufferMask] = 0; mBuffer[i & mBufferMask] = 0;
} }
mBufferTail = tick + 40; mBufferTail = tick + mInterval;
} }
} }
@@ -680,7 +692,7 @@ bool AudioGroup::NetworkThread::threadLoop()
int count = 0; int count = 0;
for (AudioStream *stream = chain; stream; stream = stream->mNext) { for (AudioStream *stream = chain; stream; stream = stream->mNext) {
if (!stream->mTick || tick - stream->mTick >= 0) { if (tick - stream->mTick >= 0) {
stream->encode(tick, chain); stream->encode(tick, chain);
} }
if (deadline - stream->mTick > 0) { if (deadline - stream->mTick > 0) {