Merge "Make sure we restore our input buffer to its original state if we want to revisit it."
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 80d2d72..70f79c6 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -38,7 +38,7 @@
 
 // ----------------------------------------------------------------------------
 
-class AudioRecord
+class AudioRecord : virtual public RefBase
 {
 public:
 
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 4906bd3..98b1f3e 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -138,7 +138,7 @@
      * frameCount:         Minimum size of track PCM buffer in frames. This defines the
      *                     latency of the track. The actual size selected by the AudioTrack could be
      *                     larger if the requested size is not compatible with current audio HAL
-     *                     latency.
+     *                     latency.  Zero means to use a default value.
      * flags:              See comments on audio_output_flags_t in <system/audio.h>.
      * cbf:                Callback function. If not null, this function is called periodically
      *                     to request new PCM data.
@@ -460,12 +460,24 @@
     {
     public:
         AudioTrackThread(AudioTrack& receiver, bool bCanCallJava = false);
+
+        // Do not call Thread::requestExitAndWait() without first calling requestExit().
+        // Thread::requestExitAndWait() is not virtual, and the implementation doesn't do enough.
+        virtual void        requestExit();
+
+                void        pause();    // suspend thread from execution at next loop boundary
+                void        resume();   // allow thread to execute, if not requested to exit
+
     private:
         friend class AudioTrack;
         virtual bool        threadLoop();
         virtual status_t    readyToRun();
         virtual void        onFirstRef();
         AudioTrack& mReceiver;
+        ~AudioTrackThread();
+        Mutex               mMyLock;    // Thread::mLock is private
+        Condition           mMyCond;    // Thread::mThreadExitedCondition is private
+        bool                mPaused;    // whether thread is currently paused
     };
 
             // body of AudioTrackThread::threadLoop()
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 04ac3ee..86e228b 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -65,6 +65,7 @@
                                 track_flags_t flags,
                                 const sp<IMemory>& sharedBuffer,
                                 audio_io_handle_t output,
+                                pid_t tid,  // -1 means unused, otherwise must be valid non-0
                                 int *sessionId,
                                 status_t *status) = 0;
 
diff --git a/include/media/IAudioRecord.h b/include/media/IAudioRecord.h
index c486c6b..ebc03ea 100644
--- a/include/media/IAudioRecord.h
+++ b/include/media/IAudioRecord.h
@@ -35,10 +35,9 @@
     DECLARE_META_INTERFACE(AudioRecord);
 
     /* After it's created the track is not active. Call start() to
-     * make it active. If set, the callback will start being called.
-     * tid identifies the client callback thread, or 0 if not needed.
+     * make it active.
      */
-    virtual status_t    start(pid_t tid, int event, int triggerSession) = 0;
+    virtual status_t    start(int event, int triggerSession) = 0;
 
     /* Stop a track. If set, the callback will cease being called and
      * obtainBuffer will return an error. Buffers that are already released
diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h
index 577b095..9e0e389 100644
--- a/include/media/IAudioTrack.h
+++ b/include/media/IAudioTrack.h
@@ -39,10 +39,9 @@
     virtual sp<IMemory> getCblk() const = 0;
 
     /* After it's created the track is not active. Call start() to
-     * make it active. If set, the callback will start being called.
-     * tid identifies the client callback thread, or 0 if not needed.
+     * make it active.
      */
-    virtual status_t    start(pid_t tid) = 0;
+    virtual status_t    start() = 0;
 
     /* Stop a track. If set, the callback will cease being called and
      * obtainBuffer will return an error. Buffers that are already released
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/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index af2db93..469f5ff 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -53,6 +53,7 @@
 #define CBLK_RESTORED_MSK       0x0040
 #define CBLK_RESTORED_ON        0x0040  // track has been restored after invalidation
 #define CBLK_RESTORED_OFF       0x0040  // by AudioFlinger
+#define CBLK_FAST               0x0080  // AudioFlinger successfully created a fast track
 
 // Important: do not add any virtual methods, including ~
 struct audio_track_cblk_t
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/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 1fdc536..950f5c6 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -321,8 +321,8 @@
         cblk->lock.lock();
         if (!(cblk->flags & CBLK_INVALID_MSK)) {
             cblk->lock.unlock();
-            ALOGV("mAudioRecord->start(tid=%d)", tid);
-            ret = mAudioRecord->start(tid, event, triggerSession);
+            ALOGV("mAudioRecord->start()");
+            ret = mAudioRecord->start(event, triggerSession);
             cblk->lock.lock();
             if (ret == DEAD_OBJECT) {
                 android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
@@ -542,7 +542,7 @@
                             "user=%08x, server=%08x", cblk->user, cblk->server);
                     cblk->lock.unlock();
                     // callback thread or sync event hasn't changed
-                    result = mAudioRecord->start(0, AudioSystem::SYNC_EVENT_SAME, 0);
+                    result = mAudioRecord->start(AudioSystem::SYNC_EVENT_SAME, 0);
                     cblk->lock.lock();
                     if (result == DEAD_OBJECT) {
                         android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
@@ -781,7 +781,7 @@
                 mFrameCount, getInput_l());
         if (result == NO_ERROR) {
             // callback thread or sync event hasn't changed
-            result = mAudioRecord->start(0, AudioSystem::SYNC_EVENT_SAME, 0);
+            result = mAudioRecord->start(AudioSystem::SYNC_EVENT_SAME, 0);
         }
         if (result != NO_ERROR) {
             mActive = false;
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 092b516..9d338f3 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -73,6 +73,8 @@
 
     *frameCount = (sampleRate == 0) ? afFrameCount * minBufCount :
             afFrameCount * minBufCount * sampleRate / afSampleRate;
+    ALOGV("getMinFrameCount=%d: afFrameCount=%d, minBufCount=%d, afSampleRate=%d, afLatency=%d",
+            *frameCount, afFrameCount, minBufCount, afSampleRate, afLatency);
     return NO_ERROR;
 }
 
@@ -159,6 +161,7 @@
         // Otherwise the callback thread will never exit.
         stop();
         if (mAudioTrackThread != 0) {
+            mAudioTrackThread->requestExit();   // see comment in AudioTrack.h
             mAudioTrackThread->requestExitAndWait();
             mAudioTrackThread.clear();
         }
@@ -223,8 +226,13 @@
     // force direct flag if format is not linear PCM
     if (!audio_is_linear_pcm(format)) {
         flags = (audio_output_flags_t)
+                // FIXME why can't we allow direct AND fast?
                 ((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");
@@ -251,6 +259,11 @@
     mAuxEffectId = 0;
     mCbf = cbf;
 
+    if (cbf != NULL) {
+        mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
+        mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
+    }
+
     // create the IAudioTrack
     status_t status = createTrack_l(streamType,
                                   sampleRate,
@@ -262,13 +275,13 @@
                                   output);
 
     if (status != NO_ERROR) {
+        if (mAudioTrackThread != 0) {
+            mAudioTrackThread->requestExit();
+            mAudioTrackThread.clear();
+        }
         return status;
     }
 
-    if (cbf != NULL) {
-        mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
-    }
-
     mStatus = NO_ERROR;
 
     mStreamType = streamType;
@@ -345,14 +358,6 @@
     status_t status = NO_ERROR;
 
     ALOGV("start %p", this);
-    if (t != 0) {
-        if (t->exitPending()) {
-            if (t->requestExitAndWait() == WOULD_BLOCK) {
-                ALOGE("AudioTrack::start called from thread");
-                return;
-            }
-        }
-    }
 
     AutoMutex lock(mLock);
     // acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed
@@ -369,26 +374,19 @@
         cblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
         cblk->waitTimeMs = 0;
         android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags);
-        pid_t tid;
         if (t != 0) {
-            t->run("AudioTrack", ANDROID_PRIORITY_AUDIO);
-            tid = t->getTid();  // pid_t is unknown until run()
-            ALOGV("getTid=%d", tid);
-            if (tid == -1) {
-                tid = 0;
-            }
+            t->resume();
         } else {
             mPreviousPriority = getpriority(PRIO_PROCESS, 0);
             mPreviousSchedulingGroup = androidGetThreadSchedulingGroup(0);
             androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
-            tid = 0;    // not gettid()
         }
 
         ALOGV("start %p before lock cblk %p", this, mCblk);
         if (!(cblk->flags & CBLK_INVALID_MSK)) {
             cblk->lock.unlock();
-            ALOGV("mAudioTrack->start(tid=%d)", tid);
-            status = mAudioTrack->start(tid);
+            ALOGV("mAudioTrack->start()");
+            status = mAudioTrack->start();
             cblk->lock.lock();
             if (status == DEAD_OBJECT) {
                 android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
@@ -402,7 +400,7 @@
             ALOGV("start() failed");
             mActive = false;
             if (t != 0) {
-                t->requestExit();
+                t->pause();
             } else {
                 setpriority(PRIO_PROCESS, 0, mPreviousPriority);
                 androidSetThreadSchedulingGroup(0, mPreviousSchedulingGroup);
@@ -435,7 +433,7 @@
             flush_l();
         }
         if (t != 0) {
-            t->requestExit();
+            t->pause();
         } else {
             setpriority(PRIO_PROCESS, 0, mPreviousPriority);
             androidSetThreadSchedulingGroup(0, mPreviousSchedulingGroup);
@@ -767,7 +765,7 @@
             (sharedBuffer != 0) ||
             // use case 2: callback handler
             (mCbf != NULL))) {
-        ALOGW("AUDIO_OUTPUT_FLAG_FAST denied");
+        ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client");
         flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_FAST);
     }
     ALOGV("createTrack_l() output %d afFrameCount %d afLatency %d", output, afFrameCount, afLatency);
@@ -783,6 +781,13 @@
         if (minBufCount < 2) minBufCount = 2;
 
         int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate;
+        ALOGV("minFrameCount: %d, afFrameCount=%d, minBufCount=%d, sampleRate=%d, afSampleRate=%d"
+                ", afLatency=%d",
+                minFrameCount, afFrameCount, minBufCount, sampleRate, afSampleRate, afLatency);
+#define MIN_FRAME_COUNT_FAST 128    // FIXME hard-coded
+        if ((flags & AUDIO_OUTPUT_FLAG_FAST) && (minFrameCount > MIN_FRAME_COUNT_FAST)) {
+            minFrameCount = MIN_FRAME_COUNT_FAST;
+        }
 
         if (sharedBuffer == 0) {
             if (frameCount == 0) {
@@ -796,7 +801,7 @@
             if (mNotificationFramesAct > (uint32_t)frameCount/2) {
                 mNotificationFramesAct = frameCount/2;
             }
-            if (frameCount < minFrameCount && !(flags & AUDIO_OUTPUT_FLAG_FAST)) {
+            if (frameCount < minFrameCount) {
                 // not ALOGW because it happens all the time when playing key clicks over A2DP
                 ALOGV("Minimum buffer size corrected from %d to %d",
                          frameCount, minFrameCount);
@@ -817,8 +822,13 @@
     if (mIsTimed) {
         trackFlags |= IAudioFlinger::TRACK_TIMED;
     }
+
+    pid_t tid = -1;
     if (flags & AUDIO_OUTPUT_FLAG_FAST) {
         trackFlags |= IAudioFlinger::TRACK_FAST;
+        if (mAudioTrackThread != 0) {
+            tid = mAudioTrackThread->getTid();
+        }
     }
 
     sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),
@@ -830,6 +840,7 @@
                                                       trackFlags,
                                                       sharedBuffer,
                                                       output,
+                                                      tid,
                                                       &mSessionId,
                                                       &status);
 
@@ -845,7 +856,15 @@
     mAudioTrack = track;
     mCblkMemory = cblk;
     mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
-    android_atomic_or(CBLK_DIRECTION_OUT, &mCblk->flags);
+    // old has the previous value of mCblk->flags before the "or" operation
+    int32_t old = android_atomic_or(CBLK_DIRECTION_OUT, &mCblk->flags);
+    if (flags & AUDIO_OUTPUT_FLAG_FAST) {
+        if (old & CBLK_FAST) {
+            ALOGI("AUDIO_OUTPUT_FLAG_FAST successful; frameCount %u", mCblk->frameCount);
+        } else {
+            ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %u", mCblk->frameCount);
+        }
+    }
     if (sharedBuffer == 0) {
         mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
     } else {
@@ -922,7 +941,7 @@
                                 "user=%08x, server=%08x", this, cblk->user, cblk->server);
                         //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140)
                         cblk->lock.unlock();
-                        result = mAudioTrack->start(0); // callback thread hasn't changed
+                        result = mAudioTrack->start();
                         cblk->lock.lock();
                         if (result == DEAD_OBJECT) {
                             android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
@@ -954,7 +973,7 @@
     if (mActive && (cblk->flags & CBLK_DISABLED_MSK)) {
         android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags);
         ALOGW("obtainBuffer() track %p disabled, restarting", this);
-        mAudioTrack->start(0);  // callback thread hasn't changed
+        mAudioTrack->start();
     }
 
     cblk->waitTimeMs = 0;
@@ -1092,7 +1111,7 @@
     if (mActive && (mCblk->flags & CBLK_DISABLED_MSK)) {
         android_atomic_and(~CBLK_DISABLED_ON, &mCblk->flags);
         ALOGW("queueTimedBuffer() track %p disabled, restarting", this);
-        mAudioTrack->start(0);
+        mAudioTrack->start();
     }
 
     return mAudioTrack->queueTimedBuffer(buffer, pts);
@@ -1297,7 +1316,7 @@
                 }
             }
             if (mActive) {
-                result = mAudioTrack->start(0); // callback thread hasn't changed
+                result = mAudioTrack->start();
                 ALOGW_IF(result != NO_ERROR, "restoreTrack_l() start() failed status %d", result);
             }
             if (fromStart && result == NO_ERROR) {
@@ -1365,12 +1384,24 @@
 // =========================================================================
 
 AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava)
-    : Thread(bCanCallJava), mReceiver(receiver)
+    : Thread(bCanCallJava), mReceiver(receiver), mPaused(true)
+{
+}
+
+AudioTrack::AudioTrackThread::~AudioTrackThread()
 {
 }
 
 bool AudioTrack::AudioTrackThread::threadLoop()
 {
+    {
+        AutoMutex _l(mMyLock);
+        if (mPaused) {
+            mMyCond.wait(mMyLock);
+            // caller will check for exitPending()
+            return true;
+        }
+    }
     return mReceiver.processAudioBuffer(this);
 }
 
@@ -1383,6 +1414,28 @@
 {
 }
 
+void AudioTrack::AudioTrackThread::requestExit()
+{
+    // must be in this order to avoid a race condition
+    Thread::requestExit();
+    mMyCond.signal();
+}
+
+void AudioTrack::AudioTrackThread::pause()
+{
+    AutoMutex _l(mMyLock);
+    mPaused = true;
+}
+
+void AudioTrack::AudioTrackThread::resume()
+{
+    AutoMutex _l(mMyLock);
+    if (mPaused) {
+        mPaused = false;
+        mMyCond.signal();
+    }
+}
+
 // =========================================================================
 
 
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 2b5126f..e8dd438 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -91,6 +91,7 @@
                                 track_flags_t flags,
                                 const sp<IMemory>& sharedBuffer,
                                 audio_io_handle_t output,
+                                pid_t tid,
                                 int *sessionId,
                                 status_t *status)
     {
@@ -106,6 +107,7 @@
         data.writeInt32((int32_t) flags);
         data.writeStrongBinder(sharedBuffer->asBinder());
         data.writeInt32((int32_t) output);
+        data.writeInt32((int32_t) tid);
         int lSessionId = 0;
         if (sessionId != NULL) {
             lSessionId = *sessionId;
@@ -701,11 +703,12 @@
             track_flags_t flags = (track_flags_t) data.readInt32();
             sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder());
             audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
+            pid_t tid = (pid_t) data.readInt32();
             int sessionId = data.readInt32();
             status_t status;
             sp<IAudioTrack> track = createTrack(pid,
                     (audio_stream_type_t) streamType, sampleRate, format,
-                    channelCount, bufferCount, flags, buffer, output, &sessionId, &status);
+                    channelCount, bufferCount, flags, buffer, output, tid, &sessionId, &status);
             reply->writeInt32(sessionId);
             reply->writeInt32(status);
             reply->writeStrongBinder(track->asBinder());
diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp
index 58c6d38..57a80a9 100644
--- a/media/libmedia/IAudioRecord.cpp
+++ b/media/libmedia/IAudioRecord.cpp
@@ -42,11 +42,10 @@
     {
     }
 
-    virtual status_t start(pid_t tid, int event, int triggerSession)
+    virtual status_t start(int event, int triggerSession)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor());
-        data.writeInt32(tid);
         data.writeInt32(event);
         data.writeInt32(triggerSession);
         status_t status = remote()->transact(START, data, &reply);
@@ -93,10 +92,9 @@
         } break;
         case START: {
             CHECK_INTERFACE(IAudioRecord, data, reply);
-            pid_t tid = (pid_t) data.readInt32();
             int event = data.readInt32();
             int triggerSession = data.readInt32();
-            reply->writeInt32(start(tid, event, triggerSession));
+            reply->writeInt32(start(event, triggerSession));
             return NO_ERROR;
         } break;
         case STOP: {
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
index 09f31a7..867d1a5 100644
--- a/media/libmedia/IAudioTrack.cpp
+++ b/media/libmedia/IAudioTrack.cpp
@@ -61,11 +61,10 @@
         return cblk;
     }
 
-    virtual status_t start(pid_t tid)
+    virtual status_t start()
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
-        data.writeInt32(tid);
         status_t status = remote()->transact(START, data, &reply);
         if (status == NO_ERROR) {
             status = reply.readInt32();
@@ -180,7 +179,7 @@
         } break;
         case START: {
             CHECK_INTERFACE(IAudioTrack, data, reply);
-            reply->writeInt32(start(data.readInt32()));
+            reply->writeInt32(start());
             return NO_ERROR;
         } break;
         case STOP: {
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;
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 4667649..7202b8b 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -68,4 +68,6 @@
 
 LOCAL_CFLAGS += -DSTATE_QUEUE_INSTANTIATIONS='"StateQueueInstantiations.cpp"'
 
+LOCAL_CFLAGS += -UHAVE_REQUEST_PRIORITY
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index bce30d7..865051f 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -401,6 +401,7 @@
         IAudioFlinger::track_flags_t flags,
         const sp<IMemory>& sharedBuffer,
         audio_io_handle_t output,
+        pid_t tid,
         int *sessionId,
         status_t *status)
 {
@@ -458,9 +459,8 @@
         }
         ALOGV("createTrack() lSessionId: %d", lSessionId);
 
-        bool isTimed = (flags & IAudioFlinger::TRACK_TIMED) != 0;
         track = thread->createTrack_l(client, streamType, sampleRate, format,
-                channelMask, frameCount, sharedBuffer, lSessionId, flags, &lStatus);
+                channelMask, frameCount, sharedBuffer, lSessionId, flags, tid, &lStatus);
 
         // move effect chain to this output thread if an effect on same session was waiting
         // for a track to be created
@@ -1569,6 +1569,7 @@
         const sp<IMemory>& sharedBuffer,
         int sessionId,
         IAudioFlinger::track_flags_t flags,
+        pid_t tid,
         status_t *status)
 {
     sp<Track> track;
@@ -1589,7 +1590,7 @@
               ) ||
               // use case 2: callback handler and small power-of-2 frame count
               (
-                // unfortunately we can't verify that there's a callback until start()
+                (tid != -1) &&
                 // FIXME supported frame counts should not be hard-coded
                 (
                   (frameCount == 128) ||
@@ -1678,6 +1679,20 @@
             chain->incTrackCnt();
         }
     }
+
+#ifdef HAVE_REQUEST_PRIORITY
+    if ((flags & IAudioFlinger::TRACK_FAST) && (tid != -1)) {
+        pid_t callingPid = IPCThreadState::self()->getCallingPid();
+        // we don't have CAP_SYS_NICE, nor do we want to have it as it's too powerful,
+        // so ask activity manager to do this on our behalf
+        int err = requestPriority(callingPid, tid, 1);
+        if (err != 0) {
+            ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
+                    1, callingPid, tid, err);
+        }
+    }
+#endif
+
     lStatus = NO_ERROR;
 
 Exit:
@@ -3681,20 +3696,11 @@
     return false;
 }
 
-status_t AudioFlinger::PlaybackThread::Track::start(pid_t tid,
-                                                    AudioSystem::sync_event_t event,
+status_t AudioFlinger::PlaybackThread::Track::start(AudioSystem::sync_event_t event,
                                                     int triggerSession)
 {
     status_t status = NO_ERROR;
-    ALOGV("start(%d), calling pid %d session %d tid %d",
-            mName, IPCThreadState::self()->getCallingPid(), mSessionId, tid);
-    // check for use case 2 with missing callback
-    if (isFastTrack() && (mSharedBuffer == 0) && (tid == 0)) {
-        ALOGW("AUDIO_OUTPUT_FLAG_FAST denied");
-        mFlags &= ~IAudioFlinger::TRACK_FAST;
-        // FIXME the track must be invalidated and moved to another thread or
-        // attached directly to the normal mixer now
-    }
+
     sp<ThreadBase> thread = mThread.promote();
     if (thread != 0) {
         Mutex::Autolock _l(thread->mLock);
@@ -4467,14 +4473,13 @@
     return NOT_ENOUGH_DATA;
 }
 
-status_t AudioFlinger::RecordThread::RecordTrack::start(pid_t tid,
-                                                        AudioSystem::sync_event_t event,
+status_t AudioFlinger::RecordThread::RecordTrack::start(AudioSystem::sync_event_t event,
                                                         int triggerSession)
 {
     sp<ThreadBase> thread = mThread.promote();
     if (thread != 0) {
         RecordThread *recordThread = (RecordThread *)thread.get();
-        return recordThread->start(this, tid, event, triggerSession);
+        return recordThread->start(this, event, triggerSession);
     } else {
         return BAD_VALUE;
     }
@@ -4541,11 +4546,10 @@
     clearBufferQueue();
 }
 
-status_t AudioFlinger::PlaybackThread::OutputTrack::start(pid_t tid,
-                                                          AudioSystem::sync_event_t event,
+status_t AudioFlinger::PlaybackThread::OutputTrack::start(AudioSystem::sync_event_t event,
                                                           int triggerSession)
 {
-    status_t status = Track::start(tid, event, triggerSession);
+    status_t status = Track::start(event, triggerSession);
     if (status != NO_ERROR) {
         return status;
     }
@@ -4575,7 +4579,7 @@
     uint32_t waitTimeLeftMs = mSourceThread->waitTimeMs();
 
     if (!mActive && frames != 0) {
-        start(0);
+        start();
         sp<ThreadBase> thread = mThread.promote();
         if (thread != 0) {
             MixerThread *mixerThread = (MixerThread *)thread.get();
@@ -4834,8 +4838,8 @@
     return mTrack->getCblk();
 }
 
-status_t AudioFlinger::TrackHandle::start(pid_t tid) {
-    return mTrack->start(tid);
+status_t AudioFlinger::TrackHandle::start() {
+    return mTrack->start();
 }
 
 void AudioFlinger::TrackHandle::stop() {
@@ -4988,9 +4992,9 @@
     return mRecordTrack->getCblk();
 }
 
-status_t AudioFlinger::RecordHandle::start(pid_t tid, int event, int triggerSession) {
+status_t AudioFlinger::RecordHandle::start(int event, int triggerSession) {
     ALOGV("RecordHandle::start()");
-    return mRecordTrack->start(tid, (AudioSystem::sync_event_t)event, triggerSession);
+    return mRecordTrack->start((AudioSystem::sync_event_t)event, triggerSession);
 }
 
 void AudioFlinger::RecordHandle::stop() {
@@ -5291,9 +5295,10 @@
 }
 
 status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack,
-                                           pid_t tid, AudioSystem::sync_event_t event,
+                                           AudioSystem::sync_event_t event,
                                            int triggerSession)
 {
+    // FIXME use tid here
     ALOGV("RecordThread::start tid=%d,  event %d, triggerSession %d", tid, event, triggerSession);
     sp<ThreadBase> strongMe = this;
     status_t status = NO_ERROR;
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index b1c5554..6b18945 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -91,6 +91,7 @@
                                 IAudioFlinger::track_flags_t flags,
                                 const sp<IMemory>& sharedBuffer,
                                 audio_io_handle_t output,
+                                pid_t tid,
                                 int *sessionId,
                                 status_t *status);
 
@@ -376,8 +377,7 @@
                                         int sessionId);
             virtual             ~TrackBase();
 
-            virtual status_t    start(pid_t tid,
-                                     AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
+            virtual status_t    start(AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
                                      int triggerSession = 0) = 0;
             virtual void        stop() = 0;
                     sp<IMemory> getCblk() const { return mCblkMemory; }
@@ -669,8 +669,7 @@
             virtual             ~Track();
 
                     void        dump(char* buffer, size_t size);
-            virtual status_t    start(pid_t tid,
-                                     AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
+            virtual status_t    start(AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
                                      int triggerSession = 0);
             virtual void        stop();
                     void        pause();
@@ -855,8 +854,7 @@
                                         int frameCount);
             virtual             ~OutputTrack();
 
-            virtual status_t    start(pid_t tid,
-                                     AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
+            virtual status_t    start(AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
                                      int triggerSession = 0);
             virtual void        stop();
                     bool        write(int16_t* data, uint32_t frames);
@@ -933,6 +931,7 @@
                                     const sp<IMemory>& sharedBuffer,
                                     int sessionId,
                                     IAudioFlinger::track_flags_t flags,
+                                    pid_t tid,
                                     status_t *status);
 
                     AudioStreamOut* getOutput() const;
@@ -1188,7 +1187,7 @@
                             TrackHandle(const sp<PlaybackThread::Track>& track);
         virtual             ~TrackHandle();
         virtual sp<IMemory> getCblk() const;
-        virtual status_t    start(pid_t tid);
+        virtual status_t    start();
         virtual void        stop();
         virtual void        flush();
         virtual void        mute(bool);
@@ -1227,8 +1226,7 @@
                                         int sessionId);
             virtual             ~RecordTrack();
 
-            virtual status_t    start(pid_t tid,
-                                     AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
+            virtual status_t    start(AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
                                      int triggerSession = 0);
             virtual void        stop();
 
@@ -1276,7 +1274,7 @@
                         int sessionId,
                         status_t *status);
 
-                status_t    start(RecordTrack* recordTrack, pid_t tid,
+                status_t    start(RecordTrack* recordTrack,
                                   AudioSystem::sync_event_t event,
                                   int triggerSession);
                 void        stop(RecordTrack* recordTrack);
@@ -1335,7 +1333,7 @@
         RecordHandle(const sp<RecordThread::RecordTrack>& recordTrack);
         virtual             ~RecordHandle();
         virtual sp<IMemory> getCblk() const;
-        virtual status_t    start(pid_t tid, int event, int triggerSession);
+        virtual status_t    start(int event, int triggerSession);
         virtual void        stop();
         virtual status_t onTransact(
             uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);