Merge "Rename fields of AudioSessionRef"
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 9f2bd3a..95b9d86 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -135,8 +135,10 @@
      * format:             Audio format (e.g AUDIO_FORMAT_PCM_16_BIT for signed
      *                     16 bits per sample).
      * channelMask:        Channel mask: see audio_channels_t.
-     * frameCount:         Total size of track PCM buffer in frames. This defines the
-     *                     latency of the track.
+     * 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.
      * flags:              Reserved for future use.
      * cbf:                Callback function. If not null, this function is called periodically
      *                     to request new PCM data.
diff --git a/include/media/stagefright/MediaSourceSplitter.h b/include/media/stagefright/MediaSourceSplitter.h
deleted file mode 100644
index 568f4c2..0000000
--- a/include/media/stagefright/MediaSourceSplitter.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// This class provides a way to split a single media source into multiple sources.
-// The constructor takes in the real mediaSource and createClient() can then be
-// used to create multiple sources served from this real mediaSource.
-//
-// Usage:
-// - Create MediaSourceSplitter by passing in a real mediaSource from which
-// multiple duplicate channels are needed.
-// - Create a client using createClient() and use it as any other mediaSource.
-//
-// Note that multiple clients can be created using createClient() and
-// started/stopped in any order. MediaSourceSplitter stops the real source only
-// when all clients have been stopped.
-//
-// If a new client is created/started after some existing clients have already
-// started, the new client will start getting its read frames from the current
-// time.
-
-#ifndef MEDIA_SOURCE_SPLITTER_H_
-
-#define MEDIA_SOURCE_SPLITTER_H_
-
-#include <media/stagefright/MediaSource.h>
-#include <utils/threads.h>
-#include <utils/Vector.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-class MediaBuffer;
-class MetaData;
-
-class MediaSourceSplitter : public RefBase {
-public:
-    // Constructor
-    // mediaSource: The real mediaSource. The class keeps a reference to it to
-    // implement the various clients.
-    MediaSourceSplitter(sp<MediaSource> mediaSource);
-
-    ~MediaSourceSplitter();
-
-    // Creates a new client of base type MediaSource. Multiple clients can be
-    // created which get their data through the same real mediaSource. These
-    // clients can then be used like any other MediaSource, all of which provide
-    // data from the same real source.
-    sp<MediaSource> createClient();
-
-private:
-    // Total number of clients created through createClient().
-    int32_t mNumberOfClients;
-
-    // reference to the real MediaSource passed to the constructor.
-    sp<MediaSource> mSource;
-
-    // Stores pointer to the MediaBuffer read from the real MediaSource.
-    // All clients use this to implement the read() call.
-    MediaBuffer *mLastReadMediaBuffer;
-
-    // Status code for read from the real MediaSource. All clients return
-    // this for their read().
-    status_t mLastReadStatus;
-
-    // Boolean telling whether the real MediaSource has started.
-    bool mSourceStarted;
-
-    // List of booleans, one for each client, storing whether the corresponding
-    // client's start() has been called.
-    Vector<bool> mClientsStarted;
-
-    // Stores the number of clients which are currently started.
-    int32_t mNumberOfClientsStarted;
-
-    // Since different clients call read() asynchronously, we need to keep track
-    // of what data is currently read into the mLastReadMediaBuffer.
-    // mCurrentReadBit stores the bit for the current read buffer. This bit
-    // flips each time a new buffer is read from the source.
-    // mClientsDesiredReadBit stores the bit for the next desired read buffer
-    // for each client. This bit flips each time read() is completed for this
-    // client.
-    bool mCurrentReadBit;
-    Vector<bool> mClientsDesiredReadBit;
-
-    // Number of clients whose current read has been completed.
-    int32_t mNumberOfCurrentReads;
-
-    // Boolean telling whether the last read has been completed for all clients.
-    // The variable is reset to false each time buffer is read from the real
-    // source.
-    bool mLastReadCompleted;
-
-    // A global mutex for access to critical sections.
-    Mutex mLock;
-
-    // Condition variable for waiting on read from source to complete.
-    Condition mReadFromSourceCondition;
-
-    // Condition variable for waiting on all client's last read to complete.
-    Condition mAllReadsCompleteCondition;
-
-    // Functions used by Client to implement the MediaSource interface.
-
-    // If the real source has not been started yet by any client, starts it.
-    status_t start(int clientId, MetaData *params);
-
-    // Stops the real source after all clients have called stop().
-    status_t stop(int clientId);
-
-    // returns the real source's getFormat().
-    sp<MetaData> getFormat(int clientId);
-
-    // If the client's desired buffer has already been read into
-    // mLastReadMediaBuffer, points the buffer to that. Otherwise if it is the
-    // master client, reads the buffer from source or else waits for the master
-    // client to read the buffer and uses that.
-    status_t read(int clientId,
-            MediaBuffer **buffer, const MediaSource::ReadOptions *options = NULL);
-
-    // Not implemented right now.
-    status_t pause(int clientId);
-
-    // Function which reads a buffer from the real source into
-    // mLastReadMediaBuffer
-    void readFromSource_lock(const MediaSource::ReadOptions *options);
-
-    // Waits until read from the real source has been completed.
-    // _lock means that the function should be called when the thread has already
-    // obtained the lock for the mutex mLock.
-    void waitForReadFromSource_lock(int32_t clientId);
-
-    // Waits until all clients have read the current buffer in
-    // mLastReadCompleted.
-    void waitForAllClientsLastRead_lock(int32_t clientId);
-
-    // Each client calls this after it completes its read(). Once all clients
-    // have called this for the current buffer, the function calls
-    // mAllReadsCompleteCondition.broadcast() to signal the waiting clients.
-    void signalReadComplete_lock(bool readAborted);
-
-    // Make these constructors private.
-    MediaSourceSplitter();
-    MediaSourceSplitter(const MediaSourceSplitter &);
-    MediaSourceSplitter &operator=(const MediaSourceSplitter &);
-
-    // This class implements the MediaSource interface. Each client stores a
-    // reference to the parent MediaSourceSplitter and uses it to complete the
-    // various calls.
-    class Client : public MediaSource {
-    public:
-        // Constructor stores reference to the parent MediaSourceSplitter and it
-        // client id.
-        Client(sp<MediaSourceSplitter> splitter, int32_t clientId);
-
-        // MediaSource interface
-        virtual status_t start(MetaData *params = NULL);
-
-        virtual status_t stop();
-
-        virtual sp<MetaData> getFormat();
-
-        virtual status_t read(
-                MediaBuffer **buffer, const ReadOptions *options = NULL);
-
-        virtual status_t pause();
-
-    private:
-        // Refernce to the parent MediaSourceSplitter
-        sp<MediaSourceSplitter> mSplitter;
-
-        // Id of this client.
-        int32_t mClientId;
-    };
-
-    friend class Client;
-};
-
-}  // namespace android
-
-#endif  // MEDIA_SOURCE_SPLITTER_H_
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 4890f05..a1c99e5 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -784,12 +784,9 @@
                 mNotificationFramesAct = frameCount/2;
             }
             if (frameCount < minFrameCount) {
-                if (enforceFrameCount) {
-                    ALOGE("Invalid buffer size: minFrameCount %d, frameCount %d", minFrameCount, frameCount);
-                    return BAD_VALUE;
-                } else {
-                    frameCount = minFrameCount;
-                }
+                ALOGW_IF(enforceFrameCount, "Minimum buffer size corrected from %d to %d",
+                         frameCount, minFrameCount);
+                frameCount = minFrameCount;
             }
         } else {
             // Ensure that buffer alignment matches channelCount
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index bd3e07a..1a85c9c 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -325,7 +325,7 @@
             mStreamType, mLeftVolume, mRightVolume);
     result.append(buffer);
     snprintf(buffer, 255, "  msec per frame(%f), latency (%d)\n",
-            mMsecsPerFrame, mLatency);
+            mMsecsPerFrame, (mTrack != 0) ? mTrack->latency() : -1);
     result.append(buffer);
     snprintf(buffer, 255, "  aux effect id(%d), send level (%f)\n",
             mAuxEffectId, mSendLevel);
@@ -1384,7 +1384,6 @@
     mRightVolume = 1.0;
     mPlaybackRatePermille = 1000;
     mSampleRateHz = 0;
-    mLatency = 0;
     mMsecsPerFrame = 0;
     mAuxEffectId = 0;
     mSendLevel = 0.0;
@@ -1443,7 +1442,8 @@
 
 uint32_t MediaPlayerService::AudioOutput::latency () const
 {
-    return mLatency;
+    if (mTrack == 0) return 0;
+    return mTrack->latency();
 }
 
 float MediaPlayerService::AudioOutput::msecsPerFrame() const
@@ -1533,7 +1533,6 @@
 
     mSampleRateHz = sampleRate;
     mMsecsPerFrame = mPlaybackRatePermille / (float) sampleRate;
-    mLatency = t->latency();
     mTrack = t;
 
     status_t res = t->setSampleRate(mPlaybackRatePermille * mSampleRateHz / 1000);
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 681ecab..85cec22 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -118,7 +118,6 @@
         int32_t                 mPlaybackRatePermille;
         uint32_t                mSampleRateHz; // sample rate of the content, as set in open()
         float                   mMsecsPerFrame;
-        uint32_t                mLatency;
         int                     mSessionId;
         float                   mSendLevel;
         int                     mAuxEffectId;
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 21d6866..5aea8d0 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -34,7 +34,6 @@
         MediaDefs.cpp                     \
         MediaExtractor.cpp                \
         MediaSource.cpp                   \
-        MediaSourceSplitter.cpp           \
         MetaData.cpp                      \
         NuCachedSource2.cpp               \
         NuMediaExtractor.cpp              \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 9427ef7..650b6c4 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -427,6 +427,12 @@
                 break;
             }
 
+            if (mAudioSink != NULL) {
+                mLatencyUs = (int64_t)mAudioSink->latency() * 1000;
+            } else {
+                mLatencyUs = (int64_t)mAudioTrack->latency() * 1000;
+            }
+
             CHECK(mInputBuffer->meta_data()->findInt64(
                         kKeyTime, &mPositionTimeMediaUs));
 
diff --git a/media/libstagefright/MediaSourceSplitter.cpp b/media/libstagefright/MediaSourceSplitter.cpp
deleted file mode 100644
index 3b64ded..0000000
--- a/media/libstagefright/MediaSourceSplitter.cpp
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaSourceSplitter"
-#include <utils/Log.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaSourceSplitter.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MetaData.h>
-
-namespace android {
-
-MediaSourceSplitter::MediaSourceSplitter(sp<MediaSource> mediaSource) {
-    mNumberOfClients = 0;
-    mSource = mediaSource;
-    mSourceStarted = false;
-
-    mNumberOfClientsStarted = 0;
-    mNumberOfCurrentReads = 0;
-    mCurrentReadBit = 0;
-    mLastReadCompleted = true;
-}
-
-MediaSourceSplitter::~MediaSourceSplitter() {
-}
-
-sp<MediaSource> MediaSourceSplitter::createClient() {
-    Mutex::Autolock autoLock(mLock);
-
-    sp<MediaSource> client = new Client(this, mNumberOfClients++);
-    mClientsStarted.push(false);
-    mClientsDesiredReadBit.push(0);
-    return client;
-}
-
-status_t MediaSourceSplitter::start(int clientId, MetaData *params) {
-    Mutex::Autolock autoLock(mLock);
-
-    ALOGV("start client (%d)", clientId);
-    if (mClientsStarted[clientId]) {
-        return OK;
-    }
-
-    mNumberOfClientsStarted++;
-
-    if (!mSourceStarted) {
-        ALOGV("Starting real source from client (%d)", clientId);
-        status_t err = mSource->start(params);
-
-        if (err == OK) {
-            mSourceStarted = true;
-            mClientsStarted.editItemAt(clientId) = true;
-            mClientsDesiredReadBit.editItemAt(clientId) = !mCurrentReadBit;
-        }
-
-        return err;
-    } else {
-        mClientsStarted.editItemAt(clientId) = true;
-        if (mLastReadCompleted) {
-            // Last read was completed. So join in the threads for the next read.
-            mClientsDesiredReadBit.editItemAt(clientId) = !mCurrentReadBit;
-        } else {
-            // Last read is ongoing. So join in the threads for the current read.
-            mClientsDesiredReadBit.editItemAt(clientId) = mCurrentReadBit;
-        }
-        return OK;
-    }
-}
-
-status_t MediaSourceSplitter::stop(int clientId) {
-    Mutex::Autolock autoLock(mLock);
-
-    ALOGV("stop client (%d)", clientId);
-    CHECK(clientId >= 0 && clientId < mNumberOfClients);
-    CHECK(mClientsStarted[clientId]);
-
-    if (--mNumberOfClientsStarted == 0) {
-        ALOGV("Stopping real source from client (%d)", clientId);
-        status_t err = mSource->stop();
-        mSourceStarted = false;
-        mClientsStarted.editItemAt(clientId) = false;
-        return err;
-    } else {
-        mClientsStarted.editItemAt(clientId) = false;
-        if (!mLastReadCompleted && (mClientsDesiredReadBit[clientId] == mCurrentReadBit)) {
-            // !mLastReadCompleted implies that buffer has been read from source, but all
-            // clients haven't read it.
-            // mClientsDesiredReadBit[clientId] == mCurrentReadBit implies that this
-            // client would have wanted to read from this buffer. (i.e. it has not yet
-            // called read() for the current read buffer.)
-            // Since other threads may be waiting for all the clients' reads to complete,
-            // signal that this read has been aborted.
-            signalReadComplete_lock(true);
-        }
-        return OK;
-    }
-}
-
-sp<MetaData> MediaSourceSplitter::getFormat(int clientId) {
-    Mutex::Autolock autoLock(mLock);
-
-    ALOGV("getFormat client (%d)", clientId);
-    return mSource->getFormat();
-}
-
-status_t MediaSourceSplitter::read(int clientId,
-        MediaBuffer **buffer, const MediaSource::ReadOptions *options) {
-    Mutex::Autolock autoLock(mLock);
-
-    CHECK(clientId >= 0 && clientId < mNumberOfClients);
-
-    ALOGV("read client (%d)", clientId);
-    *buffer = NULL;
-
-    if (!mClientsStarted[clientId]) {
-        return OK;
-    }
-
-    if (mCurrentReadBit != mClientsDesiredReadBit[clientId]) {
-        // Desired buffer has not been read from source yet.
-
-        // If the current client is the special client with clientId = 0
-        // then read from source, else wait until the client 0 has finished
-        // reading from source.
-        if (clientId == 0) {
-            // Wait for all client's last read to complete first so as to not
-            // corrupt the buffer at mLastReadMediaBuffer.
-            waitForAllClientsLastRead_lock(clientId);
-
-            readFromSource_lock(options);
-            *buffer = mLastReadMediaBuffer;
-        } else {
-            waitForReadFromSource_lock(clientId);
-
-            *buffer = mLastReadMediaBuffer;
-            (*buffer)->add_ref();
-        }
-        CHECK(mCurrentReadBit == mClientsDesiredReadBit[clientId]);
-    } else {
-        // Desired buffer has already been read from source. Use the cached data.
-        CHECK(clientId != 0);
-
-        *buffer = mLastReadMediaBuffer;
-        (*buffer)->add_ref();
-    }
-
-    mClientsDesiredReadBit.editItemAt(clientId) = !mClientsDesiredReadBit[clientId];
-    signalReadComplete_lock(false);
-
-    return mLastReadStatus;
-}
-
-void MediaSourceSplitter::readFromSource_lock(const MediaSource::ReadOptions *options) {
-    mLastReadStatus = mSource->read(&mLastReadMediaBuffer , options);
-
-    mCurrentReadBit = !mCurrentReadBit;
-    mLastReadCompleted = false;
-    mReadFromSourceCondition.broadcast();
-}
-
-void MediaSourceSplitter::waitForReadFromSource_lock(int32_t clientId) {
-    mReadFromSourceCondition.wait(mLock);
-}
-
-void MediaSourceSplitter::waitForAllClientsLastRead_lock(int32_t clientId) {
-    if (mLastReadCompleted) {
-        return;
-    }
-    mAllReadsCompleteCondition.wait(mLock);
-    CHECK(mLastReadCompleted);
-}
-
-void MediaSourceSplitter::signalReadComplete_lock(bool readAborted) {
-    if (!readAborted) {
-        mNumberOfCurrentReads++;
-    }
-
-    if (mNumberOfCurrentReads == mNumberOfClientsStarted) {
-        mLastReadCompleted = true;
-        mNumberOfCurrentReads = 0;
-        mAllReadsCompleteCondition.broadcast();
-    }
-}
-
-status_t MediaSourceSplitter::pause(int clientId) {
-    return ERROR_UNSUPPORTED;
-}
-
-// Client
-
-MediaSourceSplitter::Client::Client(
-        sp<MediaSourceSplitter> splitter,
-        int32_t clientId) {
-    mSplitter = splitter;
-    mClientId = clientId;
-}
-
-status_t MediaSourceSplitter::Client::start(MetaData *params) {
-    return mSplitter->start(mClientId, params);
-}
-
-status_t MediaSourceSplitter::Client::stop() {
-    return mSplitter->stop(mClientId);
-}
-
-sp<MetaData> MediaSourceSplitter::Client::getFormat() {
-    return mSplitter->getFormat(mClientId);
-}
-
-status_t MediaSourceSplitter::Client::read(
-        MediaBuffer **buffer, const ReadOptions *options) {
-    return mSplitter->read(mClientId, buffer, options);
-}
-
-status_t MediaSourceSplitter::Client::pause() {
-    return mSplitter->pause(mClientId);
-}
-
-}  // namespace android
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 639e958..d8a5d99 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -2067,9 +2067,7 @@
                 maxPeriod = seconds(mFrameCount) / mSampleRate * 15;
 }
 
-if (mType == DUPLICATING) {
-                updateWaitTime();
-}
+                updateWaitTime_l();
 
                 activeSleepTime = activeSleepTimeUs();
                 idleSleepTime = idleSleepTimeUs();
@@ -2267,79 +2265,79 @@
 // shared by MIXER and DIRECT, overridden by DUPLICATING
 void AudioFlinger::PlaybackThread::threadLoop_write()
 {
-            // FIXME rewrite to reduce number of system calls
-            mLastWriteTime = systemTime();
-            mInWrite = true;
-            mBytesWritten += mixBufferSize;
-            int bytesWritten = (int)mOutput->stream->write(mOutput->stream, mMixBuffer, mixBufferSize);
-            if (bytesWritten < 0) mBytesWritten -= mixBufferSize;
-            mNumWrites++;
-            mInWrite = false;
+    // FIXME rewrite to reduce number of system calls
+    mLastWriteTime = systemTime();
+    mInWrite = true;
+    mBytesWritten += mixBufferSize;
+    int bytesWritten = (int)mOutput->stream->write(mOutput->stream, mMixBuffer, mixBufferSize);
+    if (bytesWritten < 0) mBytesWritten -= mixBufferSize;
+    mNumWrites++;
+    mInWrite = false;
 }
 
 // shared by MIXER and DIRECT, overridden by DUPLICATING
 void AudioFlinger::PlaybackThread::threadLoop_standby()
 {
-                    ALOGV("Audio hardware entering standby, mixer %p, suspend count %u", this, mSuspended);
-                    mOutput->stream->common.standby(&mOutput->stream->common);
+    ALOGV("Audio hardware entering standby, mixer %p, suspend count %u", this, mSuspended);
+    mOutput->stream->common.standby(&mOutput->stream->common);
 }
 
 void AudioFlinger::MixerThread::threadLoop_mix()
 {
-            // obtain the presentation timestamp of the next output buffer
-            int64_t pts;
-            status_t status = INVALID_OPERATION;
+    // obtain the presentation timestamp of the next output buffer
+    int64_t pts;
+    status_t status = INVALID_OPERATION;
 
-            if (NULL != mOutput->stream->get_next_write_timestamp) {
-                status = mOutput->stream->get_next_write_timestamp(
-                        mOutput->stream, &pts);
-            }
+    if (NULL != mOutput->stream->get_next_write_timestamp) {
+        status = mOutput->stream->get_next_write_timestamp(
+                mOutput->stream, &pts);
+    }
 
-            if (status != NO_ERROR) {
-                pts = AudioBufferProvider::kInvalidPTS;
-            }
+    if (status != NO_ERROR) {
+        pts = AudioBufferProvider::kInvalidPTS;
+    }
 
-            // mix buffers...
-            mAudioMixer->process(pts);
-            // increase sleep time progressively when application underrun condition clears.
-            // Only increase sleep time if the mixer is ready for two consecutive times to avoid
-            // that a steady state of alternating ready/not ready conditions keeps the sleep time
-            // such that we would underrun the audio HAL.
-            if ((sleepTime == 0) && (sleepTimeShift > 0)) {
-                sleepTimeShift--;
-            }
-            sleepTime = 0;
-            standbyTime = systemTime() + mStandbyTimeInNsecs;
-            //TODO: delay standby when effects have a tail
+    // mix buffers...
+    mAudioMixer->process(pts);
+    // increase sleep time progressively when application underrun condition clears.
+    // Only increase sleep time if the mixer is ready for two consecutive times to avoid
+    // that a steady state of alternating ready/not ready conditions keeps the sleep time
+    // such that we would underrun the audio HAL.
+    if ((sleepTime == 0) && (sleepTimeShift > 0)) {
+        sleepTimeShift--;
+    }
+    sleepTime = 0;
+    standbyTime = systemTime() + mStandbyTimeInNsecs;
+    //TODO: delay standby when effects have a tail
 }
 
 void AudioFlinger::MixerThread::threadLoop_sleepTime()
 {
-            // If no tracks are ready, sleep once for the duration of an output
-            // buffer size, then write 0s to the output
-            if (sleepTime == 0) {
-                if (mixerStatus == MIXER_TRACKS_ENABLED) {
-                    sleepTime = activeSleepTime >> sleepTimeShift;
-                    if (sleepTime < kMinThreadSleepTimeUs) {
-                        sleepTime = kMinThreadSleepTimeUs;
-                    }
-                    // reduce sleep time in case of consecutive application underruns to avoid
-                    // starving the audio HAL. As activeSleepTimeUs() is larger than a buffer
-                    // duration we would end up writing less data than needed by the audio HAL if
-                    // the condition persists.
-                    if (sleepTimeShift < kMaxThreadSleepTimeShift) {
-                        sleepTimeShift++;
-                    }
-                } else {
-                    sleepTime = idleSleepTime;
-                }
-            } else if (mBytesWritten != 0 ||
-                       (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)) {
-                memset (mMixBuffer, 0, mixBufferSize);
-                sleepTime = 0;
-                ALOGV_IF((mBytesWritten == 0 && (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)), "anticipated start");
+    // If no tracks are ready, sleep once for the duration of an output
+    // buffer size, then write 0s to the output
+    if (sleepTime == 0) {
+        if (mixerStatus == MIXER_TRACKS_ENABLED) {
+            sleepTime = activeSleepTime >> sleepTimeShift;
+            if (sleepTime < kMinThreadSleepTimeUs) {
+                sleepTime = kMinThreadSleepTimeUs;
             }
-            // TODO add standby time extension fct of effect tail
+            // reduce sleep time in case of consecutive application underruns to avoid
+            // starving the audio HAL. As activeSleepTimeUs() is larger than a buffer
+            // duration we would end up writing less data than needed by the audio HAL if
+            // the condition persists.
+            if (sleepTimeShift < kMaxThreadSleepTimeShift) {
+                sleepTimeShift++;
+            }
+        } else {
+            sleepTime = idleSleepTime;
+        }
+    } else if (mBytesWritten != 0 ||
+               (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)) {
+        memset (mMixBuffer, 0, mixBufferSize);
+        sleepTime = 0;
+        ALOGV_IF((mBytesWritten == 0 && (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)), "anticipated start");
+    }
+    // TODO add standby time extension fct of effect tail
 }
 
 // prepareTracks_l() must be called with ThreadBase::mLock held
@@ -2858,173 +2856,173 @@
     sp<Track>& trackToRemove
 )
 {
-// FIXME Temporarily renamed to avoid confusion with the member "mixerStatus"
-mixer_state mixerStatus_ = MIXER_IDLE;
+    // FIXME Temporarily renamed to avoid confusion with the member "mixerStatus"
+    mixer_state mixerStatus_ = MIXER_IDLE;
 
-            // find out which tracks need to be processed
-            if (mActiveTracks.size() != 0) {
-                sp<Track> t = mActiveTracks[0].promote();
-                // see FIXME in AudioFlinger.h, return MIXER_IDLE might also work
-                if (t == 0) return MIXER_CONTINUE;
-                //if (t == 0) continue;
+    // find out which tracks need to be processed
+    if (mActiveTracks.size() != 0) {
+        sp<Track> t = mActiveTracks[0].promote();
+        // see FIXME in AudioFlinger.h, return MIXER_IDLE might also work
+        if (t == 0) return MIXER_CONTINUE;
+        //if (t == 0) continue;
 
-                Track* const track = t.get();
-                audio_track_cblk_t* cblk = track->cblk();
+        Track* const track = t.get();
+        audio_track_cblk_t* cblk = track->cblk();
 
-                // The first time a track is added we wait
-                // for all its buffers to be filled before processing it
-                if (cblk->framesReady() && track->isReady() &&
-                        !track->isPaused() && !track->isTerminated())
-                {
-                    //ALOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
+        // The first time a track is added we wait
+        // for all its buffers to be filled before processing it
+        if (cblk->framesReady() && track->isReady() &&
+                !track->isPaused() && !track->isTerminated())
+        {
+            //ALOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
 
-                    if (track->mFillingUpStatus == Track::FS_FILLED) {
-                        track->mFillingUpStatus = Track::FS_ACTIVE;
-                        mLeftVolFloat = mRightVolFloat = 0;
-                        mLeftVolShort = mRightVolShort = 0;
-                        if (track->mState == TrackBase::RESUMING) {
-                            track->mState = TrackBase::ACTIVE;
-                            rampVolume = true;
-                        }
-                    } else if (cblk->server != 0) {
-                        // If the track is stopped before the first frame was mixed,
-                        // do not apply ramp
-                        rampVolume = true;
-                    }
-                    // compute volume for this track
-                    float left, right;
-                    if (track->isMuted() || mMasterMute || track->isPausing() ||
-                        mStreamTypes[track->streamType()].mute) {
-                        left = right = 0;
-                        if (track->isPausing()) {
-                            track->setPaused();
-                        }
-                    } else {
-                        float typeVolume = mStreamTypes[track->streamType()].volume;
-                        float v = mMasterVolume * typeVolume;
-                        uint32_t vlr = cblk->getVolumeLR();
-                        float v_clamped = v * (vlr & 0xFFFF);
-                        if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
-                        left = v_clamped/MAX_GAIN;
-                        v_clamped = v * (vlr >> 16);
-                        if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
-                        right = v_clamped/MAX_GAIN;
-                    }
+            if (track->mFillingUpStatus == Track::FS_FILLED) {
+                track->mFillingUpStatus = Track::FS_ACTIVE;
+                mLeftVolFloat = mRightVolFloat = 0;
+                mLeftVolShort = mRightVolShort = 0;
+                if (track->mState == TrackBase::RESUMING) {
+                    track->mState = TrackBase::ACTIVE;
+                    rampVolume = true;
+                }
+            } else if (cblk->server != 0) {
+                // If the track is stopped before the first frame was mixed,
+                // do not apply ramp
+                rampVolume = true;
+            }
+            // compute volume for this track
+            float left, right;
+            if (track->isMuted() || mMasterMute || track->isPausing() ||
+                mStreamTypes[track->streamType()].mute) {
+                left = right = 0;
+                if (track->isPausing()) {
+                    track->setPaused();
+                }
+            } else {
+                float typeVolume = mStreamTypes[track->streamType()].volume;
+                float v = mMasterVolume * typeVolume;
+                uint32_t vlr = cblk->getVolumeLR();
+                float v_clamped = v * (vlr & 0xFFFF);
+                if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+                left = v_clamped/MAX_GAIN;
+                v_clamped = v * (vlr >> 16);
+                if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+                right = v_clamped/MAX_GAIN;
+            }
 
-                    if (left != mLeftVolFloat || right != mRightVolFloat) {
-                        mLeftVolFloat = left;
-                        mRightVolFloat = right;
+            if (left != mLeftVolFloat || right != mRightVolFloat) {
+                mLeftVolFloat = left;
+                mRightVolFloat = right;
 
-                        // If audio HAL implements volume control,
-                        // force software volume to nominal value
-                        if (mOutput->stream->set_volume(mOutput->stream, left, right) == NO_ERROR) {
-                            left = 1.0f;
-                            right = 1.0f;
-                        }
+                // If audio HAL implements volume control,
+                // force software volume to nominal value
+                if (mOutput->stream->set_volume(mOutput->stream, left, right) == NO_ERROR) {
+                    left = 1.0f;
+                    right = 1.0f;
+                }
 
-                        // Convert volumes from float to 8.24
-                        uint32_t vl = (uint32_t)(left * (1 << 24));
-                        uint32_t vr = (uint32_t)(right * (1 << 24));
+                // Convert volumes from float to 8.24
+                uint32_t vl = (uint32_t)(left * (1 << 24));
+                uint32_t vr = (uint32_t)(right * (1 << 24));
 
-                        // Delegate volume control to effect in track effect chain if needed
-                        // only one effect chain can be present on DirectOutputThread, so if
-                        // there is one, the track is connected to it
-                        if (!mEffectChains.isEmpty()) {
-                            // Do not ramp volume if volume is controlled by effect
-                            if (mEffectChains[0]->setVolume_l(&vl, &vr)) {
-                                rampVolume = false;
-                            }
-                        }
-
-                        // Convert volumes from 8.24 to 4.12 format
-                        uint32_t v_clamped = (vl + (1 << 11)) >> 12;
-                        if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;
-                        leftVol = (uint16_t)v_clamped;
-                        v_clamped = (vr + (1 << 11)) >> 12;
-                        if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;
-                        rightVol = (uint16_t)v_clamped;
-                    } else {
-                        leftVol = mLeftVolShort;
-                        rightVol = mRightVolShort;
+                // Delegate volume control to effect in track effect chain if needed
+                // only one effect chain can be present on DirectOutputThread, so if
+                // there is one, the track is connected to it
+                if (!mEffectChains.isEmpty()) {
+                    // Do not ramp volume if volume is controlled by effect
+                    if (mEffectChains[0]->setVolume_l(&vl, &vr)) {
                         rampVolume = false;
                     }
+                }
 
-                    // reset retry count
-                    track->mRetryCount = kMaxTrackRetriesDirect;
-                    activeTrack = t;
-                    mixerStatus_ = MIXER_TRACKS_READY;
+                // Convert volumes from 8.24 to 4.12 format
+                uint32_t v_clamped = (vl + (1 << 11)) >> 12;
+                if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;
+                leftVol = (uint16_t)v_clamped;
+                v_clamped = (vr + (1 << 11)) >> 12;
+                if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;
+                rightVol = (uint16_t)v_clamped;
+            } else {
+                leftVol = mLeftVolShort;
+                rightVol = mRightVolShort;
+                rampVolume = false;
+            }
+
+            // reset retry count
+            track->mRetryCount = kMaxTrackRetriesDirect;
+            activeTrack = t;
+            mixerStatus_ = MIXER_TRACKS_READY;
+        } else {
+            //ALOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
+            if (track->isStopped()) {
+                track->reset();
+            }
+            if (track->isTerminated() || track->isStopped() || track->isPaused()) {
+                // We have consumed all the buffers of this track.
+                // Remove it from the list of active tracks.
+                trackToRemove = track;
+            } else {
+                // No buffers for this track. Give it a few chances to
+                // fill a buffer, then remove it from active list.
+                if (--(track->mRetryCount) <= 0) {
+                    ALOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
+                    trackToRemove = track;
                 } else {
-                    //ALOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
-                    if (track->isStopped()) {
-                        track->reset();
-                    }
-                    if (track->isTerminated() || track->isStopped() || track->isPaused()) {
-                        // We have consumed all the buffers of this track.
-                        // Remove it from the list of active tracks.
-                        trackToRemove = track;
-                    } else {
-                        // No buffers for this track. Give it a few chances to
-                        // fill a buffer, then remove it from active list.
-                        if (--(track->mRetryCount) <= 0) {
-                            ALOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
-                            trackToRemove = track;
-                        } else {
-                            mixerStatus_ = MIXER_TRACKS_ENABLED;
-                        }
-                    }
+                    mixerStatus_ = MIXER_TRACKS_ENABLED;
                 }
             }
+        }
+    }
 
-            // remove all the tracks that need to be...
-            if (CC_UNLIKELY(trackToRemove != 0)) {
-                mActiveTracks.remove(trackToRemove);
-                if (!mEffectChains.isEmpty()) {
-                    ALOGV("stopping track on chain %p for session Id: %d", effectChains[0].get(),
-                            trackToRemove->sessionId());
-                    mEffectChains[0]->decActiveTrackCnt();
-                }
-                if (trackToRemove->isTerminated()) {
-                    removeTrack_l(trackToRemove);
-                }
-            }
+    // remove all the tracks that need to be...
+    if (CC_UNLIKELY(trackToRemove != 0)) {
+        mActiveTracks.remove(trackToRemove);
+        if (!mEffectChains.isEmpty()) {
+            ALOGV("stopping track on chain %p for session Id: %d", effectChains[0].get(),
+                    trackToRemove->sessionId());
+            mEffectChains[0]->decActiveTrackCnt();
+        }
+        if (trackToRemove->isTerminated()) {
+            removeTrack_l(trackToRemove);
+        }
+    }
 
-return mixerStatus_;
+    return mixerStatus_;
 }
 
 void AudioFlinger::DirectOutputThread::threadLoop_mix()
 {
-            AudioBufferProvider::Buffer buffer;
-            size_t frameCount = mFrameCount;
-            int8_t *curBuf = (int8_t *)mMixBuffer;
-            // output audio to hardware
-            while (frameCount) {
-                buffer.frameCount = frameCount;
-                activeTrack->getNextBuffer(&buffer);
-                if (CC_UNLIKELY(buffer.raw == NULL)) {
-                    memset(curBuf, 0, frameCount * mFrameSize);
-                    break;
-                }
-                memcpy(curBuf, buffer.raw, buffer.frameCount * mFrameSize);
-                frameCount -= buffer.frameCount;
-                curBuf += buffer.frameCount * mFrameSize;
-                activeTrack->releaseBuffer(&buffer);
-            }
-            sleepTime = 0;
-            standbyTime = systemTime() + standbyDelay;
+    AudioBufferProvider::Buffer buffer;
+    size_t frameCount = mFrameCount;
+    int8_t *curBuf = (int8_t *)mMixBuffer;
+    // output audio to hardware
+    while (frameCount) {
+        buffer.frameCount = frameCount;
+        activeTrack->getNextBuffer(&buffer);
+        if (CC_UNLIKELY(buffer.raw == NULL)) {
+            memset(curBuf, 0, frameCount * mFrameSize);
+            break;
+        }
+        memcpy(curBuf, buffer.raw, buffer.frameCount * mFrameSize);
+        frameCount -= buffer.frameCount;
+        curBuf += buffer.frameCount * mFrameSize;
+        activeTrack->releaseBuffer(&buffer);
+    }
+    sleepTime = 0;
+    standbyTime = systemTime() + standbyDelay;
 }
 
 void AudioFlinger::DirectOutputThread::threadLoop_sleepTime()
 {
-            if (sleepTime == 0) {
-                if (mixerStatus == MIXER_TRACKS_ENABLED) {
-                    sleepTime = activeSleepTime;
-                } else {
-                    sleepTime = idleSleepTime;
-                }
-            } else if (mBytesWritten != 0 && audio_is_linear_pcm(mFormat)) {
-                memset (mMixBuffer, 0, mFrameCount * mFrameSize);
-                sleepTime = 0;
-            }
+    if (sleepTime == 0) {
+        if (mixerStatus == MIXER_TRACKS_ENABLED) {
+            sleepTime = activeSleepTime;
+        } else {
+            sleepTime = idleSleepTime;
+        }
+    } else if (mBytesWritten != 0 && audio_is_linear_pcm(mFormat)) {
+        memset (mMixBuffer, 0, mFrameCount * mFrameSize);
+        sleepTime = 0;
+    }
 }
 
 // getTrackName_l() must be called with ThreadBase::mLock held
@@ -3139,52 +3137,52 @@
 
 void AudioFlinger::DuplicatingThread::threadLoop_mix()
 {
-            // mix buffers...
-            if (outputsReady(outputTracks)) {
-                mAudioMixer->process(AudioBufferProvider::kInvalidPTS);
-            } else {
-                memset(mMixBuffer, 0, mixBufferSize);
-            }
-            sleepTime = 0;
-            writeFrames = mFrameCount;
+    // mix buffers...
+    if (outputsReady(outputTracks)) {
+        mAudioMixer->process(AudioBufferProvider::kInvalidPTS);
+    } else {
+        memset(mMixBuffer, 0, mixBufferSize);
+    }
+    sleepTime = 0;
+    writeFrames = mFrameCount;
 }
 
 void AudioFlinger::DuplicatingThread::threadLoop_sleepTime()
 {
-            if (sleepTime == 0) {
-                if (mixerStatus == MIXER_TRACKS_ENABLED) {
-                    sleepTime = activeSleepTime;
-                } else {
-                    sleepTime = idleSleepTime;
-                }
-            } else if (mBytesWritten != 0) {
-                // flush remaining overflow buffers in output tracks
-                for (size_t i = 0; i < outputTracks.size(); i++) {
-                    if (outputTracks[i]->isActive()) {
-                        sleepTime = 0;
-                        writeFrames = 0;
-                        memset(mMixBuffer, 0, mixBufferSize);
-                        break;
-                    }
-                }
+    if (sleepTime == 0) {
+        if (mixerStatus == MIXER_TRACKS_ENABLED) {
+            sleepTime = activeSleepTime;
+        } else {
+            sleepTime = idleSleepTime;
+        }
+    } else if (mBytesWritten != 0) {
+        // flush remaining overflow buffers in output tracks
+        for (size_t i = 0; i < outputTracks.size(); i++) {
+            if (outputTracks[i]->isActive()) {
+                sleepTime = 0;
+                writeFrames = 0;
+                memset(mMixBuffer, 0, mixBufferSize);
+                break;
             }
+        }
+    }
 }
 
 void AudioFlinger::DuplicatingThread::threadLoop_write()
 {
-            standbyTime = systemTime() + mStandbyTimeInNsecs;
-            for (size_t i = 0; i < outputTracks.size(); i++) {
-                outputTracks[i]->write(mMixBuffer, writeFrames);
-            }
-            mBytesWritten += mixBufferSize;
+    standbyTime = systemTime() + mStandbyTimeInNsecs;
+    for (size_t i = 0; i < outputTracks.size(); i++) {
+        outputTracks[i]->write(mMixBuffer, writeFrames);
+    }
+    mBytesWritten += mixBufferSize;
 }
 
 void AudioFlinger::DuplicatingThread::threadLoop_standby()
 {
-                    // DuplicatingThread implements standby by stopping all tracks
-                    for (size_t i = 0; i < outputTracks.size(); i++) {
-                        outputTracks[i]->stop();
-                    }
+    // DuplicatingThread implements standby by stopping all tracks
+    for (size_t i = 0; i < outputTracks.size(); i++) {
+        outputTracks[i]->stop();
+    }
 }
 
 void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread)
@@ -3202,7 +3200,7 @@
         thread->setStreamVolume(AUDIO_STREAM_CNT, 1.0f);
         mOutputTracks.add(outputTrack);
         ALOGV("addOutputTrack() track %p, on thread %p", outputTrack, thread);
-        updateWaitTime();
+        updateWaitTime_l();
     }
 }
 
@@ -3213,14 +3211,15 @@
         if (mOutputTracks[i]->thread() == thread) {
             mOutputTracks[i]->destroy();
             mOutputTracks.removeAt(i);
-            updateWaitTime();
+            updateWaitTime_l();
             return;
         }
     }
     ALOGV("removeOutputTrack(): unkonwn thread: %p", thread);
 }
 
-void AudioFlinger::DuplicatingThread::updateWaitTime()
+// caller must hold mLock
+void AudioFlinger::DuplicatingThread::updateWaitTime_l()
 {
     mWaitTimeMs = UINT_MAX;
     for (size_t i = 0; i < mOutputTracks.size(); i++) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 5d597e9..336c777 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -812,7 +812,7 @@
         virtual     void        threadLoop_standby();
 
         // Non-trivial for DUPLICATING only
-        virtual     void        updateWaitTime() { }
+        virtual     void        updateWaitTime_l() { }
 
         // Non-trivial for DIRECT only
         virtual     void        applyVolume() { }
@@ -1046,7 +1046,9 @@
         virtual     void        threadLoop_sleepTime();
         virtual     void        threadLoop_write();
         virtual     void        threadLoop_standby();
-        virtual     void        updateWaitTime();
+
+        // called from threadLoop, addOutputTrack, removeOutputTrack
+        virtual     void        updateWaitTime_l();
     private:
 
                     uint32_t    mWaitTimeMs;