Merge "Indicate sync frames returned by encoder" into klp-dev
diff --git a/media/libeffects/loudness/EffectLoudnessEnhancer.cpp b/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
index dfc25db..91ed677 100644
--- a/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
+++ b/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
@@ -56,8 +56,7 @@
     int32_t mTargetGainmB;// target gain in mB
     // in this implementation, there is no coupling between the compression on the left and right
     // channels
-    le_fx::AdaptiveDynamicRangeCompression* mCompressorL;
-    le_fx::AdaptiveDynamicRangeCompression* mCompressorR;
+    le_fx::AdaptiveDynamicRangeCompression* mCompressor;
 };
 
 //
@@ -68,11 +67,10 @@
 {
     ALOGV("  > LE_reset(%p)", pContext);
 
-    if ((pContext->mCompressorL != NULL) && (pContext->mCompressorR != NULL)) {
+    if (pContext->mCompressor != NULL) {
         float targetAmp = pow(10, pContext->mTargetGainmB/2000.0f); // mB to linear amplification
         ALOGV("LE_reset(): Target gain=%dmB <=> factor=%.2fX", pContext->mTargetGainmB, targetAmp);
-        pContext->mCompressorL->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
-        pContext->mCompressorR->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
+        pContext->mCompressor->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
     } else {
         ALOGE("LE_reset(%p): null compressors, can't apply target gain", pContext);
     }
@@ -176,13 +174,9 @@
     float targetAmp = pow(10, pContext->mTargetGainmB/2000.0f); // mB to linear amplification
     ALOGV("LE_init(): Target gain=%dmB <=> factor=%.2fX", pContext->mTargetGainmB, targetAmp);
 
-    if (pContext->mCompressorL == NULL) {
-        pContext->mCompressorL = new le_fx::AdaptiveDynamicRangeCompression();
-        pContext->mCompressorL->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
-    }
-    if (pContext->mCompressorR == NULL) {
-        pContext->mCompressorR = new le_fx::AdaptiveDynamicRangeCompression();
-        pContext->mCompressorR->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
+    if (pContext->mCompressor == NULL) {
+        pContext->mCompressor = new le_fx::AdaptiveDynamicRangeCompression();
+        pContext->mCompressor->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
     }
 
     LE_setConfig(pContext, &pContext->mConfig);
@@ -215,8 +209,7 @@
     pContext->mItfe = &gLEInterface;
     pContext->mState = LOUDNESS_ENHANCER_STATE_UNINITIALIZED;
 
-    pContext->mCompressorL = NULL;
-    pContext->mCompressorR = NULL;
+    pContext->mCompressor = NULL;
     ret = LE_init(pContext);
     if (ret < 0) {
         ALOGW("LELib_Create() init failed");
@@ -242,13 +235,9 @@
         return -EINVAL;
     }
     pContext->mState = LOUDNESS_ENHANCER_STATE_UNINITIALIZED;
-    if (pContext->mCompressorL != NULL) {
-        delete pContext->mCompressorL;
-        pContext->mCompressorL = NULL;
-    }
-    if (pContext->mCompressorR != NULL) {
-        delete pContext->mCompressorR;
-        pContext->mCompressorR = NULL;
+    if (pContext->mCompressor != NULL) {
+        delete pContext->mCompressor;
+        pContext->mCompressor = NULL;
     }
     delete pContext;
 
@@ -293,11 +282,14 @@
     //ALOGV("LE about to process %d samples", inBuffer->frameCount);
     uint16_t inIdx;
     float inputAmp = pow(10, pContext->mTargetGainmB/2000.0f);
+    float leftSample, rightSample;
     for (inIdx = 0 ; inIdx < inBuffer->frameCount ; inIdx++) {
-        inBuffer->s16[2*inIdx] = pContext->mCompressorL->Compress(
-                inputAmp * (float)inBuffer->s16[2*inIdx]);
-        inBuffer->s16[2*inIdx +1] = pContext->mCompressorR->Compress(
-                inputAmp * (float)inBuffer->s16[2*inIdx +1]);
+        // makeup gain is applied on the input of the compressor
+        leftSample  = inputAmp * (float)inBuffer->s16[2*inIdx];
+        rightSample = inputAmp * (float)inBuffer->s16[2*inIdx +1];
+        pContext->mCompressor->Compress(&leftSample, &rightSample);
+        inBuffer->s16[2*inIdx]    = (int16_t) leftSample;
+        inBuffer->s16[2*inIdx +1] = (int16_t) rightSample;
     }
 
     if (inBuffer->raw != outBuffer->raw) {
diff --git a/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h b/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h
index fed8c2a..da75ceb 100644
--- a/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h
+++ b/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h
@@ -35,7 +35,7 @@
     float target_gain) {
   const float decibel = target_gain_to_knee_threshold_.Interpolate(
         target_gain);
-  ALOGE("set_knee_threshold_via_target_gain: decibel =%.3f", decibel);
+  ALOGV("set_knee_threshold_via_target_gain: decibel =%.3fdB", decibel);
   set_knee_threshold(decibel);
 }
 
diff --git a/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp b/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp
index 2bbd043..7bd068e 100644
--- a/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp
+++ b/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp
@@ -102,5 +102,40 @@
   return x;
 }
 
+void AdaptiveDynamicRangeCompression::Compress(float *x1, float *x2) {
+  // Taking the maximum amplitude of both channels
+  const float max_abs_x = std::max(std::fabs(*x1),
+    std::max(std::fabs(*x2), kMinLogAbsValue));
+  const float max_abs_x_dB = math::fast_log(max_abs_x);
+  // Subtract Threshold from log-encoded input to get the amount of overshoot
+  const float overshoot = max_abs_x_dB - knee_threshold_;
+  // Hard half-wave rectifier
+  const float rect = std::max(overshoot, 0.0f);
+  // Multiply rectified overshoot with slope
+  const float cv = rect * slope_;
+  const float prev_state = state_;
+  if (cv <= state_) {
+    state_ = alpha_attack_ * state_ + (1.0f - alpha_attack_) * cv;
+  } else {
+    state_ = alpha_release_ * state_ + (1.0f - alpha_release_) * cv;
+  }
+  compressor_gain_ *=
+      math::ExpApproximationViaTaylorExpansionOrder5(state_ - prev_state);
+  *x1 *= compressor_gain_;
+  if (*x1 > kFixedPointLimit) {
+    *x1 = kFixedPointLimit;
+  }
+  if (*x1 < -kFixedPointLimit) {
+    *x1 = -kFixedPointLimit;
+  }
+  *x2 *= compressor_gain_;
+  if (*x2 > kFixedPointLimit) {
+    *x2 = kFixedPointLimit;
+  }
+  if (*x2 < -kFixedPointLimit) {
+    *x2 = -kFixedPointLimit;
+  }
+}
+
 }  // namespace le_fx
 
diff --git a/media/libeffects/loudness/dsp/core/dynamic_range_compression.h b/media/libeffects/loudness/dsp/core/dynamic_range_compression.h
index 4c015df..2821a78 100644
--- a/media/libeffects/loudness/dsp/core/dynamic_range_compression.h
+++ b/media/libeffects/loudness/dsp/core/dynamic_range_compression.h
@@ -55,6 +55,9 @@
   // log(.) and exp(.).
   float Compress(float x);
 
+  // Stereo channel version of the compressor
+  void Compress(float *x1, float *x2);
+
   // This version is slower than Compress(.) but faster than CompressSlow(.)
   float CompressNormalSpeed(float x);
 
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index e38e261..a8a8786 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -363,6 +363,7 @@
     mPositionTimeMediaUs = -1;
     mPositionTimeRealUs = -1;
     mSeeking = false;
+    mSeekTimeUs = 0;
     mReachedEOS = false;
     mFinalStatus = OK;
     mStarted = false;
@@ -602,15 +603,24 @@
 
             // need to adjust the mStartPosUs for offload decoding since parser
             // might not be able to get the exact seek time requested.
-            if (refreshSeekTime && useOffload()) {
-                if (postSeekComplete) {
-                    ALOGV("fillBuffer is going to post SEEK_COMPLETE");
-                    mObserver->postAudioSeekComplete();
-                    postSeekComplete = false;
-                }
+            if (refreshSeekTime) {
+                if (useOffload()) {
+                    if (postSeekComplete) {
+                        ALOGV("fillBuffer is going to post SEEK_COMPLETE");
+                        mObserver->postAudioSeekComplete();
+                        postSeekComplete = false;
+                    }
 
-                mStartPosUs = mPositionTimeMediaUs;
-                ALOGV("adjust seek time to: %.2f", mStartPosUs/ 1E6);
+                    mStartPosUs = mPositionTimeMediaUs;
+                    ALOGV("adjust seek time to: %.2f", mStartPosUs/ 1E6);
+                }
+                // clear seek time with mLock locked and once we have valid mPositionTimeMediaUs
+                // and mPositionTimeRealUs
+                // before clearing mSeekTimeUs check if a new seek request has been received while
+                // we were reading from the source with mLock released.
+                if (!mSeeking) {
+                    mSeekTimeUs = 0;
+                }
             }
 
             if (!useOffload()) {
@@ -741,12 +751,10 @@
         return mPositionTimeRealUs;
     }
 
-    if (mPositionTimeMediaUs < 0 || mPositionTimeRealUs < 0) {
-        if (mSeeking) {
-            return mSeekTimeUs;
-        }
 
-        return 0;
+    if (mPositionTimeMediaUs < 0 || mPositionTimeRealUs < 0) {
+        // mSeekTimeUs is either seek time while seeking or 0 if playback did not start.
+        return mSeekTimeUs;
     }
 
     int64_t realTimeOffset = getRealTimeUsLocked() - mPositionTimeRealUs;
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 5fbee7e..3b516af 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -259,6 +259,7 @@
 
         mQueue.cancelEvent(mBufferingEvent->eventID());
         mBufferingEventPending = false;
+        mAudioTearDown = false;
     }
 }
 
@@ -927,6 +928,9 @@
 
             if ((err != OK) && mOffloadAudio) {
                 ALOGI("play_l() cannot create offload output, fallback to sw decode");
+                int64_t curTimeUs;
+                getPosition(&curTimeUs);
+
                 delete mAudioPlayer;
                 mAudioPlayer = NULL;
                 // if the player was started it will take care of stopping the source when destroyed
@@ -942,6 +946,10 @@
                     if (err != OK) {
                         mAudioSource.clear();
                     } else {
+                        mSeekNotificationSent = true;
+                        if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
+                            seekTo_l(curTimeUs);
+                        }
                         createAudioPlayer_l();
                         err = startAudioPlayer_l(false);
                     }
@@ -2301,6 +2309,7 @@
     modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR);
     mAsyncPrepareEvent = NULL;
     mPreparedCondition.broadcast();
+    mAudioTearDown = false;
 }
 
 // static
@@ -2374,6 +2383,20 @@
     modifyFlags(PREPARED, SET);
     mAsyncPrepareEvent = NULL;
     mPreparedCondition.broadcast();
+
+    if (mAudioTearDown) {
+        if (mPrepareResult == OK) {
+            if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
+                seekTo_l(mAudioTearDownPosition);
+            }
+
+            if (mAudioTearDownWasPlaying) {
+                modifyFlags(CACHE_UNDERRUN, CLEAR);
+                play_l();
+            }
+        }
+        mAudioTearDown = false;
+    }
 }
 
 uint32_t AwesomePlayer::flags() const {
@@ -2791,7 +2814,7 @@
     ALOGV("onAudioTearDownEvent");
 
     // stream info is cleared by reset_l() so copy what we need
-    const bool wasPlaying = (mFlags & PLAYING);
+    mAudioTearDownWasPlaying = (mFlags & PLAYING);
     KeyedVector<String8, String8> uriHeaders(mUriHeaders);
     sp<DataSource> fileSource(mFileSource);
 
@@ -2800,8 +2823,7 @@
     mStatsLock.unlock();
 
     // get current position so we can start recreated stream from here
-    int64_t position = 0;
-    getPosition(&position);
+    getPosition(&mAudioTearDownPosition);
 
     // Reset and recreate
     reset_l();
@@ -2825,21 +2847,8 @@
     mAudioTearDown = true;
     mIsAsyncPrepare = true;
 
-    // Call parepare for the host decoding
+    // Call prepare for the host decoding
     beginPrepareAsync_l();
-
-    if (mPrepareResult == OK) {
-        if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
-            seekTo_l(position);
-        }
-
-        if (wasPlaying) {
-            modifyFlags(CACHE_UNDERRUN, CLEAR);
-            play_l();
-        }
-    }
-
-    mAudioTearDown = false;
 }
 
 }  // namespace android
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index b001cf4..271df8e 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -342,6 +342,8 @@
 
     bool    mOffloadAudio;
     bool    mAudioTearDown;
+    bool    mAudioTearDownWasPlaying;
+    int64_t mAudioTearDownPosition;
 
     status_t setVideoScalingMode(int32_t mode);
     status_t setVideoScalingMode_l(int32_t mode);
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 0ca2107..6e0354d 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1279,9 +1279,10 @@
     }
     bool isGlobalSession = (mSessionId == AUDIO_SESSION_OUTPUT_MIX) ||
             (mSessionId == AUDIO_SESSION_OUTPUT_STAGE);
-    // always process effects unless no more tracks are on the session and the effect tail
-    // has been rendered
-    bool doProcess = true;
+    // never process effects when:
+    // - on an OFFLOAD thread
+    // - no more tracks are on the session and the effect tail has been rendered
+    bool doProcess = (thread->type() != ThreadBase::OFFLOAD);
     if (!isGlobalSession) {
         bool tracksOnSession = (trackCnt() != 0);
 
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index b771e3b..2d9d485 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1594,6 +1594,7 @@
         if (mOutput->stream->set_callback(mOutput->stream,
                                       AudioFlinger::PlaybackThread::asyncCallback, this) == 0) {
             mUseAsyncWrite = true;
+            mCallbackThread = new AudioFlinger::AsyncCallbackThread(this);
         }
     }
 
@@ -3746,9 +3747,9 @@
 // ----------------------------------------------------------------------------
 
 AudioFlinger::AsyncCallbackThread::AsyncCallbackThread(
-        const sp<AudioFlinger::OffloadThread>& offloadThread)
+        const wp<AudioFlinger::PlaybackThread>& playbackThread)
     :   Thread(false /*canCallJava*/),
-        mOffloadThread(offloadThread),
+        mPlaybackThread(playbackThread),
         mWriteAckSequence(0),
         mDrainSequence(0)
 {
@@ -3783,13 +3784,13 @@
             mDrainSequence &= ~1;
         }
         {
-            sp<AudioFlinger::OffloadThread> offloadThread = mOffloadThread.promote();
-            if (offloadThread != 0) {
+            sp<AudioFlinger::PlaybackThread> playbackThread = mPlaybackThread.promote();
+            if (playbackThread != 0) {
                 if (writeAckSequence & 1) {
-                    offloadThread->resetWriteBlocked(writeAckSequence >> 1);
+                    playbackThread->resetWriteBlocked(writeAckSequence >> 1);
                 }
                 if (drainSequence & 1) {
-                    offloadThread->resetDraining(drainSequence >> 1);
+                    playbackThread->resetDraining(drainSequence >> 1);
                 }
             }
         }
@@ -3847,7 +3848,6 @@
         mHwPaused(false),
         mPausedBytesRemaining(0)
 {
-    mCallbackThread = new AudioFlinger::AsyncCallbackThread(this);
 }
 
 AudioFlinger::OffloadThread::~OffloadThread()
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 443b8d7..241424f 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -759,7 +759,7 @@
 class AsyncCallbackThread : public Thread {
 public:
 
-    AsyncCallbackThread(const sp<OffloadThread>& offloadThread);
+    AsyncCallbackThread(const wp<PlaybackThread>& playbackThread);
 
     virtual             ~AsyncCallbackThread();
 
@@ -776,17 +776,17 @@
             void        resetDraining();
 
 private:
-    wp<OffloadThread>   mOffloadThread;
+    const wp<PlaybackThread>   mPlaybackThread;
     // mWriteAckSequence corresponds to the last write sequence passed by the offload thread via
     // setWriteBlocked(). The sequence is shifted one bit to the left and the lsb is used
     // to indicate that the callback has been received via resetWriteBlocked()
-    uint32_t            mWriteAckSequence;
+    uint32_t                   mWriteAckSequence;
     // mDrainSequence corresponds to the last drain sequence passed by the offload thread via
     // setDraining(). The sequence is shifted one bit to the left and the lsb is used
     // to indicate that the callback has been received via resetDraining()
-    uint32_t            mDrainSequence;
-    Condition           mWaitWorkCV;
-    Mutex               mLock;
+    uint32_t                   mDrainSequence;
+    Condition                  mWaitWorkCV;
+    Mutex                      mLock;
 };
 
 class DuplicatingThread : public MixerThread {
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 83466cb..76d44bf 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -298,11 +298,28 @@
         }
     }
 
+    // HACK b/10949105
+    // Query consumer usage bits to set async operation mode for
+    // GLConsumer using controlledByApp parameter.
+    bool useAsync = false;
+    int32_t consumerUsage;
+    if ((res = bufferProducer->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS,
+            &consumerUsage)) != OK) {
+        ALOGE("%s: Camera %d: Failed to query consumer usage", __FUNCTION__,
+              mCameraId);
+        return res;
+    }
+    if (consumerUsage & GraphicBuffer::USAGE_HW_TEXTURE) {
+        ALOGW("%s: Camera %d: Forcing asynchronous mode for stream",
+                __FUNCTION__, mCameraId);
+        useAsync = true;
+    }
+
     sp<IBinder> binder;
     sp<ANativeWindow> anw;
     if (bufferProducer != 0) {
         binder = bufferProducer->asBinder();
-        anw = new Surface(bufferProducer);
+        anw = new Surface(bufferProducer, useAsync);
     }
 
     // TODO: remove w,h,f since we are ignoring them