From 282a7e31681840253a4cb6fab3f6725d35798699 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Thu, 14 Aug 2014 15:56:34 -0700 Subject: [PATCH] nuplayer: create AudioSink early to verify offload is possible Offload audio playback is not guaranteed even if AudioSystem says it is allowed. Create AudioSink early to verify offload is really possible. Move AudioSink open / close into functions. Bug: 16732303 Bug: 16978805 Change-Id: Ie1c73a96656863c1281bed3280a84b86d3cbadf5 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 285 ++++++++++++---------- media/libmediaplayerservice/nuplayer/NuPlayer.h | 4 + 2 files changed, 156 insertions(+), 133 deletions(-) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 9a4e81190d..06c6e8d2d7 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -147,6 +147,7 @@ NuPlayer::NuPlayer() mSourceFlags(0), mVideoIsAVC(false), mOffloadAudio(false), + mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER), mAudioEOS(false), mVideoEOS(false), mScanSourcesPending(false), @@ -639,11 +640,18 @@ void NuPlayer::onMessageReceived(const sp &msg) { bool mHadAnySourcesBefore = (mAudioDecoder != NULL) || (mVideoDecoder != NULL); + // initialize video before audio because successful initialization of + // video may change deep buffer mode of audio. if (mNativeWindow != NULL) { instantiateDecoder(false, &mVideoDecoder); } if (mAudioSink != NULL) { + if (mOffloadAudio) { + // open audio sink early under offload mode. + sp format = mSource->getFormat(true /*audio*/); + openAudioSink(format, true /*offloadOnly*/); + } instantiateDecoder(true, &mAudioDecoder); } @@ -743,138 +751,7 @@ void NuPlayer::onMessageReceived(const sp &msg) { CHECK(msg->findMessage("format", &format)); if (audio) { - int32_t numChannels; - CHECK(format->findInt32( - "channel-count", &numChannels)); - - int32_t sampleRate; - CHECK(format->findInt32("sample-rate", &sampleRate)); - - ALOGV("Audio output format changed to %d Hz, %d channels", - sampleRate, numChannels); - - mAudioSink->close(); - - uint32_t flags; - int64_t durationUs; - // FIXME: we should handle the case where the video decoder - // is created after we receive the format change indication. - // Current code will just make that we select deep buffer - // with video which should not be a problem as it should - // not prevent from keeping A/V sync. - if (mVideoDecoder == NULL && - mSource->getDuration(&durationUs) == OK && - durationUs - > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) { - flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER; - } else { - flags = AUDIO_OUTPUT_FLAG_NONE; - } - - int32_t channelMask; - if (!format->findInt32("channel-mask", &channelMask)) { - channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER; - } - - if (mOffloadAudio) { - audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT; - audio_offload_info_t offloadInfo = - AUDIO_INFO_INITIALIZER; - - AString mime; - CHECK(format->findString("mime", &mime)); - - status_t err = - mapMimeToAudioFormat(audioFormat, mime.c_str()); - if (err != OK) { - ALOGE("Couldn't map mime \"%s\" to a valid " - "audio_format", mime.c_str()); - mOffloadAudio = false; - } else { - ALOGV("Mime \"%s\" mapped to audio_format 0x%x", - mime.c_str(), audioFormat); - - int32_t aacProfile = -1; - if (audioFormat == AUDIO_FORMAT_AAC - && format->findInt32("aac-profile", &aacProfile)) { - // Redefine AAC format as per aac profile - mapAACProfileToAudioFormat( - audioFormat, - aacProfile); - } - - flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; - - offloadInfo.duration_us = -1; - format->findInt64( - "durationUs", &offloadInfo.duration_us); - - int avgBitRate = -1; - format->findInt32("bit-rate", &avgBitRate); - - offloadInfo.sample_rate = sampleRate; - offloadInfo.channel_mask = channelMask; - offloadInfo.format = audioFormat; - offloadInfo.stream_type = AUDIO_STREAM_MUSIC; - offloadInfo.bit_rate = avgBitRate; - offloadInfo.has_video = (mVideoDecoder != NULL); - offloadInfo.is_streaming = true; - - ALOGV("try to open AudioSink in offload mode"); - err = mAudioSink->open( - sampleRate, - numChannels, - (audio_channel_mask_t)channelMask, - audioFormat, - 8 /* bufferCount */, - &NuPlayer::Renderer::AudioSinkCallback, - mRenderer.get(), - (audio_output_flags_t)flags, - &offloadInfo); - - if (err == OK) { - // If the playback is offloaded to h/w, we pass - // the HAL some metadata information. - // We don't want to do this for PCM because it - // will be going through the AudioFlinger mixer - // before reaching the hardware. - sp audioMeta = - mSource->getFormatMeta(true /* audio */); - sendMetaDataToHal(mAudioSink, audioMeta); - - err = mAudioSink->start(); - } - } - - if (err != OK) { - // Clean up, fall back to non offload mode. - mAudioSink->close(); - mAudioDecoder.clear(); - mRenderer->signalDisableOffloadAudio(); - mOffloadAudio = false; - - instantiateDecoder( - true /* audio */, &mAudioDecoder); - } - } - - if (!mOffloadAudio) { - flags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; - ALOGV("open AudioSink in NON-offload mode"); - CHECK_EQ(mAudioSink->open( - sampleRate, - numChannels, - (audio_channel_mask_t)channelMask, - AUDIO_FORMAT_PCM_16_BIT, - 8 /* bufferCount */, - NULL, - NULL, - (audio_output_flags_t)flags), - (status_t)OK); - mAudioSink->start(); - } - - mRenderer->signalAudioSinkChanged(); + openAudioSink(format, false /*offloadOnly*/); } else { // video sp inputFormat = @@ -981,7 +858,7 @@ void NuPlayer::onMessageReceived(const sp &msg) { ALOGV("Tear down audio offload, fall back to s/w path"); int64_t positionUs; CHECK(msg->findInt64("positionUs", &positionUs)); - mAudioSink->close(); + closeAudioSink(); mAudioDecoder.clear(); mRenderer->flush(true /* audio */); if (mVideoDecoder != NULL) { @@ -1108,6 +985,148 @@ void NuPlayer::postScanSources() { mScanSourcesPending = true; } +void NuPlayer::openAudioSink(const sp &format, bool offloadOnly) { + ALOGV("openAudioSink: offloadOnly(%d) mOffloadAudio(%d)", + offloadOnly, mOffloadAudio); + bool audioSinkChanged = false; + + int32_t numChannels; + CHECK(format->findInt32("channel-count", &numChannels)); + + int32_t channelMask; + if (!format->findInt32("channel-mask", &channelMask)) { + // signal to the AudioSink to derive the mask from count. + channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER; + } + + int32_t sampleRate; + CHECK(format->findInt32("sample-rate", &sampleRate)); + + uint32_t flags; + int64_t durationUs; + // FIXME: we should handle the case where the video decoder + // is created after we receive the format change indication. + // Current code will just make that we select deep buffer + // with video which should not be a problem as it should + // not prevent from keeping A/V sync. + if (mVideoDecoder == NULL && + mSource->getDuration(&durationUs) == OK && + durationUs + > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) { + flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER; + } else { + flags = AUDIO_OUTPUT_FLAG_NONE; + } + + if (mOffloadAudio) { + audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT; + AString mime; + CHECK(format->findString("mime", &mime)); + status_t err = mapMimeToAudioFormat(audioFormat, mime.c_str()); + + if (err != OK) { + ALOGE("Couldn't map mime \"%s\" to a valid " + "audio_format", mime.c_str()); + mOffloadAudio = false; + } else { + ALOGV("Mime \"%s\" mapped to audio_format 0x%x", + mime.c_str(), audioFormat); + + int avgBitRate = -1; + format->findInt32("bit-rate", &avgBitRate); + + int32_t aacProfile = -1; + if (audioFormat == AUDIO_FORMAT_AAC + && format->findInt32("aac-profile", &aacProfile)) { + // Redefine AAC format as per aac profile + mapAACProfileToAudioFormat( + audioFormat, + aacProfile); + } + + audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER; + offloadInfo.duration_us = -1; + format->findInt64( + "durationUs", &offloadInfo.duration_us); + offloadInfo.sample_rate = sampleRate; + offloadInfo.channel_mask = channelMask; + offloadInfo.format = audioFormat; + offloadInfo.stream_type = AUDIO_STREAM_MUSIC; + offloadInfo.bit_rate = avgBitRate; + offloadInfo.has_video = (mVideoDecoder != NULL); + offloadInfo.is_streaming = true; + + if (memcmp(&mCurrentOffloadInfo, &offloadInfo, sizeof(offloadInfo)) == 0) { + ALOGV("openAudioSink: no change in offload mode"); + return; // no change from previous configuration, everything ok. + } + ALOGV("openAudioSink: try to open AudioSink in offload mode"); + flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; + audioSinkChanged = true; + mAudioSink->close(); + err = mAudioSink->open( + sampleRate, + numChannels, + (audio_channel_mask_t)channelMask, + audioFormat, + 8 /* bufferCount */, + &NuPlayer::Renderer::AudioSinkCallback, + mRenderer.get(), + (audio_output_flags_t)flags, + &offloadInfo); + + if (err == OK) { + // If the playback is offloaded to h/w, we pass + // the HAL some metadata information. + // We don't want to do this for PCM because it + // will be going through the AudioFlinger mixer + // before reaching the hardware. + sp audioMeta = + mSource->getFormatMeta(true /* audio */); + sendMetaDataToHal(mAudioSink, audioMeta); + mCurrentOffloadInfo = offloadInfo; + err = mAudioSink->start(); + ALOGV_IF(err == OK, "openAudioSink: offload succeeded"); + } + if (err != OK) { + // Clean up, fall back to non offload mode. + mAudioSink->close(); + mRenderer->signalDisableOffloadAudio(); + mOffloadAudio = false; + mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; + ALOGV("openAudioSink: offload failed"); + } + } + } + if (!offloadOnly && !mOffloadAudio) { + flags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; + ALOGV("openAudioSink: open AudioSink in NON-offload mode"); + + audioSinkChanged = true; + mAudioSink->close(); + mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; + CHECK_EQ(mAudioSink->open( + sampleRate, + numChannels, + (audio_channel_mask_t)channelMask, + AUDIO_FORMAT_PCM_16_BIT, + 8 /* bufferCount */, + NULL, + NULL, + (audio_output_flags_t)flags), + (status_t)OK); + mAudioSink->start(); + } + if (audioSinkChanged) { + mRenderer->signalAudioSinkChanged(); + } +} + +void NuPlayer::closeAudioSink() { + mAudioSink->close(); + mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; +} + status_t NuPlayer::instantiateDecoder(bool audio, sp *decoder) { if (*decoder != NULL) { return OK; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index fc456a464f..48882c59c1 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -124,6 +124,7 @@ private: sp mVideoDecoder; bool mVideoIsAVC; bool mOffloadAudio; + audio_offload_info_t mCurrentOffloadInfo; sp mAudioDecoder; sp mCCDecoder; sp mRenderer; @@ -167,6 +168,9 @@ private: bool mStarted; + void openAudioSink(const sp &format, bool offloadOnly); + void closeAudioSink(); + status_t instantiateDecoder(bool audio, sp *decoder); void updateVideoSize( -- 2.11.0