| Eric Laurent | 81784c3 | 2012-11-19 14:55:58 -0800 | [diff] [blame^] | 1 | /* | 
 | 2 | ** | 
 | 3 | ** Copyright 2012, The Android Open Source Project | 
 | 4 | ** | 
 | 5 | ** Licensed under the Apache License, Version 2.0 (the "License"); | 
 | 6 | ** you may not use this file except in compliance with the License. | 
 | 7 | ** You may obtain a copy of the License at | 
 | 8 | ** | 
 | 9 | **     http://www.apache.org/licenses/LICENSE-2.0 | 
 | 10 | ** | 
 | 11 | ** Unless required by applicable law or agreed to in writing, software | 
 | 12 | ** distributed under the License is distributed on an "AS IS" BASIS, | 
 | 13 | ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | 14 | ** See the License for the specific language governing permissions and | 
 | 15 | ** limitations under the License. | 
 | 16 | */ | 
 | 17 |  | 
 | 18 | #ifndef INCLUDING_FROM_AUDIOFLINGER_H | 
 | 19 |     #error This header file should only be included from AudioFlinger.h | 
 | 20 | #endif | 
 | 21 |  | 
 | 22 | //--- Audio Effect Management | 
 | 23 |  | 
 | 24 | // EffectModule and EffectChain classes both have their own mutex to protect | 
 | 25 | // state changes or resource modifications. Always respect the following order | 
 | 26 | // if multiple mutexes must be acquired to avoid cross deadlock: | 
 | 27 | // AudioFlinger -> ThreadBase -> EffectChain -> EffectModule | 
 | 28 |  | 
 | 29 | // The EffectModule class is a wrapper object controlling the effect engine implementation | 
 | 30 | // in the effect library. It prevents concurrent calls to process() and command() functions | 
 | 31 | // from different client threads. It keeps a list of EffectHandle objects corresponding | 
 | 32 | // to all client applications using this effect and notifies applications of effect state, | 
 | 33 | // control or parameter changes. It manages the activation state machine to send appropriate | 
 | 34 | // reset, enable, disable commands to effect engine and provide volume | 
 | 35 | // ramping when effects are activated/deactivated. | 
 | 36 | // When controlling an auxiliary effect, the EffectModule also provides an input buffer used by | 
 | 37 | // the attached track(s) to accumulate their auxiliary channel. | 
 | 38 | class EffectModule : public RefBase { | 
 | 39 | public: | 
 | 40 |     EffectModule(ThreadBase *thread, | 
 | 41 |                     const wp<AudioFlinger::EffectChain>& chain, | 
 | 42 |                     effect_descriptor_t *desc, | 
 | 43 |                     int id, | 
 | 44 |                     int sessionId); | 
 | 45 |     virtual ~EffectModule(); | 
 | 46 |  | 
 | 47 |     enum effect_state { | 
 | 48 |         IDLE, | 
 | 49 |         RESTART, | 
 | 50 |         STARTING, | 
 | 51 |         ACTIVE, | 
 | 52 |         STOPPING, | 
 | 53 |         STOPPED, | 
 | 54 |         DESTROYED | 
 | 55 |     }; | 
 | 56 |  | 
 | 57 |     int         id() const { return mId; } | 
 | 58 |     void process(); | 
 | 59 |     void updateState(); | 
 | 60 |     status_t command(uint32_t cmdCode, | 
 | 61 |                      uint32_t cmdSize, | 
 | 62 |                      void *pCmdData, | 
 | 63 |                      uint32_t *replySize, | 
 | 64 |                      void *pReplyData); | 
 | 65 |  | 
 | 66 |     void reset_l(); | 
 | 67 |     status_t configure(); | 
 | 68 |     status_t init(); | 
 | 69 |     effect_state state() const { | 
 | 70 |         return mState; | 
 | 71 |     } | 
 | 72 |     uint32_t status() { | 
 | 73 |         return mStatus; | 
 | 74 |     } | 
 | 75 |     int sessionId() const { | 
 | 76 |         return mSessionId; | 
 | 77 |     } | 
 | 78 |     status_t    setEnabled(bool enabled); | 
 | 79 |     status_t    setEnabled_l(bool enabled); | 
 | 80 |     bool isEnabled() const; | 
 | 81 |     bool isProcessEnabled() const; | 
 | 82 |  | 
 | 83 |     void        setInBuffer(int16_t *buffer) { mConfig.inputCfg.buffer.s16 = buffer; } | 
 | 84 |     int16_t     *inBuffer() { return mConfig.inputCfg.buffer.s16; } | 
 | 85 |     void        setOutBuffer(int16_t *buffer) { mConfig.outputCfg.buffer.s16 = buffer; } | 
 | 86 |     int16_t     *outBuffer() { return mConfig.outputCfg.buffer.s16; } | 
 | 87 |     void        setChain(const wp<EffectChain>& chain) { mChain = chain; } | 
 | 88 |     void        setThread(const wp<ThreadBase>& thread) { mThread = thread; } | 
 | 89 |     const wp<ThreadBase>& thread() { return mThread; } | 
 | 90 |  | 
 | 91 |     status_t addHandle(EffectHandle *handle); | 
 | 92 |     size_t disconnect(EffectHandle *handle, bool unpinIfLast); | 
 | 93 |     size_t removeHandle(EffectHandle *handle); | 
 | 94 |  | 
 | 95 |     const effect_descriptor_t& desc() const { return mDescriptor; } | 
 | 96 |     wp<EffectChain>&     chain() { return mChain; } | 
 | 97 |  | 
 | 98 |     status_t         setDevice(audio_devices_t device); | 
 | 99 |     status_t         setVolume(uint32_t *left, uint32_t *right, bool controller); | 
 | 100 |     status_t         setMode(audio_mode_t mode); | 
 | 101 |     status_t         setAudioSource(audio_source_t source); | 
 | 102 |     status_t         start(); | 
 | 103 |     status_t         stop(); | 
 | 104 |     void             setSuspended(bool suspended); | 
 | 105 |     bool             suspended() const; | 
 | 106 |  | 
 | 107 |     EffectHandle*    controlHandle_l(); | 
 | 108 |  | 
 | 109 |     bool             isPinned() const { return mPinned; } | 
 | 110 |     void             unPin() { mPinned = false; } | 
 | 111 |     bool             purgeHandles(); | 
 | 112 |     void             lock() { mLock.lock(); } | 
 | 113 |     void             unlock() { mLock.unlock(); } | 
 | 114 |  | 
 | 115 |     void             dump(int fd, const Vector<String16>& args); | 
 | 116 |  | 
 | 117 | protected: | 
 | 118 |     friend class AudioFlinger;      // for mHandles | 
 | 119 |     bool                mPinned; | 
 | 120 |  | 
 | 121 |     // Maximum time allocated to effect engines to complete the turn off sequence | 
 | 122 |     static const uint32_t MAX_DISABLE_TIME_MS = 10000; | 
 | 123 |  | 
 | 124 |     EffectModule(const EffectModule&); | 
 | 125 |     EffectModule& operator = (const EffectModule&); | 
 | 126 |  | 
 | 127 |     status_t start_l(); | 
 | 128 |     status_t stop_l(); | 
 | 129 |  | 
 | 130 | mutable Mutex               mLock;      // mutex for process, commands and handles list protection | 
 | 131 |     wp<ThreadBase>      mThread;    // parent thread | 
 | 132 |     wp<EffectChain>     mChain;     // parent effect chain | 
 | 133 |     const int           mId;        // this instance unique ID | 
 | 134 |     const int           mSessionId; // audio session ID | 
 | 135 |     const effect_descriptor_t mDescriptor;// effect descriptor received from effect engine | 
 | 136 |     effect_config_t     mConfig;    // input and output audio configuration | 
 | 137 |     effect_handle_t  mEffectInterface; // Effect module C API | 
 | 138 |     status_t            mStatus;    // initialization status | 
 | 139 |     effect_state        mState;     // current activation state | 
 | 140 |     Vector<EffectHandle *> mHandles;    // list of client handles | 
 | 141 |                 // First handle in mHandles has highest priority and controls the effect module | 
 | 142 |     uint32_t mMaxDisableWaitCnt;    // maximum grace period before forcing an effect off after | 
 | 143 |                                     // sending disable command. | 
 | 144 |     uint32_t mDisableWaitCnt;       // current process() calls count during disable period. | 
 | 145 |     bool     mSuspended;            // effect is suspended: temporarily disabled by framework | 
 | 146 | }; | 
 | 147 |  | 
 | 148 | // The EffectHandle class implements the IEffect interface. It provides resources | 
 | 149 | // to receive parameter updates, keeps track of effect control | 
 | 150 | // ownership and state and has a pointer to the EffectModule object it is controlling. | 
 | 151 | // There is one EffectHandle object for each application controlling (or using) | 
 | 152 | // an effect module. | 
 | 153 | // The EffectHandle is obtained by calling AudioFlinger::createEffect(). | 
 | 154 | class EffectHandle: public android::BnEffect { | 
 | 155 | public: | 
 | 156 |  | 
 | 157 |     EffectHandle(const sp<EffectModule>& effect, | 
 | 158 |             const sp<AudioFlinger::Client>& client, | 
 | 159 |             const sp<IEffectClient>& effectClient, | 
 | 160 |             int32_t priority); | 
 | 161 |     virtual ~EffectHandle(); | 
 | 162 |  | 
 | 163 |     // IEffect | 
 | 164 |     virtual status_t enable(); | 
 | 165 |     virtual status_t disable(); | 
 | 166 |     virtual status_t command(uint32_t cmdCode, | 
 | 167 |                              uint32_t cmdSize, | 
 | 168 |                              void *pCmdData, | 
 | 169 |                              uint32_t *replySize, | 
 | 170 |                              void *pReplyData); | 
 | 171 |     virtual void disconnect(); | 
 | 172 | private: | 
 | 173 |             void disconnect(bool unpinIfLast); | 
 | 174 | public: | 
 | 175 |     virtual sp<IMemory> getCblk() const { return mCblkMemory; } | 
 | 176 |     virtual status_t onTransact(uint32_t code, const Parcel& data, | 
 | 177 |             Parcel* reply, uint32_t flags); | 
 | 178 |  | 
 | 179 |  | 
 | 180 |     // Give or take control of effect module | 
 | 181 |     // - hasControl: true if control is given, false if removed | 
 | 182 |     // - signal: true client app should be signaled of change, false otherwise | 
 | 183 |     // - enabled: state of the effect when control is passed | 
 | 184 |     void setControl(bool hasControl, bool signal, bool enabled); | 
 | 185 |     void commandExecuted(uint32_t cmdCode, | 
 | 186 |                          uint32_t cmdSize, | 
 | 187 |                          void *pCmdData, | 
 | 188 |                          uint32_t replySize, | 
 | 189 |                          void *pReplyData); | 
 | 190 |     void setEnabled(bool enabled); | 
 | 191 |     bool enabled() const { return mEnabled; } | 
 | 192 |  | 
 | 193 |     // Getters | 
 | 194 |     int id() const { return mEffect->id(); } | 
 | 195 |     int priority() const { return mPriority; } | 
 | 196 |     bool hasControl() const { return mHasControl; } | 
 | 197 |     sp<EffectModule> effect() const { return mEffect; } | 
 | 198 |     // destroyed_l() must be called with the associated EffectModule mLock held | 
 | 199 |     bool destroyed_l() const { return mDestroyed; } | 
 | 200 |  | 
 | 201 |     void dump(char* buffer, size_t size); | 
 | 202 |  | 
 | 203 | protected: | 
 | 204 |     friend class AudioFlinger;          // for mEffect, mHasControl, mEnabled | 
 | 205 |     EffectHandle(const EffectHandle&); | 
 | 206 |     EffectHandle& operator =(const EffectHandle&); | 
 | 207 |  | 
 | 208 |     sp<EffectModule> mEffect;           // pointer to controlled EffectModule | 
 | 209 |     sp<IEffectClient> mEffectClient;    // callback interface for client notifications | 
 | 210 |     /*const*/ sp<Client> mClient;       // client for shared memory allocation, see disconnect() | 
 | 211 |     sp<IMemory>         mCblkMemory;    // shared memory for control block | 
 | 212 |     effect_param_cblk_t* mCblk;         // control block for deferred parameter setting via | 
 | 213 |                                         // shared memory | 
 | 214 |     uint8_t*            mBuffer;        // pointer to parameter area in shared memory | 
 | 215 |     int mPriority;                      // client application priority to control the effect | 
 | 216 |     bool mHasControl;                   // true if this handle is controlling the effect | 
 | 217 |     bool mEnabled;                      // cached enable state: needed when the effect is | 
 | 218 |                                         // restored after being suspended | 
 | 219 |     bool mDestroyed;                    // Set to true by destructor. Access with EffectModule | 
 | 220 |                                         // mLock held | 
 | 221 | }; | 
 | 222 |  | 
 | 223 | // the EffectChain class represents a group of effects associated to one audio session. | 
 | 224 | // There can be any number of EffectChain objects per output mixer thread (PlaybackThread). | 
 | 225 | // The EffecChain with session ID 0 contains global effects applied to the output mix. | 
 | 226 | // Effects in this chain can be insert or auxiliary. Effects in other chains (attached to | 
 | 227 | // tracks) are insert only. The EffectChain maintains an ordered list of effect module, the | 
 | 228 | // order corresponding in the effect process order. When attached to a track (session ID != 0), | 
 | 229 | // it also provide it's own input buffer used by the track as accumulation buffer. | 
 | 230 | class EffectChain : public RefBase { | 
 | 231 | public: | 
 | 232 |     EffectChain(const wp<ThreadBase>& wThread, int sessionId); | 
 | 233 |     EffectChain(ThreadBase *thread, int sessionId); | 
 | 234 |     virtual ~EffectChain(); | 
 | 235 |  | 
 | 236 |     // special key used for an entry in mSuspendedEffects keyed vector | 
 | 237 |     // corresponding to a suspend all request. | 
 | 238 |     static const int        kKeyForSuspendAll = 0; | 
 | 239 |  | 
 | 240 |     // minimum duration during which we force calling effect process when last track on | 
 | 241 |     // a session is stopped or removed to allow effect tail to be rendered | 
 | 242 |     static const int        kProcessTailDurationMs = 1000; | 
 | 243 |  | 
 | 244 |     void process_l(); | 
 | 245 |  | 
 | 246 |     void lock() { | 
 | 247 |         mLock.lock(); | 
 | 248 |     } | 
 | 249 |     void unlock() { | 
 | 250 |         mLock.unlock(); | 
 | 251 |     } | 
 | 252 |  | 
 | 253 |     status_t addEffect_l(const sp<EffectModule>& handle); | 
 | 254 |     size_t removeEffect_l(const sp<EffectModule>& handle); | 
 | 255 |  | 
 | 256 |     int sessionId() const { return mSessionId; } | 
 | 257 |     void setSessionId(int sessionId) { mSessionId = sessionId; } | 
 | 258 |  | 
 | 259 |     sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor); | 
 | 260 |     sp<EffectModule> getEffectFromId_l(int id); | 
 | 261 |     sp<EffectModule> getEffectFromType_l(const effect_uuid_t *type); | 
 | 262 |     bool setVolume_l(uint32_t *left, uint32_t *right); | 
 | 263 |     void setDevice_l(audio_devices_t device); | 
 | 264 |     void setMode_l(audio_mode_t mode); | 
 | 265 |     void setAudioSource_l(audio_source_t source); | 
 | 266 |  | 
 | 267 |     void setInBuffer(int16_t *buffer, bool ownsBuffer = false) { | 
 | 268 |         mInBuffer = buffer; | 
 | 269 |         mOwnInBuffer = ownsBuffer; | 
 | 270 |     } | 
 | 271 |     int16_t *inBuffer() const { | 
 | 272 |         return mInBuffer; | 
 | 273 |     } | 
 | 274 |     void setOutBuffer(int16_t *buffer) { | 
 | 275 |         mOutBuffer = buffer; | 
 | 276 |     } | 
 | 277 |     int16_t *outBuffer() const { | 
 | 278 |         return mOutBuffer; | 
 | 279 |     } | 
 | 280 |  | 
 | 281 |     void incTrackCnt() { android_atomic_inc(&mTrackCnt); } | 
 | 282 |     void decTrackCnt() { android_atomic_dec(&mTrackCnt); } | 
 | 283 |     int32_t trackCnt() const { return android_atomic_acquire_load(&mTrackCnt); } | 
 | 284 |  | 
 | 285 |     void incActiveTrackCnt() { android_atomic_inc(&mActiveTrackCnt); | 
 | 286 |                                mTailBufferCount = mMaxTailBuffers; } | 
 | 287 |     void decActiveTrackCnt() { android_atomic_dec(&mActiveTrackCnt); } | 
 | 288 |     int32_t activeTrackCnt() const { return android_atomic_acquire_load(&mActiveTrackCnt); } | 
 | 289 |  | 
 | 290 |     uint32_t strategy() const { return mStrategy; } | 
 | 291 |     void setStrategy(uint32_t strategy) | 
 | 292 |             { mStrategy = strategy; } | 
 | 293 |  | 
 | 294 |     // suspend effect of the given type | 
 | 295 |     void setEffectSuspended_l(const effect_uuid_t *type, | 
 | 296 |                               bool suspend); | 
 | 297 |     // suspend all eligible effects | 
 | 298 |     void setEffectSuspendedAll_l(bool suspend); | 
 | 299 |     // check if effects should be suspend or restored when a given effect is enable or disabled | 
 | 300 |     void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect, | 
 | 301 |                                           bool enabled); | 
 | 302 |  | 
 | 303 |     void clearInputBuffer(); | 
 | 304 |  | 
 | 305 |     void dump(int fd, const Vector<String16>& args); | 
 | 306 |  | 
 | 307 | protected: | 
 | 308 |     friend class AudioFlinger;  // for mThread, mEffects | 
 | 309 |     EffectChain(const EffectChain&); | 
 | 310 |     EffectChain& operator =(const EffectChain&); | 
 | 311 |  | 
 | 312 |     class SuspendedEffectDesc : public RefBase { | 
 | 313 |     public: | 
 | 314 |         SuspendedEffectDesc() : mRefCount(0) {} | 
 | 315 |  | 
 | 316 |         int mRefCount; | 
 | 317 |         effect_uuid_t mType; | 
 | 318 |         wp<EffectModule> mEffect; | 
 | 319 |     }; | 
 | 320 |  | 
 | 321 |     // get a list of effect modules to suspend when an effect of the type | 
 | 322 |     // passed is enabled. | 
 | 323 |     void                       getSuspendEligibleEffects(Vector< sp<EffectModule> > &effects); | 
 | 324 |  | 
 | 325 |     // get an effect module if it is currently enable | 
 | 326 |     sp<EffectModule> getEffectIfEnabled(const effect_uuid_t *type); | 
 | 327 |     // true if the effect whose descriptor is passed can be suspended | 
 | 328 |     // OEMs can modify the rules implemented in this method to exclude specific effect | 
 | 329 |     // types or implementations from the suspend/restore mechanism. | 
 | 330 |     bool isEffectEligibleForSuspend(const effect_descriptor_t& desc); | 
 | 331 |  | 
 | 332 |     void clearInputBuffer_l(sp<ThreadBase> thread); | 
 | 333 |  | 
 | 334 |     wp<ThreadBase> mThread;     // parent mixer thread | 
 | 335 |     Mutex mLock;                // mutex protecting effect list | 
 | 336 |     Vector< sp<EffectModule> > mEffects; // list of effect modules | 
 | 337 |     int mSessionId;             // audio session ID | 
 | 338 |     int16_t *mInBuffer;         // chain input buffer | 
 | 339 |     int16_t *mOutBuffer;        // chain output buffer | 
 | 340 |  | 
 | 341 |     // 'volatile' here means these are accessed with atomic operations instead of mutex | 
 | 342 |     volatile int32_t mActiveTrackCnt;    // number of active tracks connected | 
 | 343 |     volatile int32_t mTrackCnt;          // number of tracks connected | 
 | 344 |  | 
 | 345 |     int32_t mTailBufferCount;   // current effect tail buffer count | 
 | 346 |     int32_t mMaxTailBuffers;    // maximum effect tail buffers | 
 | 347 |     bool mOwnInBuffer;          // true if the chain owns its input buffer | 
 | 348 |     int mVolumeCtrlIdx;         // index of insert effect having control over volume | 
 | 349 |     uint32_t mLeftVolume;       // previous volume on left channel | 
 | 350 |     uint32_t mRightVolume;      // previous volume on right channel | 
 | 351 |     uint32_t mNewLeftVolume;       // new volume on left channel | 
 | 352 |     uint32_t mNewRightVolume;      // new volume on right channel | 
 | 353 |     uint32_t mStrategy; // strategy for this effect chain | 
 | 354 |     // mSuspendedEffects lists all effects currently suspended in the chain. | 
 | 355 |     // Use effect type UUID timelow field as key. There is no real risk of identical | 
 | 356 |     // timeLow fields among effect type UUIDs. | 
 | 357 |     // Updated by updateSuspendedSessions_l() only. | 
 | 358 |     KeyedVector< int, sp<SuspendedEffectDesc> > mSuspendedEffects; | 
 | 359 | }; |