diff options
-rw-r--r-- | include/media/AudioSystem.h | 27 | ||||
-rw-r--r-- | include/media/IAudioFlinger.h | 2 | ||||
-rw-r--r-- | include/media/IAudioPolicyService.h | 16 | ||||
-rw-r--r-- | media/libeffects/factory/EffectsFactory.c | 2 | ||||
-rw-r--r-- | media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp | 2 | ||||
-rw-r--r-- | media/libmedia/AudioSystem.cpp | 44 | ||||
-rw-r--r-- | media/libmedia/IAudioFlinger.cpp | 22 | ||||
-rw-r--r-- | media/libmedia/IAudioPolicyService.cpp | 148 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 412 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.h | 50 | ||||
-rw-r--r-- | services/audioflinger/AudioPolicyManagerBase.cpp | 210 | ||||
-rw-r--r-- | services/audioflinger/AudioPolicyService.cpp | 133 | ||||
-rw-r--r-- | services/audioflinger/AudioPolicyService.h | 47 |
13 files changed, 887 insertions, 228 deletions
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h index 194f23a..9fd905f 100644 --- a/include/media/AudioSystem.h +++ b/include/media/AudioSystem.h @@ -168,6 +168,15 @@ public: TX_DISABLE = 0 }; + // special audio session values + enum audio_sessions { + SESSION_OUTPUT_STAGE = -1, // session for effects attached to a particular output stream + // (value must be less than 0) + SESSION_OUTPUT_MIX = 0, // session for effects applied to output mix. These effects can + // be moved by audio policy manager to another output stream + // (value must be 0) + }; + /* These are static methods to control the system-wide AudioFlinger * only privileged processes can have access to them */ @@ -353,8 +362,12 @@ public: uint32_t format = FORMAT_DEFAULT, uint32_t channels = CHANNEL_OUT_STEREO, output_flags flags = OUTPUT_FLAG_INDIRECT); - static status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream); - static status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream); + static status_t startOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session = 0); + static status_t stopOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session = 0); static void releaseOutput(audio_io_handle_t output); static audio_io_handle_t getInput(int inputSource, uint32_t samplingRate = 0, @@ -370,6 +383,16 @@ public: static status_t setStreamVolumeIndex(stream_type stream, int index); static status_t getStreamVolumeIndex(stream_type stream, int *index); + static uint32_t getStrategyForStream(stream_type stream); + + static audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc); + static status_t registerEffect(effect_descriptor_t *desc, + audio_io_handle_t output, + uint32_t strategy, + int session, + int id); + static status_t unregisterEffect(int id); + static const sp<IAudioPolicyService>& get_audio_policy_service(); // ---------------------------------------------------------------------------- diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h index 5814fd6..70e505e 100644 --- a/include/media/IAudioFlinger.h +++ b/include/media/IAudioFlinger.h @@ -161,6 +161,8 @@ public: status_t *status, int *id, int *enabled) = 0; + + virtual status_t moveEffects(int session, int srcOutput, int dstOutput) = 0; }; diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h index 4804bbd..49eee59 100644 --- a/include/media/IAudioPolicyService.h +++ b/include/media/IAudioPolicyService.h @@ -53,8 +53,12 @@ public: uint32_t format = AudioSystem::FORMAT_DEFAULT, uint32_t channels = 0, AudioSystem::output_flags flags = AudioSystem::OUTPUT_FLAG_INDIRECT) = 0; - virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream) = 0; - virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream) = 0; + virtual status_t startOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session = 0) = 0; + virtual status_t stopOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session = 0) = 0; virtual void releaseOutput(audio_io_handle_t output) = 0; virtual audio_io_handle_t getInput(int inputSource, uint32_t samplingRate = 0, @@ -69,6 +73,14 @@ public: int indexMax) = 0; virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index) = 0; virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index) = 0; + virtual uint32_t getStrategyForStream(AudioSystem::stream_type stream) = 0; + virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc) = 0; + virtual status_t registerEffect(effect_descriptor_t *desc, + audio_io_handle_t output, + uint32_t strategy, + int session, + int id) = 0; + virtual status_t unregisterEffect(int id) = 0; }; diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c index edd6184..0be280c 100644 --- a/media/libeffects/factory/EffectsFactory.c +++ b/media/libeffects/factory/EffectsFactory.c @@ -31,7 +31,7 @@ static list_elem_t *gCurLib; // current library in enumeration process static list_elem_t *gCurEffect; // current effect in enumeration process static uint32_t gCurEffectIdx; // current effect index in enumeration process -static const char * const gEffectLibPath = "/system/lib/soundfx"; // path to built-in effect libraries +const char * const gEffectLibPath = "/system/lib/soundfx"; // path to built-in effect libraries static int gInitDone; // true is global initialization has been preformed static int gNextLibId; // used by loadLibrary() to allocate unique library handles static int gCanQueryEffect; // indicates that call to EffectQueryEffect() is valid, i.e. that the list of effects diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp index 3bbcf55..9e39e79 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp @@ -18,7 +18,7 @@ #define LOG_TAG "Bundle" #define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) #define LVM_BUNDLE // Include all the bundle code -#define LOG_NDEBUG 0 +//#define LOG_NDEBUG 0 #include <cutils/log.h> #include <assert.h> diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index c77f551..7e3b743 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -590,18 +590,22 @@ audio_io_handle_t AudioSystem::getOutput(stream_type stream, return output; } -status_t AudioSystem::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream) +status_t AudioSystem::startOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return PERMISSION_DENIED; - return aps->startOutput(output, stream); + return aps->startOutput(output, stream, session); } -status_t AudioSystem::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream) +status_t AudioSystem::stopOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return PERMISSION_DENIED; - return aps->stopOutput(output, stream); + return aps->stopOutput(output, stream, session); } void AudioSystem::releaseOutput(audio_io_handle_t output) @@ -666,6 +670,38 @@ status_t AudioSystem::getStreamVolumeIndex(stream_type stream, int *index) return aps->getStreamVolumeIndex(stream, index); } +uint32_t AudioSystem::getStrategyForStream(AudioSystem::stream_type stream) +{ + const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return 0; + return aps->getStrategyForStream(stream); +} + +audio_io_handle_t AudioSystem::getOutputForEffect(effect_descriptor_t *desc) +{ + const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->getOutputForEffect(desc); +} + +status_t AudioSystem::registerEffect(effect_descriptor_t *desc, + audio_io_handle_t output, + uint32_t strategy, + int session, + int id) +{ + const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->registerEffect(desc, output, strategy, session, id); +} + +status_t AudioSystem::unregisterEffect(int id) +{ + const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->unregisterEffect(id); +} + // --------------------------------------------------------------------------- void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who) { diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 7d6a5d3..3a89e25 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -69,7 +69,8 @@ enum { QUERY_NUM_EFFECTS, QUERY_EFFECT, GET_EFFECT_DESCRIPTOR, - CREATE_EFFECT + CREATE_EFFECT, + MOVE_EFFECTS }; class BpAudioFlinger : public BpInterface<IAudioFlinger> @@ -676,6 +677,17 @@ public: return effect; } + + virtual status_t moveEffects(int session, int srcOutput, int dstOutput) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(session); + data.writeInt32(srcOutput); + data.writeInt32(dstOutput); + remote()->transact(MOVE_EFFECTS, data, &reply); + return reply.readInt32(); + } }; IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger"); @@ -1024,6 +1036,14 @@ status_t BnAudioFlinger::onTransact( reply->write(&desc, sizeof(effect_descriptor_t)); return NO_ERROR; } break; + case MOVE_EFFECTS: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + int session = data.readInt32(); + int srcOutput = data.readInt32(); + int dstOutput = data.readInt32(); + reply->writeInt32(moveEffects(session, srcOutput, dstOutput)); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index 18dd173..950c213 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -44,7 +44,11 @@ enum { RELEASE_INPUT, INIT_STREAM_VOLUME, SET_STREAM_VOLUME, - GET_STREAM_VOLUME + GET_STREAM_VOLUME, + GET_STRATEGY_FOR_STREAM, + GET_OUTPUT_FOR_EFFECT, + REGISTER_EFFECT, + UNREGISTER_EFFECT }; class BpAudioPolicyService : public BpInterface<IAudioPolicyService> @@ -137,22 +141,28 @@ public: return static_cast <audio_io_handle_t> (reply.readInt32()); } - virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream) + virtual status_t startOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session) { Parcel data, reply; data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); data.writeInt32(output); data.writeInt32(stream); + data.writeInt32(session); remote()->transact(START_OUTPUT, data, &reply); return static_cast <status_t> (reply.readInt32()); } - virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream) + virtual status_t stopOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session) { Parcel data, reply; data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); data.writeInt32(output); data.writeInt32(stream); + data.writeInt32(session); remote()->transact(STOP_OUTPUT, data, &reply); return static_cast <status_t> (reply.readInt32()); } @@ -242,6 +252,51 @@ public: if (index) *index = lIndex; return static_cast <status_t> (reply.readInt32()); } + + virtual uint32_t getStrategyForStream(AudioSystem::stream_type stream) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.writeInt32(static_cast <uint32_t>(stream)); + remote()->transact(GET_STRATEGY_FOR_STREAM, data, &reply); + return reply.readInt32(); + } + + virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.write(desc, sizeof(effect_descriptor_t)); + remote()->transact(GET_OUTPUT_FOR_EFFECT, data, &reply); + return static_cast <audio_io_handle_t> (reply.readInt32()); + } + + virtual status_t registerEffect(effect_descriptor_t *desc, + audio_io_handle_t output, + uint32_t strategy, + int session, + int id) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.write(desc, sizeof(effect_descriptor_t)); + data.writeInt32(output); + data.writeInt32(strategy); + data.writeInt32(session); + data.writeInt32(id); + remote()->transact(REGISTER_EFFECT, data, &reply); + return static_cast <status_t> (reply.readInt32()); + } + + virtual status_t unregisterEffect(int id) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.writeInt32(id); + remote()->transact(UNREGISTER_EFFECT, data, &reply); + return static_cast <status_t> (reply.readInt32()); + } + }; IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService"); @@ -255,18 +310,24 @@ status_t BnAudioPolicyService::onTransact( switch(code) { case SET_DEVICE_CONNECTION_STATE: { CHECK_INTERFACE(IAudioPolicyService, data, reply); - AudioSystem::audio_devices device = static_cast <AudioSystem::audio_devices>(data.readInt32()); - AudioSystem::device_connection_state state = static_cast <AudioSystem::device_connection_state>(data.readInt32()); + AudioSystem::audio_devices device = + static_cast <AudioSystem::audio_devices>(data.readInt32()); + AudioSystem::device_connection_state state = + static_cast <AudioSystem::device_connection_state>(data.readInt32()); const char *device_address = data.readCString(); - reply->writeInt32(static_cast <uint32_t>(setDeviceConnectionState(device, state, device_address))); + reply->writeInt32(static_cast<uint32_t> (setDeviceConnectionState(device, + state, + device_address))); return NO_ERROR; } break; case GET_DEVICE_CONNECTION_STATE: { CHECK_INTERFACE(IAudioPolicyService, data, reply); - AudioSystem::audio_devices device = static_cast <AudioSystem::audio_devices>(data.readInt32()); + AudioSystem::audio_devices device = + static_cast<AudioSystem::audio_devices> (data.readInt32()); const char *device_address = data.readCString(); - reply->writeInt32(static_cast <uint32_t>(getDeviceConnectionState(device, device_address))); + reply->writeInt32(static_cast<uint32_t> (getDeviceConnectionState(device, + device_address))); return NO_ERROR; } break; @@ -287,7 +348,8 @@ status_t BnAudioPolicyService::onTransact( case SET_FORCE_USE: { CHECK_INTERFACE(IAudioPolicyService, data, reply); AudioSystem::force_use usage = static_cast <AudioSystem::force_use>(data.readInt32()); - AudioSystem::forced_config config = static_cast <AudioSystem::forced_config>(data.readInt32()); + AudioSystem::forced_config config = + static_cast <AudioSystem::forced_config>(data.readInt32()); reply->writeInt32(static_cast <uint32_t>(setForceUse(usage, config))); return NO_ERROR; } break; @@ -301,11 +363,13 @@ status_t BnAudioPolicyService::onTransact( case GET_OUTPUT: { CHECK_INTERFACE(IAudioPolicyService, data, reply); - AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32()); + AudioSystem::stream_type stream = + static_cast <AudioSystem::stream_type>(data.readInt32()); uint32_t samplingRate = data.readInt32(); uint32_t format = data.readInt32(); uint32_t channels = data.readInt32(); - AudioSystem::output_flags flags = static_cast <AudioSystem::output_flags>(data.readInt32()); + AudioSystem::output_flags flags = + static_cast <AudioSystem::output_flags>(data.readInt32()); audio_io_handle_t output = getOutput(stream, samplingRate, @@ -320,7 +384,10 @@ status_t BnAudioPolicyService::onTransact( CHECK_INTERFACE(IAudioPolicyService, data, reply); audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32()); uint32_t stream = data.readInt32(); - reply->writeInt32(static_cast <uint32_t>(startOutput(output, (AudioSystem::stream_type)stream))); + int session = data.readInt32(); + reply->writeInt32(static_cast <uint32_t>(startOutput(output, + (AudioSystem::stream_type)stream, + session))); return NO_ERROR; } break; @@ -328,7 +395,10 @@ status_t BnAudioPolicyService::onTransact( CHECK_INTERFACE(IAudioPolicyService, data, reply); audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32()); uint32_t stream = data.readInt32(); - reply->writeInt32(static_cast <uint32_t>(stopOutput(output, (AudioSystem::stream_type)stream))); + int session = data.readInt32(); + reply->writeInt32(static_cast <uint32_t>(stopOutput(output, + (AudioSystem::stream_type)stream, + session))); return NO_ERROR; } break; @@ -345,7 +415,8 @@ status_t BnAudioPolicyService::onTransact( uint32_t samplingRate = data.readInt32(); uint32_t format = data.readInt32(); uint32_t channels = data.readInt32(); - AudioSystem::audio_in_acoustics acoustics = static_cast <AudioSystem::audio_in_acoustics>(data.readInt32()); + AudioSystem::audio_in_acoustics acoustics = + static_cast <AudioSystem::audio_in_acoustics>(data.readInt32()); audio_io_handle_t input = getInput(inputSource, samplingRate, format, @@ -378,7 +449,8 @@ status_t BnAudioPolicyService::onTransact( case INIT_STREAM_VOLUME: { CHECK_INTERFACE(IAudioPolicyService, data, reply); - AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32()); + AudioSystem::stream_type stream = + static_cast <AudioSystem::stream_type>(data.readInt32()); int indexMin = data.readInt32(); int indexMax = data.readInt32(); reply->writeInt32(static_cast <uint32_t>(initStreamVolume(stream, indexMin,indexMax))); @@ -387,7 +459,8 @@ status_t BnAudioPolicyService::onTransact( case SET_STREAM_VOLUME: { CHECK_INTERFACE(IAudioPolicyService, data, reply); - AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32()); + AudioSystem::stream_type stream = + static_cast <AudioSystem::stream_type>(data.readInt32()); int index = data.readInt32(); reply->writeInt32(static_cast <uint32_t>(setStreamVolumeIndex(stream, index))); return NO_ERROR; @@ -395,7 +468,8 @@ status_t BnAudioPolicyService::onTransact( case GET_STREAM_VOLUME: { CHECK_INTERFACE(IAudioPolicyService, data, reply); - AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32()); + AudioSystem::stream_type stream = + static_cast <AudioSystem::stream_type>(data.readInt32()); int index; status_t status = getStreamVolumeIndex(stream, &index); reply->writeInt32(index); @@ -403,6 +477,46 @@ status_t BnAudioPolicyService::onTransact( return NO_ERROR; } break; + case GET_STRATEGY_FOR_STREAM: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + AudioSystem::stream_type stream = + static_cast <AudioSystem::stream_type>(data.readInt32()); + reply->writeInt32(getStrategyForStream(stream)); + return NO_ERROR; + } break; + + case GET_OUTPUT_FOR_EFFECT: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + effect_descriptor_t desc; + data.read(&desc, sizeof(effect_descriptor_t)); + audio_io_handle_t output = getOutputForEffect(&desc); + reply->writeInt32(static_cast <int>(output)); + return NO_ERROR; + } break; + + case REGISTER_EFFECT: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + effect_descriptor_t desc; + data.read(&desc, sizeof(effect_descriptor_t)); + audio_io_handle_t output = data.readInt32(); + uint32_t strategy = data.readInt32(); + int session = data.readInt32(); + int id = data.readInt32(); + reply->writeInt32(static_cast <int32_t>(registerEffect(&desc, + output, + strategy, + session, + id))); + return NO_ERROR; + } break; + + case UNREGISTER_EFFECT: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + int id = data.readInt32(); + reply->writeInt32(static_cast <int32_t>(unregisterEffect(id))); + return NO_ERROR; + } break; + default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index b38a5c8..b88e69d 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -63,6 +63,8 @@ // ---------------------------------------------------------------------------- +extern const char * const gEffectLibPath; + namespace android { static const char* kDeadlockedString = "AudioFlinger may be deadlocked\n"; @@ -127,8 +129,7 @@ static bool settingsAllowed() { AudioFlinger::AudioFlinger() : BnAudioFlinger(), - mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1), - mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0) + mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1) { mHardwareStatus = AUDIO_HW_IDLE; @@ -321,13 +322,19 @@ sp<IAudioTrack> AudioFlinger::createTrack( mClients.add(pid, client); } - // If no audio session id is provided, create one here - // TODO: enforce same stream type for all tracks in same audio session? - // TODO: prevent same audio session on different output threads LOGV("createTrack() sessionId: %d", (sessionId == NULL) ? -2 : *sessionId); - if (sessionId != NULL && *sessionId != 0) { + if (sessionId != NULL && *sessionId != AudioSystem::SESSION_OUTPUT_MIX) { + // prevent same audio session on different output threads + for (size_t i = 0; i < mPlaybackThreads.size(); i++) { + if (mPlaybackThreads.keyAt(i) != output && + mPlaybackThreads.valueAt(i)->hasAudioSession(*sessionId)) { + lStatus = BAD_VALUE; + goto Exit; + } + } lSessionId = *sessionId; } else { + // if no audio session id is provided, create one here lSessionId = nextUniqueId(); if (sessionId != NULL) { *sessionId = lSessionId; @@ -1141,6 +1148,23 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTra { // scope for mLock Mutex::Autolock _l(mLock); + + // all tracks in same audio session must share the same routing strategy otherwise + // conflicts will happen when tracks are moved from one output to another by audio policy + // manager + uint32_t strategy = + AudioSystem::getStrategyForStream((AudioSystem::stream_type)streamType); + for (size_t i = 0; i < mTracks.size(); ++i) { + sp<Track> t = mTracks[i]; + if (t != 0) { + if (sessionId == t->sessionId() && + strategy != AudioSystem::getStrategyForStream((AudioSystem::stream_type)t->type())) { + lStatus = BAD_VALUE; + goto Exit; + } + } + } + track = new Track(this, client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer, sessionId); if (track->getCblk() == NULL || track->name() < 0) { @@ -1153,6 +1177,7 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTra if (chain != 0) { LOGV("createTrack_l() setting main buffer %p", chain->inBuffer()); track->setMainBuffer(chain->inBuffer()); + chain->setStrategy(AudioSystem::getStrategyForStream((AudioSystem::stream_type)track->type())); } } lStatus = NO_ERROR; @@ -1344,7 +1369,16 @@ void AudioFlinger::PlaybackThread::readOutputParameters() mMixBuffer = new int16_t[mFrameCount * 2]; memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t)); - //TODO handle effects reconfig + // force reconfiguration of effect chains and engines to take new buffer size and audio + // parameters into account + // Note that mLock is not held when readOutputParameters() is called from the constructor + // but in this case nothing is done below as no audio sessions have effect yet so it doesn't + // matter. + // create a copy of mEffectChains as calling moveEffectChain_l() can reorder some effect chains + Vector< sp<EffectChain> > effectChains = mEffectChains; + for (size_t i = 0; i < effectChains.size(); i ++) { + mAudioFlinger->moveEffectChain_l(effectChains[i]->sessionId(), this, this); + } } status_t AudioFlinger::PlaybackThread::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames) @@ -1369,7 +1403,8 @@ bool AudioFlinger::PlaybackThread::hasAudioSession(int sessionId) for (size_t i = 0; i < mTracks.size(); ++i) { sp<Track> track = mTracks[i]; - if (sessionId == track->sessionId()) { + if (sessionId == track->sessionId() && + !(track->mCblk->flags & CBLK_INVALID_MSK)) { return true; } } @@ -1377,6 +1412,23 @@ bool AudioFlinger::PlaybackThread::hasAudioSession(int sessionId) return false; } +uint32_t AudioFlinger::PlaybackThread::getStrategyForSession_l(int sessionId) +{ + // session AudioSystem::SESSION_OUTPUT_MIX is placed in same strategy as MUSIC stream so that + // it is moved to correct output by audio policy manager when A2DP is connected or disconnected + if (sessionId == AudioSystem::SESSION_OUTPUT_MIX) { + return AudioSystem::getStrategyForStream(AudioSystem::MUSIC); + } + for (size_t i = 0; i < mTracks.size(); i++) { + sp<Track> track = mTracks[i]; + if (sessionId == track->sessionId() && + !(track->mCblk->flags & CBLK_INVALID_MSK)) { + return AudioSystem::getStrategyForStream((AudioSystem::stream_type) track->type()); + } + } + return AudioSystem::getStrategyForStream(AudioSystem::MUSIC); +} + sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain(int sessionId) { Mutex::Autolock _l(mLock); @@ -1503,8 +1555,7 @@ bool AudioFlinger::MixerThread::threadLoop() // prevent any changes in effect chain list and in each effect chain // during mixing and effect process as the audio buffers could be deleted // or modified if an effect is created or deleted - lockEffectChains_l(); - effectChains = mEffectChains; + lockEffectChains_l(effectChains); } if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) { @@ -1540,7 +1591,7 @@ bool AudioFlinger::MixerThread::threadLoop() effectChains[i]->process_l(); } // enable changes in effect chain - unlockEffectChains(); + unlockEffectChains(effectChains); #ifdef LVMX int audioOutputType = LifeVibes::getMixerType(mId, mType); if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) { @@ -1571,7 +1622,7 @@ bool AudioFlinger::MixerThread::threadLoop() mStandby = false; } else { // enable changes in effect chain - unlockEffectChains(); + unlockEffectChains(effectChains); usleep(sleepTime); } @@ -1625,7 +1676,7 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track } #endif // Delegate master volume control to effect in output mix effect chain if needed - sp<EffectChain> chain = getEffectChain_l(0); + sp<EffectChain> chain = getEffectChain_l(AudioSystem::SESSION_OUTPUT_MIX); if (chain != 0) { uint32_t v = (uint32_t)(masterVolume * (1 << 24)); chain->setVolume_l(&v, &v); @@ -1814,8 +1865,10 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track void AudioFlinger::MixerThread::invalidateTracks(int streamType) { - LOGV ("MixerThread::invalidateTracks() mixer %p, streamType %d, mTracks.size %d", this, streamType, mTracks.size()); + LOGV ("MixerThread::invalidateTracks() mixer %p, streamType %d, mTracks.size %d", + this, streamType, mTracks.size()); Mutex::Autolock _l(mLock); + size_t size = mTracks.size(); for (size_t i = 0; i < size; i++) { sp<Track> t = mTracks[i]; @@ -2070,7 +2123,6 @@ bool AudioFlinger::DirectOutputThread::threadLoop() // hardware resources as soon as possible nsecs_t standbyDelay = microseconds(activeSleepTime*2); - while (!exitPending()) { bool rampVolume; @@ -2246,7 +2298,8 @@ bool AudioFlinger::DirectOutputThread::threadLoop() if (UNLIKELY(trackToRemove != 0)) { mActiveTracks.remove(trackToRemove); if (!effectChains.isEmpty()) { - LOGV("stopping track on chain %p for session Id: %d", effectChains[0].get(), trackToRemove->sessionId()); + LOGV("stopping track on chain %p for session Id: %d", effectChains[0].get(), + trackToRemove->sessionId()); effectChains[0]->stopTrack(); } if (trackToRemove->isTerminated()) { @@ -2255,7 +2308,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() } } - lockEffectChains_l(); + lockEffectChains_l(effectChains); } if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) { @@ -2301,7 +2354,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() for (size_t i = 0; i < effectChains.size(); i ++) { effectChains[i]->process_l(); } - unlockEffectChains(); + unlockEffectChains(effectChains); mLastWriteTime = systemTime(); mInWrite = true; @@ -2312,7 +2365,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() mInWrite = false; mStandby = false; } else { - unlockEffectChains(); + unlockEffectChains(effectChains); usleep(sleepTime); } @@ -2505,8 +2558,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop() // prevent any changes in effect chain list and in each effect chain // during mixing and effect process as the audio buffers could be deleted // or modified if an effect is created or deleted - lockEffectChains_l(); - effectChains = mEffectChains; + lockEffectChains_l(effectChains); } if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) { @@ -2547,7 +2599,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop() effectChains[i]->process_l(); } // enable changes in effect chain - unlockEffectChains(); + unlockEffectChains(effectChains); standbyTime = systemTime() + kStandbyTimeInNsecs; for (size_t i = 0; i < outputTracks.size(); i++) { @@ -2557,7 +2609,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop() mBytesWritten += mixBufferSize; } else { // enable changes in effect chain - unlockEffectChains(); + unlockEffectChains(effectChains); usleep(sleepTime); } @@ -2859,7 +2911,9 @@ void AudioFlinger::PlaybackThread::Track::destroy() if (thread != 0) { if (!isOutputTrack()) { if (mState == ACTIVE || mState == RESUMING) { - AudioSystem::stopOutput(thread->id(), (AudioSystem::stream_type)mStreamType); + AudioSystem::stopOutput(thread->id(), + (AudioSystem::stream_type)mStreamType, + mSessionId); } AudioSystem::releaseOutput(thread->id()); } @@ -2966,7 +3020,9 @@ status_t AudioFlinger::PlaybackThread::Track::start() if (!isOutputTrack() && state != ACTIVE && state != RESUMING) { thread->mLock.unlock(); - status = AudioSystem::startOutput(thread->id(), (AudioSystem::stream_type)mStreamType); + status = AudioSystem::startOutput(thread->id(), + (AudioSystem::stream_type)mStreamType, + mSessionId); thread->mLock.lock(); } if (status == NO_ERROR) { @@ -2999,7 +3055,9 @@ void AudioFlinger::PlaybackThread::Track::stop() } if (!isOutputTrack() && (state == ACTIVE || state == RESUMING)) { thread->mLock.unlock(); - AudioSystem::stopOutput(thread->id(), (AudioSystem::stream_type)mStreamType); + AudioSystem::stopOutput(thread->id(), + (AudioSystem::stream_type)mStreamType, + mSessionId); thread->mLock.lock(); } } @@ -3016,7 +3074,9 @@ void AudioFlinger::PlaybackThread::Track::pause() LOGV("ACTIVE/RESUMING => PAUSING (%d) on thread %p", mName, thread.get()); if (!isOutputTrack()) { thread->mLock.unlock(); - AudioSystem::stopOutput(thread->id(), (AudioSystem::stream_type)mStreamType); + AudioSystem::stopOutput(thread->id(), + (AudioSystem::stream_type)mStreamType, + mSessionId); thread->mLock.lock(); } } @@ -3585,7 +3645,7 @@ sp<IAudioRecord> AudioFlinger::openRecord( } // If no audio session id is provided, create one here - if (sessionId != NULL && *sessionId != 0) { + if (sessionId != NULL && *sessionId != AudioSystem::SESSION_OUTPUT_MIX) { lSessionId = *sessionId; } else { lSessionId = nextUniqueId(); @@ -4416,8 +4476,8 @@ status_t AudioFlinger::setStreamOutput(uint32_t stream, int output) thread->type() != PlaybackThread::DIRECT) { MixerThread *srcThread = (MixerThread *)thread; srcThread->invalidateTracks(stream); - } } + } return NO_ERROR; } @@ -4472,12 +4532,26 @@ int AudioFlinger::nextUniqueId() status_t AudioFlinger::loadEffectLibrary(const char *libPath, int *handle) { + // check calling permissions + if (!settingsAllowed()) { + return PERMISSION_DENIED; + } + // only allow libraries loaded from /system/lib/soundfx for now + if (strncmp(gEffectLibPath, libPath, strlen(gEffectLibPath)) != 0) { + return PERMISSION_DENIED; + } + Mutex::Autolock _l(mLock); return EffectLoadLibrary(libPath, handle); } status_t AudioFlinger::unloadEffectLibrary(int handle) { + // check calling permissions + if (!settingsAllowed()) { + return PERMISSION_DENIED; + } + Mutex::Autolock _l(mLock); return EffectUnloadLibrary(handle); } @@ -4522,7 +4596,8 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, sp<Client> client; wp<Client> wclient; - LOGV("createEffect pid %d, client %p, priority %d, sessionId %d, output %d", pid, effectClient.get(), priority, sessionId, output); + LOGV("createEffect pid %d, client %p, priority %d, sessionId %d, output %d", + pid, effectClient.get(), priority, sessionId, output); if (pDesc == NULL) { lStatus = BAD_VALUE; @@ -4577,7 +4652,7 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, // an auxiliary version of this effect type is available found = true; memcpy(&d, &desc, sizeof(effect_descriptor_t)); - if (sessionId != 0 || + if (sessionId != AudioSystem::SESSION_OUTPUT_MIX || (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { break; } @@ -4590,22 +4665,23 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, } // For same effect type, chose auxiliary version over insert version if // connect to output mix (Compliance to OpenSL ES) - if (sessionId == 0 && + if (sessionId == AudioSystem::SESSION_OUTPUT_MIX && (d.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_AUXILIARY) { memcpy(&desc, &d, sizeof(effect_descriptor_t)); } } // Do not allow auxiliary effects on a session different from 0 (output mix) - if (sessionId != 0 && + if (sessionId != AudioSystem::SESSION_OUTPUT_MIX && (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { lStatus = INVALID_OPERATION; goto Exit; } - // Session -1 is reserved for output stage effects that can only be created - // by audio policy manager (running in same process) - if (sessionId == -1 && getpid() != IPCThreadState::self()->getCallingPid()) { + // Session AudioSystem::SESSION_OUTPUT_STAGE is reserved for output stage effects + // that can only be created by audio policy manager (running in same process) + if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE && + getpid() != IPCThreadState::self()->getCallingPid()) { lStatus = INVALID_OPERATION; goto Exit; } @@ -4617,13 +4693,14 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, // output threads. // TODO: allow attachment of effect to inputs if (output == 0) { - if (sessionId <= 0) { - // default to first output - // TODO: define criteria to choose output when not specified. Or - // receive output from audio policy manager - if (mPlaybackThreads.size() != 0) { - output = mPlaybackThreads.keyAt(0); - } + if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE) { + // output must be specified by AudioPolicyManager when using session + // AudioSystem::SESSION_OUTPUT_STAGE + lStatus = BAD_VALUE; + goto Exit; + } else if (sessionId == AudioSystem::SESSION_OUTPUT_MIX) { + output = AudioSystem::getOutputForEffect(&desc); + LOGV("createEffect() got output %d for effect %s", output, desc.name); } else { // look for the thread where the specified audio session is present for (size_t i = 0; i < mPlaybackThreads.size(); i++) { @@ -4636,7 +4713,7 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, } PlaybackThread *thread = checkPlaybackThread_l(output); if (thread == NULL) { - LOGE("unknown output thread"); + LOGE("createEffect() unknown output thread"); lStatus = BAD_VALUE; goto Exit; } @@ -4651,7 +4728,8 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, } // create effect on selected output trhead - handle = thread->createEffect_l(client, effectClient, priority, sessionId, &desc, enabled, &lStatus); + handle = thread->createEffect_l(client, effectClient, priority, sessionId, + &desc, enabled, &lStatus); if (handle != 0 && id != NULL) { *id = handle->id(); } @@ -4664,31 +4742,64 @@ Exit: return handle; } -status_t AudioFlinger::registerEffectResource_l(effect_descriptor_t *desc) { - if (mTotalEffectsCpuLoad + desc->cpuLoad > MAX_EFFECTS_CPU_LOAD) { - LOGW("registerEffectResource() CPU Load limit exceeded for Fx %s, CPU %f MIPS", - desc->name, (float)desc->cpuLoad/10); - return INVALID_OPERATION; +status_t AudioFlinger::moveEffects(int session, int srcOutput, int dstOutput) +{ + LOGV("moveEffects() session %d, srcOutput %d, dstOutput %d", + session, srcOutput, dstOutput); + Mutex::Autolock _l(mLock); + if (srcOutput == dstOutput) { + LOGW("moveEffects() same dst and src outputs %d", dstOutput); + return NO_ERROR; } - if (mTotalEffectsMemory + desc->memoryUsage > MAX_EFFECTS_MEMORY) { - LOGW("registerEffectResource() memory limit exceeded for Fx %s, Memory %d KB", - desc->name, desc->memoryUsage); - return INVALID_OPERATION; + PlaybackThread *srcThread = checkPlaybackThread_l(srcOutput); + if (srcThread == NULL) { + LOGW("moveEffects() bad srcOutput %d", srcOutput); + return BAD_VALUE; + } + PlaybackThread *dstThread = checkPlaybackThread_l(dstOutput); + if (dstThread == NULL) { + LOGW("moveEffects() bad dstOutput %d", dstOutput); + return BAD_VALUE; } - mTotalEffectsCpuLoad += desc->cpuLoad; - mTotalEffectsMemory += desc->memoryUsage; - LOGV("registerEffectResource_l() effect %s, CPU %d, memory %d", - desc->name, desc->cpuLoad, desc->memoryUsage); - LOGV(" total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory); + + Mutex::Autolock _dl(dstThread->mLock); + Mutex::Autolock _sl(srcThread->mLock); + moveEffectChain_l(session, srcThread, dstThread); + return NO_ERROR; } -void AudioFlinger::unregisterEffectResource_l(effect_descriptor_t *desc) { - mTotalEffectsCpuLoad -= desc->cpuLoad; - mTotalEffectsMemory -= desc->memoryUsage; - LOGV("unregisterEffectResource_l() effect %s, CPU %d, memory %d", - desc->name, desc->cpuLoad, desc->memoryUsage); - LOGV(" total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory); +// moveEffectChain_l mustbe called with both srcThread and dstThread mLocks held +status_t AudioFlinger::moveEffectChain_l(int session, + AudioFlinger::PlaybackThread *srcThread, + AudioFlinger::PlaybackThread *dstThread) +{ + LOGV("moveEffectChain_l() session %d from thread %p to thread %p", + session, srcThread, dstThread); + + sp<EffectChain> chain = srcThread->getEffectChain_l(session); + if (chain == 0) { + LOGW("moveEffectChain_l() effect chain for session %d not on source thread %p", + session, srcThread); + return INVALID_OPERATION; + } + + // remove chain first. This is usefull only if reconfiguring effect chain on same output thread, + // so that a new chain is created with correct parameters when first effect is added. This is + // otherwise unecessary as removeEffect_l() will remove the chain when last effect is + // removed. + srcThread->removeEffectChain_l(chain); + + // transfer all effects one by one so that new effect chain is created on new thread with + // correct buffer sizes and audio parameters and effect engines reconfigured accordingly + sp<EffectModule> effect = chain->getEffectFromId_l(0); + while (effect != 0) { + srcThread->removeEffect_l(effect); + dstThread->addEffect_l(effect); + effect = chain->getEffectFromId_l(0); + } + + return NO_ERROR; } // PlaybackThread::createEffect_l() must be called with AudioFlinger::mLock held @@ -4707,6 +4818,7 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l( status_t lStatus; sp<Track> track; sp<EffectChain> chain; + bool chainCreated = false; bool effectCreated = false; bool effectRegistered = false; @@ -4718,16 +4830,18 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l( // Do not allow auxiliary effect on session other than 0 if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY && - sessionId != 0) { - LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", desc->name, sessionId); + sessionId != AudioSystem::SESSION_OUTPUT_MIX) { + LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", + desc->name, sessionId); lStatus = BAD_VALUE; goto Exit; } // Do not allow effects with session ID 0 on direct output or duplicating threads // TODO: add rule for hw accelerated effects on direct outputs with non PCM format - if (sessionId == 0 && mType != MIXER) { - LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", desc->name, sessionId); + if (sessionId == AudioSystem::SESSION_OUTPUT_MIX && mType != MIXER) { + LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", + desc->name, sessionId); lStatus = BAD_VALUE; goto Exit; } @@ -4744,6 +4858,8 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l( LOGV("createEffect_l() new effect chain for session %d", sessionId); chain = new EffectChain(this, sessionId); addEffectChain_l(chain); + chain->setStrategy(getStrategyForSession_l(sessionId)); + chainCreated = true; } else { effect = chain->getEffectFromDesc_l(desc); } @@ -4751,14 +4867,15 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l( LOGV("createEffect_l() got effect %p on chain %p", effect == 0 ? 0 : effect.get(), chain.get()); if (effect == 0) { + int id = mAudioFlinger->nextUniqueId(); // Check CPU and memory usage - lStatus = mAudioFlinger->registerEffectResource_l(desc); + lStatus = AudioSystem::registerEffect(desc, mId, chain->strategy(), sessionId, id); if (lStatus != NO_ERROR) { goto Exit; } effectRegistered = true; // create a new effect module if none present in the chain - effect = new EffectModule(this, chain, desc, mAudioFlinger->nextUniqueId(), sessionId); + effect = new EffectModule(this, chain, desc, id, sessionId); lStatus = effect->status(); if (lStatus != NO_ERROR) { goto Exit; @@ -4782,14 +4899,15 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l( Exit: if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) { + Mutex::Autolock _l(mLock); if (effectCreated) { - Mutex::Autolock _l(mLock); - if (chain->removeEffect_l(effect) == 0) { - removeEffectChain_l(chain); - } + chain->removeEffect_l(effect); } if (effectRegistered) { - mAudioFlinger->unregisterEffectResource_l(desc); + AudioSystem::unregisterEffect(effect->id()); + } + if (chainCreated) { + removeEffectChain_l(chain); } handle.clear(); } @@ -4800,26 +4918,71 @@ Exit: return handle; } -void AudioFlinger::PlaybackThread::disconnectEffect(const sp< EffectModule>& effect, - const wp<EffectHandle>& handle) { +// PlaybackThread::addEffect_l() must be called with AudioFlinger::mLock and +// PlaybackThread::mLock held +status_t AudioFlinger::PlaybackThread::addEffect_l(const sp<EffectModule>& effect) +{ + // check for existing effect chain with the requested audio session + int sessionId = effect->sessionId(); + sp<EffectChain> chain = getEffectChain_l(sessionId); + bool chainCreated = false; + + if (chain == 0) { + // create a new chain for this session + LOGV("addEffect_l() new effect chain for session %d", sessionId); + chain = new EffectChain(this, sessionId); + addEffectChain_l(chain); + chain->setStrategy(getStrategyForSession_l(sessionId)); + chainCreated = true; + } + LOGV("addEffect_l() %p chain %p effect %p", this, chain.get(), effect.get()); + + if (chain->getEffectFromId_l(effect->id()) != 0) { + LOGW("addEffect_l() %p effect %s already present in chain %p", + this, effect->desc().name, chain.get()); + return BAD_VALUE; + } + + status_t status = chain->addEffect_l(effect); + if (status != NO_ERROR) { + if (chainCreated) { + removeEffectChain_l(chain); + } + return status; + } + + effect->setDevice(mDevice); + effect->setMode(mAudioFlinger->getMode()); + return NO_ERROR; +} + +void AudioFlinger::PlaybackThread::removeEffect_l(const sp<EffectModule>& effect) { + + LOGV("removeEffect_l() %p effect %p", this, effect.get()); effect_descriptor_t desc = effect->desc(); + if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { + detachAuxEffect_l(effect->id()); + } + + sp<EffectChain> chain = effect->chain().promote(); + if (chain != 0) { + // remove effect chain if removing last effect + if (chain->removeEffect_l(effect) == 0) { + removeEffectChain_l(chain); + } + } else { + LOGW("removeEffect_l() %p cannot promote chain for effect %p", this, effect.get()); + } +} + +void AudioFlinger::PlaybackThread::disconnectEffect(const sp<EffectModule>& effect, + const wp<EffectHandle>& handle) { Mutex::Autolock _l(mLock); + LOGV("disconnectEffect() %p effect %p", this, effect.get()); // delete the effect module if removing last handle on it if (effect->removeHandle(handle) == 0) { - if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { - detachAuxEffect_l(effect->id()); - } - sp<EffectChain> chain = effect->chain().promote(); - if (chain != 0) { - // remove effect chain if remove last effect - if (chain->removeEffect_l(effect) == 0) { - removeEffectChain_l(chain); - } - } - mLock.unlock(); - mAudioFlinger->mLock.lock(); - mAudioFlinger->unregisterEffectResource_l(&desc); - mAudioFlinger->mLock.unlock(); + removeEffect_l(effect); + AudioSystem::unregisterEffect(effect->id()); } } @@ -4863,13 +5026,16 @@ status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& c chain->setInBuffer(buffer, ownsBuffer); chain->setOutBuffer(mMixBuffer); - // Effect chain for session -1 is inserted at end of effect chains list - // in order to be processed last as it contains output stage effects - // Effect chain for session 0 is inserted before session -1 to be processed + // Effect chain for session AudioSystem::SESSION_OUTPUT_STAGE is inserted at end of effect + // chains list in order to be processed last as it contains output stage effects + // Effect chain for session AudioSystem::SESSION_OUTPUT_MIX is inserted before + // session AudioSystem::SESSION_OUTPUT_STAGE to be processed // after track specific effects and before output stage - // Effect chain for session other than 0 is inserted at beginning of effect - // chains list to be processed before output mix effects. Relative order between - // sessions other than 0 is not important + // It is therefore mandatory that AudioSystem::SESSION_OUTPUT_MIX == 0 and + // that AudioSystem::SESSION_OUTPUT_STAGE < AudioSystem::SESSION_OUTPUT_MIX + // Effect chain for other sessions are inserted at beginning of effect + // chains list to be processed before output mix effects. Relative order between other + // sessions is not important size_t size = mEffectChains.size(); size_t i = 0; for (i = 0; i < size; i++) { @@ -4896,26 +5062,30 @@ size_t AudioFlinger::PlaybackThread::removeEffectChain_l(const sp<EffectChain>& track->setMainBuffer(mMixBuffer); } } + break; } } return mEffectChains.size(); } -void AudioFlinger::PlaybackThread::lockEffectChains_l() +void AudioFlinger::PlaybackThread::lockEffectChains_l( + Vector<sp <AudioFlinger::EffectChain> >& effectChains) { + effectChains = mEffectChains; for (size_t i = 0; i < mEffectChains.size(); i++) { mEffectChains[i]->lock(); } } -void AudioFlinger::PlaybackThread::unlockEffectChains() +void AudioFlinger::PlaybackThread::unlockEffectChains( + Vector<sp <AudioFlinger::EffectChain> >& effectChains) { - Mutex::Autolock _l(mLock); - for (size_t i = 0; i < mEffectChains.size(); i++) { - mEffectChains[i]->unlock(); + for (size_t i = 0; i < effectChains.size(); i++) { + effectChains[i]->unlock(); } } + sp<AudioFlinger::EffectModule> AudioFlinger::PlaybackThread::getEffect_l(int sessionId, int effectId) { sp<EffectModule> effect; @@ -4927,21 +5097,23 @@ sp<AudioFlinger::EffectModule> AudioFlinger::PlaybackThread::getEffect_l(int ses return effect; } -status_t AudioFlinger::PlaybackThread::attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId) +status_t AudioFlinger::PlaybackThread::attachAuxEffect( + const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId) { Mutex::Autolock _l(mLock); return attachAuxEffect_l(track, EffectId); } -status_t AudioFlinger::PlaybackThread::attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId) +status_t AudioFlinger::PlaybackThread::attachAuxEffect_l( + const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId) { status_t status = NO_ERROR; if (EffectId == 0) { track->setAuxBuffer(0, NULL); } else { - // Auxiliary effects are always in audio session 0 - sp<EffectModule> effect = getEffect_l(0, EffectId); + // Auxiliary effects are always in audio session AudioSystem::SESSION_OUTPUT_MIX + sp<EffectModule> effect = getEffect_l(AudioSystem::SESSION_OUTPUT_MIX, EffectId); if (effect != 0) { if ((effect->desc().flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { track->setAuxBuffer(EffectId, (int32_t *)effect->inBuffer()); @@ -5137,7 +5309,7 @@ void AudioFlinger::EffectModule::process() if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { AudioMixer::ditherAndClamp(mConfig.inputCfg.buffer.s32, mConfig.inputCfg.buffer.s32, - mConfig.inputCfg.buffer.frameCount); + mConfig.inputCfg.buffer.frameCount/2); } // do the actual processing in the effect engine @@ -5214,7 +5386,8 @@ status_t AudioFlinger::EffectModule::configure() mConfig.outputCfg.bufferProvider.releaseBuffer = NULL; mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; // Insert effect: - // - in session 0 or -1, always overwrites output buffer: input buffer == output buffer + // - in session AudioSystem::SESSION_OUTPUT_MIX or AudioSystem::SESSION_OUTPUT_STAGE, + // always overwrites output buffer: input buffer == output buffer // - in other sessions: // last effect in the chain accumulates in output buffer: input buffer != output buffer // other effect: overwrites output buffer: input buffer == output buffer @@ -5231,6 +5404,9 @@ status_t AudioFlinger::EffectModule::configure() mConfig.inputCfg.buffer.frameCount = thread->frameCount(); mConfig.outputCfg.buffer.frameCount = mConfig.inputCfg.buffer.frameCount; + LOGV("configure() %p thread %p buffer %p framecount %d", + this, thread.get(), mConfig.inputCfg.buffer.raw, mConfig.inputCfg.buffer.frameCount); + status_t cmdStatus; int size = sizeof(int); status_t status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_CONFIGURE, sizeof(effect_config_t), &mConfig, &size, &cmdStatus); @@ -5753,7 +5929,7 @@ AudioFlinger::EffectChain::EffectChain(const wp<ThreadBase>& wThread, mVolumeCtrlIdx(-1), mLeftVolume(0), mRightVolume(0), mNewLeftVolume(0), mNewRightVolume(0) { - + mStrategy = AudioSystem::getStrategyForStream(AudioSystem::MUSIC); } AudioFlinger::EffectChain::~EffectChain() @@ -5786,7 +5962,8 @@ sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromId_l(int size_t size = mEffects.size(); for (size_t i = 0; i < size; i++) { - if (mEffects[i]->id() == id) { + // by convention, return first effect if id provided is 0 (0 is never a valid id) + if (id == 0 || mEffects[i]->id() == id) { effect = mEffects[i]; break; } @@ -5816,21 +5993,24 @@ void AudioFlinger::EffectChain::process_l() } // addEffect_l() must be called with PlaybackThread::mLock held -status_t AudioFlinger::EffectChain::addEffect_l(sp<EffectModule>& effect) +status_t AudioFlinger::EffectChain::addEffect_l(const sp<EffectModule>& effect) { effect_descriptor_t desc = effect->desc(); uint32_t insertPref = desc.flags & EFFECT_FLAG_INSERT_MASK; Mutex::Autolock _l(mLock); + effect->setChain(this); + sp<ThreadBase> thread = mThread.promote(); + if (thread == 0) { + return NO_INIT; + } + effect->setThread(thread); if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { // Auxiliary effects are inserted at the beginning of mEffects vector as // they are processed first and accumulated in chain input buffer mEffects.insertAt(effect, 0); - sp<ThreadBase> thread = mThread.promote(); - if (thread == 0) { - return NO_INIT; - } + // the input buffer for auxiliary effect contains mono samples in // 32 bit format. This is to avoid saturation in AudoMixer // accumulation stage. Saturation is done in EffectModule::process() before diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 99816f9..a8c9a92 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -168,8 +168,7 @@ public: int *id, int *enabled); - status_t registerEffectResource_l(effect_descriptor_t *desc); - void unregisterEffectResource_l(effect_descriptor_t *desc); + virtual status_t moveEffects(int session, int srcOutput, int dstOutput); enum hardware_call_state { AUDIO_HW_IDLE = 0, @@ -619,15 +618,22 @@ private: sp<EffectChain> getEffectChain_l(int sessionId); status_t addEffectChain_l(const sp<EffectChain>& chain); size_t removeEffectChain_l(const sp<EffectChain>& chain); - void lockEffectChains_l(); - void unlockEffectChains(); + void lockEffectChains_l(Vector<sp <EffectChain> >& effectChains); + void unlockEffectChains(Vector<sp <EffectChain> >& effectChains); sp<AudioFlinger::EffectModule> getEffect_l(int sessionId, int effectId); void detachAuxEffect_l(int effectId); - status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId); - status_t attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId); + status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track, + int EffectId); + status_t attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track, + int EffectId); void setMode(uint32_t mode); + status_t addEffect_l(const sp< EffectModule>& effect); + void removeEffect_l(const sp< EffectModule>& effect); + + uint32_t getStrategyForSession_l(int sessionId); + struct stream_type_t { stream_type_t() : volume(1.0f), @@ -690,7 +696,10 @@ private: class MixerThread : public PlaybackThread { public: - MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device); + MixerThread (const sp<AudioFlinger>& audioFlinger, + AudioStreamOut* output, + int id, + uint32_t device); virtual ~MixerThread(); // Thread virtuals @@ -701,7 +710,8 @@ private: virtual status_t dumpInternals(int fd, const Vector<String16>& args); protected: - uint32_t prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove); + uint32_t prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, + Vector< sp<Track> > *tracksToRemove); virtual int getTrackName_l(); virtual void deleteTrackName_l(int name); virtual uint32_t activeSleepTimeUs(); @@ -764,6 +774,9 @@ private: void audioConfigChanged_l(int event, int ioHandle, void *param2); int nextUniqueId(); + status_t moveEffectChain_l(int session, + AudioFlinger::PlaybackThread *srcThread, + AudioFlinger::PlaybackThread *dstThread); friend class AudioBuffer; @@ -931,6 +944,9 @@ private: uint32_t status() { return mStatus; } + int sessionId() { + return mSessionId; + } status_t setEnabled(bool enabled); bool isEnabled(); @@ -938,6 +954,8 @@ private: int16_t *inBuffer() { return mConfig.inputCfg.buffer.s16; } void setOutBuffer(int16_t *buffer) { mConfig.outputCfg.buffer.s16 = buffer; } int16_t *outBuffer() { return mConfig.outputCfg.buffer.s16; } + void setChain(const wp<EffectChain>& chain) { mChain = chain; } + void setThread(const wp<ThreadBase>& thread) { mThread = thread; } status_t addHandle(sp<EffectHandle>& handle); void disconnect(const wp<EffectHandle>& handle); @@ -1061,19 +1079,19 @@ private: mLock.unlock(); } - status_t addEffect_l(sp<EffectModule>& handle); + status_t addEffect_l(const sp<EffectModule>& handle); size_t removeEffect_l(const sp<EffectModule>& handle); int sessionId() { return mSessionId; } + sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor); sp<EffectModule> getEffectFromId_l(int id); bool setVolume_l(uint32_t *left, uint32_t *right); void setDevice_l(uint32_t device); void setMode_l(uint32_t mode); - void setInBuffer(int16_t *buffer, bool ownsBuffer = false) { mInBuffer = buffer; mOwnInBuffer = ownsBuffer; @@ -1092,6 +1110,10 @@ private: void stopTrack() {mActiveTrackCnt--;} int activeTracks() { return mActiveTrackCnt;} + uint32_t strategy() { return mStrategy; } + void setStrategy(uint32_t strategy) + { mStrategy = strategy; } + status_t dump(int fd, const Vector<String16>& args); protected: @@ -1112,7 +1134,7 @@ private: uint32_t mRightVolume; // previous volume on right channel uint32_t mNewLeftVolume; // new volume on left channel uint32_t mNewRightVolume; // new volume on right channel - + uint32_t mStrategy; // strategy for this effect chain }; friend class RecordThread; @@ -1142,12 +1164,6 @@ private: #endif uint32_t mMode; - // Maximum CPU load allocated to audio effects in 0.1 MIPS (ARMv5TE, 0 WS memory) units - static const uint32_t MAX_EFFECTS_CPU_LOAD = 1000; - // Maximum memory allocated to audio effects in KB - static const uint32_t MAX_EFFECTS_MEMORY = 512; - uint32_t mTotalEffectsCpuLoad; // current CPU load used by effects - uint32_t mTotalEffectsMemory; // current memory used by effects }; // ---------------------------------------------------------------------------- diff --git a/services/audioflinger/AudioPolicyManagerBase.cpp b/services/audioflinger/AudioPolicyManagerBase.cpp index 381a958..1d87c0d 100644 --- a/services/audioflinger/AudioPolicyManagerBase.cpp +++ b/services/audioflinger/AudioPolicyManagerBase.cpp @@ -538,9 +538,11 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str return output; } -status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream) +status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session) { - LOGV("startOutput() output %d, stream %d", output, stream); + LOGV("startOutput() output %d, stream %d, session %d", output, stream, session); ssize_t index = mOutputs.indexOfKey(output); if (index < 0) { LOGW("startOutput() unknow output %d", output); @@ -574,9 +576,11 @@ status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output, AudioSyst return NO_ERROR; } -status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream) +status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session) { - LOGV("stopOutput() output %d, stream %d", output, stream); + LOGV("stopOutput() output %d, stream %d, session %d", output, stream, session); ssize_t index = mOutputs.indexOfKey(output); if (index < 0) { LOGW("stopOutput() unknow output %d", output); @@ -602,8 +606,12 @@ status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output, AudioSyste setOutputDevice(output, getNewDevice(output)); #ifdef WITH_A2DP - if (mA2dpOutput != 0 && !a2dpUsedForSonification() && strategy == STRATEGY_SONIFICATION) { - setStrategyMute(STRATEGY_MEDIA, false, mA2dpOutput, mOutputs.valueFor(mHardwareOutput)->mLatency*2); + if (mA2dpOutput != 0 && !a2dpUsedForSonification() && + strategy == STRATEGY_SONIFICATION) { + setStrategyMute(STRATEGY_MEDIA, + false, + mA2dpOutput, + mOutputs.valueFor(mHardwareOutput)->mLatency*2); } #endif if (output != mHardwareOutput) { @@ -826,6 +834,85 @@ status_t AudioPolicyManagerBase::getStreamVolumeIndex(AudioSystem::stream_type s return NO_ERROR; } +audio_io_handle_t AudioPolicyManagerBase::getOutputForEffect(effect_descriptor_t *desc) +{ + LOGV("getOutputForEffect()"); + // apply simple rule where global effects are attached to the same output as MUSIC streams + return getOutput(AudioSystem::MUSIC); +} + +status_t AudioPolicyManagerBase::registerEffect(effect_descriptor_t *desc, + audio_io_handle_t output, + uint32_t strategy, + int session, + int id) +{ + ssize_t index = mOutputs.indexOfKey(output); + if (index < 0) { + LOGW("registerEffect() unknown output %d", output); + return INVALID_OPERATION; + } + + if (mTotalEffectsCpuLoad + desc->cpuLoad > getMaxEffectsCpuLoad()) { + LOGW("registerEffect() CPU Load limit exceeded for Fx %s, CPU %f MIPS", + desc->name, (float)desc->cpuLoad/10); + return INVALID_OPERATION; + } + if (mTotalEffectsMemory + desc->memoryUsage > getMaxEffectsMemory()) { + LOGW("registerEffect() memory limit exceeded for Fx %s, Memory %d KB", + desc->name, desc->memoryUsage); + return INVALID_OPERATION; + } + mTotalEffectsCpuLoad += desc->cpuLoad; + mTotalEffectsMemory += desc->memoryUsage; + LOGV("registerEffect() effect %s, output %d, strategy %d session %d id %d", + desc->name, output, strategy, session, id); + + LOGV("registerEffect() CPU %d, memory %d", desc->cpuLoad, desc->memoryUsage); + LOGV(" total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory); + + EffectDescriptor *pDesc = new EffectDescriptor(); + memcpy (&pDesc->mDesc, desc, sizeof(effect_descriptor_t)); + pDesc->mOutput = output; + pDesc->mStrategy = (routing_strategy)strategy; + pDesc->mSession = session; + mEffects.add(id, pDesc); + + return NO_ERROR; +} + +status_t AudioPolicyManagerBase::unregisterEffect(int id) +{ + ssize_t index = mEffects.indexOfKey(id); + if (index < 0) { + LOGW("unregisterEffect() unknown effect ID %d", id); + return INVALID_OPERATION; + } + + EffectDescriptor *pDesc = mEffects.valueAt(index); + + if (mTotalEffectsCpuLoad < pDesc->mDesc.cpuLoad) { + LOGW("unregisterEffect() CPU load %d too high for total %d", + pDesc->mDesc.cpuLoad, mTotalEffectsCpuLoad); + pDesc->mDesc.cpuLoad = mTotalEffectsCpuLoad; + } + mTotalEffectsCpuLoad -= pDesc->mDesc.cpuLoad; + if (mTotalEffectsMemory < pDesc->mDesc.memoryUsage) { + LOGW("unregisterEffect() memory %d too big for total %d", + pDesc->mDesc.memoryUsage, mTotalEffectsMemory); + pDesc->mDesc.memoryUsage = mTotalEffectsMemory; + } + mTotalEffectsMemory -= pDesc->mDesc.memoryUsage; + LOGV("unregisterEffect() effect %s, ID %d, CPU %d, memory %d", + pDesc->mDesc.name, id, pDesc->mDesc.cpuLoad, pDesc->mDesc.memoryUsage); + LOGV(" total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory); + + mEffects.removeItem(id); + delete pDesc; + + return NO_ERROR; +} + status_t AudioPolicyManagerBase::dump(int fd) { const size_t SIZE = 256; @@ -890,6 +977,19 @@ status_t AudioPolicyManagerBase::dump(int fd) write(fd, buffer, strlen(buffer)); } + snprintf(buffer, SIZE, "\nTotal Effects CPU: %f MIPS, Total Effects memory: %d KB\n", + (float)mTotalEffectsCpuLoad/10, mTotalEffectsMemory); + write(fd, buffer, strlen(buffer)); + + snprintf(buffer, SIZE, "Registered effects:\n"); + write(fd, buffer, strlen(buffer)); + for (size_t i = 0; i < mEffects.size(); i++) { + snprintf(buffer, SIZE, "- Effect %d dump:\n", mEffects.keyAt(i)); + write(fd, buffer, strlen(buffer)); + mEffects.valueAt(i)->dump(fd); + } + + return NO_ERROR; } @@ -902,7 +1002,8 @@ AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clien #ifdef AUDIO_POLICY_TEST Thread(false), #endif //AUDIO_POLICY_TEST - mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0), mMusicStopTime(0), mLimitRingtoneVolume(false) + mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0), mMusicStopTime(0), + mLimitRingtoneVolume(false), mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0) { mpClientInterface = clientInterface; @@ -938,6 +1039,7 @@ AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clien } else { addOutput(mHardwareOutput, outputDesc); setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER, true); + //TODO: configure audio effect output stage here } updateDeviceForStrategy(); @@ -1152,6 +1254,9 @@ status_t AudioPolicyManagerBase::handleA2dpConnection(AudioSystem::audio_devices if (mA2dpOutput) { // add A2DP output descriptor addOutput(mA2dpOutput, outputDesc); + + //TODO: configure audio effect output stage here + // set initial stream volume for A2DP device applyStreamVolumes(mA2dpOutput, device); if (a2dpUsedForSonification()) { @@ -1269,6 +1374,7 @@ void AudioPolicyManagerBase::closeA2dpOutputs() AudioParameter param; param.add(String8("closing"), String8("true")); mpClientInterface->setParameters(mA2dpOutput, param.toString()); + mpClientInterface->closeOutput(mA2dpOutput); delete mOutputs.valueFor(mA2dpOutput); mOutputs.removeItem(mA2dpOutput); @@ -1282,48 +1388,54 @@ void AudioPolicyManagerBase::checkOutputForStrategy(routing_strategy strategy, u uint32_t curDevice = getDeviceForStrategy(strategy, false); bool a2dpWasUsed = AudioSystem::isA2dpDevice((AudioSystem::audio_devices)(prevDevice & ~AudioSystem::DEVICE_OUT_SPEAKER)); bool a2dpIsUsed = AudioSystem::isA2dpDevice((AudioSystem::audio_devices)(curDevice & ~AudioSystem::DEVICE_OUT_SPEAKER)); - AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mHardwareOutput); - AudioOutputDescriptor *a2dpOutputDesc; + audio_io_handle_t srcOutput = 0; + audio_io_handle_t dstOutput = 0; if (a2dpWasUsed && !a2dpIsUsed) { bool dupUsed = a2dpUsedForSonification() && a2dpWasUsed && (AudioSystem::popCount(prevDevice) == 2); - + dstOutput = mHardwareOutput; if (dupUsed) { - LOGV("checkOutputForStrategy() moving strategy %d to duplicated", strategy); - a2dpOutputDesc = mOutputs.valueFor(mDuplicatedOutput); + LOGV("checkOutputForStrategy() moving strategy %d from duplicated", strategy); + srcOutput = mDuplicatedOutput; } else { - LOGV("checkOutputForStrategy() moving strategy %d to a2dp", strategy); - a2dpOutputDesc = mOutputs.valueFor(mA2dpOutput); + LOGV("checkOutputForStrategy() moving strategy %d from a2dp", strategy); + srcOutput = mA2dpOutput; } - for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { - if (getStrategy((AudioSystem::stream_type)i) == strategy) { - mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, mHardwareOutput); - } - } // do not change newDevice if it was already set before this call by a previous call to // getNewDevice() or checkOutputForStrategy() for a strategy with higher priority - if (newDevice == 0 && hwOutputDesc->isUsedByStrategy(strategy)) { + if (newDevice == 0 && mOutputs.valueFor(mHardwareOutput)->isUsedByStrategy(strategy)) { newDevice = getDeviceForStrategy(strategy, false); } } if (a2dpIsUsed && !a2dpWasUsed) { bool dupUsed = a2dpUsedForSonification() && a2dpIsUsed && (AudioSystem::popCount(curDevice) == 2); - audio_io_handle_t a2dpOutput; - + srcOutput = mHardwareOutput; if (dupUsed) { - LOGV("checkOutputForStrategy() moving strategy %d from duplicated", strategy); - a2dpOutputDesc = mOutputs.valueFor(mDuplicatedOutput); - a2dpOutput = mDuplicatedOutput; + LOGV("checkOutputForStrategy() moving strategy %d to duplicated", strategy); + dstOutput = mDuplicatedOutput; } else { - LOGV("checkOutputForStrategy() moving strategy %d from a2dp", strategy); - a2dpOutputDesc = mOutputs.valueFor(mA2dpOutput); - a2dpOutput = mA2dpOutput; + LOGV("checkOutputForStrategy() moving strategy %d to a2dp", strategy); + dstOutput = mA2dpOutput; } + } + if (srcOutput != 0 && dstOutput != 0) { + // Move effects associated to this strategy from previous output to new output + for (size_t i = 0; i < mEffects.size(); i++) { + EffectDescriptor *desc = mEffects.valueAt(i); + if (desc->mSession != AudioSystem::SESSION_OUTPUT_STAGE && + desc->mStrategy == strategy && + desc->mOutput == srcOutput) { + LOGV("checkOutputForStrategy() moving effect %d to output %d", mEffects.keyAt(i), dstOutput); + mpClientInterface->moveEffects(desc->mSession, srcOutput, dstOutput); + desc->mOutput = dstOutput; + } + } + // Move tracks associated to this strategy from previous output to new output for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { if (getStrategy((AudioSystem::stream_type)i) == strategy) { - mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, a2dpOutput); + mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, dstOutput); } } } @@ -1371,8 +1483,12 @@ uint32_t AudioPolicyManagerBase::getNewDevice(audio_io_handle_t output, bool fro return device; } -AudioPolicyManagerBase::routing_strategy AudioPolicyManagerBase::getStrategy(AudioSystem::stream_type stream) -{ +uint32_t AudioPolicyManagerBase::getStrategyForStream(AudioSystem::stream_type stream) { + return (uint32_t)getStrategy(stream); +} + +AudioPolicyManagerBase::routing_strategy AudioPolicyManagerBase::getStrategy( + AudioSystem::stream_type stream) { // stream to strategy mapping switch (stream) { case AudioSystem::VOICE_CALL: @@ -1836,6 +1952,16 @@ bool AudioPolicyManagerBase::needsDirectOuput(AudioSystem::stream_type stream, (format !=0 && !AudioSystem::isLinearPCM(format))); } +uint32_t AudioPolicyManagerBase::getMaxEffectsCpuLoad() +{ + return MAX_EFFECTS_CPU_LOAD; +} + +uint32_t AudioPolicyManagerBase::getMaxEffectsMemory() +{ + return MAX_EFFECTS_MEMORY; +} + // --- AudioOutputDescriptor class implementation AudioPolicyManagerBase::AudioOutputDescriptor::AudioOutputDescriptor() @@ -1969,5 +2095,27 @@ void AudioPolicyManagerBase::StreamDescriptor::dump(char* buffer, size_t size) mCanBeMuted); } +// --- EffectDescriptor class implementation + +status_t AudioPolicyManagerBase::EffectDescriptor::dump(int fd) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + snprintf(buffer, SIZE, " Output: %d\n", mOutput); + result.append(buffer); + snprintf(buffer, SIZE, " Strategy: %d\n", mStrategy); + result.append(buffer); + snprintf(buffer, SIZE, " Session: %d\n", mSession); + result.append(buffer); + snprintf(buffer, SIZE, " Name: %s\n", mDesc.name); + result.append(buffer); + write(fd, result.string(), result.size()); + + return NO_ERROR; +} + + }; // namespace android diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp index bb3905c..f24e08e 100644 --- a/services/audioflinger/AudioPolicyService.cpp +++ b/services/audioflinger/AudioPolicyService.cpp @@ -119,7 +119,8 @@ status_t AudioPolicyService::setDeviceConnectionState(AudioSystem::audio_devices if (!AudioSystem::isOutputDevice(device) && !AudioSystem::isInputDevice(device)) { return BAD_VALUE; } - if (state != AudioSystem::DEVICE_STATE_AVAILABLE && state != AudioSystem::DEVICE_STATE_UNAVAILABLE) { + if (state != AudioSystem::DEVICE_STATE_AVAILABLE && + state != AudioSystem::DEVICE_STATE_UNAVAILABLE) { return BAD_VALUE; } @@ -128,8 +129,9 @@ status_t AudioPolicyService::setDeviceConnectionState(AudioSystem::audio_devices return mpPolicyManager->setDeviceConnectionState(device, state, device_address); } -AudioSystem::device_connection_state AudioPolicyService::getDeviceConnectionState(AudioSystem::audio_devices device, - const char *device_address) +AudioSystem::device_connection_state AudioPolicyService::getDeviceConnectionState( + AudioSystem::audio_devices device, + const char *device_address) { if (mpPolicyManager == NULL) { return AudioSystem::DEVICE_STATE_UNAVAILABLE; @@ -175,7 +177,8 @@ status_t AudioPolicyService::setRingerMode(uint32_t mode, uint32_t mask) return NO_ERROR; } -status_t AudioPolicyService::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) +status_t AudioPolicyService::setForceUse(AudioSystem::force_use usage, + AudioSystem::forced_config config) { if (mpPolicyManager == NULL) { return NO_INIT; @@ -223,24 +226,28 @@ audio_io_handle_t AudioPolicyService::getOutput(AudioSystem::stream_type stream, return mpPolicyManager->getOutput(stream, samplingRate, format, channels, flags); } -status_t AudioPolicyService::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream) +status_t AudioPolicyService::startOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session) { if (mpPolicyManager == NULL) { return NO_INIT; } LOGV("startOutput() tid %d", gettid()); Mutex::Autolock _l(mLock); - return mpPolicyManager->startOutput(output, stream); + return mpPolicyManager->startOutput(output, stream, session); } -status_t AudioPolicyService::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream) +status_t AudioPolicyService::stopOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session) { if (mpPolicyManager == NULL) { return NO_INIT; } LOGV("stopOutput() tid %d", gettid()); Mutex::Autolock _l(mLock); - return mpPolicyManager->stopOutput(output, stream); + return mpPolicyManager->stopOutput(output, stream, session); } void AudioPolicyService::releaseOutput(audio_io_handle_t output) @@ -339,8 +346,46 @@ status_t AudioPolicyService::getStreamVolumeIndex(AudioSystem::stream_type strea return mpPolicyManager->getStreamVolumeIndex(stream, index); } +uint32_t AudioPolicyService::getStrategyForStream(AudioSystem::stream_type stream) +{ + if (mpPolicyManager == NULL) { + return 0; + } + return mpPolicyManager->getStrategyForStream(stream); +} + +audio_io_handle_t AudioPolicyService::getOutputForEffect(effect_descriptor_t *desc) +{ + if (mpPolicyManager == NULL) { + return NO_INIT; + } + Mutex::Autolock _l(mLock); + return mpPolicyManager->getOutputForEffect(desc); +} + +status_t AudioPolicyService::registerEffect(effect_descriptor_t *desc, + audio_io_handle_t output, + uint32_t strategy, + int session, + int id) +{ + if (mpPolicyManager == NULL) { + return NO_INIT; + } + return mpPolicyManager->registerEffect(desc, output, strategy, session, id); +} + +status_t AudioPolicyService::unregisterEffect(int id) +{ + if (mpPolicyManager == NULL) { + return NO_INIT; + } + return mpPolicyManager->unregisterEffect(id); +} + void AudioPolicyService::binderDied(const wp<IBinder>& who) { - LOGW("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid()); + LOGW("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), + IPCThreadState::self()->getCallingPid()); } static bool tryLock(Mutex& mutex) @@ -447,10 +492,16 @@ audio_io_handle_t AudioPolicyService::openOutput(uint32_t *pDevices, return 0; } - return af->openOutput(pDevices, pSamplingRate, (uint32_t *)pFormat, pChannels, pLatencyMs, flags); + return af->openOutput(pDevices, + pSamplingRate, + (uint32_t *)pFormat, + pChannels, + pLatencyMs, + flags); } -audio_io_handle_t AudioPolicyService::openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2) +audio_io_handle_t AudioPolicyService::openDuplicateOutput(audio_io_handle_t output1, + audio_io_handle_t output2) { sp<IAudioFlinger> af = AudioSystem::get_audio_flinger(); if (af == 0) { @@ -514,12 +565,16 @@ status_t AudioPolicyService::closeInput(audio_io_handle_t input) return af->closeInput(input); } -status_t AudioPolicyService::setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output, int delayMs) +status_t AudioPolicyService::setStreamVolume(AudioSystem::stream_type stream, + float volume, + audio_io_handle_t output, + int delayMs) { return mAudioCommandThread->volumeCommand((int)stream, volume, (int)output, delayMs); } -status_t AudioPolicyService::setStreamOutput(AudioSystem::stream_type stream, audio_io_handle_t output) +status_t AudioPolicyService::setStreamOutput(AudioSystem::stream_type stream, + audio_io_handle_t output) { sp<IAudioFlinger> af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; @@ -527,8 +582,18 @@ status_t AudioPolicyService::setStreamOutput(AudioSystem::stream_type stream, au return af->setStreamOutput(stream, output); } +status_t AudioPolicyService::moveEffects(int session, audio_io_handle_t srcOutput, + audio_io_handle_t dstOutput) +{ + sp<IAudioFlinger> af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + + return af->moveEffects(session, (int)srcOutput, (int)dstOutput); +} -void AudioPolicyService::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs, int delayMs) +void AudioPolicyService::setParameters(audio_io_handle_t ioHandle, + const String8& keyValuePairs, + int delayMs) { mAudioCommandThread->parametersCommand((int)ioHandle, keyValuePairs, delayMs); } @@ -539,7 +604,8 @@ String8 AudioPolicyService::getParameters(audio_io_handle_t ioHandle, const Stri return result; } -status_t AudioPolicyService::startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream) +status_t AudioPolicyService::startTone(ToneGenerator::tone_type tone, + AudioSystem::stream_type stream) { mTonePlaybackThread->startToneCommand(tone, stream); return NO_ERROR; @@ -623,8 +689,11 @@ bool AudioPolicyService::AudioCommandThread::threadLoop() }break; case SET_VOLUME: { VolumeData *data = (VolumeData *)command->mParam; - LOGV("AudioCommandThread() processing set volume stream %d, volume %f, output %d", data->mStream, data->mVolume, data->mIO); - command->mStatus = AudioSystem::setStreamVolume(data->mStream, data->mVolume, data->mIO); + LOGV("AudioCommandThread() processing set volume stream %d, \ + volume %f, output %d", data->mStream, data->mVolume, data->mIO); + command->mStatus = AudioSystem::setStreamVolume(data->mStream, + data->mVolume, + data->mIO); if (command->mWaitStatus) { command->mCond.signal(); mWaitWorkCV.wait(mLock); @@ -633,7 +702,8 @@ bool AudioPolicyService::AudioCommandThread::threadLoop() }break; case SET_PARAMETERS: { ParametersData *data = (ParametersData *)command->mParam; - LOGV("AudioCommandThread() processing set parameters string %s, io %d", data->mKeyValuePairs.string(), data->mIO); + LOGV("AudioCommandThread() processing set parameters string %s, io %d", + data->mKeyValuePairs.string(), data->mIO); command->mStatus = AudioSystem::setParameters(data->mIO, data->mKeyValuePairs); if (command->mWaitStatus) { command->mCond.signal(); @@ -643,7 +713,8 @@ bool AudioPolicyService::AudioCommandThread::threadLoop() }break; case SET_VOICE_VOLUME: { VoiceVolumeData *data = (VoiceVolumeData *)command->mParam; - LOGV("AudioCommandThread() processing set voice volume volume %f", data->mVolume); + LOGV("AudioCommandThread() processing set voice volume volume %f", + data->mVolume); command->mStatus = AudioSystem::setVoiceVolume(data->mVolume); if (command->mWaitStatus) { command->mCond.signal(); @@ -734,7 +805,10 @@ void AudioPolicyService::AudioCommandThread::stopToneCommand() mWaitWorkCV.signal(); } -status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, float volume, int output, int delayMs) +status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, + float volume, + int output, + int delayMs) { status_t status = NO_ERROR; @@ -752,7 +826,8 @@ status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, float } Mutex::Autolock _l(mLock); insertCommand_l(command, delayMs); - LOGV("AudioCommandThread() adding set volume stream %d, volume %f, output %d", stream, volume, output); + LOGV("AudioCommandThread() adding set volume stream %d, volume %f, output %d", + stream, volume, output); mWaitWorkCV.signal(); if (command->mWaitStatus) { command->mCond.wait(mLock); @@ -762,7 +837,9 @@ status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, float return status; } -status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle, const String8& keyValuePairs, int delayMs) +status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle, + const String8& keyValuePairs, + int delayMs) { status_t status = NO_ERROR; @@ -779,7 +856,8 @@ status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle, } Mutex::Autolock _l(mLock); insertCommand_l(command, delayMs); - LOGV("AudioCommandThread() adding set parameter string %s, io %d ,delay %d", keyValuePairs.string(), ioHandle, delayMs); + LOGV("AudioCommandThread() adding set parameter string %s, io %d ,delay %d", + keyValuePairs.string(), ioHandle, delayMs); mWaitWorkCV.signal(); if (command->mWaitStatus) { command->mCond.wait(mLock); @@ -840,7 +918,8 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma ParametersData *data = (ParametersData *)command->mParam; ParametersData *data2 = (ParametersData *)command2->mParam; if (data->mIO != data2->mIO) break; - LOGV("Comparing parameter command %s to new command %s", data2->mKeyValuePairs.string(), data->mKeyValuePairs.string()); + LOGV("Comparing parameter command %s to new command %s", + data2->mKeyValuePairs.string(), data->mKeyValuePairs.string()); AudioParameter param = AudioParameter(data->mKeyValuePairs); AudioParameter param2 = AudioParameter(data2->mKeyValuePairs); for (size_t j = 0; j < param.size(); j++) { @@ -872,7 +951,8 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma VolumeData *data2 = (VolumeData *)command2->mParam; if (data->mIO != data2->mIO) break; if (data->mStream != data2->mStream) break; - LOGV("Filtering out volume command on output %d for stream %d", data->mIO, data->mStream); + LOGV("Filtering out volume command on output %d for stream %d", + data->mIO, data->mStream); removedCommands.add(command2); } break; case START_TONE: @@ -896,7 +976,8 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma removedCommands.clear(); // insert command at the right place according to its time stamp - LOGV("inserting command: %d at index %d, num commands %d", command->mCommand, (int)i+1, mAudioCommands.size()); + LOGV("inserting command: %d at index %d, num commands %d", + command->mCommand, (int)i+1, mAudioCommands.size()); mAudioCommands.insertAt(command, i + 1); } diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h index a13d0bd..558f455 100644 --- a/services/audioflinger/AudioPolicyService.h +++ b/services/audioflinger/AudioPolicyService.h @@ -28,7 +28,8 @@ class String8; // ---------------------------------------------------------------------------- -class AudioPolicyService: public BnAudioPolicyService, public AudioPolicyClientInterface, public IBinder::DeathRecipient +class AudioPolicyService: public BnAudioPolicyService, public AudioPolicyClientInterface, + public IBinder::DeathRecipient { public: @@ -43,8 +44,9 @@ public: virtual status_t setDeviceConnectionState(AudioSystem::audio_devices device, AudioSystem::device_connection_state state, const char *device_address); - virtual AudioSystem::device_connection_state getDeviceConnectionState(AudioSystem::audio_devices device, - const char *device_address); + virtual AudioSystem::device_connection_state getDeviceConnectionState( + AudioSystem::audio_devices device, + const char *device_address); virtual status_t setPhoneState(int state); virtual status_t setRingerMode(uint32_t mode, uint32_t mask); virtual status_t setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config); @@ -53,15 +55,21 @@ public: uint32_t samplingRate = 0, uint32_t format = AudioSystem::FORMAT_DEFAULT, uint32_t channels = 0, - AudioSystem::output_flags flags = AudioSystem::OUTPUT_FLAG_INDIRECT); - virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream); - virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream); + AudioSystem::output_flags flags = + AudioSystem::OUTPUT_FLAG_INDIRECT); + virtual status_t startOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session = 0); + virtual status_t stopOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session = 0); virtual void releaseOutput(audio_io_handle_t output); virtual audio_io_handle_t getInput(int inputSource, uint32_t samplingRate = 0, uint32_t format = AudioSystem::FORMAT_DEFAULT, uint32_t channels = 0, - AudioSystem::audio_in_acoustics acoustics = (AudioSystem::audio_in_acoustics)0); + AudioSystem::audio_in_acoustics acoustics = + (AudioSystem::audio_in_acoustics)0); virtual status_t startInput(audio_io_handle_t input); virtual status_t stopInput(audio_io_handle_t input); virtual void releaseInput(audio_io_handle_t input); @@ -71,6 +79,16 @@ public: virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index); virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index); + virtual uint32_t getStrategyForStream(AudioSystem::stream_type stream); + + virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc); + virtual status_t registerEffect(effect_descriptor_t *desc, + audio_io_handle_t output, + uint32_t strategy, + int session, + int id); + virtual status_t unregisterEffect(int id); + virtual status_t onTransact( uint32_t code, const Parcel& data, @@ -89,7 +107,8 @@ public: uint32_t *pChannels, uint32_t *pLatencyMs, AudioSystem::output_flags flags); - virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2); + virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1, + audio_io_handle_t output2); virtual status_t closeOutput(audio_io_handle_t output); virtual status_t suspendOutput(audio_io_handle_t output); virtual status_t restoreOutput(audio_io_handle_t output); @@ -99,13 +118,21 @@ public: uint32_t *pChannels, uint32_t acoustics); virtual status_t closeInput(audio_io_handle_t input); - virtual status_t setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output, int delayMs = 0); + virtual status_t setStreamVolume(AudioSystem::stream_type stream, + float volume, + audio_io_handle_t output, + int delayMs = 0); virtual status_t setStreamOutput(AudioSystem::stream_type stream, audio_io_handle_t output); - virtual void setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs, int delayMs = 0); + virtual void setParameters(audio_io_handle_t ioHandle, + const String8& keyValuePairs, + int delayMs = 0); virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys); virtual status_t startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream); virtual status_t stopTone(); virtual status_t setVoiceVolume(float volume, int delayMs = 0); + virtual status_t moveEffects(int session, + audio_io_handle_t srcOutput, + audio_io_handle_t dstOutput); private: AudioPolicyService(); |