Merge "MediaRecorder: only dequeue available buffers from MediaCodec" into lmp-dev
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index d225851..5270efc 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -966,6 +966,8 @@
                 ALOGV("Tear down audio offload, fall back to s/w path");
                 int64_t positionUs;
                 CHECK(msg->findInt64("positionUs", &positionUs));
+                int32_t reason;
+                CHECK(msg->findInt32("reason", &reason));
                 closeAudioSink();
                 mAudioDecoder.clear();
                 ++mAudioDecoderGeneration;
@@ -977,7 +979,9 @@
                 mOffloadAudio = false;
 
                 performSeek(positionUs, false /* needNotify */);
-                instantiateDecoder(true /* audio */, &mAudioDecoder);
+                if (reason == Renderer::kDueToError) {
+                    instantiateDecoder(true /* audio */, &mAudioDecoder);
+                }
             }
             break;
         }
@@ -1044,6 +1048,11 @@
             } else {
                 ALOGW("resume called when source is gone or not set");
             }
+            // |mAudioDecoder| may have been released due to the pause timeout, so try to re-create
+            // it if needed.
+            if (mFlushingAudio != SHUT_DOWN) {
+                instantiateDecoder(true /* audio */, &mAudioDecoder);
+            }
             if (mRenderer != NULL) {
                 mRenderer->resume();
             } else {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 7e5087f..d6bf1de 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -274,7 +274,7 @@
 
         case kWhatAudioOffloadTearDown:
         {
-            onAudioOffloadTearDown();
+            onAudioOffloadTearDown(kDueToError);
             break;
         }
 
@@ -285,7 +285,8 @@
             if (generation != mAudioOffloadPauseTimeoutGeneration) {
                 break;
             }
-            onAudioOffloadTearDown();
+            ALOGV("Audio Offload tear down due to pause timeout.");
+            onAudioOffloadTearDown(kDueToTimeout);
             break;
         }
 
@@ -1089,7 +1090,7 @@
     return durationUs;
 }
 
-void NuPlayer::Renderer::onAudioOffloadTearDown() {
+void NuPlayer::Renderer::onAudioOffloadTearDown(AudioOffloadTearDownReason reason) {
     if (mAudioOffloadTornDown) {
         return;
     }
@@ -1110,6 +1111,7 @@
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("what", kWhatAudioOffloadTearDown);
     notify->setInt64("positionUs", currentPositionUs);
+    notify->setInt32("reason", reason);
     notify->post();
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 8e6112b..4237902 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -69,6 +69,11 @@
         kWhatAudioOffloadPauseTimeout = 'aOPT',
     };
 
+    enum AudioOffloadTearDownReason {
+        kDueToError = 0,
+        kDueToTimeout,
+    };
+
 protected:
     virtual ~Renderer();
 
@@ -157,7 +162,7 @@
     void onPause();
     void onResume();
     void onSetVideoFrameRate(float fps);
-    void onAudioOffloadTearDown();
+    void onAudioOffloadTearDown(AudioOffloadTearDownReason reason);
 
     void notifyEOS(bool audio, status_t finalResult, int64_t delayUs = 0);
     void notifyFlushComplete(bool audio);
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index e200857..e48af20 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1436,6 +1436,16 @@
                                                   IPCThreadState::self()->getCallingUid(),
                                                   flags, tid, &lStatus);
         LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (recordTrack == 0));
+
+        if (lStatus == NO_ERROR) {
+            // Check if one effect chain was awaiting for an AudioRecord to be created on this
+            // session and move it to this thread.
+            sp<EffectChain> chain = getOrphanEffectChain_l((audio_session_t)lSessionId);
+            if (chain != 0) {
+                Mutex::Autolock _l(thread->mLock);
+                thread->addEffectChain_l(chain);
+            }
+        }
     }
 
     if (lStatus != NO_ERROR) {
@@ -2034,14 +2044,41 @@
         }
 
         ALOGV("closeInput() %d", input);
+
+        // If we still have effect chains, it means that a client still holds a handle
+        // on at least one effect. We must either move the chain to an existing thread with the
+        // same session ID or put it aside in case a new record thread is opened for a
+        // new capture on the same session
+        sp<EffectChain> chain;
         {
-            // If we still have effect chains, it means that a client still holds a handle
-            // on at least one effect. We must keep the chain alive in case a new record
-            // thread is opened for a new capture on the same session
             Mutex::Autolock _sl(thread->mLock);
             Vector< sp<EffectChain> > effectChains = thread->getEffectChains_l();
-            for (size_t i = 0; i < effectChains.size(); i++) {
-                putOrphanEffectChain_l(effectChains[i]);
+            // Note: maximum one chain per record thread
+            if (effectChains.size() != 0) {
+                chain = effectChains[0];
+            }
+        }
+        if (chain != 0) {
+            // first check if a record thread is already opened with a client on the same session.
+            // This should only happen in case of overlap between one thread tear down and the
+            // creation of its replacement
+            size_t i;
+            for (i = 0; i < mRecordThreads.size(); i++) {
+                sp<RecordThread> t = mRecordThreads.valueAt(i);
+                if (t == thread) {
+                    continue;
+                }
+                if (t->hasAudioSession(chain->sessionId()) != 0) {
+                    Mutex::Autolock _l(t->mLock);
+                    ALOGV("closeInput() found thread %d for effect session %d",
+                          t->id(), chain->sessionId());
+                    t->addEffectChain_l(chain);
+                    break;
+                }
+            }
+            // put the chain aside if we could not find a record thread with the same session id.
+            if (i == mRecordThreads.size()) {
+                putOrphanEffectChain_l(chain);
             }
         }
         audioConfigChanged(AudioSystem::INPUT_CLOSED, input, NULL);
@@ -2478,6 +2515,7 @@
             // session and used it instead of creating a new one.
             sp<EffectChain> chain = getOrphanEffectChain_l((audio_session_t)sessionId);
             if (chain != 0) {
+                Mutex::Autolock _l(thread->mLock);
                 thread->addEffectChain_l(chain);
             }
         }
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 4678880..bcaf8ae 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -440,6 +440,20 @@
     return status;
 }
 
+void AudioFlinger::EffectModule::addEffectToHal_l()
+{
+    if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
+         (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) {
+        sp<ThreadBase> thread = mThread.promote();
+        if (thread != 0) {
+            audio_stream_t *stream = thread->stream();
+            if (stream != NULL) {
+                stream->add_audio_effect(stream, mEffectInterface);
+            }
+        }
+    }
+}
+
 status_t AudioFlinger::EffectModule::start()
 {
     Mutex::Autolock _l(mLock);
@@ -466,16 +480,7 @@
         status = cmdStatus;
     }
     if (status == 0) {
-        if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
-             (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) {
-            sp<ThreadBase> thread = mThread.promote();
-            if (thread != 0) {
-                audio_stream_t *stream = thread->stream();
-                if (stream != NULL) {
-                    stream->add_audio_effect(stream, mEffectInterface);
-                }
-            }
-        }
+        addEffectToHal_l();
         sp<EffectChain> chain = mChain.promote();
         if (chain != 0) {
             chain->forceVolume();
@@ -1696,6 +1701,17 @@
     return hasControl;
 }
 
+void AudioFlinger::EffectChain::syncHalEffectsState()
+{
+    Mutex::Autolock _l(mLock);
+    for (size_t i = 0; i < mEffects.size(); i++) {
+        if (mEffects[i]->state() == EffectModule::ACTIVE ||
+                mEffects[i]->state() == EffectModule::STOPPING) {
+            mEffects[i]->addEffectToHal_l();
+        }
+    }
+}
+
 void AudioFlinger::EffectChain::dump(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index b87a1fd..6f93f81 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -119,6 +119,7 @@
                         { return (mDescriptor.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) != 0; }
     status_t         setOffloaded(bool offloaded, audio_io_handle_t io);
     bool             isOffloaded() const;
+    void             addEffectToHal_l();
 
     void             dump(int fd, const Vector<String16>& args);
 
@@ -325,6 +326,8 @@
     // we are the only observers.
     bool isVolumeForced() { return (android_atomic_acquire_cas(true, false, &mForceVolume) == 0); }
 
+    void syncHalEffectsState();
+
     void dump(int fd, const Vector<String16>& args);
 
 protected:
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index b1e9c07..44e34b7 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -6207,6 +6207,10 @@
 
     checkSuspendOnAddEffectChain_l(chain);
 
+    // make sure enabled pre processing effects state is communicated to the HAL as we
+    // just moved them to a new input stream.
+    chain->syncHalEffectsState();
+
     mEffectChains.add(chain);
 
     return NO_ERROR;