fix volume and effect enable delay on offloaded tracks

Volume: add a method to wake up the mediaserver playback
thread when a volume command is received on an offloaded track.

Effects: call effect chain process on offloaded playback threads
asynchronously from writes to allow effect state updates while
waiting for async write callback.

Bug: 10796540.

Change-Id: Id2747ae88783575d1d7ffd6fc86fbd054ab2c739
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index b41d480..2aeb263 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -412,6 +412,7 @@
                                                   int target);
         virtual status_t    setParameters(const String8& keyValuePairs);
         virtual status_t    getTimestamp(AudioTimestamp& timestamp);
+        virtual void        signal(); // signal playback thread for a change in control block
 
         virtual status_t onTransact(
             uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 6e0354d..a8a5169 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -972,13 +972,20 @@
         }
         mEnabled = false;
     } else {
-        if (thread != 0 && !mEffect->isOffloadable()) {
-            if ((thread->type() == ThreadBase::OFFLOAD)) {
+        if (thread != 0) {
+            if (thread->type() == ThreadBase::OFFLOAD) {
                 PlaybackThread *t = (PlaybackThread *)thread.get();
-                t->invalidateTracks(AUDIO_STREAM_MUSIC);
+                Mutex::Autolock _l(t->mLock);
+                t->broadcast_l();
             }
-            if (mEffect->sessionId() == AUDIO_SESSION_OUTPUT_MIX) {
-                thread->mAudioFlinger->onNonOffloadableGlobalEffectEnable();
+            if (!mEffect->isOffloadable()) {
+                if (thread->type() == ThreadBase::OFFLOAD) {
+                    PlaybackThread *t = (PlaybackThread *)thread.get();
+                    t->invalidateTracks(AUDIO_STREAM_MUSIC);
+                }
+                if (mEffect->sessionId() == AUDIO_SESSION_OUTPUT_MIX) {
+                    thread->mAudioFlinger->onNonOffloadableGlobalEffectEnable();
+                }
             }
         }
     }
@@ -1009,6 +1016,11 @@
     sp<ThreadBase> thread = mEffect->thread().promote();
     if (thread != 0) {
         thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId());
+        if (thread->type() == ThreadBase::OFFLOAD) {
+            PlaybackThread *t = (PlaybackThread *)thread.get();
+            Mutex::Autolock _l(t->mLock);
+            t->broadcast_l();
+        }
     }
 
     return status;
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index f7ad6b1..a2e2511 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -60,6 +60,7 @@
             int16_t     *mainBuffer() const { return mMainBuffer; }
             int         auxEffectId() const { return mAuxEffectId; }
     virtual status_t    getTimestamp(AudioTimestamp& timestamp);
+            void        signal();
 
 // implement FastMixerState::VolumeProvider interface
     virtual uint32_t    getVolumeLR();
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 2d9d485..187adf3 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2238,12 +2238,21 @@
             }
 
             // only process effects if we're going to write
-            if (sleepTime == 0) {
+            if (sleepTime == 0 && mType != OFFLOAD) {
                 for (size_t i = 0; i < effectChains.size(); i ++) {
                     effectChains[i]->process_l();
                 }
             }
         }
+        // Process effect chains for offloaded thread even if no audio
+        // was read from audio track: process only updates effect state
+        // and thus does have to be synchronized with audio writes but may have
+        // to be called while waiting for async write callback
+        if (mType == OFFLOAD) {
+            for (size_t i = 0; i < effectChains.size(); i ++) {
+                effectChains[i]->process_l();
+            }
+        }
 
         // enable changes in effect chain
         unlockEffectChains(effectChains);
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index d8d325d..9c6e724 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -288,6 +288,12 @@
     return mTrack->getTimestamp(timestamp);
 }
 
+
+void AudioFlinger::TrackHandle::signal()
+{
+    return mTrack->signal();
+}
+
 status_t AudioFlinger::TrackHandle::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -926,6 +932,16 @@
     mIsInvalid = true;
 }
 
+void AudioFlinger::PlaybackThread::Track::signal()
+{
+    sp<ThreadBase> thread = mThread.promote();
+    if (thread != 0) {
+        PlaybackThread *t = (PlaybackThread *)thread.get();
+        Mutex::Autolock _l(t->mLock);
+        t->broadcast_l();
+    }
+}
+
 // ----------------------------------------------------------------------------
 
 sp<AudioFlinger::PlaybackThread::TimedTrack>