From 296fb13dd9b5e90d6a05cce897c3b1e7914a478a Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 1 May 2015 11:38:42 -0700 Subject: Implement audio device callback Add class AudioSystem::AudioDeviceCallback notifying AudioSystem clients upon device selection change on a given input or output thread. Maintain a list of installed callback per I/O handle in AudioSystem and call registered callbacks when an OPEN of CONFIG_CHANGED event is received on IAudioFlingerClient::ioConfigChanged(). Add methods to AudioTrack and AudioRecord to add and remove device change callbacks. Add methods to AudioTrack and AudioRecord to query currently selected device. ioConfigChanged() events now convey the audio patch describing the input or output thread routing. Fix AudioRecord failure to start when invalidation is handled by start(). Change-Id: I9e938adf025fa712337c63b1e02a8c18f2a20d39 --- media/libmedia/AudioSystem.cpp | 249 +++++++++++++++++++++++++++++++---------- 1 file changed, 187 insertions(+), 62 deletions(-) (limited to 'media/libmedia/AudioSystem.cpp') diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 85ed2b1..4c2e77b 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -76,6 +76,25 @@ const sp AudioSystem::get_audio_flinger() return af; } +const sp AudioSystem::getAudioFlingerClient() +{ + // calling get_audio_flinger() will initialize gAudioFlingerClient if needed + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return 0; + Mutex::Autolock _l(gLock); + return gAudioFlingerClient; +} + +sp AudioSystem::getIoDescriptor(audio_io_handle_t ioHandle) +{ + sp desc; + const sp afc = getAudioFlingerClient(); + if (afc != 0) { + desc = afc->getIoDescriptor(ioHandle); + } + return desc; +} + /* static */ status_t AudioSystem::checkAudioFlinger() { if (defaultServiceManager()->checkService(String16("media.audio_flinger")) != 0) { @@ -249,9 +268,7 @@ status_t AudioSystem::getSamplingRate(audio_io_handle_t output, { const sp& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; - - LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0); - sp outputDesc = gAudioFlingerClient->getIoDescriptor(output); + sp outputDesc = getIoDescriptor(output); if (outputDesc == 0) { ALOGV("getOutputSamplingRate() no output descriptor for output %d in gOutputs", output); *samplingRate = af->sampleRate(output); @@ -290,9 +307,7 @@ status_t AudioSystem::getFrameCount(audio_io_handle_t output, { const sp& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; - - LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0); - sp outputDesc = gAudioFlingerClient->getIoDescriptor(output); + sp outputDesc = getIoDescriptor(output); if (outputDesc == 0) { *frameCount = af->frameCount(output); } else { @@ -329,9 +344,7 @@ status_t AudioSystem::getLatency(audio_io_handle_t output, { const sp& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; - - LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0); - sp outputDesc = gAudioFlingerClient->getIoDescriptor(output); + sp outputDesc = getIoDescriptor(output); if (outputDesc == 0) { *latency = af->latency(output); } else { @@ -346,10 +359,11 @@ status_t AudioSystem::getLatency(audio_io_handle_t output, status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, size_t* buffSize) { - const sp& af = AudioSystem::get_audio_flinger(); - if (af == 0) return PERMISSION_DENIED; - LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0); - return gAudioFlingerClient->getInputBufferSize(sampleRate, format, channelMask, buffSize); + const sp afc = getAudioFlingerClient(); + if (afc == 0) { + return NO_INIT; + } + return afc->getInputBufferSize(sampleRate, format, channelMask, buffSize); } status_t AudioSystem::setVoiceVolume(float value) @@ -446,47 +460,77 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event even if (ioDesc == 0 || ioDesc->mIoHandle == AUDIO_IO_HANDLE_NONE) return; - Mutex::Autolock _l(mLock); + audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE; + Vector < sp > callbacks; - switch (event) { - case AUDIO_OUTPUT_OPENED: - case AUDIO_INPUT_OPENED: { - if (getIoDescriptor(ioDesc->mIoHandle) != 0) { - ALOGV("ioConfigChanged() opening already existing output! %d", ioDesc->mIoHandle); - break; - } - 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 AUDIO_OUTPUT_CLOSED: - case AUDIO_INPUT_CLOSED: { - if (getIoDescriptor(ioDesc->mIoHandle) == 0) { - ALOGW("ioConfigChanged() closing unknown %s %d", + { + Mutex::Autolock _l(mLock); + + switch (event) { + case AUDIO_OUTPUT_OPENED: + case AUDIO_INPUT_OPENED: { + if (getIoDescriptor(ioDesc->mIoHandle) != 0) { + ALOGV("ioConfigChanged() opening already existing output! %d", ioDesc->mIoHandle); + break; + } + mIoDescriptors.add(ioDesc->mIoHandle, ioDesc); + + if (ioDesc->getDeviceId() != AUDIO_PORT_HANDLE_NONE) { + deviceId = ioDesc->getDeviceId(); + ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle); + if (ioIndex >= 0) { + callbacks = mAudioDeviceCallbacks.valueAt(ioIndex); + } + } + ALOGV("ioConfigChanged() new %s opened %d samplingRate %u, format %#x channel mask %#x " + "frameCount %zu deviceId %d", event == AUDIO_OUTPUT_OPENED ? "output" : "input", + ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat, ioDesc->mChannelMask, + ioDesc->mFrameCount, ioDesc->getDeviceId()); + } break; + 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() %s %d closed", event == AUDIO_OUTPUT_CLOSED ? "output" : "input", ioDesc->mIoHandle); - break; - } - ALOGV("ioConfigChanged() %s %d closed", event == AUDIO_OUTPUT_CLOSED ? "output" : "input", - ioDesc->mIoHandle); - mIoDescriptors.removeItem(ioDesc->mIoHandle); - } break; + mIoDescriptors.removeItem(ioDesc->mIoHandle); + mAudioDeviceCallbacks.removeItem(ioDesc->mIoHandle); + } break; - case AUDIO_OUTPUT_CONFIG_CHANGED: - case AUDIO_INPUT_CONFIG_CHANGED: { - if (getIoDescriptor(ioDesc->mIoHandle) == 0) { - ALOGW("ioConfigChanged() modifying unknown output! %d", ioDesc->mIoHandle); - break; + case AUDIO_OUTPUT_CONFIG_CHANGED: + case AUDIO_INPUT_CONFIG_CHANGED: { + sp oldDesc = getIoDescriptor(ioDesc->mIoHandle); + if (oldDesc == 0) { + ALOGW("ioConfigChanged() modifying unknown output! %d", ioDesc->mIoHandle); + break; + } + + deviceId = oldDesc->getDeviceId(); + mIoDescriptors.replaceValueFor(ioDesc->mIoHandle, ioDesc); + + if (deviceId != ioDesc->getDeviceId()) { + deviceId = ioDesc->getDeviceId(); + ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle); + if (ioIndex >= 0) { + callbacks = mAudioDeviceCallbacks.valueAt(ioIndex); + } + } + ALOGV("ioConfigChanged() new config for %s %d samplingRate %u, format %#x " + "channel mask %#x frameCount %zu deviceId %d", + event == AUDIO_OUTPUT_CONFIG_CHANGED ? "output" : "input", + ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat, + ioDesc->mChannelMask, ioDesc->mFrameCount, ioDesc->getDeviceId()); + + } break; } - 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; + } + // callbacks.size() != 0 => ioDesc->mIoHandle and deviceId are valid + for (size_t i = 0; i < callbacks.size(); i++) { + callbacks[i]->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId); } } @@ -532,7 +576,56 @@ sp AudioSystem::AudioFlingerClient::getIoDescriptor(audio_io_ return desc; } -/*static*/ void AudioSystem::setErrorCallback(audio_error_callback cb) +status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback( + const sp& callback, audio_io_handle_t audioIo) +{ + Mutex::Autolock _l(mLock); + Vector < sp > callbacks; + ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo); + if (ioIndex >= 0) { + callbacks = mAudioDeviceCallbacks.valueAt(ioIndex); + } + + for (size_t cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) { + if (callbacks[cbIndex] == callback) { + return INVALID_OPERATION; + } + } + callbacks.add(callback); + + mAudioDeviceCallbacks.replaceValueFor(audioIo, callbacks); + return NO_ERROR; +} + +status_t AudioSystem::AudioFlingerClient::removeAudioDeviceCallback( + const sp& callback, audio_io_handle_t audioIo) +{ + Mutex::Autolock _l(mLock); + ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo); + if (ioIndex < 0) { + return INVALID_OPERATION; + } + Vector < sp > callbacks = mAudioDeviceCallbacks.valueAt(ioIndex); + + size_t cbIndex; + for (cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) { + if (callbacks[cbIndex] == callback) { + break; + } + } + if (cbIndex == callbacks.size()) { + return INVALID_OPERATION; + } + callbacks.removeAt(cbIndex); + if (callbacks.size() != 0) { + mAudioDeviceCallbacks.replaceValueFor(audioIo, callbacks); + } else { + mAudioDeviceCallbacks.removeItem(audioIo); + } + return NO_ERROR; +} + +/* static */ void AudioSystem::setErrorCallback(audio_error_callback cb) { Mutex::Autolock _l(gLock); gAudioErrorCallback = cb; @@ -864,11 +957,11 @@ void AudioSystem::clearAudioConfigCache() { // called by restoreTrack_l(), which needs new IAudioFlinger and IAudioPolicyService instances ALOGV("clearAudioConfigCache()"); - if (gAudioFlingerClient != 0) { - gAudioFlingerClient->clearIoCache(); - } { Mutex::Autolock _l(gLock); + if (gAudioFlingerClient != 0) { + gAudioFlingerClient->clearIoCache(); + } gAudioFlinger.clear(); } { @@ -934,7 +1027,7 @@ status_t AudioSystem::setAudioPortConfig(const struct audio_port_config *config) return aps->setAudioPortConfig(config); } -status_t AudioSystem::addAudioPortCallback(const sp& callBack) +status_t AudioSystem::addAudioPortCallback(const sp& callback) { const sp& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return PERMISSION_DENIED; @@ -943,11 +1036,11 @@ status_t AudioSystem::addAudioPortCallback(const sp& callBack if (gAudioPolicyServiceClient == 0) { return NO_INIT; } - return gAudioPolicyServiceClient->addAudioPortCallback(callBack); + return gAudioPolicyServiceClient->addAudioPortCallback(callback); } /*static*/ -status_t AudioSystem::removeAudioPortCallback(const sp& callBack) +status_t AudioSystem::removeAudioPortCallback(const sp& callback) { const sp& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return PERMISSION_DENIED; @@ -956,7 +1049,38 @@ status_t AudioSystem::removeAudioPortCallback(const sp& callB if (gAudioPolicyServiceClient == 0) { return NO_INIT; } - return gAudioPolicyServiceClient->removeAudioPortCallback(callBack); + return gAudioPolicyServiceClient->removeAudioPortCallback(callback); +} + +status_t AudioSystem::addAudioDeviceCallback( + const sp& callback, audio_io_handle_t audioIo) +{ + const sp afc = getAudioFlingerClient(); + if (afc == 0) { + return NO_INIT; + } + return afc->addAudioDeviceCallback(callback, audioIo); +} + +status_t AudioSystem::removeAudioDeviceCallback( + const sp& callback, audio_io_handle_t audioIo) +{ + const sp afc = getAudioFlingerClient(); + if (afc == 0) { + return NO_INIT; + } + return afc->removeAudioDeviceCallback(callback, audioIo); +} + +audio_port_handle_t AudioSystem::getDeviceIdForIo(audio_io_handle_t audioIo) +{ + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + const sp desc = getIoDescriptor(audioIo); + if (desc == 0) { + return AUDIO_PORT_HANDLE_NONE; + } + return desc->getDeviceId(); } status_t AudioSystem::acquireSoundTriggerSession(audio_session_t *session, @@ -1008,25 +1132,25 @@ status_t AudioSystem::stopAudioSource(audio_io_handle_t handle) // --------------------------------------------------------------------------- status_t AudioSystem::AudioPolicyServiceClient::addAudioPortCallback( - const sp& callBack) + const sp& callback) { Mutex::Autolock _l(mLock); for (size_t i = 0; i < mAudioPortCallbacks.size(); i++) { - if (mAudioPortCallbacks[i] == callBack) { + if (mAudioPortCallbacks[i] == callback) { return INVALID_OPERATION; } } - mAudioPortCallbacks.add(callBack); + mAudioPortCallbacks.add(callback); return NO_ERROR; } status_t AudioSystem::AudioPolicyServiceClient::removeAudioPortCallback( - const sp& callBack) + const sp& callback) { Mutex::Autolock _l(mLock); size_t i; for (i = 0; i < mAudioPortCallbacks.size(); i++) { - if (mAudioPortCallbacks[i] == callBack) { + if (mAudioPortCallbacks[i] == callback) { break; } } @@ -1037,6 +1161,7 @@ status_t AudioSystem::AudioPolicyServiceClient::removeAudioPortCallback( return NO_ERROR; } + void AudioSystem::AudioPolicyServiceClient::onAudioPortListUpdate() { Mutex::Autolock _l(mLock); -- cgit v1.1