move audio sink open/close to NuPlayerRenderer

Bug: 17675112
Change-Id: I7eb3d02380658f848baedafe2aea287586ccf016
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index eb5821b..a63a940 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -153,7 +153,6 @@
       mSourceFlags(0),
       mVideoIsAVC(false),
       mOffloadAudio(false),
-      mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER),
       mAudioDecoderGeneration(0),
       mVideoDecoderGeneration(0),
       mRendererGeneration(0),
@@ -1112,30 +1111,15 @@
 }
 
 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;
+    bool hasVideo = (mVideoDecoder != NULL);
     // 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 &&
+    if (hasVideo &&
             mSource->getDuration(&durationUs) == OK &&
             durationUs
                 > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) {
@@ -1144,114 +1128,18 @@
         flags = AUDIO_OUTPUT_FLAG_NONE;
     }
 
+    mOffloadAudio = mRenderer->openAudioSink(
+            format, offloadOnly, hasVideo, flags);
+
     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;
-            flags &= ~AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
-            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();
+        sp<MetaData> audioMeta =
+                mSource->getFormatMeta(true /* audio */);
+        sendMetaDataToHal(mAudioSink, audioMeta);
     }
 }
 
 void NuPlayer::closeAudioSink() {
-    mAudioSink->close();
-    mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
+    mRenderer->closeAudioSink();
 }
 
 status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index c61510c..d6120d2 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -132,7 +132,6 @@
     sp<Decoder> mVideoDecoder;
     bool mVideoIsAVC;
     bool mOffloadAudio;
-    audio_offload_info_t mCurrentOffloadInfo;
     sp<Decoder> mAudioDecoder;
     sp<CCDecoder> mCCDecoder;
     sp<Renderer> mRenderer;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 7b9dbb7..e5c83dd 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -28,6 +28,7 @@
 #include <media/stagefright/foundation/AUtils.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
 
 #include <VideoFrameScheduler.h>
 
@@ -80,7 +81,8 @@
       mVideoRenderingStartGeneration(0),
       mAudioRenderingStartGeneration(0),
       mAudioOffloadPauseTimeoutGeneration(0),
-      mAudioOffloadTornDown(false) {
+      mAudioOffloadTornDown(false),
+      mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER) {
     readProperties();
 }
 
@@ -237,8 +239,72 @@
     mPauseStartedTimeRealUs = realUs;
 }
 
+bool NuPlayer::Renderer::openAudioSink(
+        const sp<AMessage> &format,
+        bool offloadOnly,
+        bool hasVideo,
+        uint32_t flags) {
+    sp<AMessage> msg = new AMessage(kWhatOpenAudioSink, id());
+    msg->setMessage("format", format);
+    msg->setInt32("offload-only", offloadOnly);
+    msg->setInt32("has-video", hasVideo);
+    msg->setInt32("flags", flags);
+
+    sp<AMessage> response;
+    msg->postAndAwaitResponse(&response);
+
+    int32_t offload;
+    CHECK(response->findInt32("offload", &offload));
+    return (offload != 0);
+}
+
+void NuPlayer::Renderer::closeAudioSink() {
+    sp<AMessage> msg = new AMessage(kWhatCloseAudioSink, id());
+
+    sp<AMessage> response;
+    msg->postAndAwaitResponse(&response);
+}
+
 void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {
     switch (msg->what()) {
+        case kWhatOpenAudioSink:
+        {
+            sp<AMessage> format;
+            CHECK(msg->findMessage("format", &format));
+
+            int32_t offloadOnly;
+            CHECK(msg->findInt32("offload-only", &offloadOnly));
+
+            int32_t hasVideo;
+            CHECK(msg->findInt32("has-video", &hasVideo));
+
+            uint32_t flags;
+            CHECK(msg->findInt32("flags", (int32_t *)&flags));
+
+            bool offload = onOpenAudioSink(format, offloadOnly, hasVideo, flags);
+
+            sp<AMessage> response = new AMessage;
+            response->setInt32("offload", offload);
+
+            uint32_t replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+            response->postReply(replyID);
+
+            break;
+        }
+
+        case kWhatCloseAudioSink:
+        {
+            uint32_t replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
+            onCloseAudioSink();
+
+            sp<AMessage> response = new AMessage;
+            response->postReply(replyID);
+            break;
+        }
+
         case kWhatStopAudioSink:
         {
             mAudioSink->stop();
@@ -1162,5 +1228,136 @@
     }
 }
 
+bool NuPlayer::Renderer::onOpenAudioSink(
+        const sp<AMessage> &format,
+        bool offloadOnly,
+        bool hasVideo,
+        uint32_t flags) {
+    ALOGV("openAudioSink: offloadOnly(%d) offloadingAudio(%d)",
+            offloadOnly, offloadingAudio());
+    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));
+
+    if (offloadingAudio()) {
+        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());
+            onDisableOffloadAudio();
+        } 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 = hasVideo;
+            offloadInfo.is_streaming = true;
+
+            if (memcmp(&mCurrentOffloadInfo, &offloadInfo, sizeof(offloadInfo)) == 0) {
+                ALOGV("openAudioSink: no change in offload mode");
+                // no change from previous configuration, everything ok.
+                return offloadingAudio();
+            }
+            ALOGV("openAudioSink: try to open AudioSink in offload mode");
+            flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
+            flags &= ~AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
+            audioSinkChanged = true;
+            mAudioSink->close();
+            err = mAudioSink->open(
+                    sampleRate,
+                    numChannels,
+                    (audio_channel_mask_t)channelMask,
+                    audioFormat,
+                    8 /* bufferCount */,
+                    &NuPlayer::Renderer::AudioSinkCallback,
+                    this,
+                    (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.
+                // TODO
+                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();
+                onDisableOffloadAudio();
+                mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
+                ALOGV("openAudioSink: offload failed");
+            }
+        }
+    }
+    if (!offloadOnly && !offloadingAudio()) {
+        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) {
+        onAudioSinkChanged();
+    }
+
+    return offloadingAudio();
+}
+
+void NuPlayer::Renderer::onCloseAudioSink() {
+    mAudioSink->close();
+    mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
+}
+
 }  // namespace android
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index db1dab6..3e30226 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -70,6 +70,13 @@
     int64_t getVideoLateByUs();
     void setPauseStartedTimeRealUs(int64_t realUs);
 
+    bool openAudioSink(
+            const sp<AMessage> &format,
+            bool offloadOnly,
+            bool hasVideo,
+            uint32_t flags);
+    void closeAudioSink();
+
     enum {
         kWhatEOS                 = 'eos ',
         kWhatFlushComplete       = 'fluC',
@@ -100,6 +107,8 @@
         kWhatAudioSinkChanged    = 'auSC',
         kWhatPause               = 'paus',
         kWhatResume              = 'resm',
+        kWhatOpenAudioSink       = 'opnA',
+        kWhatCloseAudioSink      = 'clsA',
         kWhatStopAudioSink       = 'stpA',
         kWhatDisableOffloadAudio = 'noOA',
         kWhatSetVideoFrameRate   = 'sVFR',
@@ -158,6 +167,7 @@
 
     int32_t mAudioOffloadPauseTimeoutGeneration;
     bool mAudioOffloadTornDown;
+    audio_offload_info_t mCurrentOffloadInfo;
 
     size_t fillAudioBuffer(void *buffer, size_t size);
 
@@ -183,6 +193,12 @@
     void onResume();
     void onSetVideoFrameRate(float fps);
     void onAudioOffloadTearDown(AudioOffloadTearDownReason reason);
+    bool onOpenAudioSink(
+            const sp<AMessage> &format,
+            bool offloadOnly,
+            bool hasVideo,
+            uint32_t flags);
+    void onCloseAudioSink();
 
     void notifyEOS(bool audio, status_t finalResult, int64_t delayUs = 0);
     void notifyFlushComplete(bool audio);