Add support for deep audio buffers

Allow AudioSink to use deep audio buffering when the
source is audio only and its duration is more than
a certain threshold.
This helps improve battery life but implies higher
audio latency.

Change-Id: Ie79915b61c370292f05aabda9779356570e03cbb
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 9a8f4b0..a70fe8c 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -63,6 +63,9 @@
 // when the channel mask isn't known, use the channel count to derive a mask in AudioSink::open()
 #define CHANNEL_MASK_USE_CHANNEL_ORDER 0
 
+// duration below which we do not allow deep audio buffering
+#define AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US 5000000
+
 // callback mechanism for passing messages to MediaPlayer object
 typedef void (*notify_callback_f)(void* cookie,
         int msg, int ext1, int ext2, const Parcel *obj);
@@ -98,7 +101,8 @@
                 audio_format_t format=AUDIO_FORMAT_PCM_16_BIT,
                 int bufferCount=DEFAULT_AUDIOSINK_BUFFERCOUNT,
                 AudioCallback cb = NULL,
-                void *cookie = NULL) = 0;
+                void *cookie = NULL,
+                audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE) = 0;
 
         virtual void        start() = 0;
         virtual ssize_t     write(const void* buffer, size_t size) = 0;
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index 70c47ae..9e8e4bb 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -37,6 +37,7 @@
     };
 
     AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink,
+                bool allowDeepBuffering = false,
                 AwesomePlayer *audioObserver = NULL);
 
     virtual ~AudioPlayer();
@@ -95,6 +96,8 @@
     MediaBuffer *mFirstBuffer;
 
     sp<MediaPlayerBase::AudioSink> mAudioSink;
+    bool mAllowDeepBuffering;       // allow audio deep audio buffers. Helps with low power audio
+                                    // playback but implies high latency
     AwesomePlayer *mObserver;
 
     static void AudioCallback(int event, void *user, void *info);
diff --git a/libvideoeditor/lvpp/VideoEditorPlayer.cpp b/libvideoeditor/lvpp/VideoEditorPlayer.cpp
index c9cff81..fc9fb49 100755
--- a/libvideoeditor/lvpp/VideoEditorPlayer.cpp
+++ b/libvideoeditor/lvpp/VideoEditorPlayer.cpp
@@ -392,7 +392,7 @@
 status_t VideoEditorPlayer::VeAudioOutput::open(
         uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
         audio_format_t format, int bufferCount,
-        AudioCallback cb, void *cookie) {
+        AudioCallback cb, void *cookie, audio_output_flags_t flags) {
 
     mCallback = cb;
     mCallbackCookie = cookie;
@@ -442,7 +442,7 @@
                 format,
                 channelMask,
                 frameCount,
-                AUDIO_OUTPUT_FLAG_NONE,
+                flags,
                 CallbackWrapper,
                 this);
     } else {
@@ -451,7 +451,8 @@
                 sampleRate,
                 format,
                 channelMask,
-                frameCount);
+                frameCount,
+                flags);
     }
 
     if ((t == 0) || (t->initCheck() != NO_ERROR)) {
diff --git a/libvideoeditor/lvpp/VideoEditorPlayer.h b/libvideoeditor/lvpp/VideoEditorPlayer.h
index 350b384..2ab4eef 100755
--- a/libvideoeditor/lvpp/VideoEditorPlayer.h
+++ b/libvideoeditor/lvpp/VideoEditorPlayer.h
@@ -52,7 +52,7 @@
         virtual status_t        open(
                 uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
                 audio_format_t format, int bufferCount,
-                AudioCallback cb, void *cookie);
+                AudioCallback cb, void *cookie, audio_output_flags_t flags);
 
         virtual void            start();
         virtual ssize_t         write(const void* buffer, size_t size);
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 092b516..25d79d6 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -225,6 +225,10 @@
         flags = (audio_output_flags_t)
                 ((flags | AUDIO_OUTPUT_FLAG_DIRECT) & ~AUDIO_OUTPUT_FLAG_FAST);
     }
+    // only allow deep buffering for music stream type
+    if (streamType != AUDIO_STREAM_MUSIC) {
+        flags = (audio_output_flags_t)(flags &~AUDIO_OUTPUT_FLAG_DEEP_BUFFER);
+    }
 
     if (!audio_is_output_channel(channelMask)) {
         ALOGE("Invalid channel mask");
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 7254599..bfdf250 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1412,7 +1412,8 @@
       mCallbackCookie(NULL),
       mCallbackData(NULL),
       mBytesWritten(0),
-      mSessionId(sessionId) {
+      mSessionId(sessionId),
+      mFlags(AUDIO_OUTPUT_FLAG_NONE) {
     ALOGV("AudioOutput(%d)", sessionId);
     mTrack = 0;
     mRecycledTrack = 0;
@@ -1506,7 +1507,8 @@
 status_t MediaPlayerService::AudioOutput::open(
         uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
         audio_format_t format, int bufferCount,
-        AudioCallback cb, void *cookie)
+        AudioCallback cb, void *cookie,
+        audio_output_flags_t flags)
 {
     mCallback = cb;
     mCallbackCookie = cookie;
@@ -1521,7 +1523,7 @@
             format, bufferCount, mSessionId);
     int afSampleRate;
     int afFrameCount;
-    int frameCount;
+    uint32_t frameCount;
 
     if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) {
         return NO_INIT;
@@ -1539,6 +1541,7 @@
             return NO_INIT;
         }
     }
+
     if (mRecycledTrack) {
         // check if the existing track can be reused as-is, or if a new track needs to be created.
 
@@ -1553,6 +1556,9 @@
                 (mRecycledTrack->frameCount() != frameCount)) {
             ALOGV("samplerate, channelcount or framecount differ");
             reuse = false;
+        } if (flags != mFlags) {
+            ALOGV("output flags differ");
+            reuse = false;
         }
         if (reuse) {
             ALOGV("chaining to next output");
@@ -1587,7 +1593,7 @@
                 format,
                 channelMask,
                 frameCount,
-                AUDIO_OUTPUT_FLAG_NONE,
+                flags,
                 CallbackWrapper,
                 mCallbackData,
                 0,  // notification frames
@@ -1599,7 +1605,7 @@
                 format,
                 channelMask,
                 frameCount,
-                AUDIO_OUTPUT_FLAG_NONE,
+                flags,
                 NULL,
                 NULL,
                 0,
@@ -1616,6 +1622,7 @@
     t->setVolume(mLeftVolume, mRightVolume);
 
     mSampleRateHz = sampleRate;
+    mFlags = flags;
     mMsecsPerFrame = mPlaybackRatePermille / (float) sampleRate;
     uint32_t pos;
     if (t->getPosition(&pos) == OK) {
@@ -1891,7 +1898,7 @@
 status_t MediaPlayerService::AudioCache::open(
         uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
         audio_format_t format, int bufferCount,
-        AudioCallback cb, void *cookie)
+        AudioCallback cb, void *cookie, audio_output_flags_t flags)
 {
     ALOGV("open(%u, %d, 0x%x, %d, %d)", sampleRate, channelCount, channelMask, format, bufferCount);
     if (mHeap->getHeapID() < 0) {
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 2a8cfd2..95b1b05 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -91,7 +91,8 @@
         virtual status_t        open(
                 uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
                 audio_format_t format, int bufferCount,
-                AudioCallback cb, void *cookie);
+                AudioCallback cb, void *cookie,
+                audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE);
 
         virtual void            start();
         virtual ssize_t         write(const void* buffer, size_t size);
@@ -135,6 +136,7 @@
         int                     mAuxEffectId;
         static bool             mIsOnEmulator;
         static int              mMinBufferCount;  // 12 for emulator; otherwise 4
+        audio_output_flags_t    mFlags;
 
         // CallbackData is what is passed to the AudioTrack as the "user" data.
         // We need to be able to target this to a different Output on the fly,
@@ -190,7 +192,8 @@
         virtual status_t        open(
                 uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
                 audio_format_t format, int bufferCount = 1,
-                AudioCallback cb = NULL, void *cookie = NULL);
+                AudioCallback cb = NULL, void *cookie = NULL,
+                audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE);
 
         virtual void            start();
         virtual ssize_t         write(const void* buffer, size_t size);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 11cea3b..f1467c4 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -390,12 +390,30 @@
                          sampleRate, numChannels);
 
                     mAudioSink->close();
+
+                    audio_output_flags_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;
+                    }
+
                     CHECK_EQ(mAudioSink->open(
                                 sampleRate,
                                 numChannels,
                                 CHANNEL_MASK_USE_CHANNEL_ORDER,
                                 AUDIO_FORMAT_PCM_16_BIT,
-                                8 /* bufferCount */),
+                                8 /* bufferCount */,
+                                NULL,
+                                NULL,
+                                flags),
                              (status_t)OK);
                     mAudioSink->start();
 
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 468fe2c..2e0b013 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -33,6 +33,7 @@
 
 AudioPlayer::AudioPlayer(
         const sp<MediaPlayerBase::AudioSink> &audioSink,
+        bool allowDeepBuffering,
         AwesomePlayer *observer)
     : mAudioTrack(NULL),
       mInputBuffer(NULL),
@@ -50,6 +51,7 @@
       mFirstBufferResult(OK),
       mFirstBuffer(NULL),
       mAudioSink(audioSink),
+      mAllowDeepBuffering(allowDeepBuffering),
       mObserver(observer) {
 }
 
@@ -120,10 +122,15 @@
     }
 
     if (mAudioSink.get() != NULL) {
+
         status_t err = mAudioSink->open(
                 mSampleRate, numChannels, channelMask, AUDIO_FORMAT_PCM_16_BIT,
                 DEFAULT_AUDIOSINK_BUFFERCOUNT,
-                &AudioPlayer::AudioSinkCallback, this);
+                &AudioPlayer::AudioSinkCallback,
+                this,
+                (mAllowDeepBuffering ?
+                            AUDIO_OUTPUT_FLAG_DEEP_BUFFER :
+                            AUDIO_OUTPUT_FLAG_NONE));
         if (err != OK) {
             if (mFirstBuffer != NULL) {
                 mFirstBuffer->release();
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index b67476b..b15cb67 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -870,7 +870,18 @@
     if (mAudioSource != NULL) {
         if (mAudioPlayer == NULL) {
             if (mAudioSink != NULL) {
-                mAudioPlayer = new AudioPlayer(mAudioSink, this);
+                bool allowDeepBuffering;
+                int64_t cachedDurationUs;
+                bool eos;
+                if (mVideoSource == NULL && (mDurationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US ||
+                        getCachedDuration_l(&cachedDurationUs, &eos) &&
+                        cachedDurationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US)) {
+                    allowDeepBuffering = true;
+                } else {
+                    allowDeepBuffering = false;
+                }
+
+                mAudioPlayer = new AudioPlayer(mAudioSink, allowDeepBuffering, this);
                 mAudioPlayer->setSource(mAudioSource);
 
                 mTimeSource = mAudioPlayer;