summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--services/audioflinger/Android.mk1
-rw-r--r--services/audioflinger/AudioFlinger.cpp3
-rw-r--r--services/audioflinger/AudioFlinger.h37
-rw-r--r--services/audioflinger/PatchPanel.cpp409
-rw-r--r--services/audioflinger/PatchPanel.h60
-rw-r--r--services/audioflinger/Threads.cpp132
-rw-r--r--services/audioflinger/Threads.h62
-rw-r--r--services/audiopolicy/AudioPolicyClientImpl.cpp11
-rw-r--r--services/audiopolicy/AudioPolicyInterface.h9
-rw-r--r--services/audiopolicy/AudioPolicyManager.cpp621
-rw-r--r--services/audiopolicy/AudioPolicyManager.h146
-rw-r--r--services/audiopolicy/AudioPolicyService.cpp69
-rw-r--r--services/audiopolicy/AudioPolicyService.h37
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 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();
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;
};