Merge "Fix green or corrupted video frames in the exported movies" into jb-dev
diff --git a/include/media/AudioParameter.h b/include/media/AudioParameter.h
index 8cb2fa7..891bc4b 100644
--- a/include/media/AudioParameter.h
+++ b/include/media/AudioParameter.h
@@ -40,12 +40,14 @@
     //  keyFrameCount: to change audio output frame count, value is an int
     //  keyInputSource: to change audio input source, value is an int in audio_source_t
     //     (defined in media/mediarecorder.h)
+    //  keyScreenState: either "on" or "off"
     static const char * const keyRouting;
     static const char * const keySamplingRate;
     static const char * const keyFormat;
     static const char * const keyChannels;
     static const char * const keyFrameCount;
     static const char * const keyInputSource;
+    static const char * const keyScreenState;
 
     String8 toString();
 
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 44d05cd..d3c69f4 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -52,6 +52,8 @@
 // that the framework has stopped playing audio and we must start returning silence
 #define MAX_STALL_TIME_MS 1000
 
+#define CAPTURE_BUF_SIZE 65536 // "64k should be enough for everyone"
+
 struct VisualizerContext {
     const struct effect_interface_s *mItfe;
     effect_config_t mConfig;
@@ -59,10 +61,10 @@
     uint32_t mCaptureSize;
     uint32_t mScalingMode;
     uint8_t mState;
-    uint8_t mCurrentBuf;
-    uint8_t mLastBuf;
+    uint8_t mLastCaptureIdx;
+    uint32_t mLatency;
     struct timespec mBufferUpdateTime;
-    uint8_t mCaptureBuf[2][VISUALIZER_CAPTURE_SIZE_MAX];
+    uint8_t mCaptureBuf[CAPTURE_BUF_SIZE];
 };
 
 //
@@ -72,11 +74,10 @@
 void Visualizer_reset(VisualizerContext *pContext)
 {
     pContext->mCaptureIdx = 0;
-    pContext->mCurrentBuf = 0;
-    pContext->mLastBuf = 1;
+    pContext->mLastCaptureIdx = 0;
     pContext->mBufferUpdateTime.tv_sec = 0;
-    memset(pContext->mCaptureBuf[0], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
-    memset(pContext->mCaptureBuf[1], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
+    pContext->mLatency = 0;
+    memset(pContext->mCaptureBuf, 0x80, CAPTURE_BUF_SIZE);
 }
 
 //----------------------------------------------------------------------------
@@ -316,25 +317,25 @@
 
     uint32_t captIdx;
     uint32_t inIdx;
-    uint8_t *buf = pContext->mCaptureBuf[pContext->mCurrentBuf];
+    uint8_t *buf = pContext->mCaptureBuf;
     for (inIdx = 0, captIdx = pContext->mCaptureIdx;
-         inIdx < inBuffer->frameCount && captIdx < pContext->mCaptureSize;
+         inIdx < inBuffer->frameCount;
          inIdx++, captIdx++) {
+        if (captIdx >= CAPTURE_BUF_SIZE) {
+            // wrap around
+            captIdx = 0;
+        }
         int32_t smp = inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1];
         smp = smp >> shift;
         buf[captIdx] = ((uint8_t)smp)^0x80;
     }
+
+    // XXX the following two should really be atomic, though it probably doesn't
+    // matter much for visualization purposes
     pContext->mCaptureIdx = captIdx;
-
-    // go to next buffer when buffer full
-    if (pContext->mCaptureIdx == pContext->mCaptureSize) {
-        pContext->mCurrentBuf ^= 1;
-        pContext->mCaptureIdx = 0;
-
-        // update last buffer update time stamp
-        if (clock_gettime(CLOCK_MONOTONIC, &pContext->mBufferUpdateTime) < 0) {
-            pContext->mBufferUpdateTime.tv_sec = 0;
-        }
+    // update last buffer update time stamp
+    if (clock_gettime(CLOCK_MONOTONIC, &pContext->mBufferUpdateTime) < 0) {
+        pContext->mBufferUpdateTime.tv_sec = 0;
     }
 
     if (inBuffer->raw != outBuffer->raw) {
@@ -464,6 +465,10 @@
             pContext->mScalingMode = *((uint32_t *)p->data + 1);
             ALOGV("set mScalingMode = %d", pContext->mScalingMode);
             break;
+        case VISUALIZER_PARAM_LATENCY:
+            pContext->mLatency = *((uint32_t *)p->data + 1);
+            ALOGV("set mLatency = %d", pContext->mLatency);
+            break;
         default:
             *(int32_t *)pReplyData = -EINVAL;
         }
@@ -481,13 +486,9 @@
             return -EINVAL;
         }
         if (pContext->mState == VISUALIZER_STATE_ACTIVE) {
-            memcpy(pReplyData,
-                   pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
-                   pContext->mCaptureSize);
-            // if audio framework has stopped playing audio although the effect is still
-            // active we must clear the capture buffer to return silence
-            if ((pContext->mLastBuf == pContext->mCurrentBuf) &&
-                    (pContext->mBufferUpdateTime.tv_sec != 0)) {
+            int32_t latencyMs = pContext->mLatency;
+            uint32_t deltaMs = 0;
+            if (pContext->mBufferUpdateTime.tv_sec != 0) {
                 struct timespec ts;
                 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
                     time_t secs = ts.tv_sec - pContext->mBufferUpdateTime.tv_sec;
@@ -496,17 +497,45 @@
                         --secs;
                         nsec += 1000000000;
                     }
-                    uint32_t deltaMs = secs * 1000 + nsec / 1000000;
-                    if (deltaMs > MAX_STALL_TIME_MS) {
-                        ALOGV("capture going to idle");
-                        pContext->mBufferUpdateTime.tv_sec = 0;
-                        memset(pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
-                                0x80,
-                                pContext->mCaptureSize);
+                    deltaMs = secs * 1000 + nsec / 1000000;
+                    latencyMs -= deltaMs;
+                    if (latencyMs < 0) {
+                        latencyMs = 0;
                     }
                 }
             }
-            pContext->mLastBuf = pContext->mCurrentBuf;
+            uint32_t deltaSmpl = pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000;
+
+            int32_t capturePoint = pContext->mCaptureIdx - pContext->mCaptureSize - deltaSmpl;
+            int32_t captureSize = pContext->mCaptureSize;
+            if (capturePoint < 0) {
+                int32_t size = -capturePoint;
+                if (size > captureSize) {
+                    size = captureSize;
+                }
+                memcpy(pReplyData,
+                       pContext->mCaptureBuf + CAPTURE_BUF_SIZE + capturePoint,
+                       size);
+                pReplyData += size;
+                captureSize -= size;
+                capturePoint = 0;
+            }
+            memcpy(pReplyData,
+                   pContext->mCaptureBuf + capturePoint,
+                   captureSize);
+
+
+            // if audio framework has stopped playing audio although the effect is still
+            // active we must clear the capture buffer to return silence
+            if ((pContext->mLastCaptureIdx == pContext->mCaptureIdx) &&
+                    (pContext->mBufferUpdateTime.tv_sec != 0)) {
+                if (deltaMs > MAX_STALL_TIME_MS) {
+                    ALOGV("capture going to idle");
+                    pContext->mBufferUpdateTime.tv_sec = 0;
+                    memset(pReplyData, 0x80, pContext->mCaptureSize);
+                }
+            }
+            pContext->mLastCaptureIdx = pContext->mCaptureIdx;
         } else {
             memset(pReplyData, 0x80, pContext->mCaptureSize);
         }
diff --git a/media/libmedia/AudioParameter.cpp b/media/libmedia/AudioParameter.cpp
index 9766ee6..e3fea77 100644
--- a/media/libmedia/AudioParameter.cpp
+++ b/media/libmedia/AudioParameter.cpp
@@ -31,6 +31,7 @@
 const char * const AudioParameter::keyChannels = AUDIO_PARAMETER_STREAM_CHANNELS;
 const char * const AudioParameter::keyFrameCount = AUDIO_PARAMETER_STREAM_FRAME_COUNT;
 const char * const AudioParameter::keyInputSource = AUDIO_PARAMETER_STREAM_INPUT_SOURCE;
+const char * const AudioParameter::keyScreenState = AUDIO_PARAMETER_KEY_SCREEN_STATE;
 
 AudioParameter::AudioParameter(const String8& keyValuePairs)
 {
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 14b7fc1..ee843aa 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -30,6 +30,9 @@
 #LOCAL_C_INCLUDES += path/to/libsndfile/src
 #LOCAL_STATIC_LIBRARIES += libsndfile
 
+# uncomment for systrace
+# LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_AUDIO
+
 LOCAL_MODULE := libnbaio
 
 include $(BUILD_STATIC_LIBRARY)
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 2cfc3e8..be59ca0 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -164,6 +164,9 @@
     //  up large writes into smaller ones, and the wrapper would need to deal with scheduler.
 } kUseFastMixer = FastMixer_Static;
 
+static uint32_t gScreenState; // incremented by 2 when screen state changes, bit 0 == 1 means "off"
+                              // AudioFlinger::setParameters() updates, other threads read w/o lock
+
 // ----------------------------------------------------------------------------
 
 #ifdef ADD_BATTERY_DATA
@@ -889,6 +892,13 @@
                 mBtNrecIsOff = btNrecIsOff;
             }
         }
+        String8 screenState;
+        if (param.get(String8(AudioParameter::keyScreenState), screenState) == NO_ERROR) {
+            bool isOff = screenState == "off";
+            if (isOff != (gScreenState & 1)) {
+                gScreenState = ((gScreenState & ~1) + 2) | isOff;
+            }
+        }
         return final_result;
     }
 
@@ -1501,6 +1511,7 @@
         mMixerStatus(MIXER_IDLE),
         mMixerStatusIgnoringFastTracks(MIXER_IDLE),
         standbyDelay(AudioFlinger::mStandbyTimeInNsecs),
+        mScreenState(gScreenState),
         // index 0 is reserved for normal mixer's submix
         mFastTrackAvailMask(((1 << FastMixerState::kMaxFastTracks) - 1) & ~1)
 {
@@ -1818,6 +1829,10 @@
 uint32_t AudioFlinger::PlaybackThread::latency() const
 {
     Mutex::Autolock _l(mLock);
+    return latency_l();
+}
+uint32_t AudioFlinger::PlaybackThread::latency_l() const
+{
     if (initCheck() == NO_ERROR) {
         return correctLatency(mOutput->stream->get_latency(mOutput->stream));
     } else {
@@ -2220,6 +2235,8 @@
         size_t numCounterOffers = 0;
         ssize_t index = monoPipe->negotiate(offers, 1, NULL, numCounterOffers);
         ALOG_ASSERT(index == 0);
+        monoPipe->setAvgFrames((mScreenState & 1) ?
+                (monoPipe->maxFrames() * 7) / 8 : mNormalFrameCount * 2);
         mPipeSink = monoPipe;
 
 #ifdef TEE_SINK_FRAMES
@@ -2682,6 +2699,16 @@
 #if defined(ATRACE_TAG) && (ATRACE_TAG != ATRACE_TAG_NEVER)
         Tracer::traceBegin(ATRACE_TAG, "write");
 #endif
+        // update the setpoint when gScreenState changes
+        uint32_t screenState = gScreenState;
+        if (screenState != mScreenState) {
+            mScreenState = screenState;
+            MonoPipe *pipe = (MonoPipe *)mPipeSink.get();
+            if (pipe != NULL) {
+                pipe->setAvgFrames((mScreenState & 1) ?
+                        (pipe->maxFrames() * 7) / 8 : mNormalFrameCount * 2);
+            }
+        }
         ssize_t framesWritten = mNormalSink->write(mMixBuffer, count);
 #if defined(ATRACE_TAG) && (ATRACE_TAG != ATRACE_TAG_NEVER)
         Tracer::traceEnd(ATRACE_TAG);
@@ -3887,6 +3914,7 @@
     }
     sleepTime = 0;
     writeFrames = mNormalFrameCount;
+    standbyTime = systemTime() + standbyDelay;
 }
 
 void AudioFlinger::DuplicatingThread::threadLoop_sleepTime()
@@ -3898,21 +3926,19 @@
             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 (mMixerStatus == MIXER_TRACKS_ENABLED) {
+            writeFrames = mNormalFrameCount;
+            memset(mMixBuffer, 0, mixBufferSize);
+        } else {
+            // flush remaining overflow buffers in output tracks
+            writeFrames = 0;
         }
+        sleepTime = 0;
     }
 }
 
 void AudioFlinger::DuplicatingThread::threadLoop_write()
 {
-    standbyTime = systemTime() + standbyDelay;
     for (size_t i = 0; i < outputTracks.size(); i++) {
         outputTracks[i]->write(mMixBuffer, writeFrames);
     }
@@ -8187,6 +8213,31 @@
         status = cmdStatus;
     }
 
+    if (status == 0 &&
+            (memcmp(&mDescriptor.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0)) {
+        uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
+        effect_param_t *p = (effect_param_t *)buf32;
+
+        p->psize = sizeof(uint32_t);
+        p->vsize = sizeof(uint32_t);
+        size = sizeof(int);
+        *(int32_t *)p->data = VISUALIZER_PARAM_LATENCY;
+
+        uint32_t latency = 0;
+        PlaybackThread *pbt = thread->mAudioFlinger->checkPlaybackThread_l(thread->mId);
+        if (pbt != NULL) {
+            latency = pbt->latency_l();
+        }
+
+        *((int32_t *)p->data + 1)= latency;
+        (*mEffectInterface)->command(mEffectInterface,
+                                     EFFECT_CMD_SET_PARAM,
+                                     sizeof(effect_param_t) + 8,
+                                     &buf32,
+                                     &size,
+                                     &cmdStatus);
+    }
+
     mMaxDisableWaitCnt = (MAX_DISABLE_TIME_MS * mConfig.outputCfg.samplingRate) /
             (1000 * mConfig.outputCfg.buffer.frameCount);
 
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index a0e0ea5..677d466 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -965,6 +965,8 @@
 
                     // return estimated latency in milliseconds, as reported by HAL
                     uint32_t    latency() const;
+                    // same, but lock must already be held
+                    uint32_t    latency_l() const;
 
                     void        setMasterVolume(float value);
                     void        setMasterMute(bool muted);
@@ -1117,6 +1119,7 @@
         // For dumpsys
         sp<NBAIO_Sink>          mTeeSink;
         sp<NBAIO_Source>        mTeeSource;
+        uint32_t                mScreenState;   // cached copy of gScreenState
     public:
         virtual     bool        hasFastMixer() const = 0;
         virtual     FastTrackUnderruns getFastTrackUnderruns(size_t fastIndex) const
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index d8bed40..3bb7b44 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -483,7 +483,10 @@
                                 (int) sec, nsec / 1000000L);
                         dumpState->mOverruns++;
                     }
-                    sleepNs = periodNs - overrunNs;
+                    // Code for non blocking audio HAL. Sleep time must be tuned to allow
+                    // catching up after an underrun
+                    //     sleepNs = periodNs - overrunNs;
+                    sleepNs = -1;
                 } else {
                     sleepNs = -1;
                     ignoreNextOverrun = false;
diff --git a/services/audioflinger/MonoPipe.cpp b/services/audioflinger/MonoPipe.cpp
index 6efb8b1..f3fc19a 100644
--- a/services/audioflinger/MonoPipe.cpp
+++ b/services/audioflinger/MonoPipe.cpp
@@ -20,6 +20,7 @@
 #include <cutils/atomic.h>
 #include <cutils/compiler.h>
 #include <utils/Log.h>
+#include <utils/Trace.h>
 #include "MonoPipe.h"
 #include "roundup.h"
 
@@ -32,6 +33,9 @@
         mBuffer(malloc(mMaxFrames * Format_frameSize(format))),
         mFront(0),
         mRear(0),
+        mWriteTsValid(false),
+        // mWriteTs
+        mSetpoint((reqFrames * 11) / 16),
         mWriteCanBlock(writeCanBlock)
 {
 }
@@ -87,40 +91,75 @@
         count -= written;
         buffer = (char *) buffer + (written << mBitShift);
         // Simulate blocking I/O by sleeping at different rates, depending on a throttle.
-        // The throttle tries to keep the pipe about 11/16 full on average, with a slight jitter.
+        // The throttle tries to keep the mean pipe depth near the setpoint, with a slight jitter.
         uint32_t ns;
         if (written > 0) {
             size_t filled = (mMaxFrames - avail) + written;
             // FIXME cache these values to avoid re-computation
-            if (filled <= mReqFrames / 4) {
+            if (filled <= mSetpoint / 2) {
                 // pipe is (nearly) empty, fill quickly
                 ns = written * ( 500000000 / Format_sampleRate(mFormat));
-            } else if (filled <= mReqFrames / 2) {
-                // pipe is normal, fill at slightly faster rate
+            } else if (filled <= (mSetpoint * 3) / 4) {
+                // pipe is below setpoint, fill at slightly faster rate
                 ns = written * ( 750000000 / Format_sampleRate(mFormat));
-            } else if (filled <= (mReqFrames * 5) / 8) {
-                // pipe is normal, fill at nominal rate
+            } else if (filled <= (mSetpoint * 5) / 4) {
+                // pipe is at setpoint, fill at nominal rate
                 ns = written * (1000000000 / Format_sampleRate(mFormat));
-            } else if (filled <= (mReqFrames * 3) / 4) {
-                // pipe is normal, fill at slightly slower rate
-                ns = written * (1100000000 / Format_sampleRate(mFormat));
+            } else if (filled <= (mSetpoint * 3) / 2) {
+                // pipe is above setpoint, fill at slightly slower rate
+                ns = written * (1150000000 / Format_sampleRate(mFormat));
+            } else if (filled <= (mSetpoint * 7) / 4) {
+                // pipe is overflowing, fill slowly
+                ns = written * (1350000000 / Format_sampleRate(mFormat));
             } else {
-                // pipe is (nearly) full, fill slowly
-                ns = written * (1250000000 / Format_sampleRate(mFormat));
+                // pipe is severely overflowing
+                ns = written * (1750000000 / Format_sampleRate(mFormat));
             }
         } else {
-            ns = mReqFrames * (250000000 / Format_sampleRate(mFormat));
+            ns = count * (1350000000 / Format_sampleRate(mFormat));
         }
         if (ns > 999999999) {
             ns = 999999999;
         }
-        struct timespec sleep;
-        sleep.tv_sec = 0;
-        sleep.tv_nsec = ns;
-        nanosleep(&sleep, NULL);
+        struct timespec nowTs;
+        bool nowTsValid = !clock_gettime(CLOCK_MONOTONIC, &nowTs);
+        // deduct the elapsed time since previous write() completed
+        if (nowTsValid && mWriteTsValid) {
+            time_t sec = nowTs.tv_sec - mWriteTs.tv_sec;
+            long nsec = nowTs.tv_nsec - mWriteTs.tv_nsec;
+            if (nsec < 0) {
+                --sec;
+                nsec += 1000000000;
+            }
+            if (sec == 0) {
+                if ((long) ns > nsec) {
+                    ns -= nsec;
+                } else {
+                    ns = 0;
+                }
+            }
+        }
+        if (ns > 0) {
+            const struct timespec req = {0, ns};
+            nanosleep(&req, NULL);
+        }
+        // record the time that this write() completed
+        if (nowTsValid) {
+            mWriteTs = nowTs;
+            if ((mWriteTs.tv_nsec += ns) >= 1000000000) {
+                mWriteTs.tv_nsec -= 1000000000;
+                ++mWriteTs.tv_sec;
+            }
+        }
+        mWriteTsValid = nowTsValid;
     }
     mFramesWritten += totalFramesWritten;
     return totalFramesWritten;
 }
 
+void MonoPipe::setAvgFrames(size_t setpoint)
+{
+    mSetpoint = setpoint;
+}
+
 }   // namespace android
diff --git a/services/audioflinger/MonoPipe.h b/services/audioflinger/MonoPipe.h
index aaaa51f..f6e2cb3 100644
--- a/services/audioflinger/MonoPipe.h
+++ b/services/audioflinger/MonoPipe.h
@@ -58,7 +58,9 @@
 
             // average number of frames present in the pipe under normal conditions.
             // See throttling mechanism in MonoPipe::write()
-            size_t  getAvgFrames() const { return (mReqFrames * 11) / 16; }
+            size_t  getAvgFrames() const { return mSetpoint; }
+            void    setAvgFrames(size_t setpoint);
+            size_t  maxFrames() const { return mMaxFrames; }
 
 private:
     const size_t    mReqFrames;     // as requested in constructor, unrounded
@@ -71,6 +73,9 @@
                                     // read by writer with android_atomic_acquire_load
     volatile int32_t mRear;         // written by writer with android_atomic_release_store,
                                     // read by reader with android_atomic_acquire_load
+    bool            mWriteTsValid;  // whether mWriteTs is valid
+    struct timespec mWriteTs;       // time that the previous write() completed
+    size_t          mSetpoint;      // target value for pipe fill depth
     const bool      mWriteCanBlock; // whether write() should block if the pipe is full
 };