OSDN Git Service

nuplayer: create AudioSink early to verify offload is possible
authorAndy Hung <hunga@google.com>
Thu, 14 Aug 2014 22:56:34 +0000 (15:56 -0700)
committerLajos Molnar <lajos@google.com>
Fri, 15 Aug 2014 02:43:15 +0000 (02:43 +0000)
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
media/libmediaplayerservice/nuplayer/NuPlayer.h

index 9a4e811..06c6e8d 100644 (file)
@@ -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<AMessage> &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<AMessage> format = mSource->getFormat(true /*audio*/);
+                    openAudioSink(format, true /*offloadOnly*/);
+                }
                 instantiateDecoder(true, &mAudioDecoder);
             }
 
@@ -743,138 +751,7 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &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<MetaData> 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<AMessage> inputFormat =
@@ -981,7 +858,7 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &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<AMessage> &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<MetaData> 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> *decoder) {
     if (*decoder != NULL) {
         return OK;
index fc456a4..48882c5 100644 (file)
@@ -124,6 +124,7 @@ private:
     sp<Decoder> mVideoDecoder;
     bool mVideoIsAVC;
     bool mOffloadAudio;
+    audio_offload_info_t mCurrentOffloadInfo;
     sp<Decoder> mAudioDecoder;
     sp<CCDecoder> mCCDecoder;
     sp<Renderer> mRenderer;
@@ -167,6 +168,9 @@ private:
 
     bool mStarted;
 
+    void openAudioSink(const sp<AMessage> &format, bool offloadOnly);
+    void closeAudioSink();
+
     status_t instantiateDecoder(bool audio, sp<Decoder> *decoder);
 
     void updateVideoSize(