Loading include/media/AudioIoDescriptor.h 0 → 100644 +52 −0 Original line number Diff line number Diff line /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_AUDIO_IO_DESCRIPTOR_H #define ANDROID_AUDIO_IO_DESCRIPTOR_H namespace android { enum audio_io_config_event { AUDIO_OUTPUT_OPENED, AUDIO_OUTPUT_CLOSED, AUDIO_OUTPUT_CONFIG_CHANGED, AUDIO_INPUT_OPENED, AUDIO_INPUT_CLOSED, AUDIO_INPUT_CONFIG_CHANGED, }; // audio input/output descriptor used to cache output configurations in client process to avoid // frequent calls through IAudioFlinger class AudioIoDescriptor : public RefBase { public: AudioIoDescriptor() : mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(AUDIO_CHANNEL_NONE), mFrameCount(0), mLatency(0) {} virtual ~AudioIoDescriptor() {} audio_io_handle_t mIoHandle; uint32_t mSamplingRate; audio_format_t mFormat; audio_channel_mask_t mChannelMask; size_t mFrameCount; uint32_t mLatency; }; }; // namespace android #endif /*ANDROID_AUDIO_IO_DESCRIPTOR_H*/ include/media/AudioSystem.h +20 −35 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <hardware/audio_effect.h> #include <media/AudioPolicy.h> #include <media/AudioIoDescriptor.h> #include <media/IAudioFlingerClient.h> #include <media/IAudioPolicyServiceClient.h> #include <system/audio.h> Loading Loading @@ -157,33 +158,6 @@ public: // or no HW sync source is used. static audio_hw_sync_t getAudioHwSyncForSession(audio_session_t sessionId); // types of io configuration change events received with ioConfigChanged() enum io_config_event { OUTPUT_OPENED, OUTPUT_CLOSED, OUTPUT_CONFIG_CHANGED, INPUT_OPENED, INPUT_CLOSED, INPUT_CONFIG_CHANGED, STREAM_CONFIG_CHANGED, NUM_CONFIG_EVENTS }; // audio output descriptor used to cache output configurations in client process to avoid // frequent calls through IAudioFlinger class OutputDescriptor { public: OutputDescriptor() : samplingRate(0), format(AUDIO_FORMAT_DEFAULT), channelMask(0), frameCount(0), latency(0) {} uint32_t samplingRate; audio_format_t format; audio_channel_mask_t channelMask; size_t frameCount; uint32_t latency; }; // Events used to synchronize actions between audio sessions. // For instance SYNC_EVENT_PRESENTATION_COMPLETE can be used to delay recording start until // playback is complete on another audio session. Loading Loading @@ -366,9 +340,16 @@ private: class AudioFlingerClient: public IBinder::DeathRecipient, public BnAudioFlingerClient { public: AudioFlingerClient() { AudioFlingerClient() : mInBuffSize(0), mInSamplingRate(0), mInFormat(AUDIO_FORMAT_DEFAULT), mInChannelMask(AUDIO_CHANNEL_NONE) { } void clearIoCache(); status_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, size_t* buffSize); sp<AudioIoDescriptor> getIoDescriptor(audio_io_handle_t ioHandle); // DeathRecipient virtual void binderDied(const wp<IBinder>& who); Loading @@ -376,7 +357,17 @@ private: // indicate a change in the configuration of an output or input: keeps the cached // values for output/input parameters up-to-date in client process virtual void ioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2); virtual void ioConfigChanged(audio_io_config_event event, const sp<AudioIoDescriptor>& ioDesc); private: Mutex mLock; DefaultKeyedVector<audio_io_handle_t, sp<AudioIoDescriptor> > mIoDescriptors; // cached values for recording getInputBufferSize() queries size_t mInBuffSize; // zero indicates cache is invalid uint32_t mInSamplingRate; audio_format_t mInFormat; audio_channel_mask_t mInChannelMask; }; class AudioPolicyServiceClient: public IBinder::DeathRecipient, Loading Loading @@ -408,8 +399,6 @@ private: friend class AudioPolicyServiceClient; static Mutex gLock; // protects gAudioFlinger and gAudioErrorCallback, static Mutex gLockCache; // protects gOutputs, gPrevInSamplingRate, gPrevInFormat, // gPrevInChannelMask and gInBuffSize static Mutex gLockAPS; // protects gAudioPolicyService and gAudioPolicyServiceClient static sp<IAudioFlinger> gAudioFlinger; static audio_error_callback gAudioErrorCallback; Loading @@ -422,10 +411,6 @@ private: static audio_channel_mask_t gPrevInChannelMask; static sp<IAudioPolicyService> gAudioPolicyService; // list of output descriptors containing cached parameters // (sampling rate, framecount, channel count...) static DefaultKeyedVector<audio_io_handle_t, OutputDescriptor *> gOutputs; }; }; // namespace android Loading include/media/IAudioFlingerClient.h +3 −1 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <binder/IInterface.h> #include <utils/KeyedVector.h> #include <system/audio.h> #include <media/AudioIoDescriptor.h> namespace android { Loading @@ -33,7 +34,8 @@ public: DECLARE_META_INTERFACE(AudioFlingerClient); // Notifies a change of audio input/output configuration. virtual void ioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2) = 0; virtual void ioConfigChanged(audio_io_config_event event, const sp<AudioIoDescriptor>& ioDesc) = 0; }; Loading media/libmedia/AudioSystem.cpp +102 −108 Original line number Diff line number Diff line Loading @@ -32,21 +32,12 @@ namespace android { // client singleton for AudioFlinger binder interface Mutex AudioSystem::gLock; Mutex AudioSystem::gLockCache; Mutex AudioSystem::gLockAPS; sp<IAudioFlinger> AudioSystem::gAudioFlinger; sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient; audio_error_callback AudioSystem::gAudioErrorCallback = NULL; dynamic_policy_callback AudioSystem::gDynPolicyCallback = NULL; // Cached values for output handles DefaultKeyedVector<audio_io_handle_t, AudioSystem::OutputDescriptor *> AudioSystem::gOutputs(NULL); // Cached values for recording queries, all protected by gLock uint32_t AudioSystem::gPrevInSamplingRate; audio_format_t AudioSystem::gPrevInFormat; audio_channel_mask_t AudioSystem::gPrevInChannelMask; size_t AudioSystem::gInBuffSize = 0; // zero indicates cache is invalid // establish binder interface to AudioFlinger service const sp<IAudioFlinger> AudioSystem::get_audio_flinger() Loading Loading @@ -259,17 +250,14 @@ status_t AudioSystem::getSamplingRate(audio_io_handle_t output, const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; Mutex::Autolock _l(gLockCache); OutputDescriptor *outputDesc = AudioSystem::gOutputs.valueFor(output); if (outputDesc == NULL) { LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0); sp<AudioIoDescriptor> outputDesc = gAudioFlingerClient->getIoDescriptor(output); if (outputDesc == 0) { ALOGV("getOutputSamplingRate() no output descriptor for output %d in gOutputs", output); gLockCache.unlock(); *samplingRate = af->sampleRate(output); gLockCache.lock(); } else { ALOGV("getOutputSamplingRate() reading from output desc"); *samplingRate = outputDesc->samplingRate; *samplingRate = outputDesc->mSamplingRate; } if (*samplingRate == 0) { ALOGE("AudioSystem::getSamplingRate failed for output %d", output); Loading Loading @@ -303,15 +291,12 @@ status_t AudioSystem::getFrameCount(audio_io_handle_t output, const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; Mutex::Autolock _l(gLockCache); OutputDescriptor *outputDesc = AudioSystem::gOutputs.valueFor(output); if (outputDesc == NULL) { gLockCache.unlock(); LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0); sp<AudioIoDescriptor> outputDesc = gAudioFlingerClient->getIoDescriptor(output); if (outputDesc == 0) { *frameCount = af->frameCount(output); gLockCache.lock(); } else { *frameCount = outputDesc->frameCount; *frameCount = outputDesc->mFrameCount; } if (*frameCount == 0) { ALOGE("AudioSystem::getFrameCount failed for output %d", output); Loading Loading @@ -345,15 +330,12 @@ status_t AudioSystem::getLatency(audio_io_handle_t output, const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; Mutex::Autolock _l(gLockCache); OutputDescriptor *outputDesc = AudioSystem::gOutputs.valueFor(output); if (outputDesc == NULL) { gLockCache.unlock(); LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0); sp<AudioIoDescriptor> outputDesc = gAudioFlingerClient->getIoDescriptor(output); if (outputDesc == 0) { *latency = af->latency(output); gLockCache.lock(); } else { *latency = outputDesc->latency; *latency = outputDesc->mLatency; } ALOGV("getLatency() output %d, latency %d", output, *latency); Loading @@ -365,33 +347,9 @@ status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, audio_format_t for audio_channel_mask_t channelMask, size_t* buffSize) { const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) { return PERMISSION_DENIED; } Mutex::Autolock _l(gLockCache); // Do we have a stale gInBufferSize or are we requesting the input buffer size for new values size_t inBuffSize = gInBuffSize; if ((inBuffSize == 0) || (sampleRate != gPrevInSamplingRate) || (format != gPrevInFormat) || (channelMask != gPrevInChannelMask)) { gLockCache.unlock(); inBuffSize = af->getInputBufferSize(sampleRate, format, channelMask); gLockCache.lock(); if (inBuffSize == 0) { ALOGE("AudioSystem::getInputBufferSize failed sampleRate %d format %#x channelMask %x", sampleRate, format, channelMask); return BAD_VALUE; } // A benign race is possible here: we could overwrite a fresher cache entry // save the request params gPrevInSamplingRate = sampleRate; gPrevInFormat = format; gPrevInChannelMask = channelMask; gInBuffSize = inBuffSize; } *buffSize = inBuffSize; return NO_ERROR; if (af == 0) return PERMISSION_DENIED; LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0); return gAudioFlingerClient->getInputBufferSize(sampleRate, format, channelMask, buffSize); } status_t AudioSystem::setVoiceVolume(float value) Loading Loading @@ -453,6 +411,17 @@ audio_hw_sync_t AudioSystem::getAudioHwSyncForSession(audio_session_t sessionId) // --------------------------------------------------------------------------- void AudioSystem::AudioFlingerClient::clearIoCache() { Mutex::Autolock _l(mLock); mIoDescriptors.clear(); mInBuffSize = 0; mInSamplingRate = 0; mInFormat = AUDIO_FORMAT_DEFAULT; mInChannelMask = AUDIO_CHANNEL_NONE; } void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who __unused) { audio_error_callback cb = NULL; Loading @@ -462,11 +431,8 @@ void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who __unused cb = gAudioErrorCallback; } { // clear output handles and stream to output map caches Mutex::Autolock _l(gLockCache); AudioSystem::gOutputs.clear(); } clearIoCache(); if (cb) { cb(DEAD_OBJECT); Loading @@ -474,67 +440,96 @@ void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who __unused ALOGW("AudioFlinger server died!"); } void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2) { void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event event, const sp<AudioIoDescriptor>& ioDesc) { ALOGV("ioConfigChanged() event %d", event); const OutputDescriptor *desc; if (ioHandle == AUDIO_IO_HANDLE_NONE) return; if (ioDesc == 0 || ioDesc->mIoHandle == AUDIO_IO_HANDLE_NONE) return; Mutex::Autolock _l(AudioSystem::gLockCache); Mutex::Autolock _l(mLock); switch (event) { case STREAM_CONFIG_CHANGED: break; case OUTPUT_OPENED: { if (gOutputs.indexOfKey(ioHandle) >= 0) { ALOGV("ioConfigChanged() opening already existing output! %d", ioHandle); case AUDIO_OUTPUT_OPENED: case AUDIO_INPUT_OPENED: { if (getIoDescriptor(ioDesc->mIoHandle) != 0) { ALOGV("ioConfigChanged() opening already existing output! %d", ioDesc->mIoHandle); break; } if (param2 == NULL) break; desc = (const OutputDescriptor *)param2; OutputDescriptor *outputDesc = new OutputDescriptor(*desc); gOutputs.add(ioHandle, outputDesc); ALOGV("ioConfigChanged() new output samplingRate %u, format %#x channel mask %#x " "frameCount %zu latency %d", outputDesc->samplingRate, outputDesc->format, outputDesc->channelMask, outputDesc->frameCount, outputDesc->latency); mIoDescriptors.add(ioDesc->mIoHandle, ioDesc); ALOGV("ioConfigChanged() new %s opened %d samplingRate %u, format %#x channel mask %#x " "frameCount %zu", event == AUDIO_OUTPUT_OPENED ? "output" : "input", ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat, ioDesc->mChannelMask, ioDesc->mFrameCount); } break; case OUTPUT_CLOSED: { if (gOutputs.indexOfKey(ioHandle) < 0) { ALOGW("ioConfigChanged() closing unknown output! %d", ioHandle); case AUDIO_OUTPUT_CLOSED: case AUDIO_INPUT_CLOSED: { if (getIoDescriptor(ioDesc->mIoHandle) == 0) { ALOGW("ioConfigChanged() closing unknown %s %d", event == AUDIO_OUTPUT_CLOSED ? "output" : "input", ioDesc->mIoHandle); break; } ALOGV("ioConfigChanged() output %d closed", ioHandle); ALOGV("ioConfigChanged() %s %d closed", event == AUDIO_OUTPUT_CLOSED ? "output" : "input", ioDesc->mIoHandle); gOutputs.removeItem(ioHandle); mIoDescriptors.removeItem(ioDesc->mIoHandle); } break; case OUTPUT_CONFIG_CHANGED: { int index = gOutputs.indexOfKey(ioHandle); if (index < 0) { ALOGW("ioConfigChanged() modifying unknown output! %d", ioHandle); case AUDIO_OUTPUT_CONFIG_CHANGED: case AUDIO_INPUT_CONFIG_CHANGED: { if (getIoDescriptor(ioDesc->mIoHandle) == 0) { ALOGW("ioConfigChanged() modifying unknown output! %d", ioDesc->mIoHandle); break; } if (param2 == NULL) break; desc = (const OutputDescriptor *)param2; ALOGV("ioConfigChanged() new config for output %d samplingRate %u, format %#x " "channel mask %#x frameCount %zu latency %d", ioHandle, desc->samplingRate, desc->format, desc->channelMask, desc->frameCount, desc->latency); OutputDescriptor *outputDesc = gOutputs.valueAt(index); delete outputDesc; outputDesc = new OutputDescriptor(*desc); gOutputs.replaceValueFor(ioHandle, outputDesc); mIoDescriptors.replaceValueFor(ioDesc->mIoHandle, ioDesc); ALOGV("ioConfigChanged() new config for %s %d samplingRate %u, format %#x " "channel mask %#x frameCount %zu", event == AUDIO_OUTPUT_CONFIG_CHANGED ? "output" : "input", ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat, ioDesc->mChannelMask, ioDesc->mFrameCount); } break; case INPUT_OPENED: case INPUT_CLOSED: case INPUT_CONFIG_CHANGED: break; } } status_t AudioSystem::AudioFlingerClient::getInputBufferSize( uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, size_t* buffSize) { const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) { return PERMISSION_DENIED; } Mutex::Autolock _l(mLock); // Do we have a stale mInBuffSize or are we requesting the input buffer size for new values if ((mInBuffSize == 0) || (sampleRate != mInSamplingRate) || (format != mInFormat) || (channelMask != mInChannelMask)) { size_t inBuffSize = af->getInputBufferSize(sampleRate, format, channelMask); if (inBuffSize == 0) { ALOGE("AudioSystem::getInputBufferSize failed sampleRate %d format %#x channelMask %x", sampleRate, format, channelMask); return BAD_VALUE; } // A benign race is possible here: we could overwrite a fresher cache entry // save the request params mInSamplingRate = sampleRate; mInFormat = format; mInChannelMask = channelMask; mInBuffSize = inBuffSize; } *buffSize = mInBuffSize; return NO_ERROR; } sp<AudioIoDescriptor> AudioSystem::AudioFlingerClient::getIoDescriptor(audio_io_handle_t ioHandle) { sp<AudioIoDescriptor> desc; ssize_t index = mIoDescriptors.indexOfKey(ioHandle); if (index >= 0) { desc = mIoDescriptors.valueAt(index); } return desc; } /*static*/ void AudioSystem::setErrorCallback(audio_error_callback cb) Loading Loading @@ -869,9 +864,8 @@ void AudioSystem::clearAudioConfigCache() { // called by restoreTrack_l(), which needs new IAudioFlinger and IAudioPolicyService instances ALOGV("clearAudioConfigCache()"); { Mutex::Autolock _l(gLockCache); gOutputs.clear(); if (gAudioFlingerClient != 0) { gAudioFlingerClient->clearIoCache(); } { Mutex::Autolock _l(gLock); Loading media/libmedia/IAudioFlingerClient.cpp +16 −33 Original line number Diff line number Diff line Loading @@ -39,25 +39,17 @@ public: { } void ioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2) void ioConfigChanged(audio_io_config_event event, const sp<AudioIoDescriptor>& ioDesc) { Parcel data, reply; data.writeInterfaceToken(IAudioFlingerClient::getInterfaceDescriptor()); data.writeInt32(event); data.writeInt32((int32_t) ioHandle); if (event == AudioSystem::STREAM_CONFIG_CHANGED) { uint32_t stream = *(const uint32_t *)param2; ALOGV("ioConfigChanged stream %d", stream); data.writeInt32(stream); } else if (event != AudioSystem::OUTPUT_CLOSED && event != AudioSystem::INPUT_CLOSED) { const AudioSystem::OutputDescriptor *desc = (const AudioSystem::OutputDescriptor *)param2; data.writeInt32(desc->samplingRate); data.writeInt32(desc->format); data.writeInt32(desc->channelMask); data.writeInt64(desc->frameCount); data.writeInt32(desc->latency); } data.writeInt32((int32_t)ioDesc->mIoHandle); data.writeInt32(ioDesc->mSamplingRate); data.writeInt32(ioDesc->mFormat); data.writeInt32(ioDesc->mChannelMask); data.writeInt64(ioDesc->mFrameCount); data.writeInt32(ioDesc->mLatency); remote()->transact(IO_CONFIG_CHANGED, data, &reply, IBinder::FLAG_ONEWAY); } }; Loading @@ -72,24 +64,15 @@ status_t BnAudioFlingerClient::onTransact( switch (code) { case IO_CONFIG_CHANGED: { CHECK_INTERFACE(IAudioFlingerClient, data, reply); int event = data.readInt32(); audio_io_handle_t ioHandle = (audio_io_handle_t) data.readInt32(); const void *param2 = NULL; AudioSystem::OutputDescriptor desc; uint32_t stream; if (event == AudioSystem::STREAM_CONFIG_CHANGED) { stream = data.readInt32(); param2 = &stream; ALOGV("STREAM_CONFIG_CHANGED stream %d", stream); } else if (event != AudioSystem::OUTPUT_CLOSED && event != AudioSystem::INPUT_CLOSED) { desc.samplingRate = data.readInt32(); desc.format = (audio_format_t) data.readInt32(); desc.channelMask = (audio_channel_mask_t) data.readInt32(); desc.frameCount = data.readInt64(); desc.latency = data.readInt32(); param2 = &desc; } ioConfigChanged(event, ioHandle, param2); audio_io_config_event event = (audio_io_config_event)data.readInt32(); sp<AudioIoDescriptor> ioDesc = new AudioIoDescriptor(); ioDesc->mIoHandle = (audio_io_handle_t) data.readInt32(); ioDesc->mSamplingRate = data.readInt32(); ioDesc->mFormat = (audio_format_t) data.readInt32(); ioDesc->mChannelMask = (audio_channel_mask_t) data.readInt32(); ioDesc->mFrameCount = data.readInt64(); ioDesc->mLatency = data.readInt32(); ioConfigChanged(event, ioDesc); return NO_ERROR; } break; default: Loading Loading
include/media/AudioIoDescriptor.h 0 → 100644 +52 −0 Original line number Diff line number Diff line /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_AUDIO_IO_DESCRIPTOR_H #define ANDROID_AUDIO_IO_DESCRIPTOR_H namespace android { enum audio_io_config_event { AUDIO_OUTPUT_OPENED, AUDIO_OUTPUT_CLOSED, AUDIO_OUTPUT_CONFIG_CHANGED, AUDIO_INPUT_OPENED, AUDIO_INPUT_CLOSED, AUDIO_INPUT_CONFIG_CHANGED, }; // audio input/output descriptor used to cache output configurations in client process to avoid // frequent calls through IAudioFlinger class AudioIoDescriptor : public RefBase { public: AudioIoDescriptor() : mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(AUDIO_CHANNEL_NONE), mFrameCount(0), mLatency(0) {} virtual ~AudioIoDescriptor() {} audio_io_handle_t mIoHandle; uint32_t mSamplingRate; audio_format_t mFormat; audio_channel_mask_t mChannelMask; size_t mFrameCount; uint32_t mLatency; }; }; // namespace android #endif /*ANDROID_AUDIO_IO_DESCRIPTOR_H*/
include/media/AudioSystem.h +20 −35 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <hardware/audio_effect.h> #include <media/AudioPolicy.h> #include <media/AudioIoDescriptor.h> #include <media/IAudioFlingerClient.h> #include <media/IAudioPolicyServiceClient.h> #include <system/audio.h> Loading Loading @@ -157,33 +158,6 @@ public: // or no HW sync source is used. static audio_hw_sync_t getAudioHwSyncForSession(audio_session_t sessionId); // types of io configuration change events received with ioConfigChanged() enum io_config_event { OUTPUT_OPENED, OUTPUT_CLOSED, OUTPUT_CONFIG_CHANGED, INPUT_OPENED, INPUT_CLOSED, INPUT_CONFIG_CHANGED, STREAM_CONFIG_CHANGED, NUM_CONFIG_EVENTS }; // audio output descriptor used to cache output configurations in client process to avoid // frequent calls through IAudioFlinger class OutputDescriptor { public: OutputDescriptor() : samplingRate(0), format(AUDIO_FORMAT_DEFAULT), channelMask(0), frameCount(0), latency(0) {} uint32_t samplingRate; audio_format_t format; audio_channel_mask_t channelMask; size_t frameCount; uint32_t latency; }; // Events used to synchronize actions between audio sessions. // For instance SYNC_EVENT_PRESENTATION_COMPLETE can be used to delay recording start until // playback is complete on another audio session. Loading Loading @@ -366,9 +340,16 @@ private: class AudioFlingerClient: public IBinder::DeathRecipient, public BnAudioFlingerClient { public: AudioFlingerClient() { AudioFlingerClient() : mInBuffSize(0), mInSamplingRate(0), mInFormat(AUDIO_FORMAT_DEFAULT), mInChannelMask(AUDIO_CHANNEL_NONE) { } void clearIoCache(); status_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, size_t* buffSize); sp<AudioIoDescriptor> getIoDescriptor(audio_io_handle_t ioHandle); // DeathRecipient virtual void binderDied(const wp<IBinder>& who); Loading @@ -376,7 +357,17 @@ private: // indicate a change in the configuration of an output or input: keeps the cached // values for output/input parameters up-to-date in client process virtual void ioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2); virtual void ioConfigChanged(audio_io_config_event event, const sp<AudioIoDescriptor>& ioDesc); private: Mutex mLock; DefaultKeyedVector<audio_io_handle_t, sp<AudioIoDescriptor> > mIoDescriptors; // cached values for recording getInputBufferSize() queries size_t mInBuffSize; // zero indicates cache is invalid uint32_t mInSamplingRate; audio_format_t mInFormat; audio_channel_mask_t mInChannelMask; }; class AudioPolicyServiceClient: public IBinder::DeathRecipient, Loading Loading @@ -408,8 +399,6 @@ private: friend class AudioPolicyServiceClient; static Mutex gLock; // protects gAudioFlinger and gAudioErrorCallback, static Mutex gLockCache; // protects gOutputs, gPrevInSamplingRate, gPrevInFormat, // gPrevInChannelMask and gInBuffSize static Mutex gLockAPS; // protects gAudioPolicyService and gAudioPolicyServiceClient static sp<IAudioFlinger> gAudioFlinger; static audio_error_callback gAudioErrorCallback; Loading @@ -422,10 +411,6 @@ private: static audio_channel_mask_t gPrevInChannelMask; static sp<IAudioPolicyService> gAudioPolicyService; // list of output descriptors containing cached parameters // (sampling rate, framecount, channel count...) static DefaultKeyedVector<audio_io_handle_t, OutputDescriptor *> gOutputs; }; }; // namespace android Loading
include/media/IAudioFlingerClient.h +3 −1 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <binder/IInterface.h> #include <utils/KeyedVector.h> #include <system/audio.h> #include <media/AudioIoDescriptor.h> namespace android { Loading @@ -33,7 +34,8 @@ public: DECLARE_META_INTERFACE(AudioFlingerClient); // Notifies a change of audio input/output configuration. virtual void ioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2) = 0; virtual void ioConfigChanged(audio_io_config_event event, const sp<AudioIoDescriptor>& ioDesc) = 0; }; Loading
media/libmedia/AudioSystem.cpp +102 −108 Original line number Diff line number Diff line Loading @@ -32,21 +32,12 @@ namespace android { // client singleton for AudioFlinger binder interface Mutex AudioSystem::gLock; Mutex AudioSystem::gLockCache; Mutex AudioSystem::gLockAPS; sp<IAudioFlinger> AudioSystem::gAudioFlinger; sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient; audio_error_callback AudioSystem::gAudioErrorCallback = NULL; dynamic_policy_callback AudioSystem::gDynPolicyCallback = NULL; // Cached values for output handles DefaultKeyedVector<audio_io_handle_t, AudioSystem::OutputDescriptor *> AudioSystem::gOutputs(NULL); // Cached values for recording queries, all protected by gLock uint32_t AudioSystem::gPrevInSamplingRate; audio_format_t AudioSystem::gPrevInFormat; audio_channel_mask_t AudioSystem::gPrevInChannelMask; size_t AudioSystem::gInBuffSize = 0; // zero indicates cache is invalid // establish binder interface to AudioFlinger service const sp<IAudioFlinger> AudioSystem::get_audio_flinger() Loading Loading @@ -259,17 +250,14 @@ status_t AudioSystem::getSamplingRate(audio_io_handle_t output, const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; Mutex::Autolock _l(gLockCache); OutputDescriptor *outputDesc = AudioSystem::gOutputs.valueFor(output); if (outputDesc == NULL) { LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0); sp<AudioIoDescriptor> outputDesc = gAudioFlingerClient->getIoDescriptor(output); if (outputDesc == 0) { ALOGV("getOutputSamplingRate() no output descriptor for output %d in gOutputs", output); gLockCache.unlock(); *samplingRate = af->sampleRate(output); gLockCache.lock(); } else { ALOGV("getOutputSamplingRate() reading from output desc"); *samplingRate = outputDesc->samplingRate; *samplingRate = outputDesc->mSamplingRate; } if (*samplingRate == 0) { ALOGE("AudioSystem::getSamplingRate failed for output %d", output); Loading Loading @@ -303,15 +291,12 @@ status_t AudioSystem::getFrameCount(audio_io_handle_t output, const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; Mutex::Autolock _l(gLockCache); OutputDescriptor *outputDesc = AudioSystem::gOutputs.valueFor(output); if (outputDesc == NULL) { gLockCache.unlock(); LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0); sp<AudioIoDescriptor> outputDesc = gAudioFlingerClient->getIoDescriptor(output); if (outputDesc == 0) { *frameCount = af->frameCount(output); gLockCache.lock(); } else { *frameCount = outputDesc->frameCount; *frameCount = outputDesc->mFrameCount; } if (*frameCount == 0) { ALOGE("AudioSystem::getFrameCount failed for output %d", output); Loading Loading @@ -345,15 +330,12 @@ status_t AudioSystem::getLatency(audio_io_handle_t output, const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; Mutex::Autolock _l(gLockCache); OutputDescriptor *outputDesc = AudioSystem::gOutputs.valueFor(output); if (outputDesc == NULL) { gLockCache.unlock(); LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0); sp<AudioIoDescriptor> outputDesc = gAudioFlingerClient->getIoDescriptor(output); if (outputDesc == 0) { *latency = af->latency(output); gLockCache.lock(); } else { *latency = outputDesc->latency; *latency = outputDesc->mLatency; } ALOGV("getLatency() output %d, latency %d", output, *latency); Loading @@ -365,33 +347,9 @@ status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, audio_format_t for audio_channel_mask_t channelMask, size_t* buffSize) { const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) { return PERMISSION_DENIED; } Mutex::Autolock _l(gLockCache); // Do we have a stale gInBufferSize or are we requesting the input buffer size for new values size_t inBuffSize = gInBuffSize; if ((inBuffSize == 0) || (sampleRate != gPrevInSamplingRate) || (format != gPrevInFormat) || (channelMask != gPrevInChannelMask)) { gLockCache.unlock(); inBuffSize = af->getInputBufferSize(sampleRate, format, channelMask); gLockCache.lock(); if (inBuffSize == 0) { ALOGE("AudioSystem::getInputBufferSize failed sampleRate %d format %#x channelMask %x", sampleRate, format, channelMask); return BAD_VALUE; } // A benign race is possible here: we could overwrite a fresher cache entry // save the request params gPrevInSamplingRate = sampleRate; gPrevInFormat = format; gPrevInChannelMask = channelMask; gInBuffSize = inBuffSize; } *buffSize = inBuffSize; return NO_ERROR; if (af == 0) return PERMISSION_DENIED; LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0); return gAudioFlingerClient->getInputBufferSize(sampleRate, format, channelMask, buffSize); } status_t AudioSystem::setVoiceVolume(float value) Loading Loading @@ -453,6 +411,17 @@ audio_hw_sync_t AudioSystem::getAudioHwSyncForSession(audio_session_t sessionId) // --------------------------------------------------------------------------- void AudioSystem::AudioFlingerClient::clearIoCache() { Mutex::Autolock _l(mLock); mIoDescriptors.clear(); mInBuffSize = 0; mInSamplingRate = 0; mInFormat = AUDIO_FORMAT_DEFAULT; mInChannelMask = AUDIO_CHANNEL_NONE; } void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who __unused) { audio_error_callback cb = NULL; Loading @@ -462,11 +431,8 @@ void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who __unused cb = gAudioErrorCallback; } { // clear output handles and stream to output map caches Mutex::Autolock _l(gLockCache); AudioSystem::gOutputs.clear(); } clearIoCache(); if (cb) { cb(DEAD_OBJECT); Loading @@ -474,67 +440,96 @@ void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who __unused ALOGW("AudioFlinger server died!"); } void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2) { void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event event, const sp<AudioIoDescriptor>& ioDesc) { ALOGV("ioConfigChanged() event %d", event); const OutputDescriptor *desc; if (ioHandle == AUDIO_IO_HANDLE_NONE) return; if (ioDesc == 0 || ioDesc->mIoHandle == AUDIO_IO_HANDLE_NONE) return; Mutex::Autolock _l(AudioSystem::gLockCache); Mutex::Autolock _l(mLock); switch (event) { case STREAM_CONFIG_CHANGED: break; case OUTPUT_OPENED: { if (gOutputs.indexOfKey(ioHandle) >= 0) { ALOGV("ioConfigChanged() opening already existing output! %d", ioHandle); case AUDIO_OUTPUT_OPENED: case AUDIO_INPUT_OPENED: { if (getIoDescriptor(ioDesc->mIoHandle) != 0) { ALOGV("ioConfigChanged() opening already existing output! %d", ioDesc->mIoHandle); break; } if (param2 == NULL) break; desc = (const OutputDescriptor *)param2; OutputDescriptor *outputDesc = new OutputDescriptor(*desc); gOutputs.add(ioHandle, outputDesc); ALOGV("ioConfigChanged() new output samplingRate %u, format %#x channel mask %#x " "frameCount %zu latency %d", outputDesc->samplingRate, outputDesc->format, outputDesc->channelMask, outputDesc->frameCount, outputDesc->latency); mIoDescriptors.add(ioDesc->mIoHandle, ioDesc); ALOGV("ioConfigChanged() new %s opened %d samplingRate %u, format %#x channel mask %#x " "frameCount %zu", event == AUDIO_OUTPUT_OPENED ? "output" : "input", ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat, ioDesc->mChannelMask, ioDesc->mFrameCount); } break; case OUTPUT_CLOSED: { if (gOutputs.indexOfKey(ioHandle) < 0) { ALOGW("ioConfigChanged() closing unknown output! %d", ioHandle); case AUDIO_OUTPUT_CLOSED: case AUDIO_INPUT_CLOSED: { if (getIoDescriptor(ioDesc->mIoHandle) == 0) { ALOGW("ioConfigChanged() closing unknown %s %d", event == AUDIO_OUTPUT_CLOSED ? "output" : "input", ioDesc->mIoHandle); break; } ALOGV("ioConfigChanged() output %d closed", ioHandle); ALOGV("ioConfigChanged() %s %d closed", event == AUDIO_OUTPUT_CLOSED ? "output" : "input", ioDesc->mIoHandle); gOutputs.removeItem(ioHandle); mIoDescriptors.removeItem(ioDesc->mIoHandle); } break; case OUTPUT_CONFIG_CHANGED: { int index = gOutputs.indexOfKey(ioHandle); if (index < 0) { ALOGW("ioConfigChanged() modifying unknown output! %d", ioHandle); case AUDIO_OUTPUT_CONFIG_CHANGED: case AUDIO_INPUT_CONFIG_CHANGED: { if (getIoDescriptor(ioDesc->mIoHandle) == 0) { ALOGW("ioConfigChanged() modifying unknown output! %d", ioDesc->mIoHandle); break; } if (param2 == NULL) break; desc = (const OutputDescriptor *)param2; ALOGV("ioConfigChanged() new config for output %d samplingRate %u, format %#x " "channel mask %#x frameCount %zu latency %d", ioHandle, desc->samplingRate, desc->format, desc->channelMask, desc->frameCount, desc->latency); OutputDescriptor *outputDesc = gOutputs.valueAt(index); delete outputDesc; outputDesc = new OutputDescriptor(*desc); gOutputs.replaceValueFor(ioHandle, outputDesc); mIoDescriptors.replaceValueFor(ioDesc->mIoHandle, ioDesc); ALOGV("ioConfigChanged() new config for %s %d samplingRate %u, format %#x " "channel mask %#x frameCount %zu", event == AUDIO_OUTPUT_CONFIG_CHANGED ? "output" : "input", ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat, ioDesc->mChannelMask, ioDesc->mFrameCount); } break; case INPUT_OPENED: case INPUT_CLOSED: case INPUT_CONFIG_CHANGED: break; } } status_t AudioSystem::AudioFlingerClient::getInputBufferSize( uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, size_t* buffSize) { const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) { return PERMISSION_DENIED; } Mutex::Autolock _l(mLock); // Do we have a stale mInBuffSize or are we requesting the input buffer size for new values if ((mInBuffSize == 0) || (sampleRate != mInSamplingRate) || (format != mInFormat) || (channelMask != mInChannelMask)) { size_t inBuffSize = af->getInputBufferSize(sampleRate, format, channelMask); if (inBuffSize == 0) { ALOGE("AudioSystem::getInputBufferSize failed sampleRate %d format %#x channelMask %x", sampleRate, format, channelMask); return BAD_VALUE; } // A benign race is possible here: we could overwrite a fresher cache entry // save the request params mInSamplingRate = sampleRate; mInFormat = format; mInChannelMask = channelMask; mInBuffSize = inBuffSize; } *buffSize = mInBuffSize; return NO_ERROR; } sp<AudioIoDescriptor> AudioSystem::AudioFlingerClient::getIoDescriptor(audio_io_handle_t ioHandle) { sp<AudioIoDescriptor> desc; ssize_t index = mIoDescriptors.indexOfKey(ioHandle); if (index >= 0) { desc = mIoDescriptors.valueAt(index); } return desc; } /*static*/ void AudioSystem::setErrorCallback(audio_error_callback cb) Loading Loading @@ -869,9 +864,8 @@ void AudioSystem::clearAudioConfigCache() { // called by restoreTrack_l(), which needs new IAudioFlinger and IAudioPolicyService instances ALOGV("clearAudioConfigCache()"); { Mutex::Autolock _l(gLockCache); gOutputs.clear(); if (gAudioFlingerClient != 0) { gAudioFlingerClient->clearIoCache(); } { Mutex::Autolock _l(gLock); Loading
media/libmedia/IAudioFlingerClient.cpp +16 −33 Original line number Diff line number Diff line Loading @@ -39,25 +39,17 @@ public: { } void ioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2) void ioConfigChanged(audio_io_config_event event, const sp<AudioIoDescriptor>& ioDesc) { Parcel data, reply; data.writeInterfaceToken(IAudioFlingerClient::getInterfaceDescriptor()); data.writeInt32(event); data.writeInt32((int32_t) ioHandle); if (event == AudioSystem::STREAM_CONFIG_CHANGED) { uint32_t stream = *(const uint32_t *)param2; ALOGV("ioConfigChanged stream %d", stream); data.writeInt32(stream); } else if (event != AudioSystem::OUTPUT_CLOSED && event != AudioSystem::INPUT_CLOSED) { const AudioSystem::OutputDescriptor *desc = (const AudioSystem::OutputDescriptor *)param2; data.writeInt32(desc->samplingRate); data.writeInt32(desc->format); data.writeInt32(desc->channelMask); data.writeInt64(desc->frameCount); data.writeInt32(desc->latency); } data.writeInt32((int32_t)ioDesc->mIoHandle); data.writeInt32(ioDesc->mSamplingRate); data.writeInt32(ioDesc->mFormat); data.writeInt32(ioDesc->mChannelMask); data.writeInt64(ioDesc->mFrameCount); data.writeInt32(ioDesc->mLatency); remote()->transact(IO_CONFIG_CHANGED, data, &reply, IBinder::FLAG_ONEWAY); } }; Loading @@ -72,24 +64,15 @@ status_t BnAudioFlingerClient::onTransact( switch (code) { case IO_CONFIG_CHANGED: { CHECK_INTERFACE(IAudioFlingerClient, data, reply); int event = data.readInt32(); audio_io_handle_t ioHandle = (audio_io_handle_t) data.readInt32(); const void *param2 = NULL; AudioSystem::OutputDescriptor desc; uint32_t stream; if (event == AudioSystem::STREAM_CONFIG_CHANGED) { stream = data.readInt32(); param2 = &stream; ALOGV("STREAM_CONFIG_CHANGED stream %d", stream); } else if (event != AudioSystem::OUTPUT_CLOSED && event != AudioSystem::INPUT_CLOSED) { desc.samplingRate = data.readInt32(); desc.format = (audio_format_t) data.readInt32(); desc.channelMask = (audio_channel_mask_t) data.readInt32(); desc.frameCount = data.readInt64(); desc.latency = data.readInt32(); param2 = &desc; } ioConfigChanged(event, ioHandle, param2); audio_io_config_event event = (audio_io_config_event)data.readInt32(); sp<AudioIoDescriptor> ioDesc = new AudioIoDescriptor(); ioDesc->mIoHandle = (audio_io_handle_t) data.readInt32(); ioDesc->mSamplingRate = data.readInt32(); ioDesc->mFormat = (audio_format_t) data.readInt32(); ioDesc->mChannelMask = (audio_channel_mask_t) data.readInt32(); ioDesc->mFrameCount = data.readInt64(); ioDesc->mLatency = data.readInt32(); ioConfigChanged(event, ioDesc); return NO_ERROR; } break; default: Loading