Fix issue 3483718: audio streaming and A2DP.
The problem is that when switching from A2DP to device speakers or headset,
The AudioTrack binder interface to AudioFlinger must be destroyed and restored
to accomodate new buffer size requirements. Current AudioTrack implementation
did not restore properly the PCM buffer write index which caused a mismatch between
the written frame count in the mediaplayer renderer and the AudioTrack. The renderer
could then believe the AudioTrack buffer was full and stop writing data preventing the
AudioTrack to reach a bufffer full condition and resume playback.
The rendered was also modified to refresh the AudioTrack frame count (buffer size)
inside the write loop in NuPlayer::Renderer::onDrainAudioQueue() as this count can change
from one write to the next.
Also modified AudioTrack::obtainBuffer() to check for track invalidated status before
querying for available space in the buffer. This avoids writing to the old track's
buffer until full before detecting the invalidated condition and create a new track.
Change-Id: I16a857e464e466880847f52f640820aa271539ad
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 02e1570..fb2ee0f 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -546,12 +546,13 @@
}
if (loopStart >= loopEnd ||
- loopEnd - loopStart > cblk->frameCount) {
+ loopEnd - loopStart > cblk->frameCount ||
+ cblk->server > loopStart) {
LOGE("setLoop invalid value: loopStart %d, loopEnd %d, loopCount %d, framecount %d, user %d", loopStart, loopEnd, loopCount, cblk->frameCount, cblk->user);
return BAD_VALUE;
}
- if ((mSharedBuffer != 0) && (loopEnd > cblk->frameCount)) {
+ if ((mSharedBuffer != 0) && (loopEnd > cblk->frameCount)) {
LOGE("setLoop invalid value: loop markers beyond data: loopStart %d, loopEnd %d, framecount %d",
loopStart, loopEnd, cblk->frameCount);
return BAD_VALUE;
@@ -825,6 +826,12 @@
uint32_t framesAvail = cblk->framesAvailable();
+ cblk->lock.lock();
+ if (cblk->flags & CBLK_INVALID_MSK) {
+ goto create_new_track;
+ }
+ cblk->lock.unlock();
+
if (framesAvail == 0) {
cblk->lock.lock();
goto start_loop_here;
@@ -1148,6 +1155,7 @@
fromStart ? "start()" : "obtainBuffer()");
cblk->flags |= CBLK_RESTORING_ON;
+
// signal old cblk condition so that other threads waiting for available buffers stop
// waiting now
cblk->cv.broadcast();
@@ -1167,10 +1175,20 @@
false);
if (result == NO_ERROR) {
+ // restore write index and set other indexes to reflect empty buffer status
+ mCblk->user = cblk->user;
+ mCblk->server = cblk->user;
+ mCblk->userBase = cblk->user;
+ mCblk->serverBase = cblk->user;
+ // restore loop: this is not guaranteed to succeed if new frame count is not
+ // compatible with loop length
+ setLoop_l(cblk->loopStart, cblk->loopEnd, cblk->loopCount);
if (!fromStart) {
mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
}
- result = mAudioTrack->start();
+ if (mActive) {
+ result = mAudioTrack->start();
+ }
if (fromStart && result == NO_ERROR) {
mNewPosition = mCblk->server + mUpdatePeriod;
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 369a3a8..828e008 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -198,18 +198,21 @@
}
void NuPlayer::Renderer::onDrainAudioQueue() {
- uint32_t numFramesPlayed;
- CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
- ssize_t numFramesAvailableToWrite =
- mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
+ for (;;) {
+ uint32_t numFramesPlayed;
+ CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
- CHECK_GE(numFramesAvailableToWrite, 0);
+ ssize_t numFramesAvailableToWrite =
+ mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
- size_t numBytesAvailableToWrite =
- numFramesAvailableToWrite * mAudioSink->frameSize();
+ size_t numBytesAvailableToWrite =
+ numFramesAvailableToWrite * mAudioSink->frameSize();
- while (numBytesAvailableToWrite > 0) {
+ if (numBytesAvailableToWrite == 0) {
+ break;
+ }
+
if (mAudioQueue.empty()) {
break;
}
@@ -264,10 +267,10 @@
if (entry->mOffset == entry->mBuffer->size()) {
entry->mNotifyConsumed->post();
mAudioQueue.erase(mAudioQueue.begin());
+
entry = NULL;
}
- numBytesAvailableToWrite -= copy;
mNumFramesWritten += copy / mAudioSink->frameSize();
}