From 0479d7c79a7fd6f112e8dc7e45c009cf6602dbaa Mon Sep 17 00:00:00 2001 From: Steve Kondik Date: Thu, 14 Jan 2016 02:46:40 -0800 Subject: audiopolicy: Add notification when default effects are updated * In M, we now have the ability to define a default set of audio effect on a per-stream basis. This allows us to get around the problem of apps not sending the control intents so we can implement smart global effects for specific media types. * We still need a session id in order to get a handle and configure them from an app like AudioFX, so we'll need to add some plumbing in order to send an event to interested applications. * This patch implements the native side of this. The Java layer will call down thru AudioSystem and register a callback which will be invoked by the audio policy when default effects are updated on a stream. This callback will receive both the stream type as well as the session id. * Attaching this listener requires that the caller hold the MODIFY_AUDIO_ROUTING permission. Change-Id: I142b15f2585ffca6a953c3e828e2a7c07b24f56c --- .../audiopolicy/service/AudioPolicyService.cpp | 82 +++++++++++++++++++++- 1 file changed, 80 insertions(+), 2 deletions(-) (limited to 'services/audiopolicy/service/AudioPolicyService.cpp') diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp index 12cca65..dbeed80 100644 --- a/services/audiopolicy/service/AudioPolicyService.cpp +++ b/services/audiopolicy/service/AudioPolicyService.cpp @@ -116,7 +116,7 @@ void AudioPolicyService::onFirstRef() #endif } // load audio processing modules - spaudioPolicyEffects = new AudioPolicyEffects(); + spaudioPolicyEffects = new AudioPolicyEffects(this); { Mutex::Autolock _l(mLock); mAudioPolicyEffects = audioPolicyEffects; @@ -177,6 +177,23 @@ void AudioPolicyService::setAudioPortCallbacksEnabled(bool enabled) mNotificationClients.valueFor(uid)->setAudioPortCallbacksEnabled(enabled); } +status_t AudioPolicyService::setEffectSessionCallbacksEnabled(bool enabled) +{ + Mutex::Autolock _l(mNotificationClientsLock); + + uid_t uid = IPCThreadState::self()->getCallingUid(); + if (mNotificationClients.indexOfKey(uid) < 0) { + return NO_INIT; + } + if (!modifyAudioRoutingAllowed()) { + ALOGE("setEffectSessionCallbacksEnabled requires MODIFY_AUDIO_ROUTING"); + return PERMISSION_DENIED; + } + mNotificationClients.valueFor(uid)->setEffectSessionCallbacksEnabled(enabled); + return OK; +} + + // removeNotificationClient() is called when the client process dies. void AudioPolicyService::removeNotificationClient(uid_t uid) { @@ -254,11 +271,31 @@ status_t AudioPolicyService::clientSetAudioPortConfig(const struct audio_port_co return mAudioCommandThread->setAudioPortConfigCommand(config, delayMs); } +void AudioPolicyService::onOutputSessionEffectsUpdate(audio_stream_type_t stream, + audio_unique_id_t sessionId, + bool added) +{ + ALOGV("AudioPolicyService::onOutputSessionEffectsUpdate(%d, %d, %d)", + stream, sessionId, added); + mOutputCommandThread->effectSessionUpdateCommand(stream, sessionId, added); +} + +void AudioPolicyService::doOnOutputSessionEffectsUpdate(audio_stream_type_t stream, + audio_unique_id_t sessionId, + bool added) +{ + Mutex::Autolock _l(mNotificationClientsLock); + for (size_t i = 0; i < mNotificationClients.size(); i++) { + mNotificationClients.valueAt(i)->onOutputSessionEffectsUpdate(stream, sessionId, added); + } +} + AudioPolicyService::NotificationClient::NotificationClient(const sp& service, const sp& client, uid_t uid) : mService(service), mUid(uid), mAudioPolicyServiceClient(client), - mAudioPortCallbacksEnabled(false) + mAudioPortCallbacksEnabled(false), + mEffectSessionCallbacksEnabled(false) { } @@ -289,6 +326,14 @@ void AudioPolicyService::NotificationClient::onAudioPatchListUpdate() } } +void AudioPolicyService::NotificationClient::onOutputSessionEffectsUpdate( + audio_stream_type_t stream, audio_unique_id_t sessionId, bool added) +{ + if (mAudioPolicyServiceClient != 0 && mEffectSessionCallbacksEnabled) { + mAudioPolicyServiceClient->onOutputSessionEffectsUpdate(stream, sessionId, added); + } +} + void AudioPolicyService::NotificationClient::onDynamicPolicyMixStateUpdate( String8 regId, int32_t state) { @@ -302,6 +347,10 @@ void AudioPolicyService::NotificationClient::setAudioPortCallbacksEnabled(bool e mAudioPortCallbacksEnabled = enabled; } +void AudioPolicyService::NotificationClient::setEffectSessionCallbacksEnabled(bool enabled) +{ + mEffectSessionCallbacksEnabled = enabled; +} void AudioPolicyService::binderDied(const wp& who) { ALOGW("binderDied() %p, calling pid %d", who.unsafe_get(), @@ -579,6 +628,20 @@ bool AudioPolicyService::AudioCommandThread::threadLoop() svc->doOnDynamicPolicyMixStateUpdate(data->mRegId, data->mState); mLock.lock(); } break; + case EFFECT_SESSION_UPDATE: { + EffectSessionUpdateData *data = + (EffectSessionUpdateData *)command->mParam.get(); + ALOGV("AudioCommandThread() processing effect session update %d %d %d", + data->mStream, data->mSessionId, data->mAdded); + svc = mService.promote(); + if (svc == 0) { + break; + } + mLock.unlock(); + svc->doOnOutputSessionEffectsUpdate(data->mStream, data->mSessionId, data->mAdded); + mLock.lock(); + } break; + default: ALOGW("AudioCommandThread() unknown command %d", command->mCommand); } @@ -851,6 +914,21 @@ void AudioPolicyService::AudioCommandThread::dynamicPolicyMixStateUpdateCommand( sendCommand(command); } +void AudioPolicyService::AudioCommandThread::effectSessionUpdateCommand( + audio_stream_type_t stream, audio_unique_id_t sessionId, bool added) +{ + sp command = new AudioCommand(); + command->mCommand = EFFECT_SESSION_UPDATE; + EffectSessionUpdateData *data = new EffectSessionUpdateData(); + data->mStream = stream; + data->mSessionId = sessionId; + data->mAdded = added; + command->mParam = data; + ALOGV("AudioCommandThread() sending effect session update (id=%d) for stream %d (added=%d)", + stream, sessionId, added); + sendCommand(command); +} + status_t AudioPolicyService::AudioCommandThread::sendCommand(sp& command, int delayMs) { { -- cgit v1.1