diff options
Diffstat (limited to 'media/libmediaplayerservice')
-rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.cpp | 27 | ||||
-rw-r--r-- | media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp | 71 | ||||
-rw-r--r-- | media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h | 1 |
3 files changed, 76 insertions, 23 deletions
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 2ba05c0..02c1c38 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -1853,20 +1853,23 @@ void MediaPlayerService::AudioOutput::CallbackWrapper( me, buffer->raw, buffer->size, me->mCallbackCookie, CB_EVENT_FILL_BUFFER); - if ((me->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0 && - actualSize == 0 && buffer->size > 0 && me->mNextOutput == NULL) { - // We've reached EOS but the audio track is not stopped yet, - // keep playing silence. + // Log when no data is returned from the callback. + // (1) We may have no data (especially with network streaming sources). + // (2) We may have reached the EOS and the audio track is not stopped yet. + // Note that AwesomePlayer/AudioPlayer will only return zero size when it reaches the EOS. + // NuPlayerRenderer will return zero when it doesn't have data (it doesn't block to fill). + // + // This is a benign busy-wait, with the next data request generated 10 ms or more later; + // nevertheless for power reasons, we don't want to see too many of these. - memset(buffer->raw, 0, buffer->size); - actualSize = buffer->size; - } + ALOGV_IF(actualSize == 0 && buffer->size > 0, "callbackwrapper: empty buffer returned"); + me->mBytesWritten += actualSize; // benign race with reader. buffer->size = actualSize; } break; - case AudioTrack::EVENT_STREAM_END: + // currently only occurs for offloaded callbacks ALOGV("callbackwrapper: deliver EVENT_STREAM_END"); (*me->mCallback)(me, NULL /* buffer */, 0 /* size */, me->mCallbackCookie, CB_EVENT_STREAM_END); @@ -1879,11 +1882,15 @@ void MediaPlayerService::AudioOutput::CallbackWrapper( break; case AudioTrack::EVENT_UNDERRUN: - // This occurs when there is no data available, typically occurring + // This occurs when there is no data available, typically // when there is a failure to supply data to the AudioTrack. It can also // occur in non-offloaded mode when the audio device comes out of standby. // - // If you see this at the start of playback, there probably was a glitch. + // If an AudioTrack underruns it outputs silence. Since this happens suddenly + // it may sound like an audible pop or glitch. + // + // The underrun event is sent once per track underrun; the condition is reset + // when more data is sent to the AudioTrack. ALOGI("callbackwrapper: EVENT_UNDERRUN (discarded)"); break; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 409dedf..89c261c 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -19,7 +19,7 @@ #include <utils/Log.h> #include "NuPlayerRenderer.h" - +#include <cutils/properties.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> @@ -36,6 +36,25 @@ namespace android { +/* + * Example of common configuration settings in shell script form + + #Turn offload audio off (use PCM for Play Music) -- AudioPolicyManager + adb shell setprop audio.offload.disable 1 + + #Allow offload audio with video (requires offloading to be enabled) -- AudioPolicyManager + adb shell setprop audio.offload.video 1 + + #Use audio callbacks for PCM data + adb shell setprop media.stagefright.audio.cbk 1 + + * These configurations take effect for the next track played (not the current track). + */ + +static inline bool getUseAudioCallbackSetting() { + return property_get_bool("media.stagefright.audio.cbk", false /* default_value */); +} + // Maximum time in paused state when offloading audio decompression. When elapsed, the AudioSink // is closed to allow the audio DSP to power down. static const int64_t kOffloadPauseMaxUs = 10000000ll; @@ -87,6 +106,7 @@ NuPlayer::Renderer::Renderer( mCurrentPcmInfo(AUDIO_PCMINFO_INITIALIZER), mTotalBuffersQueued(0), mLastAudioBufferDrained(0), + mUseAudioCallback(false), mWakeLock(new AWakeLock()) { mMediaClock = new MediaClock; mPlaybackRate = mPlaybackSettings.mSpeed; @@ -593,7 +613,7 @@ void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) { void NuPlayer::Renderer::postDrainAudioQueue_l(int64_t delayUs) { if (mDrainAudioQueuePending || mSyncQueues || mPaused - || offloadingAudio()) { + || mUseAudioCallback) { return; } @@ -642,12 +662,14 @@ size_t NuPlayer::Renderer::AudioSinkCallback( case MediaPlayerBase::AudioSink::CB_EVENT_STREAM_END: { + ALOGV("AudioSink::CB_EVENT_STREAM_END"); me->notifyEOS(true /* audio */, ERROR_END_OF_STREAM); break; } case MediaPlayerBase::AudioSink::CB_EVENT_TEAR_DOWN: { + ALOGV("AudioSink::CB_EVENT_TEAR_DOWN"); me->notifyAudioTearDown(); break; } @@ -659,7 +681,7 @@ size_t NuPlayer::Renderer::AudioSinkCallback( size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) { Mutex::Autolock autoLock(mLock); - if (!offloadingAudio() || mPaused) { + if (!mUseAudioCallback || mPaused) { return 0; } @@ -667,13 +689,13 @@ size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) { size_t sizeCopied = 0; bool firstEntry = true; + QueueEntry *entry; // will be valid after while loop if hasEOS is set. while (sizeCopied < size && !mAudioQueue.empty()) { - QueueEntry *entry = &*mAudioQueue.begin(); + entry = &*mAudioQueue.begin(); if (entry->mBuffer == NULL) { // EOS hasEOS = true; mAudioQueue.erase(mAudioQueue.begin()); - entry = NULL; break; } @@ -681,7 +703,7 @@ size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) { firstEntry = false; int64_t mediaTimeUs; CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); - ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6); + ALOGV("fillAudioBuffer: rendering audio at media time %.2f secs", mediaTimeUs / 1E6); setAudioFirstAnchorTimeIfNeeded_l(mediaTimeUs); } @@ -714,10 +736,28 @@ size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) { mMediaClock->updateAnchor(nowMediaUs, nowUs, INT64_MAX); } + // for non-offloaded audio, we need to compute the frames written because + // there is no EVENT_STREAM_END notification. The frames written gives + // an estimate on the pending played out duration. + if (!offloadingAudio()) { + mNumFramesWritten += sizeCopied / mAudioSink->frameSize(); + } + if (hasEOS) { (new AMessage(kWhatStopAudioSink, this))->post(); + // As there is currently no EVENT_STREAM_END callback notification for + // non-offloaded audio tracks, we need to post the EOS ourselves. + if (!offloadingAudio()) { + int64_t postEOSDelayUs = 0; + if (mAudioSink->needsTrailingPadding()) { + postEOSDelayUs = getPendingAudioPlayoutDurationUs(ALooper::GetNowUs()); + } + ALOGV("fillAudioBuffer: notifyEOS " + "mNumFramesWritten:%u finalResult:%d postEOSDelay:%lld", + mNumFramesWritten, entry->mFinalResult, (long long)postEOSDelayUs); + notifyEOS(true /* audio */, entry->mFinalResult, postEOSDelayUs); + } } - return sizeCopied; } @@ -778,7 +818,8 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { if (entry->mOffset == 0 && entry->mBuffer->size() > 0) { int64_t mediaTimeUs; CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); - ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6); + ALOGV("onDrainAudioQueue: rendering audio at media time %.2f secs", + mediaTimeUs / 1E6); onNewAudioMediaTime(mediaTimeUs); } @@ -1230,9 +1271,8 @@ void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) { ++mAudioDrainGeneration; prepareForMediaRenderingStart_l(); - if (offloadingAudio()) { - clearAudioFirstAnchorTime_l(); - } + // the frame count will be reset after flush. + clearAudioFirstAnchorTime_l(); } mDrainAudioQueuePending = false; @@ -1590,6 +1630,7 @@ status_t NuPlayer::Renderer::onOpenAudioSink( offloadFlags &= ~AUDIO_OUTPUT_FLAG_DEEP_BUFFER; audioSinkChanged = true; mAudioSink->close(); + err = mAudioSink->open( sampleRate, numChannels, @@ -1623,6 +1664,7 @@ status_t NuPlayer::Renderer::onOpenAudioSink( mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; ALOGV("openAudioSink: offload failed"); } + mUseAudioCallback = true; // offload mode transfers data through callback } } if (!offloadOnly && !offloadingAudio()) { @@ -1646,14 +1688,17 @@ status_t NuPlayer::Renderer::onOpenAudioSink( audioSinkChanged = true; mAudioSink->close(); mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; + // Note: It is possible to set up the callback, but not use it to send audio data. + // This requires a fix in AudioSink to explicitly specify the transfer mode. + mUseAudioCallback = getUseAudioCallbackSetting(); status_t err = mAudioSink->open( sampleRate, numChannels, (audio_channel_mask_t)channelMask, AUDIO_FORMAT_PCM_16_BIT, 8 /* bufferCount */, - NULL, - NULL, + mUseAudioCallback ? &NuPlayer::Renderer::AudioSinkCallback : NULL, + mUseAudioCallback ? this : NULL, (audio_output_flags_t)pcmFlags, NULL, true /* doNotReconnect */); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h index fbdf5bf..c2fea40 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -194,6 +194,7 @@ private: int32_t mTotalBuffersQueued; int32_t mLastAudioBufferDrained; + bool mUseAudioCallback; sp<AWakeLock> mWakeLock; |