Loading services/audioflinger/AudioFlinger.cpp +6 −9 Original line number Diff line number Diff line Loading @@ -660,7 +660,7 @@ sp<IAudioTrack> AudioFlinger::createTrack( sp<PlaybackThread> t = mPlaybackThreads.valueAt(i); if (mPlaybackThreads.keyAt(i) != output) { uint32_t sessions = t->hasAudioSession(lSessionId); if (sessions & PlaybackThread::EFFECT_SESSION) { if (sessions & ThreadBase::EFFECT_SESSION) { effectThread = t.get(); break; } Loading Loading @@ -1766,7 +1766,7 @@ audio_hw_sync_t AudioFlinger::getAudioHwSyncForSession(audio_session_t sessionId for (size_t i = 0; i < mPlaybackThreads.size(); i++) { sp<PlaybackThread> thread = mPlaybackThreads.valueAt(i); uint32_t sessions = thread->hasAudioSession(sessionId); if (sessions & PlaybackThread::TRACK_SESSION) { if (sessions & ThreadBase::TRACK_SESSION) { AudioParameter param = AudioParameter(); param.addInt(String8(AUDIO_PARAMETER_STREAM_HW_AV_SYNC), value); thread->setParameters(param.toString()); Loading Loading @@ -2824,14 +2824,11 @@ status_t AudioFlinger::moveEffectChain_l(audio_session_t sessionId, return INVALID_OPERATION; } // Check whether the destination thread has a channel count of FCC_2, which is // currently required for (most) effects. Prevent moving the effect chain here rather // than disabling the addEffect_l() call in dstThread below. if ((dstThread->type() == ThreadBase::MIXER || dstThread->isDuplicating()) && dstThread->mChannelCount != FCC_2) { // Check whether the destination thread and all effects in the chain are compatible if (!chain->isCompatibleWithThread_l(dstThread)) { ALOGW("moveEffectChain_l() effect chain failed because" " destination thread %p channel count(%u) != %u", dstThread, dstThread->mChannelCount, FCC_2); " destination thread %p is not compatible with effects in the chain", dstThread); return INVALID_OPERATION; } Loading services/audioflinger/Effects.cpp +23 −0 Original line number Diff line number Diff line Loading @@ -1960,4 +1960,27 @@ void AudioFlinger::EffectChain::setThread(const sp<ThreadBase>& thread) } } bool AudioFlinger::EffectChain::hasSoftwareEffect() const { Mutex::Autolock _l(mLock); for (size_t i = 0; i < mEffects.size(); i++) { if (mEffects[i]->isImplementationSoftware()) { return true; } } return false; } // isCompatibleWithThread_l() must be called with thread->mLock held bool AudioFlinger::EffectChain::isCompatibleWithThread_l(const sp<ThreadBase>& thread) const { Mutex::Autolock _l(mLock); for (size_t i = 0; i < mEffects.size(); i++) { if (thread->checkEffectCompatibility_l(&(mEffects[i]->desc()), mSessionId) != NO_ERROR) { return false; } } return true; } } // namespace android services/audioflinger/Effects.h +27 −20 Original line number Diff line number Diff line Loading @@ -117,6 +117,8 @@ public: void unlock() { mLock.unlock(); } bool isOffloadable() const { return (mDescriptor.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) != 0; } bool isImplementationSoftware() const { return (mDescriptor.flags & EFFECT_FLAG_HW_ACC_MASK) == 0; } status_t setOffloaded(bool offloaded, audio_io_handle_t io); bool isOffloaded() const; void addEffectToHal_l(); Loading Loading @@ -330,6 +332,11 @@ public: void syncHalEffectsState(); bool hasSoftwareEffect() const; // isCompatibleWithThread_l() must be called with thread->mLock held bool isCompatibleWithThread_l(const sp<ThreadBase>& thread) const; void dump(int fd, const Vector<String16>& args); protected: Loading Loading @@ -362,7 +369,7 @@ protected: void setThread(const sp<ThreadBase>& thread); wp<ThreadBase> mThread; // parent mixer thread Mutex mLock; // mutex protecting effect list mutable Mutex mLock; // mutex protecting effect list Vector< sp<EffectModule> > mEffects; // list of effect modules audio_session_t mSessionId; // audio session ID int16_t *mInBuffer; // chain input buffer Loading services/audioflinger/Threads.cpp +199 −52 Original line number Diff line number Diff line Loading @@ -1256,6 +1256,135 @@ void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled_l(const sp<EffectModu } } // checkEffectCompatibility_l() must be called with ThreadBase::mLock held status_t AudioFlinger::RecordThread::checkEffectCompatibility_l( const effect_descriptor_t *desc, audio_session_t sessionId) { // No global effect sessions on record threads if (sessionId == AUDIO_SESSION_OUTPUT_MIX || sessionId == AUDIO_SESSION_OUTPUT_STAGE) { ALOGW("checkEffectCompatibility_l(): global effect %s on record thread %s", desc->name, mThreadName); return BAD_VALUE; } // only pre processing effects on record thread if ((desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_PRE_PROC) { ALOGW("checkEffectCompatibility_l(): non pre processing effect %s on record thread %s", desc->name, mThreadName); return BAD_VALUE; } audio_input_flags_t flags = mInput->flags; if (hasFastCapture() || (flags & AUDIO_INPUT_FLAG_FAST)) { if (flags & AUDIO_INPUT_FLAG_RAW) { ALOGW("checkEffectCompatibility_l(): effect %s on record thread %s in raw mode", desc->name, mThreadName); return BAD_VALUE; } if ((desc->flags & EFFECT_FLAG_HW_ACC_TUNNEL) == 0) { ALOGW("checkEffectCompatibility_l(): non HW effect %s on record thread %s in fast mode", desc->name, mThreadName); return BAD_VALUE; } } return NO_ERROR; } // checkEffectCompatibility_l() must be called with ThreadBase::mLock held status_t AudioFlinger::PlaybackThread::checkEffectCompatibility_l( const effect_descriptor_t *desc, audio_session_t sessionId) { // no preprocessing on playback threads if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC) { ALOGW("checkEffectCompatibility_l(): pre processing effect %s created on playback" " thread %s", desc->name, mThreadName); return BAD_VALUE; } switch (mType) { case MIXER: { // Reject any effect on mixer multichannel sinks. // TODO: fix both format and multichannel issues with effects. if (mChannelCount != FCC_2) { ALOGW("checkEffectCompatibility_l(): effect %s for multichannel(%d) on MIXER" " thread %s", desc->name, mChannelCount, mThreadName); return BAD_VALUE; } audio_output_flags_t flags = mOutput->flags; if (hasFastMixer() || (flags & AUDIO_OUTPUT_FLAG_FAST)) { if (sessionId == AUDIO_SESSION_OUTPUT_MIX) { // global effects are applied only to non fast tracks if they are SW if ((desc->flags & EFFECT_FLAG_HW_ACC_TUNNEL) == 0) { break; } } else if (sessionId == AUDIO_SESSION_OUTPUT_STAGE) { // only post processing on output stage session if ((desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_POST_PROC) { ALOGW("checkEffectCompatibility_l(): non post processing effect %s not allowed" " on output stage session", desc->name); return BAD_VALUE; } } else { // no restriction on effects applied on non fast tracks if ((hasAudioSession_l(sessionId) & ThreadBase::FAST_SESSION) == 0) { break; } } if (flags & AUDIO_OUTPUT_FLAG_RAW) { ALOGW("checkEffectCompatibility_l(): effect %s on playback thread in raw mode", desc->name); return BAD_VALUE; } if ((desc->flags & EFFECT_FLAG_HW_ACC_TUNNEL) == 0) { ALOGW("checkEffectCompatibility_l(): non HW effect %s on playback thread" " in fast mode", desc->name); return BAD_VALUE; } } } break; case OFFLOAD: // only offloadable effects on offload thread if ((desc->flags & EFFECT_FLAG_OFFLOAD_MASK) != EFFECT_FLAG_OFFLOAD_SUPPORTED) { ALOGW("checkEffectCompatibility_l(): non offloadable effect %s created on" " OFFLOAD thread %s", desc->name, mThreadName); return BAD_VALUE; } break; case DIRECT: // Reject any effect on Direct output threads for now, since the format of // mSinkBuffer is not guaranteed to be compatible with effect processing (PCM 16 stereo). ALOGW("checkEffectCompatibility_l(): effect %s on DIRECT output thread %s", desc->name, mThreadName); return BAD_VALUE; case DUPLICATING: // Reject any effect on mixer multichannel sinks. // TODO: fix both format and multichannel issues with effects. if (mChannelCount != FCC_2) { ALOGW("checkEffectCompatibility_l(): effect %s for multichannel(%d)" " on DUPLICATING thread %s", desc->name, mChannelCount, mThreadName); return BAD_VALUE; } if ((sessionId == AUDIO_SESSION_OUTPUT_STAGE) || (sessionId == AUDIO_SESSION_OUTPUT_MIX)) { ALOGW("checkEffectCompatibility_l(): global effect %s on DUPLICATING" " thread %s", desc->name, mThreadName); return BAD_VALUE; } if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) { ALOGW("checkEffectCompatibility_l(): post processing effect %s on" " DUPLICATING thread %s", desc->name, mThreadName); return BAD_VALUE; } if ((desc->flags & EFFECT_FLAG_HW_ACC_TUNNEL) != 0) { ALOGW("checkEffectCompatibility_l(): HW tunneled effect %s on" " DUPLICATING thread %s", desc->name, mThreadName); return BAD_VALUE; } break; default: LOG_ALWAYS_FATAL("checkEffectCompatibility_l(): wrong thread type %d", mType); } return NO_ERROR; } // ThreadBase::createEffect_l() must be called with AudioFlinger::mLock held sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l( const sp<AudioFlinger::Client>& client, Loading @@ -1280,54 +1409,16 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l( goto Exit; } // Reject any effect on Direct output threads for now, since the format of // mSinkBuffer is not guaranteed to be compatible with effect processing (PCM 16 stereo). if (mType == DIRECT) { ALOGW("createEffect_l() Cannot add effect %s on Direct output type thread %s", desc->name, mThreadName); lStatus = BAD_VALUE; goto Exit; } // Reject any effect on mixer or duplicating multichannel sinks. // TODO: fix both format and multichannel issues with effects. if ((mType == MIXER || mType == DUPLICATING) && mChannelCount != FCC_2) { ALOGW("createEffect_l() Cannot add effect %s for multichannel(%d) %s threads", desc->name, mChannelCount, mType == MIXER ? "MIXER" : "DUPLICATING"); lStatus = BAD_VALUE; goto Exit; } // Allow global effects only on offloaded and mixer threads if (sessionId == AUDIO_SESSION_OUTPUT_MIX) { switch (mType) { case MIXER: case OFFLOAD: break; case DIRECT: case DUPLICATING: case RECORD: default: ALOGW("createEffect_l() Cannot add global effect %s on thread %s", desc->name, mThreadName); lStatus = BAD_VALUE; goto Exit; } } // Only Pre processor effects are allowed on input threads and only on input threads if ((mType == RECORD) != ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC)) { ALOGW("createEffect_l() effect %s (flags %08x) created on wrong thread type %d", desc->name, desc->flags, mType); lStatus = BAD_VALUE; goto Exit; } ALOGV("createEffect_l() thread %p effect %s on session %d", this, desc->name, sessionId); { // scope for mLock Mutex::Autolock _l(mLock); lStatus = checkEffectCompatibility_l(desc, sessionId); if (lStatus != NO_ERROR) { goto Exit; } // check for existing effect chain with the requested audio session chain = getEffectChain_l(sessionId); if (chain == 0) { Loading Loading @@ -1804,7 +1895,43 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac } frameCount = max(frameCount, mFrameCount * sFastTrackMultiplier); // incl framecount 0 } ALOGV("AUDIO_OUTPUT_FLAG_FAST accepted: frameCount=%zu mFrameCount=%zu", // check compatibility with audio effects. { // scope for mLock Mutex::Autolock _l(mLock); // do not accept RAW flag if post processing are present. Note that post processing on // a fast mixer are necessarily hardware sp<EffectChain> chain = getEffectChain_l(AUDIO_SESSION_OUTPUT_STAGE); if (chain != 0) { ALOGV_IF((flags & AUDIO_OUTPUT_FLAG_RAW) != 0, "AUDIO_OUTPUT_FLAG_RAW denied: post processing effect present"); *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_RAW); } // Do not accept FAST flag if software global effects are present chain = getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX); if (chain != 0) { ALOGV_IF((flags & AUDIO_OUTPUT_FLAG_RAW) != 0, "AUDIO_OUTPUT_FLAG_RAW denied: global effect present"); *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_RAW); if (chain->hasSoftwareEffect()) { ALOGV("AUDIO_OUTPUT_FLAG_FAST denied: software global effect present"); *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_FAST); } } // Do not accept FAST flag if the session has software effects chain = getEffectChain_l(sessionId); if (chain != 0) { ALOGV_IF((flags & AUDIO_OUTPUT_FLAG_RAW) != 0, "AUDIO_OUTPUT_FLAG_RAW denied: effect present on session"); *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_RAW); if (chain->hasSoftwareEffect()) { ALOGV("AUDIO_OUTPUT_FLAG_FAST denied: software effect present on session"); *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_FAST); } } } ALOGV_IF((flags & AUDIO_OUTPUT_FLAG_FAST) != 0, "AUDIO_OUTPUT_FLAG_FAST accepted: frameCount=%zu mFrameCount=%zu", frameCount, mFrameCount); } else { ALOGV("AUDIO_OUTPUT_FLAG_FAST denied: sharedBuffer=%p frameCount=%zu " Loading Loading @@ -2400,9 +2527,9 @@ status_t AudioFlinger::PlaybackThread::getRenderPosition(uint32_t *halFrames, ui } } uint32_t AudioFlinger::PlaybackThread::hasAudioSession(audio_session_t sessionId) const // hasAudioSession_l() must be called with ThreadBase::mLock held uint32_t AudioFlinger::PlaybackThread::hasAudioSession_l(audio_session_t sessionId) const { Mutex::Autolock _l(mLock); uint32_t result = 0; if (getEffectChain_l(sessionId) != 0) { result = EFFECT_SESSION; Loading @@ -2412,6 +2539,9 @@ uint32_t AudioFlinger::PlaybackThread::hasAudioSession(audio_session_t sessionId sp<Track> track = mTracks[i]; if (sessionId == track->sessionId() && !track->isInvalid()) { result |= TRACK_SESSION; if (track->isFastTrack()) { result |= FAST_SESSION; } break; } } Loading Loading @@ -6333,7 +6463,21 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRe // there are sufficient fast track slots available mFastTrackAvail ) { ALOGV("AUDIO_INPUT_FLAG_FAST accepted: frameCount=%zu mFrameCount=%zu", // check compatibility with audio effects. Mutex::Autolock _l(mLock); // Do not accept FAST flag if the session has software effects sp<EffectChain> chain = getEffectChain_l(sessionId); if (chain != 0) { ALOGV_IF((flags & AUDIO_INPUT_FLAG_RAW) != 0, "AUDIO_INPUT_FLAG_RAW denied: effect present on session"); *flags = (audio_input_flags_t)(*flags & ~AUDIO_INPUT_FLAG_RAW); if (chain->hasSoftwareEffect()) { ALOGV("AUDIO_INPUT_FLAG_FAST denied: software effect present on session"); *flags = (audio_input_flags_t)(*flags & ~AUDIO_INPUT_FLAG_FAST); } } ALOGV_IF((flags & AUDIO_INPUT_FLAG_FAST) != 0, "AUDIO_INPUT_FLAG_FAST accepted: frameCount=%zu mFrameCount=%zu", frameCount, mFrameCount); } else { ALOGV("AUDIO_INPUT_FLAG_FAST denied: frameCount=%zu mFrameCount=%zu mPipeFramesP2=%zu " Loading Loading @@ -7224,9 +7368,9 @@ uint32_t AudioFlinger::RecordThread::getInputFramesLost() return mInput->stream->get_input_frames_lost(mInput->stream); } uint32_t AudioFlinger::RecordThread::hasAudioSession(audio_session_t sessionId) const // hasAudioSession_l() must be called with ThreadBase::mLock held uint32_t AudioFlinger::RecordThread::hasAudioSession_l(audio_session_t sessionId) const { Mutex::Autolock _l(mLock); uint32_t result = 0; if (getEffectChain_l(sessionId) != 0) { result = EFFECT_SESSION; Loading @@ -7235,6 +7379,9 @@ uint32_t AudioFlinger::RecordThread::hasAudioSession(audio_session_t sessionId) for (size_t i = 0; i < mTracks.size(); ++i) { if (sessionId == mTracks[i]->sessionId()) { result |= TRACK_SESSION; if (mTracks[i]->isFastTrack()) { result |= FAST_SESSION; } break; } } Loading services/audioflinger/Threads.h +25 −6 Original line number Diff line number Diff line Loading @@ -301,8 +301,10 @@ public: enum effect_state { EFFECT_SESSION = 0x1, // the audio session corresponds to at least one // effect TRACK_SESSION = 0x2 // the audio session corresponds to at least one TRACK_SESSION = 0x2, // the audio session corresponds to at least one // track FAST_SESSION = 0x4 // the audio session corresponds to at least one // fast track }; // get effect chain corresponding to session Id. Loading Loading @@ -335,9 +337,16 @@ public: void removeEffect_l(const sp< EffectModule>& effect); // detach all tracks connected to an auxiliary effect virtual void detachAuxEffect_l(int effectId __unused) {} // returns either EFFECT_SESSION if effects on this audio session exist in one // chain, or TRACK_SESSION if tracks on this audio session exist, or both virtual uint32_t hasAudioSession(audio_session_t sessionId) const = 0; // returns a combination of: // - EFFECT_SESSION if effects on this audio session exist in one chain // - TRACK_SESSION if tracks on this audio session exist // - FAST_SESSION if fast tracks on this audio session exist virtual uint32_t hasAudioSession_l(audio_session_t sessionId) const = 0; uint32_t hasAudioSession(audio_session_t sessionId) const { Mutex::Autolock _l(mLock); return hasAudioSession_l(sessionId); } // the value returned by default implementation is not important as the // strategy is only meaningful for PlaybackThread which implements this method virtual uint32_t getStrategyForSession_l(audio_session_t sessionId __unused) Loading Loading @@ -374,6 +383,10 @@ public: void systemReady(); // checkEffectCompatibility_l() must be called with ThreadBase::mLock held virtual status_t checkEffectCompatibility_l(const effect_descriptor_t *desc, audio_session_t sessionId) = 0; mutable Mutex mLock; protected: Loading Loading @@ -506,6 +519,9 @@ public: // RefBase virtual void onFirstRef(); virtual status_t checkEffectCompatibility_l(const effect_descriptor_t *desc, audio_session_t sessionId); protected: // Code snippets that were lifted up out of threadLoop() virtual void threadLoop_mix() = 0; Loading Loading @@ -605,7 +621,7 @@ public: virtual status_t addEffectChain_l(const sp<EffectChain>& chain); virtual size_t removeEffectChain_l(const sp<EffectChain>& chain); virtual uint32_t hasAudioSession(audio_session_t sessionId) const; virtual uint32_t hasAudioSession_l(audio_session_t sessionId) const; virtual uint32_t getStrategyForSession_l(audio_session_t sessionId); Loading Loading @@ -1292,7 +1308,7 @@ public: virtual status_t addEffectChain_l(const sp<EffectChain>& chain); virtual size_t removeEffectChain_l(const sp<EffectChain>& chain); virtual uint32_t hasAudioSession(audio_session_t sessionId) const; virtual uint32_t hasAudioSession_l(audio_session_t sessionId) const; // Return the set of unique session IDs across all tracks. // The keys are the session IDs, and the associated values are meaningless. Loading @@ -1308,6 +1324,9 @@ public: bool hasFastCapture() const { return mFastCapture != 0; } virtual void getAudioPortConfig(struct audio_port_config *config); virtual status_t checkEffectCompatibility_l(const effect_descriptor_t *desc, audio_session_t sessionId); private: // Enter standby if not already in standby, and set mStandby flag void standbyIfNotAlreadyInStandby(); Loading Loading
services/audioflinger/AudioFlinger.cpp +6 −9 Original line number Diff line number Diff line Loading @@ -660,7 +660,7 @@ sp<IAudioTrack> AudioFlinger::createTrack( sp<PlaybackThread> t = mPlaybackThreads.valueAt(i); if (mPlaybackThreads.keyAt(i) != output) { uint32_t sessions = t->hasAudioSession(lSessionId); if (sessions & PlaybackThread::EFFECT_SESSION) { if (sessions & ThreadBase::EFFECT_SESSION) { effectThread = t.get(); break; } Loading Loading @@ -1766,7 +1766,7 @@ audio_hw_sync_t AudioFlinger::getAudioHwSyncForSession(audio_session_t sessionId for (size_t i = 0; i < mPlaybackThreads.size(); i++) { sp<PlaybackThread> thread = mPlaybackThreads.valueAt(i); uint32_t sessions = thread->hasAudioSession(sessionId); if (sessions & PlaybackThread::TRACK_SESSION) { if (sessions & ThreadBase::TRACK_SESSION) { AudioParameter param = AudioParameter(); param.addInt(String8(AUDIO_PARAMETER_STREAM_HW_AV_SYNC), value); thread->setParameters(param.toString()); Loading Loading @@ -2824,14 +2824,11 @@ status_t AudioFlinger::moveEffectChain_l(audio_session_t sessionId, return INVALID_OPERATION; } // Check whether the destination thread has a channel count of FCC_2, which is // currently required for (most) effects. Prevent moving the effect chain here rather // than disabling the addEffect_l() call in dstThread below. if ((dstThread->type() == ThreadBase::MIXER || dstThread->isDuplicating()) && dstThread->mChannelCount != FCC_2) { // Check whether the destination thread and all effects in the chain are compatible if (!chain->isCompatibleWithThread_l(dstThread)) { ALOGW("moveEffectChain_l() effect chain failed because" " destination thread %p channel count(%u) != %u", dstThread, dstThread->mChannelCount, FCC_2); " destination thread %p is not compatible with effects in the chain", dstThread); return INVALID_OPERATION; } Loading
services/audioflinger/Effects.cpp +23 −0 Original line number Diff line number Diff line Loading @@ -1960,4 +1960,27 @@ void AudioFlinger::EffectChain::setThread(const sp<ThreadBase>& thread) } } bool AudioFlinger::EffectChain::hasSoftwareEffect() const { Mutex::Autolock _l(mLock); for (size_t i = 0; i < mEffects.size(); i++) { if (mEffects[i]->isImplementationSoftware()) { return true; } } return false; } // isCompatibleWithThread_l() must be called with thread->mLock held bool AudioFlinger::EffectChain::isCompatibleWithThread_l(const sp<ThreadBase>& thread) const { Mutex::Autolock _l(mLock); for (size_t i = 0; i < mEffects.size(); i++) { if (thread->checkEffectCompatibility_l(&(mEffects[i]->desc()), mSessionId) != NO_ERROR) { return false; } } return true; } } // namespace android
services/audioflinger/Effects.h +27 −20 Original line number Diff line number Diff line Loading @@ -117,6 +117,8 @@ public: void unlock() { mLock.unlock(); } bool isOffloadable() const { return (mDescriptor.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) != 0; } bool isImplementationSoftware() const { return (mDescriptor.flags & EFFECT_FLAG_HW_ACC_MASK) == 0; } status_t setOffloaded(bool offloaded, audio_io_handle_t io); bool isOffloaded() const; void addEffectToHal_l(); Loading Loading @@ -330,6 +332,11 @@ public: void syncHalEffectsState(); bool hasSoftwareEffect() const; // isCompatibleWithThread_l() must be called with thread->mLock held bool isCompatibleWithThread_l(const sp<ThreadBase>& thread) const; void dump(int fd, const Vector<String16>& args); protected: Loading Loading @@ -362,7 +369,7 @@ protected: void setThread(const sp<ThreadBase>& thread); wp<ThreadBase> mThread; // parent mixer thread Mutex mLock; // mutex protecting effect list mutable Mutex mLock; // mutex protecting effect list Vector< sp<EffectModule> > mEffects; // list of effect modules audio_session_t mSessionId; // audio session ID int16_t *mInBuffer; // chain input buffer Loading
services/audioflinger/Threads.cpp +199 −52 Original line number Diff line number Diff line Loading @@ -1256,6 +1256,135 @@ void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled_l(const sp<EffectModu } } // checkEffectCompatibility_l() must be called with ThreadBase::mLock held status_t AudioFlinger::RecordThread::checkEffectCompatibility_l( const effect_descriptor_t *desc, audio_session_t sessionId) { // No global effect sessions on record threads if (sessionId == AUDIO_SESSION_OUTPUT_MIX || sessionId == AUDIO_SESSION_OUTPUT_STAGE) { ALOGW("checkEffectCompatibility_l(): global effect %s on record thread %s", desc->name, mThreadName); return BAD_VALUE; } // only pre processing effects on record thread if ((desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_PRE_PROC) { ALOGW("checkEffectCompatibility_l(): non pre processing effect %s on record thread %s", desc->name, mThreadName); return BAD_VALUE; } audio_input_flags_t flags = mInput->flags; if (hasFastCapture() || (flags & AUDIO_INPUT_FLAG_FAST)) { if (flags & AUDIO_INPUT_FLAG_RAW) { ALOGW("checkEffectCompatibility_l(): effect %s on record thread %s in raw mode", desc->name, mThreadName); return BAD_VALUE; } if ((desc->flags & EFFECT_FLAG_HW_ACC_TUNNEL) == 0) { ALOGW("checkEffectCompatibility_l(): non HW effect %s on record thread %s in fast mode", desc->name, mThreadName); return BAD_VALUE; } } return NO_ERROR; } // checkEffectCompatibility_l() must be called with ThreadBase::mLock held status_t AudioFlinger::PlaybackThread::checkEffectCompatibility_l( const effect_descriptor_t *desc, audio_session_t sessionId) { // no preprocessing on playback threads if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC) { ALOGW("checkEffectCompatibility_l(): pre processing effect %s created on playback" " thread %s", desc->name, mThreadName); return BAD_VALUE; } switch (mType) { case MIXER: { // Reject any effect on mixer multichannel sinks. // TODO: fix both format and multichannel issues with effects. if (mChannelCount != FCC_2) { ALOGW("checkEffectCompatibility_l(): effect %s for multichannel(%d) on MIXER" " thread %s", desc->name, mChannelCount, mThreadName); return BAD_VALUE; } audio_output_flags_t flags = mOutput->flags; if (hasFastMixer() || (flags & AUDIO_OUTPUT_FLAG_FAST)) { if (sessionId == AUDIO_SESSION_OUTPUT_MIX) { // global effects are applied only to non fast tracks if they are SW if ((desc->flags & EFFECT_FLAG_HW_ACC_TUNNEL) == 0) { break; } } else if (sessionId == AUDIO_SESSION_OUTPUT_STAGE) { // only post processing on output stage session if ((desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_POST_PROC) { ALOGW("checkEffectCompatibility_l(): non post processing effect %s not allowed" " on output stage session", desc->name); return BAD_VALUE; } } else { // no restriction on effects applied on non fast tracks if ((hasAudioSession_l(sessionId) & ThreadBase::FAST_SESSION) == 0) { break; } } if (flags & AUDIO_OUTPUT_FLAG_RAW) { ALOGW("checkEffectCompatibility_l(): effect %s on playback thread in raw mode", desc->name); return BAD_VALUE; } if ((desc->flags & EFFECT_FLAG_HW_ACC_TUNNEL) == 0) { ALOGW("checkEffectCompatibility_l(): non HW effect %s on playback thread" " in fast mode", desc->name); return BAD_VALUE; } } } break; case OFFLOAD: // only offloadable effects on offload thread if ((desc->flags & EFFECT_FLAG_OFFLOAD_MASK) != EFFECT_FLAG_OFFLOAD_SUPPORTED) { ALOGW("checkEffectCompatibility_l(): non offloadable effect %s created on" " OFFLOAD thread %s", desc->name, mThreadName); return BAD_VALUE; } break; case DIRECT: // Reject any effect on Direct output threads for now, since the format of // mSinkBuffer is not guaranteed to be compatible with effect processing (PCM 16 stereo). ALOGW("checkEffectCompatibility_l(): effect %s on DIRECT output thread %s", desc->name, mThreadName); return BAD_VALUE; case DUPLICATING: // Reject any effect on mixer multichannel sinks. // TODO: fix both format and multichannel issues with effects. if (mChannelCount != FCC_2) { ALOGW("checkEffectCompatibility_l(): effect %s for multichannel(%d)" " on DUPLICATING thread %s", desc->name, mChannelCount, mThreadName); return BAD_VALUE; } if ((sessionId == AUDIO_SESSION_OUTPUT_STAGE) || (sessionId == AUDIO_SESSION_OUTPUT_MIX)) { ALOGW("checkEffectCompatibility_l(): global effect %s on DUPLICATING" " thread %s", desc->name, mThreadName); return BAD_VALUE; } if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) { ALOGW("checkEffectCompatibility_l(): post processing effect %s on" " DUPLICATING thread %s", desc->name, mThreadName); return BAD_VALUE; } if ((desc->flags & EFFECT_FLAG_HW_ACC_TUNNEL) != 0) { ALOGW("checkEffectCompatibility_l(): HW tunneled effect %s on" " DUPLICATING thread %s", desc->name, mThreadName); return BAD_VALUE; } break; default: LOG_ALWAYS_FATAL("checkEffectCompatibility_l(): wrong thread type %d", mType); } return NO_ERROR; } // ThreadBase::createEffect_l() must be called with AudioFlinger::mLock held sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l( const sp<AudioFlinger::Client>& client, Loading @@ -1280,54 +1409,16 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l( goto Exit; } // Reject any effect on Direct output threads for now, since the format of // mSinkBuffer is not guaranteed to be compatible with effect processing (PCM 16 stereo). if (mType == DIRECT) { ALOGW("createEffect_l() Cannot add effect %s on Direct output type thread %s", desc->name, mThreadName); lStatus = BAD_VALUE; goto Exit; } // Reject any effect on mixer or duplicating multichannel sinks. // TODO: fix both format and multichannel issues with effects. if ((mType == MIXER || mType == DUPLICATING) && mChannelCount != FCC_2) { ALOGW("createEffect_l() Cannot add effect %s for multichannel(%d) %s threads", desc->name, mChannelCount, mType == MIXER ? "MIXER" : "DUPLICATING"); lStatus = BAD_VALUE; goto Exit; } // Allow global effects only on offloaded and mixer threads if (sessionId == AUDIO_SESSION_OUTPUT_MIX) { switch (mType) { case MIXER: case OFFLOAD: break; case DIRECT: case DUPLICATING: case RECORD: default: ALOGW("createEffect_l() Cannot add global effect %s on thread %s", desc->name, mThreadName); lStatus = BAD_VALUE; goto Exit; } } // Only Pre processor effects are allowed on input threads and only on input threads if ((mType == RECORD) != ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC)) { ALOGW("createEffect_l() effect %s (flags %08x) created on wrong thread type %d", desc->name, desc->flags, mType); lStatus = BAD_VALUE; goto Exit; } ALOGV("createEffect_l() thread %p effect %s on session %d", this, desc->name, sessionId); { // scope for mLock Mutex::Autolock _l(mLock); lStatus = checkEffectCompatibility_l(desc, sessionId); if (lStatus != NO_ERROR) { goto Exit; } // check for existing effect chain with the requested audio session chain = getEffectChain_l(sessionId); if (chain == 0) { Loading Loading @@ -1804,7 +1895,43 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac } frameCount = max(frameCount, mFrameCount * sFastTrackMultiplier); // incl framecount 0 } ALOGV("AUDIO_OUTPUT_FLAG_FAST accepted: frameCount=%zu mFrameCount=%zu", // check compatibility with audio effects. { // scope for mLock Mutex::Autolock _l(mLock); // do not accept RAW flag if post processing are present. Note that post processing on // a fast mixer are necessarily hardware sp<EffectChain> chain = getEffectChain_l(AUDIO_SESSION_OUTPUT_STAGE); if (chain != 0) { ALOGV_IF((flags & AUDIO_OUTPUT_FLAG_RAW) != 0, "AUDIO_OUTPUT_FLAG_RAW denied: post processing effect present"); *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_RAW); } // Do not accept FAST flag if software global effects are present chain = getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX); if (chain != 0) { ALOGV_IF((flags & AUDIO_OUTPUT_FLAG_RAW) != 0, "AUDIO_OUTPUT_FLAG_RAW denied: global effect present"); *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_RAW); if (chain->hasSoftwareEffect()) { ALOGV("AUDIO_OUTPUT_FLAG_FAST denied: software global effect present"); *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_FAST); } } // Do not accept FAST flag if the session has software effects chain = getEffectChain_l(sessionId); if (chain != 0) { ALOGV_IF((flags & AUDIO_OUTPUT_FLAG_RAW) != 0, "AUDIO_OUTPUT_FLAG_RAW denied: effect present on session"); *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_RAW); if (chain->hasSoftwareEffect()) { ALOGV("AUDIO_OUTPUT_FLAG_FAST denied: software effect present on session"); *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_FAST); } } } ALOGV_IF((flags & AUDIO_OUTPUT_FLAG_FAST) != 0, "AUDIO_OUTPUT_FLAG_FAST accepted: frameCount=%zu mFrameCount=%zu", frameCount, mFrameCount); } else { ALOGV("AUDIO_OUTPUT_FLAG_FAST denied: sharedBuffer=%p frameCount=%zu " Loading Loading @@ -2400,9 +2527,9 @@ status_t AudioFlinger::PlaybackThread::getRenderPosition(uint32_t *halFrames, ui } } uint32_t AudioFlinger::PlaybackThread::hasAudioSession(audio_session_t sessionId) const // hasAudioSession_l() must be called with ThreadBase::mLock held uint32_t AudioFlinger::PlaybackThread::hasAudioSession_l(audio_session_t sessionId) const { Mutex::Autolock _l(mLock); uint32_t result = 0; if (getEffectChain_l(sessionId) != 0) { result = EFFECT_SESSION; Loading @@ -2412,6 +2539,9 @@ uint32_t AudioFlinger::PlaybackThread::hasAudioSession(audio_session_t sessionId sp<Track> track = mTracks[i]; if (sessionId == track->sessionId() && !track->isInvalid()) { result |= TRACK_SESSION; if (track->isFastTrack()) { result |= FAST_SESSION; } break; } } Loading Loading @@ -6333,7 +6463,21 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRe // there are sufficient fast track slots available mFastTrackAvail ) { ALOGV("AUDIO_INPUT_FLAG_FAST accepted: frameCount=%zu mFrameCount=%zu", // check compatibility with audio effects. Mutex::Autolock _l(mLock); // Do not accept FAST flag if the session has software effects sp<EffectChain> chain = getEffectChain_l(sessionId); if (chain != 0) { ALOGV_IF((flags & AUDIO_INPUT_FLAG_RAW) != 0, "AUDIO_INPUT_FLAG_RAW denied: effect present on session"); *flags = (audio_input_flags_t)(*flags & ~AUDIO_INPUT_FLAG_RAW); if (chain->hasSoftwareEffect()) { ALOGV("AUDIO_INPUT_FLAG_FAST denied: software effect present on session"); *flags = (audio_input_flags_t)(*flags & ~AUDIO_INPUT_FLAG_FAST); } } ALOGV_IF((flags & AUDIO_INPUT_FLAG_FAST) != 0, "AUDIO_INPUT_FLAG_FAST accepted: frameCount=%zu mFrameCount=%zu", frameCount, mFrameCount); } else { ALOGV("AUDIO_INPUT_FLAG_FAST denied: frameCount=%zu mFrameCount=%zu mPipeFramesP2=%zu " Loading Loading @@ -7224,9 +7368,9 @@ uint32_t AudioFlinger::RecordThread::getInputFramesLost() return mInput->stream->get_input_frames_lost(mInput->stream); } uint32_t AudioFlinger::RecordThread::hasAudioSession(audio_session_t sessionId) const // hasAudioSession_l() must be called with ThreadBase::mLock held uint32_t AudioFlinger::RecordThread::hasAudioSession_l(audio_session_t sessionId) const { Mutex::Autolock _l(mLock); uint32_t result = 0; if (getEffectChain_l(sessionId) != 0) { result = EFFECT_SESSION; Loading @@ -7235,6 +7379,9 @@ uint32_t AudioFlinger::RecordThread::hasAudioSession(audio_session_t sessionId) for (size_t i = 0; i < mTracks.size(); ++i) { if (sessionId == mTracks[i]->sessionId()) { result |= TRACK_SESSION; if (mTracks[i]->isFastTrack()) { result |= FAST_SESSION; } break; } } Loading
services/audioflinger/Threads.h +25 −6 Original line number Diff line number Diff line Loading @@ -301,8 +301,10 @@ public: enum effect_state { EFFECT_SESSION = 0x1, // the audio session corresponds to at least one // effect TRACK_SESSION = 0x2 // the audio session corresponds to at least one TRACK_SESSION = 0x2, // the audio session corresponds to at least one // track FAST_SESSION = 0x4 // the audio session corresponds to at least one // fast track }; // get effect chain corresponding to session Id. Loading Loading @@ -335,9 +337,16 @@ public: void removeEffect_l(const sp< EffectModule>& effect); // detach all tracks connected to an auxiliary effect virtual void detachAuxEffect_l(int effectId __unused) {} // returns either EFFECT_SESSION if effects on this audio session exist in one // chain, or TRACK_SESSION if tracks on this audio session exist, or both virtual uint32_t hasAudioSession(audio_session_t sessionId) const = 0; // returns a combination of: // - EFFECT_SESSION if effects on this audio session exist in one chain // - TRACK_SESSION if tracks on this audio session exist // - FAST_SESSION if fast tracks on this audio session exist virtual uint32_t hasAudioSession_l(audio_session_t sessionId) const = 0; uint32_t hasAudioSession(audio_session_t sessionId) const { Mutex::Autolock _l(mLock); return hasAudioSession_l(sessionId); } // the value returned by default implementation is not important as the // strategy is only meaningful for PlaybackThread which implements this method virtual uint32_t getStrategyForSession_l(audio_session_t sessionId __unused) Loading Loading @@ -374,6 +383,10 @@ public: void systemReady(); // checkEffectCompatibility_l() must be called with ThreadBase::mLock held virtual status_t checkEffectCompatibility_l(const effect_descriptor_t *desc, audio_session_t sessionId) = 0; mutable Mutex mLock; protected: Loading Loading @@ -506,6 +519,9 @@ public: // RefBase virtual void onFirstRef(); virtual status_t checkEffectCompatibility_l(const effect_descriptor_t *desc, audio_session_t sessionId); protected: // Code snippets that were lifted up out of threadLoop() virtual void threadLoop_mix() = 0; Loading Loading @@ -605,7 +621,7 @@ public: virtual status_t addEffectChain_l(const sp<EffectChain>& chain); virtual size_t removeEffectChain_l(const sp<EffectChain>& chain); virtual uint32_t hasAudioSession(audio_session_t sessionId) const; virtual uint32_t hasAudioSession_l(audio_session_t sessionId) const; virtual uint32_t getStrategyForSession_l(audio_session_t sessionId); Loading Loading @@ -1292,7 +1308,7 @@ public: virtual status_t addEffectChain_l(const sp<EffectChain>& chain); virtual size_t removeEffectChain_l(const sp<EffectChain>& chain); virtual uint32_t hasAudioSession(audio_session_t sessionId) const; virtual uint32_t hasAudioSession_l(audio_session_t sessionId) const; // Return the set of unique session IDs across all tracks. // The keys are the session IDs, and the associated values are meaningless. Loading @@ -1308,6 +1324,9 @@ public: bool hasFastCapture() const { return mFastCapture != 0; } virtual void getAudioPortConfig(struct audio_port_config *config); virtual status_t checkEffectCompatibility_l(const effect_descriptor_t *desc, audio_session_t sessionId); private: // Enter standby if not already in standby, and set mStandby flag void standbyIfNotAlreadyInStandby(); Loading