Merge "RTP: Delay the initialization of AudioTrack and AudioRecord." into gingerbread

This commit is contained in:
Chia-chi Yeh
2010-09-28 14:41:18 -07:00
committed by Android (Google) Code Review

View File

@ -461,18 +461,15 @@ private:
EC_ENABLED = 3, EC_ENABLED = 3,
LAST_MODE = 3, LAST_MODE = 3,
}; };
int mMode;
AudioStream *mChain; AudioStream *mChain;
int mEventQueue; int mEventQueue;
volatile int mDtmfEvent; volatile int mDtmfEvent;
int mMode;
int mSampleRate;
int mSampleCount; int mSampleCount;
int mDeviceSocket; int mDeviceSocket;
AudioTrack mTrack;
AudioRecord mRecord;
bool networkLoop();
bool deviceLoop();
class NetworkThread : public Thread class NetworkThread : public Thread
{ {
@ -490,10 +487,7 @@ private:
private: private:
AudioGroup *mGroup; AudioGroup *mGroup;
bool threadLoop() bool threadLoop();
{
return mGroup->networkLoop();
}
}; };
sp<NetworkThread> mNetworkThread; sp<NetworkThread> mNetworkThread;
@ -504,9 +498,6 @@ private:
bool start() bool start()
{ {
char c;
while (recv(mGroup->mDeviceSocket, &c, 1, MSG_DONTWAIT) == 1);
if (run("Device", ANDROID_PRIORITY_AUDIO) != NO_ERROR) { if (run("Device", ANDROID_PRIORITY_AUDIO) != NO_ERROR) {
LOGE("cannot start device thread"); LOGE("cannot start device thread");
return false; return false;
@ -516,10 +507,7 @@ private:
private: private:
AudioGroup *mGroup; AudioGroup *mGroup;
bool threadLoop() bool threadLoop();
{
return mGroup->deviceLoop();
}
}; };
sp<DeviceThread> mDeviceThread; sp<DeviceThread> mDeviceThread;
}; };
@ -539,8 +527,6 @@ AudioGroup::~AudioGroup()
{ {
mNetworkThread->requestExitAndWait(); mNetworkThread->requestExitAndWait();
mDeviceThread->requestExitAndWait(); mDeviceThread->requestExitAndWait();
mTrack.stop();
mRecord.stop();
close(mEventQueue); close(mEventQueue);
close(mDeviceSocket); close(mDeviceSocket);
while (mChain) { while (mChain) {
@ -559,40 +545,9 @@ bool AudioGroup::set(int sampleRate, int sampleCount)
return false; return false;
} }
mSampleRate = sampleRate;
mSampleCount = sampleCount; mSampleCount = sampleCount;
// Find out the frame count for AudioTrack and AudioRecord.
int output = 0;
int input = 0;
if (AudioTrack::getMinFrameCount(&output, AudioSystem::VOICE_CALL,
sampleRate) != NO_ERROR || output <= 0 ||
AudioRecord::getMinFrameCount(&input, sampleRate,
AudioSystem::PCM_16_BIT, 1) != NO_ERROR || input <= 0) {
LOGE("cannot compute frame count");
return false;
}
LOGD("reported frame count: output %d, input %d", output, input);
if (output < sampleCount * 2) {
output = sampleCount * 2;
}
if (input < sampleCount * 2) {
input = sampleCount * 2;
}
LOGD("adjusted frame count: output %d, input %d", output, input);
// Initialize AudioTrack and AudioRecord.
if (mTrack.set(AudioSystem::VOICE_CALL, sampleRate, AudioSystem::PCM_16_BIT,
AudioSystem::CHANNEL_OUT_MONO, output) != NO_ERROR ||
mRecord.set(AUDIO_SOURCE_MIC, sampleRate, AudioSystem::PCM_16_BIT,
AudioSystem::CHANNEL_IN_MONO, input) != NO_ERROR) {
LOGE("cannot initialize audio device");
return false;
}
LOGD("latency: output %d, input %d", mTrack.latency(), mRecord.latency());
// TODO: initialize echo canceler here.
// Create device socket. // Create device socket.
int pair[2]; int pair[2];
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair)) { if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair)) {
@ -610,13 +565,11 @@ bool AudioGroup::set(int sampleRate, int sampleCount)
return false; return false;
} }
// Give device socket a reasonable timeout and buffer size. // Give device socket a reasonable timeout.
timeval tv; timeval tv;
tv.tv_sec = 0; tv.tv_sec = 0;
tv.tv_usec = 1000 * sampleCount / sampleRate * 500; tv.tv_usec = 1000 * sampleCount / sampleRate * 500;
if (setsockopt(pair[0], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) || if (setsockopt(pair[0], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))) {
setsockopt(pair[0], SOL_SOCKET, SO_RCVBUF, &output, sizeof(output)) ||
setsockopt(pair[1], SOL_SOCKET, SO_SNDBUF, &output, sizeof(output))) {
LOGE("setsockopt: %s", strerror(errno)); LOGE("setsockopt: %s", strerror(errno));
return false; return false;
} }
@ -644,29 +597,10 @@ bool AudioGroup::setMode(int mode)
return true; return true;
} }
mDeviceThread->requestExitAndWait();
LOGD("group[%d] switches from mode %d to %d", mDeviceSocket, mMode, mode); LOGD("group[%d] switches from mode %d to %d", mDeviceSocket, mMode, mode);
mMode = mode; mMode = mode;
return (mode == ON_HOLD) || mDeviceThread->start();
mDeviceThread->requestExitAndWait();
if (mode == ON_HOLD) {
mTrack.stop();
mRecord.stop();
return true;
}
mTrack.start();
if (mode == MUTED) {
mRecord.stop();
} else {
mRecord.start();
}
if (!mDeviceThread->start()) {
mTrack.stop();
mRecord.stop();
return false;
}
return true;
} }
bool AudioGroup::sendDtmf(int event) bool AudioGroup::sendDtmf(int event)
@ -741,15 +675,16 @@ bool AudioGroup::remove(int socket)
return true; return true;
} }
bool AudioGroup::networkLoop() bool AudioGroup::NetworkThread::threadLoop()
{ {
AudioStream *chain = mGroup->mChain;
int tick = elapsedRealtime(); int tick = elapsedRealtime();
int deadline = tick + 10; int deadline = tick + 10;
int count = 0; int count = 0;
for (AudioStream *stream = mChain; stream; stream = stream->mNext) { for (AudioStream *stream = chain; stream; stream = stream->mNext) {
if (!stream->mTick || tick - stream->mTick >= 0) { if (!stream->mTick || tick - stream->mTick >= 0) {
stream->encode(tick, mChain); stream->encode(tick, chain);
} }
if (deadline - stream->mTick > 0) { if (deadline - stream->mTick > 0) {
deadline = stream->mTick; deadline = stream->mTick;
@ -757,12 +692,12 @@ bool AudioGroup::networkLoop()
++count; ++count;
} }
if (mDtmfEvent != -1) { int event = mGroup->mDtmfEvent;
int event = mDtmfEvent; if (event != -1) {
for (AudioStream *stream = mChain; stream; stream = stream->mNext) { for (AudioStream *stream = chain; stream; stream = stream->mNext) {
stream->sendDtmf(event); stream->sendDtmf(event);
} }
mDtmfEvent = -1; mGroup->mDtmfEvent = -1;
} }
deadline -= tick; deadline -= tick;
@ -771,7 +706,7 @@ bool AudioGroup::networkLoop()
} }
epoll_event events[count]; epoll_event events[count];
count = epoll_wait(mEventQueue, events, count, deadline); count = epoll_wait(mGroup->mEventQueue, events, count, deadline);
if (count == -1) { if (count == -1) {
LOGE("epoll_wait: %s", strerror(errno)); LOGE("epoll_wait: %s", strerror(errno));
return false; return false;
@ -783,70 +718,125 @@ bool AudioGroup::networkLoop()
return true; return true;
} }
bool AudioGroup::deviceLoop() bool AudioGroup::DeviceThread::threadLoop()
{ {
int16_t output[mSampleCount]; int mode = mGroup->mMode;
int sampleRate = mGroup->mSampleRate;
int sampleCount = mGroup->mSampleCount;
int deviceSocket = mGroup->mDeviceSocket;
if (recv(mDeviceSocket, output, sizeof(output), 0) <= 0) { // Find out the frame count for AudioTrack and AudioRecord.
memset(output, 0, sizeof(output)); int output = 0;
} int input = 0;
if (AudioTrack::getMinFrameCount(&output, AudioSystem::VOICE_CALL,
int16_t input[mSampleCount]; sampleRate) != NO_ERROR || output <= 0 ||
int toWrite = mSampleCount; AudioRecord::getMinFrameCount(&input, sampleRate,
int toRead = (mMode == MUTED) ? 0 : mSampleCount; AudioSystem::PCM_16_BIT, 1) != NO_ERROR || input <= 0) {
int chances = 100; LOGE("cannot compute frame count");
while (--chances > 0 && (toWrite > 0 || toRead > 0)) {
if (toWrite > 0) {
AudioTrack::Buffer buffer;
buffer.frameCount = toWrite;
status_t status = mTrack.obtainBuffer(&buffer, 1);
if (status == NO_ERROR) {
memcpy(buffer.i8, &output[mSampleCount - toWrite], buffer.size);
toWrite -= buffer.frameCount;
mTrack.releaseBuffer(&buffer);
} else if (status != TIMED_OUT && status != WOULD_BLOCK) {
LOGE("cannot write to AudioTrack");
return false;
}
}
if (toRead > 0) {
AudioRecord::Buffer buffer;
buffer.frameCount = mRecord.frameCount();
status_t status = mRecord.obtainBuffer(&buffer, 1);
if (status == NO_ERROR) {
int count = ((int)buffer.frameCount < toRead) ?
buffer.frameCount : toRead;
memcpy(&input[mSampleCount - toRead], buffer.i8, count * 2);
toRead -= count;
if (buffer.frameCount < mRecord.frameCount()) {
buffer.frameCount = count;
}
mRecord.releaseBuffer(&buffer);
} else if (status != TIMED_OUT && status != WOULD_BLOCK) {
LOGE("cannot read from AudioRecord");
return false;
}
}
}
if (!chances) {
LOGE("device loop timeout");
return false; return false;
} }
LOGD("reported frame count: output %d, input %d", output, input);
if (mMode != MUTED) { if (output < sampleCount * 2) {
if (mMode == NORMAL) { output = sampleCount * 2;
send(mDeviceSocket, input, sizeof(input), MSG_DONTWAIT); }
} else { if (input < sampleCount * 2) {
// TODO: Echo canceller runs here. input = sampleCount * 2;
send(mDeviceSocket, input, sizeof(input), MSG_DONTWAIT); }
LOGD("adjusted frame count: output %d, input %d", output, input);
// Initialize AudioTrack and AudioRecord.
AudioTrack track;
AudioRecord record;
if (track.set(AudioSystem::VOICE_CALL, sampleRate, AudioSystem::PCM_16_BIT,
AudioSystem::CHANNEL_OUT_MONO, output) != NO_ERROR ||
record.set(AUDIO_SOURCE_MIC, sampleRate, AudioSystem::PCM_16_BIT,
AudioSystem::CHANNEL_IN_MONO, input) != NO_ERROR) {
LOGE("cannot initialize audio device");
return false;
}
LOGD("latency: output %d, input %d", track.latency(), record.latency());
// TODO: initialize echo canceler here.
// Give device socket a reasonable buffer size.
setsockopt(deviceSocket, SOL_SOCKET, SO_RCVBUF, &output, sizeof(output));
setsockopt(deviceSocket, SOL_SOCKET, SO_SNDBUF, &output, sizeof(output));
// Drain device socket.
char c;
while (recv(deviceSocket, &c, 1, MSG_DONTWAIT) == 1);
// Start your engine!
track.start();
if (mode != MUTED) {
record.start();
}
while (!exitPending()) {
int16_t output[sampleCount];
if (recv(deviceSocket, output, sizeof(output), 0) <= 0) {
memset(output, 0, sizeof(output));
}
int16_t input[sampleCount];
int toWrite = sampleCount;
int toRead = (mode == MUTED) ? 0 : sampleCount;
int chances = 100;
while (--chances > 0 && (toWrite > 0 || toRead > 0)) {
if (toWrite > 0) {
AudioTrack::Buffer buffer;
buffer.frameCount = toWrite;
status_t status = track.obtainBuffer(&buffer, 1);
if (status == NO_ERROR) {
int offset = sampleCount - toWrite;
memcpy(buffer.i8, &output[offset], buffer.size);
toWrite -= buffer.frameCount;
track.releaseBuffer(&buffer);
} else if (status != TIMED_OUT && status != WOULD_BLOCK) {
LOGE("cannot write to AudioTrack");
break;
}
}
if (toRead > 0) {
AudioRecord::Buffer buffer;
buffer.frameCount = record.frameCount();
status_t status = record.obtainBuffer(&buffer, 1);
if (status == NO_ERROR) {
int count = ((int)buffer.frameCount < toRead) ?
buffer.frameCount : toRead;
memcpy(&input[sampleCount - toRead], buffer.i8, count * 2);
toRead -= count;
if (buffer.frameCount < record.frameCount()) {
buffer.frameCount = count;
}
record.releaseBuffer(&buffer);
} else if (status != TIMED_OUT && status != WOULD_BLOCK) {
LOGE("cannot read from AudioRecord");
break;
}
}
}
if (chances <= 0) {
LOGE("device loop timeout");
break;
}
if (mode != MUTED) {
if (mode == NORMAL) {
send(deviceSocket, input, sizeof(input), MSG_DONTWAIT);
} else {
// TODO: Echo canceller runs here.
send(deviceSocket, input, sizeof(input), MSG_DONTWAIT);
}
} }
} }
return true; return false;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------