Merge "docs: fix some broken links" into eclair
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 2024cc0..ecfe1e0 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -932,6 +932,8 @@
     result.append(buffer);
     snprintf(buffer, SIZE, "blocked in write: %d\n", mInWrite);
     result.append(buffer);
+    snprintf(buffer, SIZE, "suspend count: %d\n", mSuspended);
+    result.append(buffer);
     write(fd, result.string(), result.size());
 
     dumpBase(fd, args);
@@ -1344,7 +1346,7 @@
         if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
                 !track->isPaused())
         {
-            //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
+            //LOGV("track %d u=%08x, s=%08x [OK] on thread %p", track->name(), cblk->user, cblk->server, this);
 
             // compute volume for this track
             int16_t left, right;
@@ -1400,7 +1402,7 @@
             track->mRetryCount = kMaxTrackRetries;
             mixerStatus = MIXER_TRACKS_READY;
         } else {
-            //LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
+            //LOGV("track %d u=%08x, s=%08x [NOT READY] on thread %p", track->name(), cblk->user, cblk->server, this);
             if (track->isStopped()) {
                 track->reset();
             }
@@ -1914,7 +1916,7 @@
 // ----------------------------------------------------------------------------
 
 AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread, int id)
-    :   MixerThread(audioFlinger, mainThread->getOutput(), id)
+    :   MixerThread(audioFlinger, mainThread->getOutput(), id), mWaitTimeMs(UINT_MAX)
 {
     mType = PlaybackThread::DUPLICATING;
     addOutputTrack(mainThread);
@@ -1952,6 +1954,7 @@
 
             if (checkForNewParameters_l()) {
                 mixBufferSize = mFrameCount*mFrameSize;
+                updateWaitTime();
                 activeSleepTime = activeSleepTimeUs();
                 idleSleepTime = idleSleepTimeUs();
             }
@@ -2003,7 +2006,11 @@
 
         if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
             // mix buffers...
-            mAudioMixer->process(curBuf);
+            if (outputsReady(outputTracks)) {
+                mAudioMixer->process(curBuf);
+            } else {
+                memset(curBuf, 0, mixBufferSize);
+            }
             sleepTime = 0;
             writeFrames = mFrameCount;
         } else {
@@ -2054,6 +2061,7 @@
 {
     int frameCount = (3 * mFrameCount * mSampleRate) / thread->sampleRate();
     OutputTrack *outputTrack = new OutputTrack((ThreadBase *)thread,
+                                            this,
                                             mSampleRate,
                                             mFormat,
                                             mChannelCount,
@@ -2062,6 +2070,7 @@
         thread->setStreamVolume(AudioSystem::NUM_STREAM_TYPES, 1.0f);
         mOutputTracks.add(outputTrack);
         LOGV("addOutputTrack() track %p, on thread %p", outputTrack, thread);
+        updateWaitTime();
     }
 }
 
@@ -2072,12 +2081,50 @@
         if (mOutputTracks[i]->thread() == (ThreadBase *)thread) {
             mOutputTracks[i]->destroy();
             mOutputTracks.removeAt(i);
+            updateWaitTime();
             return;
         }
     }
     LOGV("removeOutputTrack(): unkonwn thread: %p", thread);
 }
 
+void AudioFlinger::DuplicatingThread::updateWaitTime()
+{
+    mWaitTimeMs = UINT_MAX;
+    for (size_t i = 0; i < mOutputTracks.size(); i++) {
+        sp<ThreadBase> strong = mOutputTracks[i]->thread().promote();
+        if (strong != NULL) {
+            uint32_t waitTimeMs = (strong->frameCount() * 2 * 1000) / strong->sampleRate();
+            if (waitTimeMs < mWaitTimeMs) {
+                mWaitTimeMs = waitTimeMs;
+            }
+        }
+    }
+}
+
+
+bool AudioFlinger::DuplicatingThread::outputsReady(SortedVector< sp<OutputTrack> > &outputTracks)
+{
+    for (size_t i = 0; i < outputTracks.size(); i++) {
+        sp <ThreadBase> thread = outputTracks[i]->thread().promote();
+        if (thread == 0) {
+            LOGW("DuplicatingThread::outputsReady() could not promote thread on output track %p", outputTracks[i].get());
+            return false;
+        }
+        PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+        if (playbackThread->standby() && !playbackThread->isSuspended()) {
+            LOGV("DuplicatingThread output track %p on thread %p Not Ready", outputTracks[i].get(), thread.get());
+            return false;
+        }
+    }
+    return true;
+}
+
+uint32_t AudioFlinger::DuplicatingThread::activeSleepTimeUs()
+{
+    return (mWaitTimeMs * 1000) / 2;
+}
+
 // ----------------------------------------------------------------------------
 
 // TrackBase constructor must be called with AudioFlinger::mLock held
@@ -2616,12 +2663,13 @@
 
 AudioFlinger::PlaybackThread::OutputTrack::OutputTrack(
             const wp<ThreadBase>& thread,
+            DuplicatingThread *sourceThread,
             uint32_t sampleRate,
             int format,
             int channelCount,
             int frameCount)
     :   Track(thread, NULL, AudioSystem::NUM_STREAM_TYPES, sampleRate, format, channelCount, frameCount, NULL),
-    mActive(false)
+    mActive(false), mSourceThread(sourceThread)
 {
 
     PlaybackThread *playbackThread = (PlaybackThread *)thread.unsafe_get();
@@ -2630,10 +2678,9 @@
         mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
         mCblk->volume[0] = mCblk->volume[1] = 0x1000;
         mOutBuffer.frameCount = 0;
-        mWaitTimeMs = (playbackThread->frameCount() * 2 * 1000) / playbackThread->sampleRate();
         playbackThread->mTracks.add(this);
-        LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p mWaitTimeMs %d",
-                mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd, mWaitTimeMs);
+        LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p",
+                mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd);
     } else {
         LOGW("Error creating output track on thread %p", playbackThread);
     }
@@ -2673,7 +2720,7 @@
     inBuffer.frameCount = frames;
     inBuffer.i16 = data;
 
-    uint32_t waitTimeLeftMs = mWaitTimeMs;
+    uint32_t waitTimeLeftMs = mSourceThread->waitTimeMs();
 
     if (!mActive && frames != 0) {
         start();
@@ -2712,12 +2759,11 @@
             mOutBuffer.frameCount = pInBuffer->frameCount;
             nsecs_t startTime = systemTime();
             if (obtainBuffer(&mOutBuffer, waitTimeLeftMs) == (status_t)AudioTrack::NO_MORE_BUFFERS) {
-                LOGV ("OutputTrack::write() %p no more output buffers", this);
+                LOGV ("OutputTrack::write() %p thread %p no more output buffers", this, mThread.unsafe_get());
                 outputBufferFull = true;
                 break;
             }
             uint32_t waitTimeMs = (uint32_t)ns2ms(systemTime() - startTime);
-            LOGV("OutputTrack::write() to thread %p waitTimeMs %d waitTimeLeftMs %d", mThread.unsafe_get(), waitTimeMs, waitTimeLeftMs);
             if (waitTimeLeftMs >= waitTimeMs) {
                 waitTimeLeftMs -= waitTimeMs;
             } else {
@@ -2738,7 +2784,7 @@
                 mBufferQueue.removeAt(0);
                 delete [] pInBuffer->mBuffer;
                 delete pInBuffer;
-                LOGV("OutputTrack::write() %p released overflow buffer %d", this, mBufferQueue.size());
+                LOGV("OutputTrack::write() %p thread %p released overflow buffer %d", this, mThread.unsafe_get(), mBufferQueue.size());
             } else {
                 break;
             }
@@ -2747,16 +2793,19 @@
 
     // If we could not write all frames, allocate a buffer and queue it for next time.
     if (inBuffer.frameCount) {
-        if (mBufferQueue.size() < kMaxOverFlowBuffers) {
-            pInBuffer = new Buffer;
-            pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channels];
-            pInBuffer->frameCount = inBuffer.frameCount;
-            pInBuffer->i16 = pInBuffer->mBuffer;
-            memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channels * sizeof(int16_t));
-            mBufferQueue.add(pInBuffer);
-            LOGV("OutputTrack::write() %p adding overflow buffer %d", this, mBufferQueue.size());
-        } else {
-            LOGW("OutputTrack::write() %p no more overflow buffers", this);
+        sp<ThreadBase> thread = mThread.promote();
+        if (thread != 0 && !thread->standby()) {
+            if (mBufferQueue.size() < kMaxOverFlowBuffers) {
+                pInBuffer = new Buffer;
+                pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channels];
+                pInBuffer->frameCount = inBuffer.frameCount;
+                pInBuffer->i16 = pInBuffer->mBuffer;
+                memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channels * sizeof(int16_t));
+                mBufferQueue.add(pInBuffer);
+                LOGV("OutputTrack::write() %p thread %p adding overflow buffer %d", this, mThread.unsafe_get(), mBufferQueue.size());
+            } else {
+                LOGW("OutputTrack::write() %p thread %p no more overflow buffers", mThread.unsafe_get(), this);
+            }
         }
     }
 
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 8c29da8..12c90eb 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -20,6 +20,7 @@
 
 #include <stdint.h>
 #include <sys/types.h>
+#include <limits.h>
 
 #include <media/IAudioFlinger.h>
 #include <media/IAudioFlingerClient.h>
@@ -208,6 +209,7 @@
     class PlaybackThread;
     class MixerThread;
     class DirectOutputThread;
+    class DuplicatingThread;
     class Track;
     class RecordTrack;
 
@@ -324,6 +326,7 @@
                     void        sendConfigEvent_l(int event, int param = 0);
                     void        processConfigEvents();
                     int         id() const { return mId;}
+                    bool        standby() { return mStandby; }
 
         mutable     Mutex                   mLock;
 
@@ -452,6 +455,7 @@
             };
 
                                 OutputTrack(  const wp<ThreadBase>& thread,
+                                        DuplicatingThread *sourceThread,
                                         uint32_t sampleRate,
                                         int format,
                                         int channelCount,
@@ -471,13 +475,12 @@
             void                clearBufferQueue();
 
             // Maximum number of pending buffers allocated by OutputTrack::write()
-            static const uint8_t kMaxOverFlowBuffers = 3;
+            static const uint8_t kMaxOverFlowBuffers = 10;
 
             Vector < Buffer* >          mBufferQueue;
             AudioBufferProvider::Buffer mOutBuffer;
-            uint32_t                    mWaitTimeMs;
             bool                        mActive;
-
+            DuplicatingThread*          mSourceThread;
         };  // end of OutputTrack
 
         PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id);
@@ -520,6 +523,7 @@
         virtual     int         type() const { return mType; }
                     void        suspend() { mSuspended++; }
                     void        restore() { if (mSuspended) mSuspended--; }
+                    bool        isSuspended() { return (mSuspended != 0); }
         virtual     String8     getParameters(const String8& keys);
         virtual     void        audioConfigChanged(int event, int param = 0);
 
@@ -635,9 +639,16 @@
         virtual     bool        threadLoop();
                     void        addOutputTrack(MixerThread* thread);
                     void        removeOutputTrack(MixerThread* thread);
+                    uint32_t    waitTimeMs() { return mWaitTimeMs; }
+    protected:
+        virtual     uint32_t    activeSleepTimeUs();
 
     private:
+                    bool        outputsReady(SortedVector< sp<OutputTrack> > &outputTracks);
+                    void        updateWaitTime();
+
         SortedVector < sp<OutputTrack> >  mOutputTracks;
+                    uint32_t    mWaitTimeMs;
     };
 
               PlaybackThread *checkPlaybackThread_l(int output) const;