From 951f455566775e5f01e67c5ee26863d7d19209d7 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Tue, 20 May 2014 10:48:17 -0700 Subject: DO NOT MERGE - audioflinger: first patch panel implementation. Added a new PatchPanel subclass to AudioFlinger to handle audio ports and audio patches configuration and connection. The first implementation does not add new functionnality. AudioPolicyManager uses patch panel interface to control device routing. AudioFlinger: - Added PatchPanel class. The first implementation does not add new functionnality. PatchPanel handles routing commands for audio HAL after 3.0 or converts to setParameters for audio HALs before 3.0. - Added config events to ThreadBase to control synchronized audio patch connection. AudioPolicyManager: - Use PatchPanel API to control device selection isntead of setParameters. - New base class AudioPort common to audio device descriptors and input output stream profiles. This class is RefBase and groups attributes common to audio ports. - Use same device selection flow for input as for outputs: getNewInputDevice -> getDeviceForInptusiource -> setInputDevice Change-Id: Idaa5a883b19a45816651c58cac697640dc717cd9 --- services/audioflinger/Android.mk | 1 + services/audioflinger/AudioFlinger.cpp | 3 + services/audioflinger/AudioFlinger.h | 37 +- services/audioflinger/PatchPanel.cpp | 409 ++++++++++++++++ services/audioflinger/PatchPanel.h | 60 +++ services/audioflinger/Threads.cpp | 132 ++++++ services/audioflinger/Threads.h | 62 +++ services/audiopolicy/AudioPolicyClientImpl.cpp | 11 + services/audiopolicy/AudioPolicyInterface.h | 9 + services/audiopolicy/AudioPolicyManager.cpp | 621 ++++++++++++++++--------- services/audiopolicy/AudioPolicyManager.h | 146 ++++-- services/audiopolicy/AudioPolicyService.cpp | 69 +++ services/audiopolicy/AudioPolicyService.h | 37 +- 13 files changed, 1312 insertions(+), 285 deletions(-) create mode 100644 services/audioflinger/PatchPanel.cpp create mode 100644 services/audioflinger/PatchPanel.h (limited to 'services') diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk index 8d0a705..f7b6f64 100644 --- a/services/audioflinger/Android.mk +++ b/services/audioflinger/Android.mk @@ -29,6 +29,7 @@ LOCAL_SRC_FILES:= \ Tracks.cpp \ Effects.cpp \ AudioMixer.cpp.arm \ + PatchPanel.cpp LOCAL_SRC_FILES += StateQueue.cpp diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index e174fc9..457ac3d 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -177,6 +177,7 @@ AudioFlinger::AudioFlinger() if (doLog) { mLogMemoryDealer = new MemoryDealer(kLogMemorySize, "LogWriters", MemoryHeapBase::READ_ONLY); } + #ifdef TEE_SINK (void) property_get("ro.debuggable", value, "0"); int debuggable = atoi(value); @@ -218,6 +219,8 @@ void AudioFlinger::onFirstRef() } } + mPatchPanel = new PatchPanel(this); + mMode = AUDIO_MODE_NORMAL; } diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 3d7a562..29dc6b2 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -225,41 +225,24 @@ public: /* List available audio ports and their attributes */ virtual status_t listAudioPorts(unsigned int *num_ports, - struct audio_port *ports) - { - return INVALID_OPERATION; - } + struct audio_port *ports); /* Get attributes for a given audio port */ - virtual status_t getAudioPort(struct audio_port *port) - { - return INVALID_OPERATION; - } + virtual status_t getAudioPort(struct audio_port *port); /* Create an audio patch between several source and sink ports */ virtual status_t createAudioPatch(const struct audio_patch *patch, - audio_patch_handle_t *handle) - { - return INVALID_OPERATION; - } + audio_patch_handle_t *handle); /* Release an audio patch */ - virtual status_t releaseAudioPatch(audio_patch_handle_t handle) - { - return INVALID_OPERATION; - } + virtual status_t releaseAudioPatch(audio_patch_handle_t handle); /* List existing audio patches */ virtual status_t listAudioPatches(unsigned int *num_patches, - struct audio_patch *patches) - { - return INVALID_OPERATION; - } + struct audio_patch *patches); + /* Set audio port configuration */ - virtual status_t setAudioPortConfig(const struct audio_port_config *config) - { - return INVALID_OPERATION; - } + virtual status_t setAudioPortConfig(const struct audio_port_config *config); virtual status_t onTransact( uint32_t code, @@ -435,6 +418,8 @@ private: #include "Effects.h" +#include "PatchPanel.h" + // server side of the client's IAudioTrack class TrackHandle : public android::BnAudioTrack { public: @@ -542,6 +527,8 @@ private: const char *moduleName() const { return mModuleName; } audio_hw_device_t *hwDevice() const { return mHwDevice; } + uint32_t version() const { return mHwDevice->common.version; } + private: const char * const mModuleName; audio_hw_device_t * const mHwDevice; @@ -702,6 +689,8 @@ private: bool mIsLowRamDevice; bool mIsDeviceTypeKnown; nsecs_t mGlobalEffectEnableTime; // when a global effect was last enabled + + sp mPatchPanel; }; #undef INCLUDING_FROM_AUDIOFLINGER_H diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp new file mode 100644 index 0000000..eee74b3 --- /dev/null +++ b/services/audioflinger/PatchPanel.cpp @@ -0,0 +1,409 @@ +/* +** +** Copyright 2014, 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. +*/ + + +#define LOG_TAG "AudioFlinger::PatchPanel" +//#define LOG_NDEBUG 0 + +#include "Configuration.h" +#include +#include + +#include "AudioFlinger.h" +#include "ServiceUtilities.h" +#include + +// ---------------------------------------------------------------------------- + +// Note: the following macro is used for extremely verbose logging message. In +// order to run with ALOG_ASSERT turned on, we need to have LOG_NDEBUG set to +// 0; but one side effect of this is to turn all LOGV's as well. Some messages +// are so verbose that we want to suppress them even when we have ALOG_ASSERT +// turned on. Do not uncomment the #def below unless you really know what you +// are doing and want to see all of the extremely verbose messages. +//#define VERY_VERY_VERBOSE_LOGGING +#ifdef VERY_VERY_VERBOSE_LOGGING +#define ALOGVV ALOGV +#else +#define ALOGVV(a...) do { } while(0) +#endif + +namespace android { + +/* List connected audio ports and their attributes */ +status_t AudioFlinger::listAudioPorts(unsigned int *num_ports, + struct audio_port *ports) +{ + Mutex::Autolock _l(mLock); + if (mPatchPanel != 0) { + return mPatchPanel->listAudioPorts(num_ports, ports); + } + return NO_INIT; +} + +/* Get supported attributes for a given audio port */ +status_t AudioFlinger::getAudioPort(struct audio_port *port) +{ + Mutex::Autolock _l(mLock); + if (mPatchPanel != 0) { + return mPatchPanel->getAudioPort(port); + } + return NO_INIT; +} + + +/* Connect a patch between several source and sink ports */ +status_t AudioFlinger::createAudioPatch(const struct audio_patch *patch, + audio_patch_handle_t *handle) +{ + Mutex::Autolock _l(mLock); + if (mPatchPanel != 0) { + return mPatchPanel->createAudioPatch(patch, handle); + } + return NO_INIT; +} + +/* Disconnect a patch */ +status_t AudioFlinger::releaseAudioPatch(audio_patch_handle_t handle) +{ + Mutex::Autolock _l(mLock); + if (mPatchPanel != 0) { + return mPatchPanel->releaseAudioPatch(handle); + } + return NO_INIT; +} + + +/* List connected audio ports and they attributes */ +status_t AudioFlinger::listAudioPatches(unsigned int *num_patches, + struct audio_patch *patches) +{ + Mutex::Autolock _l(mLock); + if (mPatchPanel != 0) { + return mPatchPanel->listAudioPatches(num_patches, patches); + } + return NO_INIT; +} + +/* Set audio port configuration */ +status_t AudioFlinger::setAudioPortConfig(const struct audio_port_config *config) +{ + Mutex::Autolock _l(mLock); + if (mPatchPanel != 0) { + return mPatchPanel->setAudioPortConfig(config); + } + return NO_INIT; +} + + +AudioFlinger::PatchPanel::PatchPanel(const sp& audioFlinger) + : mAudioFlinger(audioFlinger) +{ +} + +AudioFlinger::PatchPanel::~PatchPanel() +{ +} + +/* List connected audio ports and their attributes */ +status_t AudioFlinger::PatchPanel::listAudioPorts(unsigned int *num_ports __unused, + struct audio_port *ports __unused) +{ + ALOGV("listAudioPorts"); + return NO_ERROR; +} + +/* Get supported attributes for a given audio port */ +status_t AudioFlinger::PatchPanel::getAudioPort(struct audio_port *port __unused) +{ + ALOGV("getAudioPort"); + return NO_ERROR; +} + + +/* Connect a patch between several source and sink ports */ +status_t AudioFlinger::PatchPanel::createAudioPatch(const struct audio_patch *patch, + audio_patch_handle_t *handle) +{ + ALOGV("createAudioPatch() num_sources %d num_sinks %d handle %d", + patch->num_sources, patch->num_sinks, *handle); + status_t status = NO_ERROR; + + audio_patch_handle_t halHandle = AUDIO_PATCH_HANDLE_NONE; + + sp audioflinger = mAudioFlinger.promote(); + if (audioflinger == 0) { + return NO_INIT; + } + if (handle == NULL || patch == NULL) { + return BAD_VALUE; + } + // limit number of sources to 1 for now + if (patch->num_sources == 0 || patch->num_sources > 1 || + patch->num_sinks == 0 || patch->num_sinks > AUDIO_PATCH_PORTS_MAX) { + return BAD_VALUE; + } + + for (size_t index = 0; *handle != 0 && index < mPatches.size(); index++) { + if (*handle == mPatches[index]->mHandle) { + ALOGV("createAudioPatch() removing patch handle %d", *handle); + halHandle = mPatches[index]->mHalHandle; + mPatches.removeAt(index); + break; + } + } + + switch (patch->sources[0].type) { + case AUDIO_PORT_TYPE_DEVICE: { + // limit number of sinks to 1 for now + if (patch->num_sinks > 1) { + return BAD_VALUE; + } + audio_module_handle_t src_module = patch->sources[0].ext.device.hw_module; + ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(src_module); + if (index < 0) { + ALOGW("createAudioPatch() bad src hw module %d", src_module); + return BAD_VALUE; + } + for (unsigned int i = 0; i < patch->num_sinks; i++) { + // limit to connections between devices and output streams + if (patch->sinks[i].type != AUDIO_PORT_TYPE_MIX) { + ALOGW("createAudioPatch() invalid sink type %d for device source", + patch->sinks[i].type); + return BAD_VALUE; + } + // limit to connections between sinks and sources on same HW module + if (patch->sinks[i].ext.mix.hw_module != src_module) { + ALOGW("createAudioPatch() cannot connect source on module %d to" + "sink on module %d", src_module, patch->sinks[i].ext.mix.hw_module); + return BAD_VALUE; + } + } + + AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); + if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { + if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) { + sp thread = audioflinger->checkRecordThread_l( + patch->sinks[0].ext.mix.handle); + if (thread == 0) { + ALOGW("createAudioPatch() bad capture I/O handle %d", + patch->sinks[0].ext.mix.handle); + return BAD_VALUE; + } + status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle); + } else { + audio_hw_device_t *hwDevice = audioHwDevice->hwDevice(); + status = hwDevice->create_audio_patch(hwDevice, + patch->num_sources, + patch->sources, + patch->num_sinks, + patch->sinks, + &halHandle); + } + } else { + sp thread = audioflinger->checkRecordThread_l( + patch->sinks[0].ext.mix.handle); + if (thread == 0) { + ALOGW("createAudioPatch() bad capture I/O handle %d", + patch->sinks[0].ext.mix.handle); + return BAD_VALUE; + } + AudioParameter param; + param.addInt(String8(AudioParameter::keyRouting), + (int)patch->sources[0].ext.device.type); + param.addInt(String8(AudioParameter::keyInputSource), + (int)patch->sinks[0].ext.mix.usecase.source); + + ALOGW("createAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s", + param.toString().string()); + status = thread->setParameters(param.toString()); + } + } break; + case AUDIO_PORT_TYPE_MIX: { + audio_module_handle_t src_module = patch->sources[0].ext.mix.hw_module; + ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(src_module); + if (index < 0) { + ALOGW("createAudioPatch() bad src hw module %d", src_module); + return BAD_VALUE; + } + // limit to connections between devices and output streams + for (unsigned int i = 0; i < patch->num_sinks; i++) { + if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) { + ALOGW("createAudioPatch() invalid sink type %d for bus source", + patch->sinks[i].type); + return BAD_VALUE; + } + // limit to connections between sinks and sources on same HW module + if (patch->sinks[i].ext.device.hw_module != src_module) { + return BAD_VALUE; + } + } + AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); + sp thread = + audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle); + if (thread == 0) { + ALOGW("createAudioPatch() bad playback I/O handle %d", + patch->sources[0].ext.mix.handle); + return BAD_VALUE; + } + if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { + status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle); + } else { + audio_devices_t type = AUDIO_DEVICE_NONE; + for (unsigned int i = 0; i < patch->num_sinks; i++) { + type |= patch->sinks[i].ext.device.type; + } + AudioParameter param; + param.addInt(String8(AudioParameter::keyRouting), (int)type); + status = thread->setParameters(param.toString()); + } + + } break; + default: + return BAD_VALUE; + } + ALOGV("createAudioPatch() status %d", status); + if (status == NO_ERROR) { + *handle = audioflinger->nextUniqueId(); + Patch *newPatch = new Patch(patch); + newPatch->mHandle = *handle; + newPatch->mHalHandle = halHandle; + mPatches.add(newPatch); + ALOGV("createAudioPatch() added new patch handle %d halHandle %d", *handle, halHandle); + } + return status; +} + +/* Disconnect a patch */ +status_t AudioFlinger::PatchPanel::releaseAudioPatch(audio_patch_handle_t handle) +{ + ALOGV("releaseAudioPatch handle %d", handle); + status_t status = NO_ERROR; + size_t index; + + sp audioflinger = mAudioFlinger.promote(); + if (audioflinger == 0) { + return NO_INIT; + } + + for (index = 0; index < mPatches.size(); index++) { + if (handle == mPatches[index]->mHandle) { + break; + } + } + if (index == mPatches.size()) { + return BAD_VALUE; + } + + struct audio_patch *patch = &mPatches[index]->mAudioPatch; + + switch (patch->sources[0].type) { + case AUDIO_PORT_TYPE_DEVICE: { + audio_module_handle_t src_module = patch->sources[0].ext.device.hw_module; + ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(src_module); + if (index < 0) { + ALOGW("releaseAudioPatch() bad src hw module %d", src_module); + status = BAD_VALUE; + break; + } + AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); + if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { + if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) { + sp thread = audioflinger->checkRecordThread_l( + patch->sinks[0].ext.mix.handle); + if (thread == 0) { + ALOGW("createAudioPatch() bad capture I/O handle %d", + patch->sinks[0].ext.mix.handle); + status = BAD_VALUE; + break; + } + status = thread->sendReleaseAudioPatchConfigEvent(mPatches[index]->mHalHandle); + } else { + audio_hw_device_t *hwDevice = audioHwDevice->hwDevice(); + status = hwDevice->release_audio_patch(hwDevice, mPatches[index]->mHalHandle); + } + } else { + sp thread = audioflinger->checkRecordThread_l( + patch->sinks[0].ext.mix.handle); + if (thread == 0) { + ALOGW("releaseAudioPatch() bad capture I/O handle %d", + patch->sinks[0].ext.mix.handle); + status = BAD_VALUE; + break; + } + AudioParameter param; + param.addInt(String8(AudioParameter::keyRouting), 0); + ALOGW("releaseAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s", + param.toString().string()); + status = thread->setParameters(param.toString()); + } + } break; + case AUDIO_PORT_TYPE_MIX: { + audio_module_handle_t src_module = patch->sources[0].ext.mix.hw_module; + ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(src_module); + if (index < 0) { + ALOGW("releaseAudioPatch() bad src hw module %d", src_module); + status = BAD_VALUE; + break; + } + sp thread = + audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle); + if (thread == 0) { + ALOGW("releaseAudioPatch() bad playback I/O handle %d", + patch->sources[0].ext.mix.handle); + status = BAD_VALUE; + break; + } + AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); + if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { + status = thread->sendReleaseAudioPatchConfigEvent(mPatches[index]->mHalHandle); + } else { + AudioParameter param; + param.addInt(String8(AudioParameter::keyRouting), (int)0); + status = thread->setParameters(param.toString()); + } + } break; + default: + status = BAD_VALUE; + break; + } + + delete (mPatches[index]); + mPatches.removeAt(index); + return status; +} + + +/* List connected audio ports and they attributes */ +status_t AudioFlinger::PatchPanel::listAudioPatches(unsigned int *num_patches __unused, + struct audio_patch *patches __unused) +{ + ALOGV("listAudioPatches"); + return NO_ERROR; +} + +/* Set audio port configuration */ +status_t AudioFlinger::PatchPanel::setAudioPortConfig( + const struct audio_port_config *config __unused) +{ + ALOGV("setAudioPortConfig"); + return NO_ERROR; +} + + + +}; // namespace android diff --git a/services/audioflinger/PatchPanel.h b/services/audioflinger/PatchPanel.h new file mode 100644 index 0000000..7f78621 --- /dev/null +++ b/services/audioflinger/PatchPanel.h @@ -0,0 +1,60 @@ +/* +** +** Copyright 2014, 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 INCLUDING_FROM_AUDIOFLINGER_H + #error This header file should only be included from AudioFlinger.h +#endif + +class PatchPanel : public RefBase { +public: + PatchPanel(const sp& audioFlinger); + virtual ~PatchPanel(); + + /* List connected audio ports and their attributes */ + status_t listAudioPorts(unsigned int *num_ports, + struct audio_port *ports); + + /* Get supported attributes for a given audio port */ + status_t getAudioPort(struct audio_port *port); + + /* Create a patch between several source and sink ports */ + status_t createAudioPatch(const struct audio_patch *patch, + audio_patch_handle_t *handle); + + /* Release a patch */ + status_t releaseAudioPatch(audio_patch_handle_t handle); + + /* List connected audio devices and they attributes */ + status_t listAudioPatches(unsigned int *num_patches, + struct audio_patch *patches); + + /* Set audio port configuration */ + status_t setAudioPortConfig(const struct audio_port_config *config); + + class Patch { + public: + Patch(const struct audio_patch *patch) : + mAudioPatch(*patch), mHandle(0), mHalHandle(0) {} + + struct audio_patch mAudioPatch; + audio_patch_handle_t mHandle; + audio_patch_handle_t mHalHandle; + }; +private: + const wp mAudioFlinger; + SortedVector mPatches; +}; diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index cdc9a19..4972c7a 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -401,6 +401,30 @@ status_t AudioFlinger::ThreadBase::sendSetParameterConfigEvent_l(const String8& return sendConfigEvent_l(configEvent); } +status_t AudioFlinger::ThreadBase::sendCreateAudioPatchConfigEvent( + const struct audio_patch *patch, + audio_patch_handle_t *handle) +{ + Mutex::Autolock _l(mLock); + sp configEvent = (ConfigEvent *)new CreateAudioPatchConfigEvent(*patch, *handle); + status_t status = sendConfigEvent_l(configEvent); + if (status == NO_ERROR) { + CreateAudioPatchConfigEventData *data = + (CreateAudioPatchConfigEventData *)configEvent->mData.get(); + *handle = data->mHandle; + } + return status; +} + +status_t AudioFlinger::ThreadBase::sendReleaseAudioPatchConfigEvent( + const audio_patch_handle_t handle) +{ + Mutex::Autolock _l(mLock); + sp configEvent = (ConfigEvent *)new ReleaseAudioPatchConfigEvent(handle); + return sendConfigEvent_l(configEvent); +} + + // post condition: mConfigEvents.isEmpty() void AudioFlinger::ThreadBase::processConfigEvents_l() { @@ -431,6 +455,16 @@ void AudioFlinger::ThreadBase::processConfigEvents_l() configChanged = true; } } break; + case CFG_EVENT_CREATE_AUDIO_PATCH: { + CreateAudioPatchConfigEventData *data = + (CreateAudioPatchConfigEventData *)event->mData.get(); + event->mStatus = createAudioPatch_l(&data->mPatch, &data->mHandle); + } break; + case CFG_EVENT_RELEASE_AUDIO_PATCH: { + ReleaseAudioPatchConfigEventData *data = + (ReleaseAudioPatchConfigEventData *)event->mData.get(); + event->mStatus = releaseAudioPatch_l(data->mHandle); + } break; default: ALOG_ASSERT(false, "processConfigEvents_l() unknown event type %d", event->mType); break; @@ -2594,6 +2628,47 @@ status_t AudioFlinger::PlaybackThread::getTimestamp_l(AudioTimestamp& timestamp) } return INVALID_OPERATION; } + +status_t AudioFlinger::PlaybackThread::createAudioPatch_l(const struct audio_patch *patch, + audio_patch_handle_t *handle) +{ + status_t status = NO_ERROR; + if (mOutput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) { + // store new device and send to effects + audio_devices_t type = AUDIO_DEVICE_NONE; + for (unsigned int i = 0; i < patch->num_sinks; i++) { + type |= patch->sinks[i].ext.device.type; + } + mOutDevice = type; + for (size_t i = 0; i < mEffectChains.size(); i++) { + mEffectChains[i]->setDevice_l(mOutDevice); + } + + audio_hw_device_t *hwDevice = mOutput->audioHwDev->hwDevice(); + status = hwDevice->create_audio_patch(hwDevice, + patch->num_sources, + patch->sources, + patch->num_sinks, + patch->sinks, + handle); + } else { + ALOG_ASSERT(false, "createAudioPatch_l() called on a pre 3.0 HAL"); + } + return status; +} + +status_t AudioFlinger::PlaybackThread::releaseAudioPatch_l(const audio_patch_handle_t handle) +{ + status_t status = NO_ERROR; + if (mOutput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) { + audio_hw_device_t *hwDevice = mOutput->audioHwDev->hwDevice(); + status = hwDevice->release_audio_patch(hwDevice, handle); + } else { + ALOG_ASSERT(false, "releaseAudioPatch_l() called on a pre 3.0 HAL"); + } + return status; +} + // ---------------------------------------------------------------------------- AudioFlinger::MixerThread::MixerThread(const sp& audioFlinger, AudioStreamOut* output, @@ -5743,4 +5818,61 @@ size_t AudioFlinger::RecordThread::removeEffectChain_l(const sp& ch return 0; } +status_t AudioFlinger::RecordThread::createAudioPatch_l(const struct audio_patch *patch, + audio_patch_handle_t *handle) +{ + status_t status = NO_ERROR; + if (mInput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) { + // store new device and send to effects + mInDevice = patch->sources[0].ext.device.type; + for (size_t i = 0; i < mEffectChains.size(); i++) { + mEffectChains[i]->setDevice_l(mInDevice); + } + + // disable AEC and NS if the device is a BT SCO headset supporting those + // pre processings + if (mTracks.size() > 0) { + bool suspend = audio_is_bluetooth_sco_device(mInDevice) && + mAudioFlinger->btNrecIsOff(); + for (size_t i = 0; i < mTracks.size(); i++) { + sp track = mTracks[i]; + setEffectSuspended_l(FX_IID_AEC, suspend, track->sessionId()); + setEffectSuspended_l(FX_IID_NS, suspend, track->sessionId()); + } + } + + // store new source and send to effects + if (mAudioSource != patch->sinks[0].ext.mix.usecase.source) { + mAudioSource = patch->sinks[0].ext.mix.usecase.source; + for (size_t i = 0; i < mEffectChains.size(); i++) { + mEffectChains[i]->setAudioSource_l(mAudioSource); + } + } + + audio_hw_device_t *hwDevice = mInput->audioHwDev->hwDevice(); + status = hwDevice->create_audio_patch(hwDevice, + patch->num_sources, + patch->sources, + patch->num_sinks, + patch->sinks, + handle); + } else { + ALOG_ASSERT(false, "createAudioPatch_l() called on a pre 3.0 HAL"); + } + return status; +} + +status_t AudioFlinger::RecordThread::releaseAudioPatch_l(const audio_patch_handle_t handle) +{ + status_t status = NO_ERROR; + if (mInput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) { + audio_hw_device_t *hwDevice = mInput->audioHwDev->hwDevice(); + status = hwDevice->release_audio_patch(hwDevice, handle); + } else { + ALOG_ASSERT(false, "releaseAudioPatch_l() called on a pre 3.0 HAL"); + } + return status; +} + + }; // namespace android diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index cc2b246..f8037c6 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -48,6 +48,8 @@ public: CFG_EVENT_IO, CFG_EVENT_PRIO, CFG_EVENT_SET_PARAMETER, + CFG_EVENT_CREATE_AUDIO_PATCH, + CFG_EVENT_RELEASE_AUDIO_PATCH, }; class ConfigEventData: public RefBase { @@ -161,6 +163,52 @@ public: virtual ~SetParameterConfigEvent() {} }; + class CreateAudioPatchConfigEventData : public ConfigEventData { + public: + CreateAudioPatchConfigEventData(const struct audio_patch patch, + audio_patch_handle_t handle) : + mPatch(patch), mHandle(handle) {} + + virtual void dump(char *buffer, size_t size) { + snprintf(buffer, size, "Patch handle: %u\n", mHandle); + } + + const struct audio_patch mPatch; + audio_patch_handle_t mHandle; + }; + + class CreateAudioPatchConfigEvent : public ConfigEvent { + public: + CreateAudioPatchConfigEvent(const struct audio_patch patch, + audio_patch_handle_t handle) : + ConfigEvent(CFG_EVENT_CREATE_AUDIO_PATCH) { + mData = new CreateAudioPatchConfigEventData(patch, handle); + mWaitStatus = true; + } + virtual ~CreateAudioPatchConfigEvent() {} + }; + + class ReleaseAudioPatchConfigEventData : public ConfigEventData { + public: + ReleaseAudioPatchConfigEventData(const audio_patch_handle_t handle) : + mHandle(handle) {} + + virtual void dump(char *buffer, size_t size) { + snprintf(buffer, size, "Patch handle: %u\n", mHandle); + } + + audio_patch_handle_t mHandle; + }; + + class ReleaseAudioPatchConfigEvent : public ConfigEvent { + public: + ReleaseAudioPatchConfigEvent(const audio_patch_handle_t handle) : + ConfigEvent(CFG_EVENT_RELEASE_AUDIO_PATCH) { + mData = new ReleaseAudioPatchConfigEventData(handle); + mWaitStatus = true; + } + virtual ~ReleaseAudioPatchConfigEvent() {} + }; class PMDeathRecipient : public IBinder::DeathRecipient { public: @@ -209,8 +257,15 @@ public: void sendIoConfigEvent_l(int event, int param = 0); void sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio); status_t sendSetParameterConfigEvent_l(const String8& keyValuePair); + status_t sendCreateAudioPatchConfigEvent(const struct audio_patch *patch, + audio_patch_handle_t *handle); + status_t sendReleaseAudioPatchConfigEvent(audio_patch_handle_t handle); void processConfigEvents_l(); virtual void cacheParameters_l() = 0; + virtual status_t createAudioPatch_l(const struct audio_patch *patch, + audio_patch_handle_t *handle) = 0; + virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle) = 0; + // see note at declaration of mStandby, mOutDevice and mInDevice bool standby() const { return mStandby; } @@ -641,6 +696,10 @@ protected: virtual uint32_t correctLatency_l(uint32_t latency) const; + virtual status_t createAudioPatch_l(const struct audio_patch *patch, + audio_patch_handle_t *handle); + virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle); + private: friend class AudioFlinger; // for numerous @@ -1030,6 +1089,9 @@ public: virtual void cacheParameters_l() {} virtual String8 getParameters(const String8& keys); virtual void audioConfigChanged(int event, int param = 0); + virtual status_t createAudioPatch_l(const struct audio_patch *patch, + audio_patch_handle_t *handle); + virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle); void readInputParameters_l(); virtual uint32_t getInputFramesLost(); diff --git a/services/audiopolicy/AudioPolicyClientImpl.cpp b/services/audiopolicy/AudioPolicyClientImpl.cpp index 44c47c3..8225e36 100644 --- a/services/audiopolicy/AudioPolicyClientImpl.cpp +++ b/services/audiopolicy/AudioPolicyClientImpl.cpp @@ -182,6 +182,17 @@ status_t AudioPolicyService::AudioPolicyClient::moveEffects(int session, return af->moveEffects(session, src_output, dst_output); } +status_t AudioPolicyService::AudioPolicyClient::createAudioPatch(const struct audio_patch *patch, + audio_patch_handle_t *handle, + int delayMs) +{ + return mAudioPolicyService->clientCreateAudioPatch(patch, handle, delayMs); +} +status_t AudioPolicyService::AudioPolicyClient::releaseAudioPatch(audio_patch_handle_t handle, + int delayMs) +{ + return mAudioPolicyService->clientReleaseAudioPatch(handle, delayMs); +} }; // namespace android diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h index 66260e3..bb2deb6 100644 --- a/services/audiopolicy/AudioPolicyInterface.h +++ b/services/audiopolicy/AudioPolicyInterface.h @@ -246,6 +246,15 @@ public: audio_io_handle_t srcOutput, audio_io_handle_t dstOutput) = 0; + /* Create a patch between several source and sink ports */ + virtual status_t createAudioPatch(const struct audio_patch *patch, + audio_patch_handle_t *handle, + int delayMs) = 0; + + /* Release a patch */ + virtual status_t releaseAudioPatch(audio_patch_handle_t handle, + int delayMs) = 0; + }; extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface); diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp index bd9b15a..b047e1d 100644 --- a/services/audiopolicy/AudioPolicyManager.cpp +++ b/services/audiopolicy/AudioPolicyManager.cpp @@ -267,7 +267,7 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, // also force a device 0 for the two outputs it is duplicated to which may override // a valid device selection on those outputs. setOutputDevice(mOutputs.keyAt(i), - getNewDevice(mOutputs.keyAt(i), true /*fromCache*/), + getNewOutputDevice(mOutputs.keyAt(i), true /*fromCache*/), !mOutputs.valueAt(i)->isDuplicated(), 0); } @@ -419,7 +419,7 @@ void AudioPolicyManager::setPhoneState(audio_mode_t state) } // check for device and output changes triggered by new phone state - newDevice = getNewDevice(mPrimaryOutput, false /*fromCache*/); + newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/); checkA2dpSuspend(); checkOutputForAllStrategies(); updateDevicesAndOutputs(); @@ -544,7 +544,7 @@ void AudioPolicyManager::setForceUse(audio_policy_force_use_t usage, updateDevicesAndOutputs(); for (size_t i = 0; i < mOutputs.size(); i++) { audio_io_handle_t output = mOutputs.keyAt(i); - audio_devices_t newDevice = getNewDevice(output, true /*fromCache*/); + audio_devices_t newDevice = getNewOutputDevice(output, true /*fromCache*/); setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE)); if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) { applyStreamVolumes(output, newDevice, 0, true); @@ -553,16 +553,7 @@ void AudioPolicyManager::setForceUse(audio_policy_force_use_t usage, audio_io_handle_t activeInput = getActiveInput(); if (activeInput != 0) { - AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput); - audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource); - if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) { - ALOGV("setForceUse() changing device from %x to %x for input %d", - inputDesc->mDevice, newDevice, activeInput); - inputDesc->mDevice = newDevice; - AudioParameter param = AudioParameter(); - param.addInt(String8(AudioParameter::keyRouting), (int)newDevice); - mpClientInterface->setParameters(activeInput, param.toString()); - } + setInputDevice(activeInput, getNewInputDevice(activeInput)); } } @@ -579,7 +570,7 @@ void AudioPolicyManager::setSystemProperty(const char* property, const char* val // Find a direct output profile compatible with the parameters passed, even if the input flags do // not explicitly request a direct output -AudioPolicyManager::IOProfile *AudioPolicyManager::getProfileForDirectOutput( +sp AudioPolicyManager::getProfileForDirectOutput( audio_devices_t device, uint32_t samplingRate, audio_format_t format, @@ -591,7 +582,7 @@ AudioPolicyManager::IOProfile *AudioPolicyManager::getProfileForDirectOutput( continue; } for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) { - IOProfile *profile = mHwModules[i]->mOutputProfiles[j]; + sp profile = mHwModules[i]->mOutputProfiles[j]; bool found = false; if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { if (profile->isCompatibleProfile(device, samplingRate, format, @@ -676,7 +667,7 @@ audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream, // FIXME: We should check the audio session here but we do not have it in this context. // This may prevent offloading in rare situations where effects are left active by apps // in the background. - IOProfile *profile = NULL; + sp profile; if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) || !isNonOffloadableEffectEnabled()) { profile = getProfileForDirectOutput(device, @@ -686,7 +677,7 @@ audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream, (audio_output_flags_t)flags); } - if (profile != NULL) { + if (profile != 0) { AudioOutputDescriptor *outputDesc = NULL; for (size_t i = 0; i < mOutputs.size(); i++) { @@ -705,7 +696,7 @@ audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream, } // close direct output if currently open and configured with different parameters if (outputDesc != NULL) { - closeOutput(outputDesc->mId); + closeOutput(outputDesc->mIoHandle); } outputDesc = new AudioOutputDescriptor(profile); outputDesc->mDevice = device; @@ -837,7 +828,7 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output, outputDesc->changeRefCount(stream, 1); if (outputDesc->mRefCount[stream] == 1) { - audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/); + audio_devices_t newDevice = getNewOutputDevice(output, false /*fromCache*/); routing_strategy strategy = getStrategy(stream); bool shouldWait = (strategy == STRATEGY_SONIFICATION) || (strategy == STRATEGY_SONIFICATION_RESPECTFUL); @@ -910,7 +901,7 @@ status_t AudioPolicyManager::stopOutput(audio_io_handle_t output, // store time at which the stream was stopped - see isStreamActive() if (outputDesc->mRefCount[stream] == 0) { outputDesc->mStopTime[stream] = systemTime(); - audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/); + audio_devices_t newDevice = getNewOutputDevice(output, false /*fromCache*/); // delay the device switch by twice the latency because stopOutput() is executed when // the track stop() command is received and at that time the audio track buffer can // still contain data that needs to be drained. The latency only covers the audio HAL @@ -928,7 +919,7 @@ status_t AudioPolicyManager::stopOutput(audio_io_handle_t output, outputDesc->sharesHwModuleWith(desc) && (newDevice != desc->device())) { setOutputDevice(curOutput, - getNewDevice(curOutput, false /*fromCache*/), + getNewOutputDevice(curOutput, false /*fromCache*/), true, outputDesc->mLatency*2); } @@ -1018,11 +1009,11 @@ audio_io_handle_t AudioPolicyManager::getInput(audio_source_t inputSource, break; } - IOProfile *profile = getInputProfile(device, + sp profile = getInputProfile(device, samplingRate, format, channelMask); - if (profile == NULL) { + if (profile == 0) { ALOGW("getInput() could not find profile for device %04x, samplingRate %d, format %d, " "channelMask %04x", device, samplingRate, format, channelMask); @@ -1095,10 +1086,7 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input) } } - audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource); - if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) { - inputDesc->mDevice = newDevice; - } + setInputDevice(input, getNewInputDevice(input), true /* force */); // automatically enable the remote submix output when input is started if (audio_is_remote_submix_device(inputDesc->mDevice)) { @@ -1106,17 +1094,8 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input) AUDIO_POLICY_DEVICE_STATE_AVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS); } - AudioParameter param = AudioParameter(); - param.addInt(String8(AudioParameter::keyRouting), (int)inputDesc->mDevice); - - int aliasSource = (inputDesc->mInputSource == AUDIO_SOURCE_HOTWORD) ? - AUDIO_SOURCE_VOICE_RECOGNITION : inputDesc->mInputSource; - - param.addInt(String8(AudioParameter::keyInputSource), aliasSource); ALOGV("AudioPolicyManager::startInput() input source = %d", inputDesc->mInputSource); - mpClientInterface->setParameters(input, param.toString()); - inputDesc->mRefCount = 1; return NO_ERROR; } @@ -1141,9 +1120,7 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input) AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS); } - AudioParameter param = AudioParameter(); - param.addInt(String8(AudioParameter::keyRouting), 0); - mpClientInterface->setParameters(input, param.toString()); + resetInputDevice(input); inputDesc->mRefCount = 0; return NO_ERROR; } @@ -1608,13 +1585,13 @@ bool AudioPolicyManager::isOffloadSupported(const audio_offload_info_t& offloadI // See if there is a profile to support this. // AUDIO_DEVICE_NONE - IOProfile *profile = getProfileForDirectOutput(AUDIO_DEVICE_NONE /*ignore device */, + sp profile = getProfileForDirectOutput(AUDIO_DEVICE_NONE /*ignore device */, offloadInfo.sample_rate, offloadInfo.format, offloadInfo.channel_mask, AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD); - ALOGV("isOffloadSupported() profile %sfound", profile != NULL ? "" : "NOT "); - return (profile != NULL); + ALOGV("isOffloadSupported() profile %sfound", profile != 0 ? "" : "NOT "); + return (profile != 0); } // ---------------------------------------------------------------------------- @@ -1671,7 +1648,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa // This also validates mAvailableOutputDevices list for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) { - const IOProfile *outProfile = mHwModules[i]->mOutputProfiles[j]; + const sp outProfile = mHwModules[i]->mOutputProfiles[j]; if (outProfile->mSupportedDevices.isEmpty()) { ALOGW("Output profile contains no device on module %s", mHwModules[i]->mName); @@ -1683,7 +1660,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0)) { AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(outProfile); - outputDesc->mDevice = (audio_devices_t)(mDefaultOutputDevice->mType & profileTypes); + outputDesc->mDevice = (audio_devices_t)(mDefaultOutputDevice->mDeviceType & profileTypes); audio_io_handle_t output = mpClientInterface->openOutput( outProfile->mModule->mHandle, &outputDesc->mDevice, @@ -1699,7 +1676,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa delete outputDesc; } else { for (size_t k = 0; k < outProfile->mSupportedDevices.size(); k++) { - audio_devices_t type = outProfile->mSupportedDevices[k]->mType; + audio_devices_t type = outProfile->mSupportedDevices[k]->mDeviceType; ssize_t index = mAvailableOutputDevices.indexOf(outProfile->mSupportedDevices[k]); // give a valid ID to an attached device once confirmed it is reachable @@ -1722,7 +1699,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa // mAvailableInputDevices list for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++) { - const IOProfile *inProfile = mHwModules[i]->mInputProfiles[j]; + const sp inProfile = mHwModules[i]->mInputProfiles[j]; if (inProfile->mSupportedDevices.isEmpty()) { ALOGW("Input profile contains no device on module %s", mHwModules[i]->mName); @@ -1734,7 +1711,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa AudioInputDescriptor *inputDesc = new AudioInputDescriptor(inProfile); inputDesc->mInputSource = AUDIO_SOURCE_MIC; - inputDesc->mDevice = inProfile->mSupportedDevices[0]->mType; + inputDesc->mDevice = inProfile->mSupportedDevices[0]->mDeviceType; audio_io_handle_t input = mpClientInterface->openInput( inProfile->mModule->mHandle, &inputDesc->mDevice, @@ -1744,7 +1721,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa if (input != 0) { for (size_t k = 0; k < inProfile->mSupportedDevices.size(); k++) { - audio_devices_t type = inProfile->mSupportedDevices[k]->mType; + audio_devices_t type = inProfile->mSupportedDevices[k]->mDeviceType; ssize_t index = mAvailableInputDevices.indexOf(inProfile->mSupportedDevices[k]); // give a valid ID to an attached device once confirmed it is reachable @@ -1765,7 +1742,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa // make sure all attached devices have been allocated a unique ID for (size_t i = 0; i < mAvailableOutputDevices.size();) { if (mAvailableOutputDevices[i]->mId == 0) { - ALOGW("Input device %08x unreachable", mAvailableOutputDevices[i]->mType); + ALOGW("Input device %08x unreachable", mAvailableOutputDevices[i]->mDeviceType); mAvailableOutputDevices.remove(mAvailableOutputDevices[i]); continue; } @@ -1773,7 +1750,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa } for (size_t i = 0; i < mAvailableInputDevices.size();) { if (mAvailableInputDevices[i]->mId == 0) { - ALOGW("Input device %08x unreachable", mAvailableInputDevices[i]->mType); + ALOGW("Input device %08x unreachable", mAvailableInputDevices[i]->mDeviceType); mAvailableInputDevices.remove(mAvailableInputDevices[i]); continue; } @@ -1781,7 +1758,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa } // make sure default device is reachable if (mAvailableOutputDevices.indexOf(mDefaultOutputDevice) < 0) { - ALOGE("Default device %08x is unreachable", mDefaultOutputDevice->mType); + ALOGE("Default device %08x is unreachable", mDefaultOutputDevice->mDeviceType); } ALOGE_IF((mPrimaryOutput == 0), "Failed to open primary output"); @@ -1990,16 +1967,18 @@ int AudioPolicyManager::testOutputIndex(audio_io_handle_t output) // --- -void AudioPolicyManager::addOutput(audio_io_handle_t id, AudioOutputDescriptor *outputDesc) +void AudioPolicyManager::addOutput(audio_io_handle_t output, AudioOutputDescriptor *outputDesc) { - outputDesc->mId = id; - mOutputs.add(id, outputDesc); + outputDesc->mIoHandle = output; + outputDesc->mId = nextUniqueId(); + mOutputs.add(output, outputDesc); } -void AudioPolicyManager::addInput(audio_io_handle_t id, AudioInputDescriptor *inputDesc) +void AudioPolicyManager::addInput(audio_io_handle_t input, AudioInputDescriptor *inputDesc) { - inputDesc->mId = id; - mInputs.add(id, inputDesc); + inputDesc->mIoHandle = input; + inputDesc->mId = nextUniqueId(); + mInputs.add(input, inputDesc); } String8 AudioPolicyManager::addressToParameter(audio_devices_t device, const String8 address) @@ -2027,7 +2006,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, } } // then look for output profiles that can be routed to this device - SortedVector profiles; + SortedVector< sp > profiles; for (size_t i = 0; i < mHwModules.size(); i++) { if (mHwModules[i]->mHandle == 0) { @@ -2050,7 +2029,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, // open outputs for matching profiles if needed. Direct outputs are also opened to // query for dynamic parameters and will be closed later by setDeviceConnectionState() for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) { - IOProfile *profile = profiles[profile_index]; + sp profile = profiles[profile_index]; // nothing to do if one output is already opened for this profile size_t j; @@ -2096,7 +2075,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, reply.string()); value = strpbrk((char *)reply.string(), "="); if (value != NULL) { - loadSamplingRates(value + 1, profile); + profile->loadSamplingRates(value + 1); } } if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) { @@ -2106,7 +2085,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, reply.string()); value = strpbrk((char *)reply.string(), "="); if (value != NULL) { - loadFormats(value + 1, profile); + profile->loadFormats(value + 1); } } if (profile->mChannelMasks[0] == 0) { @@ -2116,7 +2095,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, reply.string()); value = strpbrk((char *)reply.string(), "="); if (value != NULL) { - loadOutChannels(value + 1, profile); + profile->loadOutChannels(value + 1); } } if (((profile->mSamplingRates[0] == 0) && @@ -2211,7 +2190,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, } for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) { - IOProfile *profile = mHwModules[i]->mOutputProfiles[j]; + sp profile = mHwModules[i]->mOutputProfiles[j]; if (profile->mSupportedDevices.types() & device) { ALOGV("checkOutputsForDevice(): " "clearing direct output profile %zu on module %zu", j, i); @@ -2251,7 +2230,7 @@ status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device, } // then look for input profiles that can be routed to this device - SortedVector profiles; + SortedVector< sp > profiles; for (size_t module_idx = 0; module_idx < mHwModules.size(); module_idx++) { if (mHwModules[module_idx]->mHandle == 0) { @@ -2279,7 +2258,7 @@ status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device, // query for dynamic parameters and will be closed later by setDeviceConnectionState() for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) { - IOProfile *profile = profiles[profile_index]; + sp profile = profiles[profile_index]; // nothing to do if one input is already opened for this profile size_t input_index; for (input_index = 0; input_index < mInputs.size(); input_index++) { @@ -2317,7 +2296,7 @@ status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device, reply.string()); value = strpbrk((char *)reply.string(), "="); if (value != NULL) { - loadSamplingRates(value + 1, profile); + profile->loadSamplingRates(value + 1); } } if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) { @@ -2326,7 +2305,7 @@ status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device, ALOGV("checkInputsForDevice() direct input sup formats %s", reply.string()); value = strpbrk((char *)reply.string(), "="); if (value != NULL) { - loadFormats(value + 1, profile); + profile->loadFormats(value + 1); } } if (profile->mChannelMasks[0] == 0) { @@ -2336,7 +2315,7 @@ status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device, reply.string()); value = strpbrk((char *)reply.string(), "="); if (value != NULL) { - loadInChannels(value + 1, profile); + profile->loadInChannels(value + 1); } } if (((profile->mSamplingRates[0] == 0) && (profile->mSamplingRates.size() < 2)) || @@ -2386,7 +2365,7 @@ status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device, for (size_t profile_index = 0; profile_index < mHwModules[module_index]->mInputProfiles.size(); profile_index++) { - IOProfile *profile = mHwModules[module_index]->mInputProfiles[profile_index]; + sp profile = mHwModules[module_index]->mInputProfiles[profile_index]; if (profile->mSupportedDevices.types() & device) { ALOGV("checkInputsForDevice(): clearing direct input profile %d on module %d", profile_index, module_index); @@ -2605,7 +2584,7 @@ void AudioPolicyManager::checkA2dpSuspend() } } -audio_devices_t AudioPolicyManager::getNewDevice(audio_io_handle_t output, bool fromCache) +audio_devices_t AudioPolicyManager::getNewOutputDevice(audio_io_handle_t output, bool fromCache) { audio_devices_t device = AUDIO_DEVICE_NONE; @@ -2638,7 +2617,16 @@ audio_devices_t AudioPolicyManager::getNewDevice(audio_io_handle_t output, bool device = getDeviceForStrategy(STRATEGY_DTMF, fromCache); } - ALOGV("getNewDevice() selected device %x", device); + ALOGV("getNewOutputDevice() selected device %x", device); + return device; +} + +audio_devices_t AudioPolicyManager::getNewInputDevice(audio_io_handle_t input) +{ + AudioInputDescriptor *inputDesc = mInputs.valueFor(input); + audio_devices_t device = getDeviceForInputSource(inputDesc->mInputSource); + + ALOGV("getNewInputDevice() selected device %x", device); return device; } @@ -2784,7 +2772,7 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate } device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_EARPIECE; if (device) break; - device = mDefaultOutputDevice->mType; + device = mDefaultOutputDevice->mDeviceType; if (device == AUDIO_DEVICE_NONE) { ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE"); } @@ -2813,7 +2801,7 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate } device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPEAKER; if (device) break; - device = mDefaultOutputDevice->mType; + device = mDefaultOutputDevice->mDeviceType; if (device == AUDIO_DEVICE_NONE) { ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER"); } @@ -2895,7 +2883,7 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate // STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise device |= device2; if (device) break; - device = mDefaultOutputDevice->mType; + device = mDefaultOutputDevice->mDeviceType; if (device == AUDIO_DEVICE_NONE) { ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA"); } @@ -2981,9 +2969,9 @@ uint32_t AudioPolicyManager::checkDeviceMuteStrategies(AudioOutputDescriptor *ou } for (size_t i = 0; i < NUM_STRATEGIES; i++) { if (outputDesc->isStrategyActive((routing_strategy)i)) { - setStrategyMute((routing_strategy)i, true, outputDesc->mId); + setStrategyMute((routing_strategy)i, true, outputDesc->mIoHandle); // do tempMute unmute after twice the mute wait time - setStrategyMute((routing_strategy)i, false, outputDesc->mId, + setStrategyMute((routing_strategy)i, false, outputDesc->mIoHandle, muteWaitMs *2, device); } } @@ -3009,8 +2997,8 @@ uint32_t AudioPolicyManager::setOutputDevice(audio_io_handle_t output, uint32_t muteWaitMs; if (outputDesc->isDuplicated()) { - muteWaitMs = setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs); - muteWaitMs += setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs); + muteWaitMs = setOutputDevice(outputDesc->mOutput1->mIoHandle, device, force, delayMs); + muteWaitMs += setOutputDevice(outputDesc->mOutput2->mIoHandle, device, force, delayMs); return muteWaitMs; } // no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current @@ -3042,9 +3030,34 @@ uint32_t AudioPolicyManager::setOutputDevice(audio_io_handle_t output, } ALOGV("setOutputDevice() changing device"); + // do the routing - param.addInt(String8(AudioParameter::keyRouting), (int)device); - mpClientInterface->setParameters(output, param.toString(), delayMs); + if (device == AUDIO_DEVICE_NONE) { + resetOutputDevice(output, delayMs); + } else { + DeviceVector deviceList = mAvailableOutputDevices.getDevicesFromType(device); + if (!deviceList.isEmpty()) { + struct audio_patch patch; + outputDesc->toAudioPortConfig(&patch.sources[0]); + patch.num_sources = 1; + patch.num_sinks = 0; + for (size_t i = 0; i < deviceList.size() && i < AUDIO_PATCH_PORTS_MAX; i++) { + deviceList.itemAt(i)->toAudioPortConfig(&patch.sinks[i]); + patch.sinks[i].ext.device.hw_module = patch.sources[0].ext.mix.hw_module; + patch.num_sinks++; + } + audio_patch_handle_t patchHandle = outputDesc->mPatchHandle; + status_t status = mpClientInterface->createAudioPatch(&patch, + &patchHandle, + delayMs); + ALOGV("setOutputDevice() createAudioPatch returned %d patchHandle %d" + "num_sources %d num_sinks %d", + status, patchHandle, patch.num_sources, patch.num_sinks); + if (status == NO_ERROR) { + outputDesc->mPatchHandle = patchHandle; + } + } + } // update stream volumes according to new device applyStreamVolumes(output, device, delayMs); @@ -3052,7 +3065,65 @@ uint32_t AudioPolicyManager::setOutputDevice(audio_io_handle_t output, return muteWaitMs; } -AudioPolicyManager::IOProfile *AudioPolicyManager::getInputProfile(audio_devices_t device, +status_t AudioPolicyManager::resetOutputDevice(audio_io_handle_t output, + int delayMs) +{ + AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output); + if (outputDesc->mPatchHandle == 0) { + return INVALID_OPERATION; + } + status_t status = mpClientInterface->releaseAudioPatch(outputDesc->mPatchHandle, delayMs); + ALOGV("resetOutputDevice() releaseAudioPatch returned %d", status); + outputDesc->mPatchHandle = 0; + return status; +} + +status_t AudioPolicyManager::setInputDevice(audio_io_handle_t input, + audio_devices_t device, + bool force) +{ + status_t status = NO_ERROR; + + AudioInputDescriptor *inputDesc = mInputs.valueFor(input); + if ((device != AUDIO_DEVICE_NONE) && ((device != inputDesc->mDevice) || force)) { + inputDesc->mDevice = device; + + DeviceVector deviceList = mAvailableInputDevices.getDevicesFromType(device); + if (!deviceList.isEmpty()) { + struct audio_patch patch; + inputDesc->toAudioPortConfig(&patch.sinks[0]); + patch.num_sinks = 1; + //only one input device for now + deviceList.itemAt(0)->toAudioPortConfig(&patch.sources[0]); + patch.sources[0].ext.device.hw_module = patch.sinks[0].ext.mix.hw_module; + patch.num_sources = 1; + audio_patch_handle_t patchHandle = inputDesc->mPatchHandle; + status_t status = mpClientInterface->createAudioPatch(&patch, + &patchHandle, + 0); + ALOGV("setInputDevice() createAudioPatch returned %d patchHandle %d", + status, patchHandle); + if (status == NO_ERROR) { + inputDesc->mPatchHandle = patchHandle; + } + } + } + return status; +} + +status_t AudioPolicyManager::resetInputDevice(audio_io_handle_t input) +{ + AudioInputDescriptor *inputDesc = mInputs.valueFor(input); + if (inputDesc->mPatchHandle == 0) { + return INVALID_OPERATION; + } + status_t status = mpClientInterface->releaseAudioPatch(inputDesc->mPatchHandle, 0); + ALOGV("resetInputDevice() releaseAudioPatch returned %d", status); + inputDesc->mPatchHandle = 0; + return status; +} + +sp AudioPolicyManager::getInputProfile(audio_devices_t device, uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask) @@ -3067,7 +3138,7 @@ AudioPolicyManager::IOProfile *AudioPolicyManager::getInputProfile(audio_devices } for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++) { - IOProfile *profile = mHwModules[i]->mInputProfiles[j]; + sp profile = mHwModules[i]->mInputProfiles[j]; // profile->log(); if (profile->isCompatibleProfile(device, samplingRate, format, channelMask, AUDIO_OUTPUT_FLAG_NONE)) { @@ -3648,10 +3719,10 @@ uint32_t AudioPolicyManager::getMaxEffectsMemory() // --- AudioOutputDescriptor class implementation AudioPolicyManager::AudioOutputDescriptor::AudioOutputDescriptor( - const IOProfile *profile) - : mId(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), + const sp& profile) + : mId(0), mIoHandle(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(0), mLatency(0), - mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE), + mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE), mPatchHandle(0), mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(0) { // clear usage count for all stream types @@ -3770,6 +3841,32 @@ bool AudioPolicyManager::AudioOutputDescriptor::isStreamActive(audio_stream_type return false; } +void AudioPolicyManager::AudioOutputDescriptor::toAudioPortConfig( + struct audio_port_config *config) const +{ + config->id = mId; + config->role = AUDIO_PORT_ROLE_SOURCE; + config->type = AUDIO_PORT_TYPE_MIX; + config->sample_rate = mSamplingRate; + config->channel_mask = mChannelMask; + config->format = mFormat; + config->gain.index = -1; + config->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK| + AUDIO_PORT_CONFIG_FORMAT; + config->ext.mix.hw_module = mProfile->mModule->mHandle; + config->ext.mix.handle = mIoHandle; + config->ext.mix.usecase.stream = AUDIO_STREAM_DEFAULT; +} + +void AudioPolicyManager::AudioOutputDescriptor::toAudioPort( + struct audio_port *port) const +{ + mProfile->toAudioPort(port); + port->id = mId; + port->ext.mix.handle = mIoHandle; + port->ext.mix.latency_class = + mFlags & AUDIO_OUTPUT_FLAG_FAST ? AUDIO_LATENCY_LOW : AUDIO_LATENCY_NORMAL; +} status_t AudioPolicyManager::AudioOutputDescriptor::dump(int fd) { @@ -3803,9 +3900,10 @@ status_t AudioPolicyManager::AudioOutputDescriptor::dump(int fd) // --- AudioInputDescriptor class implementation -AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const IOProfile *profile) - : mId(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(0), - mDevice(AUDIO_DEVICE_NONE), mRefCount(0), +AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const sp& profile) + : mId(0), mIoHandle(0), mSamplingRate(0), + mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(0), + mDevice(AUDIO_DEVICE_NONE), mPatchHandle(0), mRefCount(0), mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile) { if (profile != NULL) { @@ -3815,6 +3913,33 @@ AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const IOProfile * } } +void AudioPolicyManager::AudioInputDescriptor::toAudioPortConfig( + struct audio_port_config *config) const +{ + config->id = mId; + config->role = AUDIO_PORT_ROLE_SINK; + config->type = AUDIO_PORT_TYPE_MIX; + config->sample_rate = mSamplingRate; + config->channel_mask = mChannelMask; + config->format = mFormat; + config->gain.index = -1; + config->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK| + AUDIO_PORT_CONFIG_FORMAT; + config->ext.mix.hw_module = mProfile->mModule->mHandle; + config->ext.mix.handle = mIoHandle; + config->ext.mix.usecase.source = (mInputSource == AUDIO_SOURCE_HOTWORD) ? + AUDIO_SOURCE_VOICE_RECOGNITION : mInputSource; +} + +void AudioPolicyManager::AudioInputDescriptor::toAudioPort( + struct audio_port *port) const +{ + mProfile->toAudioPort(port); + port->id = mId; + port->ext.mix.handle = mIoHandle; + port->ext.mix.latency_class = AUDIO_LATENCY_NORMAL; +} + status_t AudioPolicyManager::AudioInputDescriptor::dump(int fd) { const size_t SIZE = 256; @@ -3897,7 +4022,7 @@ status_t AudioPolicyManager::EffectDescriptor::dump(int fd) return NO_ERROR; } -// --- IOProfile class implementation +// --- HwModule class implementation AudioPolicyManager::HwModule::HwModule(const char *name) : mName(strndup(name, AUDIO_HARDWARE_MODULE_ID_MAX_LEN)), mHandle(0) @@ -3908,11 +4033,9 @@ AudioPolicyManager::HwModule::~HwModule() { for (size_t i = 0; i < mOutputProfiles.size(); i++) { mOutputProfiles[i]->mSupportedDevices.clear(); - delete mOutputProfiles[i]; } for (size_t i = 0; i < mInputProfiles.size(); i++) { mInputProfiles[i]->mSupportedDevices.clear(); - delete mInputProfiles[i]; } free((void *)mName); } @@ -3946,8 +4069,129 @@ void AudioPolicyManager::HwModule::dump(int fd) } } -AudioPolicyManager::IOProfile::IOProfile(HwModule *module) - : mFlags((audio_output_flags_t)0), mModule(module) +// --- AudioPort class implementation + +void AudioPolicyManager::AudioPort::toAudioPort(struct audio_port *port) const +{ + port->role = mRole; + port->type = mType; + unsigned int i; + for (i = 0; i < mSamplingRates.size() && i < AUDIO_PORT_MAX_SAMPLING_RATES; i++) { + port->sample_rates[i] = mSamplingRates[i]; + } + port->num_sample_rates = i; + for (i = 0; i < mChannelMasks.size() && i < AUDIO_PORT_MAX_CHANNEL_MASKS; i++) { + port->channel_masks[i] = mChannelMasks[i]; + } + port->num_channel_masks = i; + for (i = 0; i < mFormats.size() && i < AUDIO_PORT_MAX_FORMATS; i++) { + port->formats[i] = mFormats[i]; + } + port->num_formats = i; + port->num_gains = 0; +} + + +void AudioPolicyManager::AudioPort::loadSamplingRates(char *name) +{ + char *str = strtok(name, "|"); + + // by convention, "0' in the first entry in mSamplingRates indicates the supported sampling + // rates should be read from the output stream after it is opened for the first time + if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) { + mSamplingRates.add(0); + return; + } + + while (str != NULL) { + uint32_t rate = atoi(str); + if (rate != 0) { + ALOGV("loadSamplingRates() adding rate %d", rate); + mSamplingRates.add(rate); + } + str = strtok(NULL, "|"); + } + return; +} + +void AudioPolicyManager::AudioPort::loadFormats(char *name) +{ + char *str = strtok(name, "|"); + + // by convention, "0' in the first entry in mFormats indicates the supported formats + // should be read from the output stream after it is opened for the first time + if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) { + mFormats.add(AUDIO_FORMAT_DEFAULT); + return; + } + + while (str != NULL) { + audio_format_t format = (audio_format_t)stringToEnum(sFormatNameToEnumTable, + ARRAY_SIZE(sFormatNameToEnumTable), + str); + if (format != AUDIO_FORMAT_DEFAULT) { + mFormats.add(format); + } + str = strtok(NULL, "|"); + } + return; +} + +void AudioPolicyManager::AudioPort::loadInChannels(char *name) +{ + const char *str = strtok(name, "|"); + + ALOGV("loadInChannels() %s", name); + + if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) { + mChannelMasks.add(0); + return; + } + + while (str != NULL) { + audio_channel_mask_t channelMask = + (audio_channel_mask_t)stringToEnum(sInChannelsNameToEnumTable, + ARRAY_SIZE(sInChannelsNameToEnumTable), + str); + if (channelMask != 0) { + ALOGV("loadInChannels() adding channelMask %04x", channelMask); + mChannelMasks.add(channelMask); + } + str = strtok(NULL, "|"); + } + return; +} + +void AudioPolicyManager::AudioPort::loadOutChannels(char *name) +{ + const char *str = strtok(name, "|"); + + ALOGV("loadOutChannels() %s", name); + + // by convention, "0' in the first entry in mChannelMasks indicates the supported channel + // masks should be read from the output stream after it is opened for the first time + if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) { + mChannelMasks.add(0); + return; + } + + while (str != NULL) { + audio_channel_mask_t channelMask = + (audio_channel_mask_t)stringToEnum(sOutChannelsNameToEnumTable, + ARRAY_SIZE(sOutChannelsNameToEnumTable), + str); + if (channelMask != 0) { + mChannelMasks.add(channelMask); + } + str = strtok(NULL, "|"); + } + return; +} + +// --- IOProfile class implementation + +AudioPolicyManager::IOProfile::IOProfile(audio_port_role_t role, HwModule *module) + : AudioPort(AUDIO_PORT_TYPE_MIX, role, module), mFlags((audio_output_flags_t)0) { } @@ -4083,7 +4327,7 @@ bool AudioPolicyManager::DeviceDescriptor::equals(const sp& ot // - are of the same type (a device type cannot be AUDIO_DEVICE_NONE) // - have the same address or one device does not specify the address // - have the same channel mask or one device does not specify the channel mask - return (mType == other->mType) && + return (mDeviceType == other->mDeviceType) && (mAddress == "" || other->mAddress == "" || mAddress == other->mAddress) && (mChannelMask == 0 || other->mChannelMask == 0 || mChannelMask == other->mChannelMask); @@ -4091,11 +4335,11 @@ bool AudioPolicyManager::DeviceDescriptor::equals(const sp& ot void AudioPolicyManager::DeviceVector::refreshTypes() { - mTypes = AUDIO_DEVICE_NONE; + mDeviceTypes = AUDIO_DEVICE_NONE; for(size_t i = 0; i < size(); i++) { - mTypes |= itemAt(i)->mType; + mDeviceTypes |= itemAt(i)->mDeviceType; } - ALOGV("DeviceVector::refreshTypes() mTypes %08x", mTypes); + ALOGV("DeviceVector::refreshTypes() mDeviceTypes %08x", mDeviceTypes); } ssize_t AudioPolicyManager::DeviceVector::indexOf(const sp& item) const @@ -4118,7 +4362,7 @@ ssize_t AudioPolicyManager::DeviceVector::add(const sp& item) refreshTypes(); } } else { - ALOGW("DeviceVector::add device %08x already in", item->mType); + ALOGW("DeviceVector::add device %08x already in", item->mDeviceType); ret = -1; } return ret; @@ -4130,7 +4374,7 @@ ssize_t AudioPolicyManager::DeviceVector::remove(const sp& ite ssize_t ret = indexOf(item); if (ret < 0) { - ALOGW("DeviceVector::remove device %08x not in", item->mType); + ALOGW("DeviceVector::remove device %08x not in", item->mDeviceType); } else { ret = SortedVector::removeAt(ret); if (ret >= 0) { @@ -4155,6 +4399,61 @@ void AudioPolicyManager::DeviceVector::loadDevicesFromType(audio_devices_t types } } +sp AudioPolicyManager::DeviceVector::getDevice( + audio_devices_t type, String8 address) const +{ + sp device; + for (size_t i = 0; i < size(); i++) { + if (itemAt(i)->mDeviceType == type) { + device = itemAt(i); + if (itemAt(i)->mAddress = address) { + break; + } + } + } + ALOGV("DeviceVector::getDevice() for type %d address %s found %p", + type, address.string(), device.get()); + return device; +} + +AudioPolicyManager::DeviceVector AudioPolicyManager::DeviceVector::getDevicesFromType( + audio_devices_t type) const +{ + DeviceVector devices; + for (size_t i = 0; (i < size()) && (type != AUDIO_DEVICE_NONE); i++) { + if (itemAt(i)->mDeviceType & type & ~AUDIO_DEVICE_BIT_IN) { + devices.add(itemAt(i)); + type &= ~itemAt(i)->mDeviceType; + ALOGV("DeviceVector::getDevicesFromType() for type %x found %p", + itemAt(i)->mDeviceType, itemAt(i).get()); + } + } + return devices; +} + +void AudioPolicyManager::DeviceDescriptor::toAudioPortConfig(struct audio_port_config *config) const +{ + config->id = mId; + config->role = audio_is_output_device(mDeviceType) ? + AUDIO_PORT_ROLE_SINK : AUDIO_PORT_ROLE_SOURCE; + config->type = AUDIO_PORT_TYPE_DEVICE; + config->sample_rate = 0; + config->channel_mask = mChannelMask; + config->format = AUDIO_FORMAT_DEFAULT; + config->config_mask = AUDIO_PORT_CONFIG_CHANNEL_MASK; + config->gain.index = -1; + config->ext.device.type = mDeviceType; + strncpy(config->ext.device.address, mAddress.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN); +} + +void AudioPolicyManager::DeviceDescriptor::toAudioPort(struct audio_port *port) const +{ + AudioPort::toAudioPort(port); + port->id = mId; + port->ext.device.type = mDeviceType; + strncpy(port->ext.device.address, mAddress.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN); +} + void AudioPolicyManager::DeviceDescriptor::dumpHeader(int fd, int spaces) { const size_t SIZE = 256; @@ -4174,7 +4473,7 @@ status_t AudioPolicyManager::DeviceDescriptor::dump(int fd, int spaces) const spaces, "", enumToString(sDeviceNameToEnumTable, ARRAY_SIZE(sDeviceNameToEnumTable), - mType), + mDeviceType), mId, mChannelMask, mAddress.string()); write(fd, buffer, strlen(buffer)); @@ -4225,115 +4524,19 @@ audio_devices_t AudioPolicyManager::parseDeviceNames(char *name) return device; } -void AudioPolicyManager::loadSamplingRates(char *name, IOProfile *profile) -{ - char *str = strtok(name, "|"); - - // by convention, "0' in the first entry in mSamplingRates indicates the supported sampling - // rates should be read from the output stream after it is opened for the first time - if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) { - profile->mSamplingRates.add(0); - return; - } - - while (str != NULL) { - uint32_t rate = atoi(str); - if (rate != 0) { - ALOGV("loadSamplingRates() adding rate %d", rate); - profile->mSamplingRates.add(rate); - } - str = strtok(NULL, "|"); - } - return; -} - -void AudioPolicyManager::loadFormats(char *name, IOProfile *profile) -{ - char *str = strtok(name, "|"); - - // by convention, "0' in the first entry in mFormats indicates the supported formats - // should be read from the output stream after it is opened for the first time - if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) { - profile->mFormats.add(AUDIO_FORMAT_DEFAULT); - return; - } - - while (str != NULL) { - audio_format_t format = (audio_format_t)stringToEnum(sFormatNameToEnumTable, - ARRAY_SIZE(sFormatNameToEnumTable), - str); - if (format != AUDIO_FORMAT_DEFAULT) { - profile->mFormats.add(format); - } - str = strtok(NULL, "|"); - } - return; -} - -void AudioPolicyManager::loadInChannels(char *name, IOProfile *profile) -{ - const char *str = strtok(name, "|"); - - ALOGV("loadInChannels() %s", name); - - if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) { - profile->mChannelMasks.add(0); - return; - } - - while (str != NULL) { - audio_channel_mask_t channelMask = - (audio_channel_mask_t)stringToEnum(sInChannelsNameToEnumTable, - ARRAY_SIZE(sInChannelsNameToEnumTable), - str); - if (channelMask != 0) { - ALOGV("loadInChannels() adding channelMask %04x", channelMask); - profile->mChannelMasks.add(channelMask); - } - str = strtok(NULL, "|"); - } - return; -} - -void AudioPolicyManager::loadOutChannels(char *name, IOProfile *profile) -{ - const char *str = strtok(name, "|"); - - ALOGV("loadOutChannels() %s", name); - - // by convention, "0' in the first entry in mChannelMasks indicates the supported channel - // masks should be read from the output stream after it is opened for the first time - if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) { - profile->mChannelMasks.add(0); - return; - } - - while (str != NULL) { - audio_channel_mask_t channelMask = - (audio_channel_mask_t)stringToEnum(sOutChannelsNameToEnumTable, - ARRAY_SIZE(sOutChannelsNameToEnumTable), - str); - if (channelMask != 0) { - profile->mChannelMasks.add(channelMask); - } - str = strtok(NULL, "|"); - } - return; -} - status_t AudioPolicyManager::loadInput(cnode *root, HwModule *module) { cnode *node = root->first_child; - IOProfile *profile = new IOProfile(module); + sp profile = new IOProfile(AUDIO_PORT_ROLE_SINK, module); while (node) { if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) { - loadSamplingRates((char *)node->value, profile); + profile->loadSamplingRates((char *)node->value); } else if (strcmp(node->name, FORMATS_TAG) == 0) { - loadFormats((char *)node->value, profile); + profile->loadFormats((char *)node->value); } else if (strcmp(node->name, CHANNELS_TAG) == 0) { - loadInChannels((char *)node->value, profile); + profile->loadInChannels((char *)node->value); } else if (strcmp(node->name, DEVICES_TAG) == 0) { profile->mSupportedDevices.loadDevicesFromType(parseDeviceNames((char *)node->value)); } @@ -4358,7 +4561,6 @@ status_t AudioPolicyManager::loadInput(cnode *root, HwModule *module) module->mInputProfiles.add(profile); return NO_ERROR; } else { - delete profile; return BAD_VALUE; } } @@ -4367,15 +4569,15 @@ status_t AudioPolicyManager::loadOutput(cnode *root, HwModule *module) { cnode *node = root->first_child; - IOProfile *profile = new IOProfile(module); + sp profile = new IOProfile(AUDIO_PORT_ROLE_SOURCE, module); while (node) { if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) { - loadSamplingRates((char *)node->value, profile); + profile->loadSamplingRates((char *)node->value); } else if (strcmp(node->name, FORMATS_TAG) == 0) { - loadFormats((char *)node->value, profile); + profile->loadFormats((char *)node->value); } else if (strcmp(node->name, CHANNELS_TAG) == 0) { - loadOutChannels((char *)node->value, profile); + profile->loadOutChannels((char *)node->value); } else if (strcmp(node->name, DEVICES_TAG) == 0) { profile->mSupportedDevices.loadDevicesFromType(parseDeviceNames((char *)node->value)); } else if (strcmp(node->name, FLAGS_TAG) == 0) { @@ -4402,7 +4604,6 @@ status_t AudioPolicyManager::loadOutput(cnode *root, HwModule *module) module->mOutputProfiles.add(profile); return NO_ERROR; } else { - delete profile; return BAD_VALUE; } } @@ -4480,7 +4681,7 @@ void AudioPolicyManager::loadGlobalConfig(cnode *root) } else { ALOGW("loadGlobalConfig() default device not specified"); } - ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", mDefaultOutputDevice->mType); + ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", mDefaultOutputDevice->mDeviceType); } else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) { mAvailableInputDevices.loadDevicesFromType(parseDeviceNames((char *)node->value)); ALOGV("loadGlobalConfig() Available InputDevices %08x", mAvailableInputDevices.types()); @@ -4519,14 +4720,14 @@ status_t AudioPolicyManager::loadAudioPolicyConfig(const char *path) void AudioPolicyManager::defaultAudioPolicyConfig(void) { HwModule *module; - IOProfile *profile; + sp profile; sp defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC); mAvailableOutputDevices.add(mDefaultOutputDevice); mAvailableInputDevices.add(defaultInputDevice); module = new HwModule("primary"); - profile = new IOProfile(module); + profile = new IOProfile(AUDIO_PORT_ROLE_SOURCE, module); profile->mSamplingRates.add(44100); profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT); profile->mChannelMasks.add(AUDIO_CHANNEL_OUT_STEREO); @@ -4534,7 +4735,7 @@ void AudioPolicyManager::defaultAudioPolicyConfig(void) profile->mFlags = AUDIO_OUTPUT_FLAG_PRIMARY; module->mOutputProfiles.add(profile); - profile = new IOProfile(module); + profile = new IOProfile(AUDIO_PORT_ROLE_SINK, module); profile->mSamplingRates.add(8000); profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT); profile->mChannelMasks.add(AUDIO_CHANNEL_IN_MONO); diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h index f00fa8a..905a3c8 100644 --- a/services/audiopolicy/AudioPolicyManager.h +++ b/services/audiopolicy/AudioPolicyManager.h @@ -175,58 +175,97 @@ protected: class IOProfile; - class DeviceDescriptor: public RefBase + class HwModule { + public: + HwModule(const char *name); + ~HwModule(); + + void dump(int fd); + + const char *const mName; // base name of the audio HW module (primary, a2dp ...) + audio_module_handle_t mHandle; + Vector < sp > mOutputProfiles; // output profiles exposed by this module + Vector < sp > mInputProfiles; // input profiles exposed by this module + }; + + class AudioPort: public RefBase + { + public: + AudioPort(audio_port_type_t type, audio_port_role_t role, HwModule *module) : + mType(type), mRole(role), mModule(module) {} + virtual ~AudioPort() {} + + virtual void toAudioPort(struct audio_port *port) const; + + void loadSamplingRates(char *name); + void loadFormats(char *name); + void loadOutChannels(char *name); + void loadInChannels(char *name); + + audio_port_type_t mType; + audio_port_role_t mRole; + // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats + // indicates the supported parameters should be read from the output stream + // after it is opened for the first time + Vector mSamplingRates; // supported sampling rates + Vector mChannelMasks; // supported channel masks + Vector mFormats; // supported audio formats + HwModule *mModule; // audio HW module exposing this I/O stream + }; + + + class DeviceDescriptor: public AudioPort { public: DeviceDescriptor(audio_devices_t type, String8 address, audio_channel_mask_t channelMask) : - mType(type), mAddress(address), + AudioPort(AUDIO_PORT_TYPE_DEVICE, + audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK : + AUDIO_PORT_ROLE_SOURCE, + NULL), + mDeviceType(type), mAddress(address), mChannelMask(channelMask), mId(0) {} DeviceDescriptor(audio_devices_t type) : - mType(type), mAddress(""), - mChannelMask(0), mId(0) {} + AudioPort(AUDIO_PORT_TYPE_DEVICE, + audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK : + AUDIO_PORT_ROLE_SOURCE, + NULL), + mDeviceType(type), mAddress(""), + mChannelMask(0), mId(0) {} + virtual ~DeviceDescriptor() {} + + bool equals(const sp& other) const; + void toAudioPortConfig(struct audio_port_config *config) const; + virtual void toAudioPort(struct audio_port *port) const; status_t dump(int fd, int spaces) const; static void dumpHeader(int fd, int spaces); - bool equals(const sp& other) const; - - audio_devices_t mType; + audio_devices_t mDeviceType; String8 mAddress; audio_channel_mask_t mChannelMask; - uint32_t mId; + audio_port_handle_t mId; }; class DeviceVector : public SortedVector< sp > { public: - DeviceVector() : SortedVector(), mTypes(AUDIO_DEVICE_NONE) {} + DeviceVector() : SortedVector(), mDeviceTypes(AUDIO_DEVICE_NONE) {} ssize_t add(const sp& item); ssize_t remove(const sp& item); ssize_t indexOf(const sp& item) const; - audio_devices_t types() const { return mTypes; } + audio_devices_t types() const { return mDeviceTypes; } void loadDevicesFromType(audio_devices_t types); + sp getDevice(audio_devices_t type, String8 address) const; + DeviceVector getDevicesFromType(audio_devices_t types) const; private: void refreshTypes(); - audio_devices_t mTypes; - }; - - class HwModule { - public: - HwModule(const char *name); - ~HwModule(); - - void dump(int fd); - - const char *const mName; // base name of the audio HW module (primary, a2dp ...) - audio_module_handle_t mHandle; - Vector mOutputProfiles; // output profiles exposed by this module - Vector mInputProfiles; // input profiles exposed by this module + audio_devices_t mDeviceTypes; }; // the IOProfile class describes the capabilities of an output or input stream. @@ -234,11 +273,11 @@ protected: // It is used by the policy manager to determine if an output or input is suitable for // a given use case, open/close it accordingly and connect/disconnect audio tracks // to/from it. - class IOProfile + class IOProfile : public AudioPort { public: - IOProfile(HwModule *module); - ~IOProfile(); + IOProfile(audio_port_role_t role, HwModule *module); + virtual ~IOProfile(); bool isCompatibleProfile(audio_devices_t device, uint32_t samplingRate, @@ -249,17 +288,10 @@ protected: void dump(int fd); void log(); - // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats - // indicates the supported parameters should be read from the output stream - // after it is opened for the first time - Vector mSamplingRates; // supported sampling rates - Vector mChannelMasks; // supported channel masks - Vector mFormats; // supported audio formats DeviceVector mSupportedDevices; // supported devices // (devices this output can be routed to) audio_output_flags_t mFlags; // attribute flags (e.g primary output, // direct output...). For outputs only. - HwModule *mModule; // audio HW module exposing this I/O stream }; // default volume curve @@ -284,7 +316,7 @@ protected: class AudioOutputDescriptor { public: - AudioOutputDescriptor(const IOProfile *profile); + AudioOutputDescriptor(const sp& profile); status_t dump(int fd); @@ -303,20 +335,25 @@ protected: uint32_t inPastMs = 0, nsecs_t sysTime = 0) const; - audio_io_handle_t mId; // output handle + void toAudioPortConfig(struct audio_port_config *config) const; + void toAudioPort(struct audio_port *port) const; + + audio_port_handle_t mId; + audio_io_handle_t mIoHandle; // output handle uint32_t mSamplingRate; // audio_format_t mFormat; // audio_channel_mask_t mChannelMask; // output configuration uint32_t mLatency; // audio_output_flags_t mFlags; // audio_devices_t mDevice; // current device this output is routed to + audio_patch_handle_t mPatchHandle; uint32_t mRefCount[AUDIO_STREAM_CNT]; // number of streams of each type using this output nsecs_t mStopTime[AUDIO_STREAM_CNT]; AudioOutputDescriptor *mOutput1; // used by duplicated outputs: first output AudioOutputDescriptor *mOutput2; // used by duplicated outputs: second output float mCurVolume[AUDIO_STREAM_CNT]; // current stream volume int mMuteCount[AUDIO_STREAM_CNT]; // mute request counter - const IOProfile *mProfile; // I/O profile this output derives from + const sp mProfile; // I/O profile this output derives from bool mStrategyMutedByDevice[NUM_STRATEGIES]; // strategies muted because of incompatible // device selection. See checkDeviceMuteStrategies() uint32_t mDirectOpenCount; // number of clients using this output (direct outputs only) @@ -327,18 +364,23 @@ protected: class AudioInputDescriptor { public: - AudioInputDescriptor(const IOProfile *profile); + AudioInputDescriptor(const sp& profile); status_t dump(int fd); - audio_io_handle_t mId; // input handle + audio_port_handle_t mId; + audio_io_handle_t mIoHandle; // input handle uint32_t mSamplingRate; // audio_format_t mFormat; // input configuration audio_channel_mask_t mChannelMask; // audio_devices_t mDevice; // current device this input is routed to + audio_patch_handle_t mPatchHandle; uint32_t mRefCount; // number of AudioRecord clients using this output audio_source_t mInputSource; // input source selected by application (mediarecorder.h) - const IOProfile *mProfile; // I/O profile this output derives from + const sp mProfile; // I/O profile this output derives from + + void toAudioPortConfig(struct audio_port_config *config) const; + void toAudioPort(struct audio_port *port) const; }; // stream descriptor used for volume control @@ -372,8 +414,8 @@ protected: bool mEnabled; // enabled state: CPU load being used or not }; - void addOutput(audio_io_handle_t id, AudioOutputDescriptor *outputDesc); - void addInput(audio_io_handle_t id, AudioInputDescriptor *inputDesc); + void addOutput(audio_io_handle_t output, AudioOutputDescriptor *outputDesc); + void addInput(audio_io_handle_t input, AudioInputDescriptor *inputDesc); // return the strategy corresponding to a given stream type static routing_strategy getStrategy(audio_stream_type_t stream); @@ -398,6 +440,12 @@ protected: audio_devices_t device, bool force = false, int delayMs = 0); + status_t resetOutputDevice(audio_io_handle_t output, + int delayMs = 0); + status_t setInputDevice(audio_io_handle_t input, + audio_devices_t device, + bool force = false); + status_t resetInputDevice(audio_io_handle_t input); // select input device corresponding to requested audio source virtual audio_devices_t getDeviceForInputSource(audio_source_t inputSource); @@ -484,16 +532,18 @@ protected: // must be called every time a condition that affects the device choice for a given output is // changed: connected device, phone state, force use, output start, output stop.. // see getDeviceForStrategy() for the use of fromCache parameter + audio_devices_t getNewOutputDevice(audio_io_handle_t output, bool fromCache); - audio_devices_t getNewDevice(audio_io_handle_t output, bool fromCache); // updates cache of device used by all strategies (mDeviceForStrategy[]) // must be called every time a condition that affects the device choice for a given strategy is // changed: connected device, phone state, force use... // cached values are used by getDeviceForStrategy() if parameter fromCache is true. // Must be called after checkOutputForAllStrategies() - void updateDevicesAndOutputs(); + // selects the most appropriate device on input for current state + audio_devices_t getNewInputDevice(audio_io_handle_t input); + virtual uint32_t getMaxEffectsCpuLoad(); virtual uint32_t getMaxEffectsMemory(); #ifdef AUDIO_POLICY_TEST @@ -525,11 +575,11 @@ protected: audio_io_handle_t selectOutput(const SortedVector& outputs, audio_output_flags_t flags); - IOProfile *getInputProfile(audio_devices_t device, + sp getInputProfile(audio_devices_t device, uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask); - IOProfile *getProfileForDirectOutput(audio_devices_t device, + sp getProfileForDirectOutput(audio_devices_t device, uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask, @@ -551,10 +601,6 @@ protected: static bool stringToBool(const char *value); static audio_output_flags_t parseFlagNames(char *name); static audio_devices_t parseDeviceNames(char *name); - void loadSamplingRates(char *name, IOProfile *profile); - void loadFormats(char *name, IOProfile *profile); - void loadOutChannels(char *name, IOProfile *profile); - void loadInChannels(char *name, IOProfile *profile); status_t loadOutput(cnode *root, HwModule *module); status_t loadInput(cnode *root, HwModule *module); void loadHwModule(cnode *root); diff --git a/services/audiopolicy/AudioPolicyService.cpp b/services/audiopolicy/AudioPolicyService.cpp index 4e9a2f0..ea573a4 100644 --- a/services/audiopolicy/AudioPolicyService.cpp +++ b/services/audiopolicy/AudioPolicyService.cpp @@ -150,6 +150,19 @@ AudioPolicyService::~AudioPolicyService() #endif } +status_t AudioPolicyService::clientCreateAudioPatch(const struct audio_patch *patch, + audio_patch_handle_t *handle, + int delayMs) +{ + return mAudioCommandThread->createAudioPatchCommand(patch, handle, delayMs); +} + +status_t AudioPolicyService::clientReleaseAudioPatch(audio_patch_handle_t handle, + int delayMs) +{ + return mAudioCommandThread->releaseAudioPatchCommand(handle, delayMs); +} + void AudioPolicyService::binderDied(const wp& who) { ALOGW("binderDied() %p, calling pid %d", who.unsafe_get(), @@ -357,6 +370,26 @@ bool AudioPolicyService::AudioCommandThread::threadLoop() svc->doReleaseOutput(data->mIO); mLock.lock(); }break; + case CREATE_AUDIO_PATCH: { + CreateAudioPatchData *data = (CreateAudioPatchData *)command->mParam.get(); + ALOGV("AudioCommandThread() processing create audio patch"); + sp af = AudioSystem::get_audio_flinger(); + if (af == 0) { + command->mStatus = PERMISSION_DENIED; + } else { + command->mStatus = af->createAudioPatch(&data->mPatch, &data->mHandle); + } + } break; + case RELEASE_AUDIO_PATCH: { + ReleaseAudioPatchData *data = (ReleaseAudioPatchData *)command->mParam.get(); + ALOGV("AudioCommandThread() processing release audio patch"); + sp af = AudioSystem::get_audio_flinger(); + if (af == 0) { + command->mStatus = PERMISSION_DENIED; + } else { + command->mStatus = af->releaseAudioPatch(data->mHandle); + } + } break; default: ALOGW("AudioCommandThread() unknown command %d", command->mCommand); } @@ -516,6 +549,41 @@ void AudioPolicyService::AudioCommandThread::releaseOutputCommand(audio_io_handl sendCommand(command); } +status_t AudioPolicyService::AudioCommandThread::createAudioPatchCommand( + const struct audio_patch *patch, + audio_patch_handle_t *handle, + int delayMs) +{ + status_t status = NO_ERROR; + + sp command = new AudioCommand(); + command->mCommand = CREATE_AUDIO_PATCH; + CreateAudioPatchData *data = new CreateAudioPatchData(); + data->mPatch = *patch; + data->mHandle = *handle; + command->mParam = data; + command->mWaitStatus = true; + ALOGV("AudioCommandThread() adding create patch delay %d", delayMs); + status = sendCommand(command, delayMs); + if (status == NO_ERROR) { + *handle = data->mHandle; + } + return status; +} + +status_t AudioPolicyService::AudioCommandThread::releaseAudioPatchCommand(audio_patch_handle_t handle, + int delayMs) +{ + sp command = new AudioCommand(); + command->mCommand = RELEASE_AUDIO_PATCH; + ReleaseAudioPatchData *data = new ReleaseAudioPatchData(); + data->mHandle = handle; + command->mParam = data; + command->mWaitStatus = true; + ALOGV("AudioCommandThread() adding release patch delay %d", delayMs); + return sendCommand(command, delayMs); +} + status_t AudioPolicyService::AudioCommandThread::sendCommand(sp& command, int delayMs) { { @@ -534,6 +602,7 @@ status_t AudioPolicyService::AudioCommandThread::sendCommand(sp& c return command->mStatus; } + // insertCommand_l() must be called with mLock held void AudioPolicyService::AudioCommandThread::insertCommand_l(sp& command, int delayMs) { diff --git a/services/audiopolicy/AudioPolicyService.h b/services/audiopolicy/AudioPolicyService.h index 26037e4..a7ed9e8 100644 --- a/services/audiopolicy/AudioPolicyService.h +++ b/services/audiopolicy/AudioPolicyService.h @@ -145,6 +145,12 @@ public: int session = 0); void doReleaseOutput(audio_io_handle_t output); + status_t clientCreateAudioPatch(const struct audio_patch *patch, + audio_patch_handle_t *handle, + int delayMs); + status_t clientReleaseAudioPatch(audio_patch_handle_t handle, + int delayMs); + private: AudioPolicyService() ANDROID_API; virtual ~AudioPolicyService(); @@ -169,7 +175,9 @@ private: SET_PARAMETERS, SET_VOICE_VOLUME, STOP_OUTPUT, - RELEASE_OUTPUT + RELEASE_OUTPUT, + CREATE_AUDIO_PATCH, + RELEASE_AUDIO_PATCH, }; AudioCommandThread (String8 name, const wp& service); @@ -196,6 +204,13 @@ private: void releaseOutputCommand(audio_io_handle_t output); status_t sendCommand(sp& command, int delayMs = 0); void insertCommand_l(sp& command, int delayMs = 0); + status_t createAudioPatchCommand(const struct audio_patch *patch, + audio_patch_handle_t *handle, + int delayMs); + status_t releaseAudioPatchCommand(audio_patch_handle_t handle, + int delayMs); + + void insertCommand_l(AudioCommand *command, int delayMs = 0); private: class AudioCommandData; @@ -261,6 +276,17 @@ private: audio_io_handle_t mIO; }; + class CreateAudioPatchData : public AudioCommandData { + public: + struct audio_patch mPatch; + audio_patch_handle_t mHandle; + }; + + class ReleaseAudioPatchData : public AudioCommandData { + public: + audio_patch_handle_t mHandle; + }; + Mutex mLock; Condition mWaitWorkCV; Vector < sp > mAudioCommands; // list of pending commands @@ -405,6 +431,15 @@ private: audio_io_handle_t srcOutput, audio_io_handle_t dstOutput); + /* Create a patch between several source and sink ports */ + virtual status_t createAudioPatch(const struct audio_patch *patch, + audio_patch_handle_t *handle, + int delayMs); + + /* Release a patch */ + virtual status_t releaseAudioPatch(audio_patch_handle_t handle, + int delayMs); + private: AudioPolicyService *mAudioPolicyService; }; -- cgit v1.1