Merge "audioflinger: no effects on offloaded tracks" into klp-dev
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index b8a6b37..626b5c2 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -98,6 +98,11 @@
 size_t AudioFlinger::mTeeSinkTrackFrames = kTeeSinkTrackFramesDefault;
 #endif
 
+//TODO: remove when effect offload is implemented
+// In order to avoid invalidating offloaded tracks each time a Visualizer is turned on and off
+// we define a minimum time during which a global effect is considered enabled.
+static const nsecs_t kMinGlobalEffectEnabletimeNs = seconds(7200);
+
 // ----------------------------------------------------------------------------
 
 static int load_audio_interface(const char *if_name, audio_hw_device_t **dev)
@@ -141,7 +146,8 @@
       mMode(AUDIO_MODE_INVALID),
       mBtNrecIsOff(false),
       mIsLowRamDevice(true),
-      mIsDeviceTypeKnown(false)
+      mIsDeviceTypeKnown(false),
+      mGlobalEffectEnableTime(0)
 {
     getpid_cached = getpid();
     char value[PROPERTY_VALUE_MAX];
@@ -2314,6 +2320,38 @@
     return NO_ERROR;
 }
 
+bool AudioFlinger::isGlobalEffectEnabled_l()
+{
+    if (mGlobalEffectEnableTime != 0 &&
+            ((systemTime() - mGlobalEffectEnableTime) < kMinGlobalEffectEnabletimeNs)) {
+        return true;
+    }
+
+    for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+        sp<EffectChain> ec =
+                mPlaybackThreads.valueAt(i)->getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX);
+        if (ec != 0 && ec->isEnabled()) {
+            return true;
+        }
+    }
+    return false;
+}
+
+void AudioFlinger::onGlobalEffectEnable()
+{
+    Mutex::Autolock _l(mLock);
+
+    mGlobalEffectEnableTime = systemTime();
+
+    for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+        sp<PlaybackThread> t = mPlaybackThreads.valueAt(i);
+        if (t->mType == ThreadBase::OFFLOAD) {
+            t->invalidateTracks(AUDIO_STREAM_MUSIC);
+        }
+    }
+
+}
+
 struct Entry {
 #define MAX_NAME 32     // %Y%m%d%H%M%S_%d.wav
     char mName[MAX_NAME];
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 5df04f4..0992308 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -466,6 +466,10 @@
                 void        removeClient_l(pid_t pid);
                 void        removeNotificationClient(pid_t pid);
 
+                //TODO: remove when effect offload is implemented
+                bool isGlobalEffectEnabled_l();
+                void onGlobalEffectEnable();
+
     class AudioHwDevice {
     public:
         enum Flags {
@@ -641,6 +645,8 @@
 private:
     bool    mIsLowRamDevice;
     bool    mIsDeviceTypeKnown;
+    //TODO: remove when effect offload is implemented
+    nsecs_t mGlobalEffectEnableTime;  // when a global effect was last enabled
 };
 
 #undef INCLUDING_FROM_AUDIOFLINGER_H
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index d5a21a7..86671a9 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -593,17 +593,6 @@
                 h->setEnabled(enabled);
             }
         }
-//EL_FIXME not sure why this is needed?
-//        sp<ThreadBase> thread = mThread.promote();
-//        if (thread == 0) {
-//            return NO_ERROR;
-//        }
-//
-//        if ((thread->type() == ThreadBase::OFFLOAD) && (enabled)) {
-//            PlaybackThread *p = (PlaybackThread *)thread.get();
-//            ALOGV("setEnabled: Offload, invalidate tracks");
-//            p->invalidateTracks(AUDIO_STREAM_MUSIC);
-//        }
     }
     return NO_ERROR;
 }
@@ -942,6 +931,17 @@
             thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId());
         }
         mEnabled = false;
+    } else {
+        //TODO: remove when effect offload is implemented
+        if (thread != 0) {
+            if ((thread->type() == ThreadBase::OFFLOAD)) {
+                PlaybackThread *t = (PlaybackThread *)thread.get();
+                t->invalidateTracks(AUDIO_STREAM_MUSIC);
+            }
+            if (mEffect->sessionId() == AUDIO_SESSION_OUTPUT_MIX) {
+                thread->mAudioFlinger->onGlobalEffectEnable();
+            }
+        }
     }
     return status;
 }
@@ -1728,4 +1728,16 @@
     }
 }
 
+bool AudioFlinger::EffectChain::isEnabled()
+{
+    Mutex::Autolock _l(mLock);
+    size_t size = mEffects.size();
+    for (size_t i = 0; i < size; i++) {
+        if (mEffects[i]->isEnabled()) {
+            return true;
+        }
+    }
+    return false;
+}
+
 }; // namespace android
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 0b7fb83..bac50f2 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -303,6 +303,10 @@
 
     void clearInputBuffer();
 
+    // At least one effect in the chain is enabled
+    bool isEnabled();
+
+
     void dump(int fd, const Vector<String16>& args);
 
 protected:
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 2042050..6002aa3 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -543,7 +543,17 @@
 
     sp<ThreadBase> thread = mThread.promote();
     if (thread != 0) {
-        Mutex::Autolock _l(thread->mLock);
+        //TODO: remove when effect offload is implemented
+        if (isOffloaded()) {
+            Mutex::Autolock _laf(thread->mAudioFlinger->mLock);
+            Mutex::Autolock _lth(thread->mLock);
+            sp<EffectChain> ec = thread->getEffectChain_l(mSessionId);
+            if (thread->mAudioFlinger->isGlobalEffectEnabled_l() || (ec != 0 && ec->isEnabled())) {
+                invalidate();
+                return PERMISSION_DENIED;
+            }
+        }
+        Mutex::Autolock _lth(thread->mLock);
         track_state state = mState;
         // here the track could be either new, or restarted
         // in both cases "unstop" the track