diff options
Diffstat (limited to 'services')
-rw-r--r-- | services/audioflinger/Android.mk | 1 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 3 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.h | 37 | ||||
-rw-r--r-- | services/audioflinger/PatchPanel.cpp | 409 | ||||
-rw-r--r-- | services/audioflinger/PatchPanel.h | 60 | ||||
-rw-r--r-- | services/audioflinger/Threads.cpp | 132 | ||||
-rw-r--r-- | services/audioflinger/Threads.h | 62 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyClientImpl.cpp | 11 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyInterface.h | 9 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyManager.cpp | 621 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyManager.h | 146 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyService.cpp | 69 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyService.h | 37 |
13 files changed, 1312 insertions, 285 deletions
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<PatchPanel> 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 <utils/Log.h> +#include <audio_utils/primitives.h> + +#include "AudioFlinger.h" +#include "ServiceUtilities.h" +#include <media/AudioParameter.h> + +// ---------------------------------------------------------------------------- + +// 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>& 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> 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<ThreadBase> 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<ThreadBase> 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<ThreadBase> 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> 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<ThreadBase> 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<ThreadBase> 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<ThreadBase> 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>& 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<AudioFlinger> mAudioFlinger; + SortedVector <Patch *> 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 = (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 = (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>& audioFlinger, AudioStreamOut* output, @@ -5743,4 +5818,61 @@ size_t AudioFlinger::RecordThread::removeEffectChain_l(const sp<EffectChain>& 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<RecordTrack> 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::IOProfile> 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<IOProfile> 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<IOProfile> 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<IOProfile> 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<IOProfile> 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<IOProfile> 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<IOProfile> 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<IOProfile *> profiles; + SortedVector< sp<IOProfile> > 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<IOProfile> 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<IOProfile> 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<IOProfile *> profiles; + SortedVector< sp<IOProfile> > 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<IOProfile> 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<IOProfile> 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::IOProfile> 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<IOProfile> 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<IOProfile>& 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<IOProfile>& 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<DeviceDescriptor>& 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<DeviceDescriptor>& 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<DeviceDescriptor>& item) const @@ -4118,7 +4362,7 @@ ssize_t AudioPolicyManager::DeviceVector::add(const sp<DeviceDescriptor>& 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<DeviceDescriptor>& 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::DeviceDescriptor> AudioPolicyManager::DeviceVector::getDevice( + audio_devices_t type, String8 address) const +{ + sp<DeviceDescriptor> 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<IOProfile> 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<IOProfile> 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<IOProfile> profile; sp<DeviceDescriptor> 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<IOProfile> > mOutputProfiles; // output profiles exposed by this module + Vector < sp<IOProfile> > 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 <uint32_t> mSamplingRates; // supported sampling rates + Vector <audio_channel_mask_t> mChannelMasks; // supported channel masks + Vector <audio_format_t> 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<DeviceDescriptor>& 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<DeviceDescriptor>& 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<DeviceDescriptor> > { public: - DeviceVector() : SortedVector(), mTypes(AUDIO_DEVICE_NONE) {} + DeviceVector() : SortedVector(), mDeviceTypes(AUDIO_DEVICE_NONE) {} ssize_t add(const sp<DeviceDescriptor>& item); ssize_t remove(const sp<DeviceDescriptor>& item); ssize_t indexOf(const sp<DeviceDescriptor>& item) const; - audio_devices_t types() const { return mTypes; } + audio_devices_t types() const { return mDeviceTypes; } void loadDevicesFromType(audio_devices_t types); + sp<DeviceDescriptor> 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 <IOProfile *> mOutputProfiles; // output profiles exposed by this module - Vector <IOProfile *> 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 <uint32_t> mSamplingRates; // supported sampling rates - Vector <audio_channel_mask_t> mChannelMasks; // supported channel masks - Vector <audio_format_t> 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<IOProfile>& 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<IOProfile> 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<IOProfile>& 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<IOProfile> 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<audio_io_handle_t>& outputs, audio_output_flags_t flags); - IOProfile *getInputProfile(audio_devices_t device, + sp<IOProfile> getInputProfile(audio_devices_t device, uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask); - IOProfile *getProfileForDirectOutput(audio_devices_t device, + sp<IOProfile> 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<IBinder>& 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<IAudioFlinger> 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<IAudioFlinger> 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<AudioCommand> 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<AudioCommand> 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<AudioCommand>& command, int delayMs) { { @@ -534,6 +602,7 @@ status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& c return command->mStatus; } + // insertCommand_l() must be called with mLock held void AudioPolicyService::AudioCommandThread::insertCommand_l(sp<AudioCommand>& 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<AudioPolicyService>& service); @@ -196,6 +204,13 @@ private: void releaseOutputCommand(audio_io_handle_t output); status_t sendCommand(sp<AudioCommand>& command, int delayMs = 0); void insertCommand_l(sp<AudioCommand>& 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<AudioCommand> > 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; }; |