From 3f9eb321481de3e118632a594bf1b0c9001c281c Mon Sep 17 00:00:00 2001 From: Steve Kondik Date: Fri, 22 Apr 2016 18:32:39 -0700 Subject: audiopolicy: Add AudioSessionInfo API * This patch introduces a new API which allows applications to query the state of the audio effects system, and receive callbacks with the necessary information to attach effects to any stream. * In the future, this may come as part of the AudioPort system, but since that's an active area of development by Google, we will dodge it for now. * The policy now simply keeps a refcounted list of objects which hold various bits of stream metadata. Callbacks are sent on stream open/close to applications which might be listening for them. Change-Id: I2d554d36e1378f4eb7b276010a3bfe8345c22ecd --- services/audiopolicy/AudioPolicyInterface.h | 3 + .../audiopolicy/service/AudioPolicyClientImpl.cpp | 6 ++ .../audiopolicy/service/AudioPolicyEffects.cpp | 111 ++++++++++++++++++++- services/audiopolicy/service/AudioPolicyEffects.h | 21 +++- .../service/AudioPolicyInterfaceImpl.cpp | 66 +++++++++--- .../service/AudioPolicyInterfaceImplLegacy.cpp | 5 + .../audiopolicy/service/AudioPolicyService.cpp | 54 +++++++++- services/audiopolicy/service/AudioPolicyService.h | 22 +++- 8 files changed, 270 insertions(+), 18 deletions(-) (limited to 'services/audiopolicy') diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h index c1e7bc0..93e6266 100644 --- a/services/audiopolicy/AudioPolicyInterface.h +++ b/services/audiopolicy/AudioPolicyInterface.h @@ -331,6 +331,9 @@ public: virtual audio_unique_id_t newAudioUniqueId() = 0; virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state) = 0; + + virtual void onOutputSessionEffectsUpdate(sp& streamInfo, bool added) = 0; + }; extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface); diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp index 489a9be..82720f4 100644 --- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp @@ -219,6 +219,12 @@ void AudioPolicyService::AudioPolicyClient::onDynamicPolicyMixStateUpdate( mAudioPolicyService->onDynamicPolicyMixStateUpdate(regId, state); } +void AudioPolicyService::AudioPolicyClient::onOutputSessionEffectsUpdate( + sp& info, bool added) +{ + mAudioPolicyService->onOutputSessionEffectsUpdate(info, added); +} + audio_unique_id_t AudioPolicyService::AudioPolicyClient::newAudioUniqueId() { return AudioSystem::newAudioUniqueId(); diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp index 26857b1..31b1637 100644 --- a/services/audiopolicy/service/AudioPolicyEffects.cpp +++ b/services/audiopolicy/service/AudioPolicyEffects.cpp @@ -28,6 +28,7 @@ #include #include #include +#include "AudioPolicyService.h" #include "AudioPolicyEffects.h" #include "ServiceUtilities.h" @@ -37,7 +38,8 @@ namespace android { // AudioPolicyEffects Implementation // ---------------------------------------------------------------------------- -AudioPolicyEffects::AudioPolicyEffects() +AudioPolicyEffects::AudioPolicyEffects(AudioPolicyService *audioPolicyService) : + mAudioPolicyService(audioPolicyService) { // load automatic audio effect modules if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE2, R_OK) == 0) { @@ -226,6 +228,8 @@ status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output, { status_t status = NO_ERROR; + ALOGV("addOutputSessionEffects %d", audioSession); + Mutex::Autolock _l(mLock); // create audio processors according to stream // FIXME: should we have specific post processing settings for internal streams? @@ -233,6 +237,22 @@ status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output, if (stream >= AUDIO_STREAM_PUBLIC_CNT) { stream = AUDIO_STREAM_MUSIC; } + + // send the streaminfo notification only once + ssize_t sidx = mOutputAudioSessionInfo.indexOfKey(audioSession); + if (sidx >= 0) { + // AudioSessionInfo is existing and we just need to increase ref count + sp info = mOutputAudioSessionInfo.valueAt(sidx); + info->mRefCount++; + + if (info->mRefCount == 1) { + mAudioPolicyService->onOutputSessionEffectsUpdate(info, true); + } + ALOGV("addOutputSessionEffects(): session info %d refCount=%d", audioSession, info->mRefCount); + } else { + ALOGV("addOutputSessionEffects(): no output stream info found for stream"); + } + ssize_t index = mOutputStreams.indexOfKey(stream); if (index < 0) { ALOGV("addOutputSessionEffects(): no output processing needed for this stream"); @@ -275,6 +295,81 @@ status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output, return status; } +status_t AudioPolicyEffects::releaseOutputAudioSessionInfo(audio_io_handle_t /* output */, + audio_stream_type_t stream, + int session) +{ + if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + return BAD_VALUE; + } + + Mutex::Autolock _l(mLock); + + ssize_t idx = mOutputAudioSessionInfo.indexOfKey(session); + if (idx >= 0) { + sp info = mOutputAudioSessionInfo.valueAt(idx); + if (info->mRefCount == 0) { + mOutputAudioSessionInfo.removeItemsAt(idx); + } + ALOGV("releaseOutputAudioSessionInfo() sessionId=%d refcount=%d", + session, info->mRefCount); + } else { + ALOGV("releaseOutputAudioSessionInfo() no session info found"); + } + return NO_ERROR; +} + +status_t AudioPolicyEffects::updateOutputAudioSessionInfo(audio_io_handle_t /* output */, + audio_stream_type_t stream, + int session, + audio_output_flags_t flags, + audio_channel_mask_t channelMask, uid_t uid) +{ + if (uint32_t(stream) >= AUDIO_STREAM_CNT) { + return BAD_VALUE; + } + + Mutex::Autolock _l(mLock); + + // update AudioSessionInfo. This is used in the stream open/close path + // to notify userspace applications about session creation and + // teardown, allowing the app to make decisions about effects for + // a particular stream. This is independent of the current + // output_session_processing feature which forcibly attaches a + // static list of effects to a stream. + ssize_t idx = mOutputAudioSessionInfo.indexOfKey(session); + sp info; + if (idx < 0) { + info = new AudioSessionInfo(session, stream, flags, channelMask, uid); + mOutputAudioSessionInfo.add(session, info); + } else { + // the streaminfo may actually change + info = mOutputAudioSessionInfo.valueAt(idx); + info->mFlags = flags; + info->mChannelMask = channelMask; + } + + ALOGV("updateOutputAudioSessionInfo() sessionId=%d, flags=0x%x, channelMask=0x%x uid=%d refCount=%d", + info->mSessionId, info->mFlags, info->mChannelMask, info->mUid, info->mRefCount); + + return NO_ERROR; +} + +status_t AudioPolicyEffects::listAudioSessions(audio_stream_type_t streams, + Vector< sp> &sessions) +{ + ALOGV("listAudioSessions() streams %d", streams); + + for (unsigned int i = 0; i < mOutputAudioSessionInfo.size(); i++) { + sp info = mOutputAudioSessionInfo.valueAt(i); + if (streams == -1 || info->mStream == streams) { + sessions.push_back(info); + } + } + + return NO_ERROR; +} + status_t AudioPolicyEffects::releaseOutputSessionEffects(audio_io_handle_t output, audio_stream_type_t stream, int audioSession) @@ -284,7 +379,19 @@ status_t AudioPolicyEffects::releaseOutputSessionEffects(audio_io_handle_t outpu (void) stream; // argument not used for now Mutex::Autolock _l(mLock); - ssize_t index = mOutputSessions.indexOfKey(audioSession); + ssize_t index = mOutputAudioSessionInfo.indexOfKey(audioSession); + if (index >= 0) { + sp info = mOutputAudioSessionInfo.valueAt(index); + info->mRefCount--; + if (info->mRefCount == 0) { + mAudioPolicyService->onOutputSessionEffectsUpdate(info, false); + } + ALOGV("releaseOutputSessionEffects(): session=%d refCount=%d", info->mSessionId, info->mRefCount); + } else { + ALOGV("releaseOutputSessionEffects: no stream info was attached to this stream"); + } + + index = mOutputSessions.indexOfKey(audioSession); if (index < 0) { ALOGV("releaseOutputSessionEffects: no output processing was attached to this stream"); return NO_ERROR; diff --git a/services/audiopolicy/service/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h index 3845050..a95d49f 100644 --- a/services/audiopolicy/service/AudioPolicyEffects.h +++ b/services/audiopolicy/service/AudioPolicyEffects.h @@ -31,6 +31,8 @@ namespace android { +class AudioPolicyService; + // ---------------------------------------------------------------------------- // AudioPolicyEffects class @@ -44,7 +46,7 @@ public: // The constructor will parse audio_effects.conf // First it will look whether vendor specific file exists, // otherwise it will parse the system default file. - AudioPolicyEffects(); + AudioPolicyEffects(AudioPolicyService *audioPolicyService); virtual ~AudioPolicyEffects(); // NOTE: methods on AudioPolicyEffects should never be called with the AudioPolicyService @@ -84,6 +86,19 @@ public: audio_stream_type_t stream, int audioSession); + status_t updateOutputAudioSessionInfo(audio_io_handle_t output, + audio_stream_type_t stream, + int audioSession, + audio_output_flags_t flags, + audio_channel_mask_t channelMask, uid_t uid); + + status_t releaseOutputAudioSessionInfo(audio_io_handle_t output, + audio_stream_type_t stream, + int audioSession); + + status_t listAudioSessions(audio_stream_type_t streams, + Vector< sp> &sessions); + private: // class to store the description of an effects and its parameters @@ -192,6 +207,10 @@ private: KeyedVector< audio_stream_type_t, EffectDescVector* > mOutputStreams; // Automatic output effects are unique for audiosession ID KeyedVector< int32_t, EffectVector* > mOutputSessions; + // Stream info for session events + KeyedVector< int32_t, sp > mOutputAudioSessionInfo; + + AudioPolicyService *mAudioPolicyService; }; }; // namespace android diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp index c0d3866..f0be341 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp @@ -161,19 +161,32 @@ status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr, if (mAudioPolicyManager == NULL) { return NO_INIT; } - ALOGV("getOutput()"); - Mutex::Autolock _l(mLock); + ALOGV("getOutputForAttr()"); + status_t status = NO_ERROR; + sp audioPolicyEffects; + { + Mutex::Autolock _l(mLock); - // if the caller is us, trust the specified uid - if (IPCThreadState::self()->getCallingPid() != getpid_cached || uid == (uid_t)-1) { - uid_t newclientUid = IPCThreadState::self()->getCallingUid(); - if (uid != (uid_t)-1 && uid != newclientUid) { - ALOGW("%s uid %d tried to pass itself off as %d", __FUNCTION__, newclientUid, uid); + // if the caller is us, trust the specified uid + if (IPCThreadState::self()->getCallingPid() != getpid_cached || uid == (uid_t)-1) { + uid_t newclientUid = IPCThreadState::self()->getCallingUid(); + if (uid != (uid_t)-1 && uid != newclientUid) { + ALOGW("%s uid %d tried to pass itself off as %d", __FUNCTION__, newclientUid, uid); + } + uid = newclientUid; } - uid = newclientUid; + status = mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid, samplingRate, + format, channelMask, flags, selectedDeviceId, offloadInfo); + + audioPolicyEffects = mAudioPolicyEffects; + } + + if (status == NO_ERROR && audioPolicyEffects != 0) { + audioPolicyEffects->updateOutputAudioSessionInfo(*output, + *stream, session, flags, channelMask, uid); } - return mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid, samplingRate, - format, channelMask, flags, selectedDeviceId, offloadInfo); + + return status; } status_t AudioPolicyService::startOutput(audio_io_handle_t output, @@ -269,8 +282,16 @@ void AudioPolicyService::doReleaseOutput(audio_io_handle_t output, audio_session_t session) { ALOGV("doReleaseOutput from tid %d", gettid()); - Mutex::Autolock _l(mLock); - mAudioPolicyManager->releaseOutput(output, stream, session); + spaudioPolicyEffects; + { + Mutex::Autolock _l(mLock); + audioPolicyEffects = mAudioPolicyEffects; + mAudioPolicyManager->releaseOutput(output, stream, session); + } + if (audioPolicyEffects != 0) { + audioPolicyEffects->releaseOutputAudioSessionInfo(output, + stream, session); + } } status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr, @@ -717,4 +738,25 @@ status_t AudioPolicyService::stopAudioSource(audio_io_handle_t handle) return mAudioPolicyManager->stopAudioSource(handle); } +status_t AudioPolicyService::listAudioSessions(audio_stream_type_t streams, + Vector< sp> &sessions) +{ + sp audioPolicyEffects; + { + Mutex::Autolock _l(mLock); + if (mAudioPolicyManager == NULL) { + return NO_INIT; + } + audioPolicyEffects = mAudioPolicyEffects; + } + + if (audioPolicyEffects != 0) { + return audioPolicyEffects->listAudioSessions(streams, sessions); + } + + // no errors here if effects are not available + return NO_ERROR; +} + + }; // namespace android diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp index 318c6d2..0aad54d 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp @@ -642,4 +642,9 @@ status_t AudioPolicyService::stopAudioSource(audio_io_handle_t handle) return INVALID_OPERATION; } +status_t AudioPolicyService::listAudioSessions(audio_stream_type_t streams, + Vector< sp> &sessions) +{ + return INVALID_OPERATION; +} }; // namespace android diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp index 12cca65..79370f4 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; @@ -254,6 +254,21 @@ status_t AudioPolicyService::clientSetAudioPortConfig(const struct audio_port_co return mAudioCommandThread->setAudioPortConfigCommand(config, delayMs); } +void AudioPolicyService::onOutputSessionEffectsUpdate(sp& info, bool added) +{ + ALOGV("AudioPolicyService::onOutputSessionEffectsUpdate(%d, %d, %d)", + info->mStream, info->mSessionId, added); + mOutputCommandThread->effectSessionUpdateCommand(info, added); +} + +void AudioPolicyService::doOnOutputSessionEffectsUpdate(sp& info, bool added) +{ + Mutex::Autolock _l(mNotificationClientsLock); + for (size_t i = 0; i < mNotificationClients.size(); i++) { + mNotificationClients.valueAt(i)->onOutputSessionEffectsUpdate(info, added); + } +} + AudioPolicyService::NotificationClient::NotificationClient(const sp& service, const sp& client, uid_t uid) @@ -289,6 +304,14 @@ void AudioPolicyService::NotificationClient::onAudioPatchListUpdate() } } +void AudioPolicyService::NotificationClient::onOutputSessionEffectsUpdate( + sp& info, bool added) +{ + if (mAudioPolicyServiceClient != 0) { + mAudioPolicyServiceClient->onOutputSessionEffectsUpdate(info, added); + } +} + void AudioPolicyService::NotificationClient::onDynamicPolicyMixStateUpdate( String8 regId, int32_t state) { @@ -579,6 +602,21 @@ 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->mAudioSessionInfo->mStream, data->mAudioSessionInfo->mSessionId, + data->mAdded); + svc = mService.promote(); + if (svc == 0) { + break; + } + mLock.unlock(); + svc->doOnOutputSessionEffectsUpdate(data->mAudioSessionInfo, data->mAdded); + mLock.lock(); + } break; + default: ALOGW("AudioCommandThread() unknown command %d", command->mCommand); } @@ -851,6 +889,20 @@ void AudioPolicyService::AudioCommandThread::dynamicPolicyMixStateUpdateCommand( sendCommand(command); } +void AudioPolicyService::AudioCommandThread::effectSessionUpdateCommand( + sp& streamInfo, bool added) +{ + sp command = new AudioCommand(); + command->mCommand = EFFECT_SESSION_UPDATE; + EffectSessionUpdateData *data = new EffectSessionUpdateData(); + data->mAudioSessionInfo = streamInfo; + data->mAdded = added; + command->mParam = data; + ALOGV("AudioCommandThread() sending effect session update (id=%d) for stream %d (added=%d)", + streamInfo->mStream, streamInfo->mSessionId, added); + sendCommand(command); +} + status_t AudioPolicyService::AudioCommandThread::sendCommand(sp& command, int delayMs) { { diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h index d11294b..b7f55ae 100644 --- a/services/audiopolicy/service/AudioPolicyService.h +++ b/services/audiopolicy/service/AudioPolicyService.h @@ -202,6 +202,9 @@ public: audio_io_handle_t *handle); virtual status_t stopAudioSource(audio_io_handle_t handle); + virtual status_t listAudioSessions(audio_stream_type_t stream, + Vector< sp>& sessions); + status_t doStartOutput(audio_io_handle_t output, audio_stream_type_t stream, audio_session_t session); @@ -229,6 +232,9 @@ public: void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state); void doOnDynamicPolicyMixStateUpdate(String8 regId, int32_t state); + void onOutputSessionEffectsUpdate(sp& info, bool added); + void doOnOutputSessionEffectsUpdate(sp& info, bool added); + private: AudioPolicyService() ANDROID_API; virtual ~AudioPolicyService(); @@ -260,7 +266,8 @@ private: UPDATE_AUDIOPORT_LIST, UPDATE_AUDIOPATCH_LIST, SET_AUDIOPORT_CONFIG, - DYN_POLICY_MIX_STATE_UPDATE + DYN_POLICY_MIX_STATE_UPDATE, + EFFECT_SESSION_UPDATE, }; AudioCommandThread (String8 name, const wp& service); @@ -303,6 +310,7 @@ private: int delayMs); void dynamicPolicyMixStateUpdateCommand(String8 regId, int32_t state); void insertCommand_l(AudioCommand *command, int delayMs = 0); + void effectSessionUpdateCommand(sp& info, bool added); private: class AudioCommandData; @@ -399,6 +407,12 @@ private: int32_t mState; }; + class EffectSessionUpdateData : public AudioCommandData { + public: + sp mAudioSessionInfo; + bool mAdded; + }; + Mutex mLock; Condition mWaitWorkCV; Vector < sp > mAudioCommands; // list of pending commands @@ -508,6 +522,9 @@ private: virtual audio_unique_id_t newAudioUniqueId(); + virtual void onOutputSessionEffectsUpdate(sp& info, bool added); + + private: AudioPolicyService *mAudioPolicyService; }; @@ -524,7 +541,8 @@ private: void onAudioPatchListUpdate(); void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state); void setAudioPortCallbacksEnabled(bool enabled); - + void onOutputSessionEffectsUpdate(sp& info, + bool added); // IBinder::DeathRecipient virtual void binderDied(const wp& who); -- cgit v1.1