Merge "Fix audio dropouts with multiple playback streams." into lmp-dev
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index a3c976d..bf6b3df 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -410,8 +410,11 @@
if (entry->mBuffer == NULL) {
// EOS
-
- notifyEOS(true /* audio */, entry->mFinalResult);
+ int64_t postEOSDelayUs = 0;
+ if (mAudioSink->needsTrailingPadding()) {
+ postEOSDelayUs = getAudioPendingPlayoutUs() + 1000 * mAudioSink->latency();
+ }
+ notifyEOS(true /* audio */, entry->mFinalResult, postEOSDelayUs);
mAudioQueue.erase(mAudioQueue.begin());
entry = NULL;
@@ -421,26 +424,11 @@
if (entry->mOffset == 0) {
int64_t mediaTimeUs;
CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
-
ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
-
mAnchorTimeMediaUs = mediaTimeUs;
- uint32_t numFramesPlayed;
- CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
-
- uint32_t numFramesPendingPlayout =
- mNumFramesWritten - numFramesPlayed;
-
- int64_t realTimeOffsetUs =
- (mAudioSink->latency() / 2 /* XXX */
- + numFramesPendingPlayout
- * mAudioSink->msecsPerFrame()) * 1000ll;
-
- // ALOGI("realTimeOffsetUs = %lld us", realTimeOffsetUs);
-
- mAnchorTimeRealUs =
- ALooper::GetNowUs() + realTimeOffsetUs;
+ mAnchorTimeRealUs = ALooper::GetNowUs()
+ + getAudioPendingPlayoutUs() + 1000 * mAudioSink->latency() / 2;
}
size_t copy = entry->mBuffer->size() - entry->mOffset;
@@ -494,6 +482,14 @@
return !mAudioQueue.empty();
}
+int64_t NuPlayer::Renderer::getAudioPendingPlayoutUs() {
+ uint32_t numFramesPlayed;
+ CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
+
+ uint32_t numFramesPendingPlayout = mNumFramesWritten - numFramesPlayed;
+ return numFramesPendingPlayout * mAudioSink->msecsPerFrame() * 1000;
+}
+
void NuPlayer::Renderer::postDrainVideoQueue() {
if (mDrainVideoQueuePending || mSyncQueues || mPaused) {
return;
@@ -607,12 +603,12 @@
notify->post();
}
-void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult) {
+void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult, int64_t delayUs) {
sp<AMessage> notify = mNotify->dup();
notify->setInt32("what", kWhatEOS);
notify->setInt32("audio", static_cast<int32_t>(audio));
notify->setInt32("finalResult", finalResult);
- notify->post();
+ notify->post(delayUs);
}
void NuPlayer::Renderer::notifyAudioOffloadTearDown() {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 1cba1a0..8da6458 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -129,6 +129,7 @@
size_t fillAudioBuffer(void *buffer, size_t size);
bool onDrainAudioQueue();
+ int64_t getAudioPendingPlayoutUs();
void postDrainAudioQueue_l(int64_t delayUs = 0);
void onDrainVideoQueue();
@@ -146,7 +147,7 @@
void onResume();
void onAudioOffloadTearDown();
- void notifyEOS(bool audio, status_t finalResult);
+ void notifyEOS(bool audio, status_t finalResult, int64_t delayUs = 0);
void notifyFlushComplete(bool audio);
void notifyPosition();
void notifyVideoLateBy(int64_t lateByUs);
diff --git a/media/libstagefright/foundation/ALooperRoster.cpp b/media/libstagefright/foundation/ALooperRoster.cpp
index 0c181ff..0f44b52 100644
--- a/media/libstagefright/foundation/ALooperRoster.cpp
+++ b/media/libstagefright/foundation/ALooperRoster.cpp
@@ -72,15 +72,27 @@
}
void ALooperRoster::unregisterStaleHandlers() {
- Mutex::Autolock autoLock(mLock);
- for (size_t i = mHandlers.size(); i-- > 0;) {
- const HandlerInfo &info = mHandlers.valueAt(i);
+ Vector<sp<ALooper> > activeLoopers;
+ {
+ Mutex::Autolock autoLock(mLock);
- sp<ALooper> looper = info.mLooper.promote();
- if (looper == NULL) {
- ALOGV("Unregistering stale handler %d", mHandlers.keyAt(i));
- mHandlers.removeItemsAt(i);
+ for (size_t i = mHandlers.size(); i-- > 0;) {
+ const HandlerInfo &info = mHandlers.valueAt(i);
+
+ sp<ALooper> looper = info.mLooper.promote();
+ if (looper == NULL) {
+ ALOGV("Unregistering stale handler %d", mHandlers.keyAt(i));
+ mHandlers.removeItemsAt(i);
+ } else {
+ // At this point 'looper' might be the only sp<> keeping
+ // the object alive. To prevent it from going out of scope
+ // and having ~ALooper call this method again recursively
+ // and then deadlocking because of the Autolock above, add
+ // it to a Vector which will go out of scope after the lock
+ // has been released.
+ activeLoopers.add(looper);
+ }
}
}
}
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index 41d726c..06dd22c 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -1469,19 +1469,31 @@
return;
}
- mpClientInterface->closeInput(input);
- mInputs.removeItem(input);
- nextAudioPortGeneration();
+ closeInput(input);
mpClientInterface->onAudioPortListUpdate();
ALOGV("releaseInput() exit");
}
void AudioPolicyManager::closeAllInputs() {
+ bool patchRemoved = false;
+
for(size_t input_index = 0; input_index < mInputs.size(); input_index++) {
+ sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(input_index);
+ ssize_t patch_index = mAudioPatches.indexOfKey(inputDesc->mPatchHandle);
+ if (patch_index >= 0) {
+ sp<AudioPatch> patchDesc = mAudioPatches.valueAt(patch_index);
+ status_t status = mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
+ mAudioPatches.removeItemsAt(patch_index);
+ patchRemoved = true;
+ }
mpClientInterface->closeInput(mInputs.keyAt(input_index));
}
mInputs.clear();
nextAudioPortGeneration();
+
+ if (patchRemoved) {
+ mpClientInterface->onAudioPatchListUpdate();
+ }
}
void AudioPolicyManager::initStreamVolume(audio_stream_type_t stream,
@@ -3512,6 +3524,16 @@
}
}
+ nextAudioPortGeneration();
+
+ ssize_t index = mAudioPatches.indexOfKey(outputDesc->mPatchHandle);
+ if (index >= 0) {
+ sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
+ status_t status = mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
+ mAudioPatches.removeItemsAt(index);
+ mpClientInterface->onAudioPatchListUpdate();
+ }
+
AudioParameter param;
param.add(String8("closing"), String8("true"));
mpClientInterface->setParameters(output, param.toString());
@@ -3519,7 +3541,30 @@
mpClientInterface->closeOutput(output);
mOutputs.removeItem(output);
mPreviousOutputs = mOutputs;
+}
+
+void AudioPolicyManager::closeInput(audio_io_handle_t input)
+{
+ ALOGV("closeInput(%d)", input);
+
+ sp<AudioInputDescriptor> inputDesc = mInputs.valueFor(input);
+ if (inputDesc == NULL) {
+ ALOGW("closeInput() unknown input %d", input);
+ return;
+ }
+
nextAudioPortGeneration();
+
+ ssize_t index = mAudioPatches.indexOfKey(inputDesc->mPatchHandle);
+ if (index >= 0) {
+ sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
+ status_t status = mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
+ mAudioPatches.removeItemsAt(index);
+ mpClientInterface->onAudioPatchListUpdate();
+ }
+
+ mpClientInterface->closeInput(input);
+ mInputs.removeItem(input);
}
SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevice(audio_devices_t device,
diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h
index 6712eb7..57e015e 100644
--- a/services/audiopolicy/AudioPolicyManager.h
+++ b/services/audiopolicy/AudioPolicyManager.h
@@ -649,6 +649,9 @@
// close an output and its companion duplicating output.
void closeOutput(audio_io_handle_t output);
+ // close an input.
+ void closeInput(audio_io_handle_t input);
+
// checks and if necessary changes outputs used for all strategies.
// must be called every time a condition that affects the output choice for a given strategy
// changes: connected device, phone state, force use...
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
index b388079..2d31275 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
@@ -78,8 +78,12 @@
ALOGV("%s: Initialize buffer queue and frame list depth based on max pipeline depth (%d)",
__FUNCTION__, pipelineMaxDepth);
- mBufferQueueDepth = pipelineMaxDepth + 1;
- mFrameListDepth = pipelineMaxDepth + 1;
+ // Need to keep buffer queue longer than metadata queue because sometimes buffer arrives
+ // earlier than metadata which causes the buffer corresponding to oldest metadata being
+ // removed.
+ mFrameListDepth = pipelineMaxDepth;
+ mBufferQueueDepth = mFrameListDepth + 1;
+
mZslQueue.insertAt(0, mBufferQueueDepth);
mFrameList.insertAt(0, mFrameListDepth);
@@ -554,13 +558,15 @@
}
void ZslProcessor3::onBufferReleased(const BufferInfo& bufferInfo) {
- Mutex::Autolock l(mInputMutex);
// ignore output buffers
if (bufferInfo.mOutput) {
return;
}
+ // Lock mutex only once we know this is an input buffer returned to avoid
+ // potential deadlock
+ Mutex::Autolock l(mInputMutex);
// TODO: Verify that the buffer is in our queue by looking at timestamp
// theoretically unnecessary unless we change the following assumptions:
// -- only 1 buffer reprocessed at a time (which is the case now)