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 --- media/libmedia/AudioSystem.cpp | 39 +++++++++++++++++++++++++- media/libmedia/IAudioPolicyService.cpp | 42 ++++++++++++++++++++++++++++ media/libmedia/IAudioPolicyServiceClient.cpp | 30 +++++++++++++++++++- 3 files changed, 109 insertions(+), 2 deletions(-) (limited to 'media/libmedia') diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 9d645f0..2e9fca9 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -37,7 +37,7 @@ sp AudioSystem::gAudioFlinger; sp AudioSystem::gAudioFlingerClient; audio_error_callback AudioSystem::gAudioErrorCallback = NULL; dynamic_policy_callback AudioSystem::gDynPolicyCallback = NULL; - +audio_session_callback AudioSystem::gAudioSessionCallback = NULL; // establish binder interface to AudioFlinger service const sp AudioSystem::get_audio_flinger() @@ -652,6 +652,17 @@ status_t AudioSystem::AudioFlingerClient::removeAudioDeviceCallback( gDynPolicyCallback = cb; } +/*static*/ status_t AudioSystem::setAudioSessionCallback(audio_session_callback cb) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + + Mutex::Autolock _l(gLock); + gAudioSessionCallback = cb; + + return NO_ERROR; +} + // client singleton for AudioPolicyService binder interface // protected by gLockAPS sp AudioSystem::gAudioPolicyService; @@ -1223,6 +1234,32 @@ void AudioSystem::AudioPolicyServiceClient::onDynamicPolicyMixStateUpdate( } } +// --------------------------------------------------------------------------- + +status_t AudioSystem::listAudioSessions(audio_stream_type_t stream, + Vector< sp> &sessions) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->listAudioSessions(stream, sessions); +} + +void AudioSystem::AudioPolicyServiceClient::onOutputSessionEffectsUpdate( + sp& info, bool added) +{ + ALOGV("AudioPolicyServiceClient::onOutputSessionEffectsUpdate(%d, %d, %d)", + info->mStream, info->mSessionId, added); + audio_session_callback cb = NULL; + { + Mutex::Autolock _l(AudioSystem::gLock); + cb = gAudioSessionCallback; + } + + if (cb != NULL) { + cb(AUDIO_OUTPUT_SESSION_EFFECTS_UPDATE, info, added); + } +} + void AudioSystem::AudioPolicyServiceClient::binderDied(const wp& who __unused) { { diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index 76b5924..abae614 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -74,6 +74,7 @@ enum { START_AUDIO_SOURCE, STOP_AUDIO_SOURCE, SET_AUDIO_PORT_CALLBACK_ENABLED, + LIST_AUDIO_SESSIONS, }; #define MAX_ITEMS_PER_LIST 1024 @@ -767,6 +768,30 @@ public: status = (status_t)reply.readInt32(); return status; } + + virtual status_t listAudioSessions(audio_stream_type_t streams, + Vector< sp> &sessions) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.writeInt32(streams); + status_t status = remote()->transact(LIST_AUDIO_SESSIONS, data, &reply); + if (status != NO_ERROR) { + return status; + } + + status = reply.readInt32(); + if (status == NO_ERROR) { + size_t size = (size_t)reply.readUint32(); + for (size_t i = 0; i < size && reply.dataAvail() > 0; i++) { + sp info = new AudioSessionInfo(); + info->readFromParcel(reply); + sessions.push_back(info); + } + } + return status; + } + }; IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService"); @@ -1238,6 +1263,23 @@ status_t BnAudioPolicyService::onTransact( return NO_ERROR; } break; + case LIST_AUDIO_SESSIONS: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + audio_stream_type_t streams = (audio_stream_type_t)data.readInt32(); + + Vector< sp> sessions; + status_t status = listAudioSessions(streams, sessions); + + reply->writeInt32(status); + if (status == NO_ERROR) { + reply->writeUint32(static_cast(sessions.size())); + for (size_t i = 0; i < sessions.size(); i++) { + sessions[i]->writeToParcel(reply); + } + } + return NO_ERROR; + } + case ACQUIRE_SOUNDTRIGGER_SESSION: { CHECK_INTERFACE(IAudioPolicyService, data, reply); sp client = interface_cast( diff --git a/media/libmedia/IAudioPolicyServiceClient.cpp b/media/libmedia/IAudioPolicyServiceClient.cpp index 65cc7d6..a325996 100644 --- a/media/libmedia/IAudioPolicyServiceClient.cpp +++ b/media/libmedia/IAudioPolicyServiceClient.cpp @@ -30,7 +30,8 @@ namespace android { enum { PORT_LIST_UPDATE = IBinder::FIRST_CALL_TRANSACTION, PATCH_LIST_UPDATE, - MIX_STATE_UPDATE + MIX_STATE_UPDATE, + OUTPUT_SESSION_EFFECTS_UPDATE }; class BpAudioPolicyServiceClient : public BpInterface @@ -63,6 +64,19 @@ public: data.writeInt32(state); remote()->transact(MIX_STATE_UPDATE, data, &reply, IBinder::FLAG_ONEWAY); } + + void onOutputSessionEffectsUpdate(sp& info, bool added) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyServiceClient::getInterfaceDescriptor()); + data.writeInt32(info->mStream); + data.writeInt32(info->mSessionId); + data.writeInt32(info->mFlags); + data.writeInt32(info->mChannelMask); + data.writeInt32(info->mUid); + data.writeInt32(added ? 1 : 0); + remote()->transact(OUTPUT_SESSION_EFFECTS_UPDATE, data, &reply, IBinder::FLAG_ONEWAY); + } }; IMPLEMENT_META_INTERFACE(AudioPolicyServiceClient, "android.media.IAudioPolicyServiceClient"); @@ -90,6 +104,20 @@ status_t BnAudioPolicyServiceClient::onTransact( onDynamicPolicyMixStateUpdate(regId, state); return NO_ERROR; } + case OUTPUT_SESSION_EFFECTS_UPDATE: { + CHECK_INTERFACE(IAudioPolicyServiceClient, data, reply); + audio_stream_type_t stream = static_cast(data.readInt32()); + audio_session_t sessionId = static_cast(data.readInt32()); + audio_output_flags_t flags = static_cast(data.readInt32()); + audio_channel_mask_t channelMask = static_cast(data.readInt32()); + uid_t uid = static_cast(data.readInt32()); + bool added = data.readInt32() > 0; + + sp info = new AudioSessionInfo( + sessionId, stream, flags, channelMask, uid); + onOutputSessionEffectsUpdate(info, added); + return NO_ERROR; + } default: return BBinder::onTransact(code, data, reply, flags); } -- cgit v1.1