diff options
Diffstat (limited to 'services/audioflinger')
-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 |
7 files changed, 680 insertions, 24 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 68fa553..447b208 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 7843387..aeca41e 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; @@ -2593,6 +2627,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, @@ -5748,4 +5823,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 44008e5..8c9943c 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; } @@ -644,6 +699,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 @@ -1035,6 +1094,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(); |