audio policy: enable more than one sink per audio patch.
Allow creation of audio patches with more than one sink.
More than one sink is enabled when:
- Connecting an input device to output devices on the same audio HW module.
- Connecting an output mix to output devices on the same audio HA module.
All other patches are limited to one sink.
Bug: 16879363.
Change-Id: I95be6948ef29df64e51e5b8ace38c2db7f3e89f2
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 49422a9..2d0a25f 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -151,12 +151,15 @@
if (handle == NULL || patch == NULL) {
return BAD_VALUE;
}
- // limit number of sources to 1 for now or 2 sources for special cross hw module case.
- // only the audio policy manager can request a patch creation with 2 sources.
- if (patch->num_sources == 0 || patch->num_sources > 2 ||
+ if (patch->num_sources == 0 || patch->num_sources > AUDIO_PATCH_PORTS_MAX ||
patch->num_sinks == 0 || patch->num_sinks > AUDIO_PATCH_PORTS_MAX) {
return BAD_VALUE;
}
+ // limit number of sources to 1 for now or 2 sources for special cross hw module case.
+ // only the audio policy manager can request a patch creation with 2 sources.
+ if (patch->num_sources > 2) {
+ return INVALID_OPERATION;
+ }
if (*handle != AUDIO_PATCH_HANDLE_NONE) {
for (size_t index = 0; *handle != 0 && index < mPatches.size(); index++) {
@@ -173,20 +176,22 @@
switch (patch->sources[0].type) {
case AUDIO_PORT_TYPE_DEVICE: {
- // limit number of sinks to 1 for now
- if (patch->num_sinks > 1) {
- status = BAD_VALUE;
- goto exit;
- }
- audio_module_handle_t src_module = patch->sources[0].ext.device.hw_module;
- ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(src_module);
+ audio_module_handle_t srcModule = patch->sources[0].ext.device.hw_module;
+ ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
if (index < 0) {
- ALOGW("createAudioPatch() bad src hw module %d", src_module);
+ ALOGW("createAudioPatch() bad src hw module %d", srcModule);
status = BAD_VALUE;
goto exit;
}
AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
for (unsigned int i = 0; i < patch->num_sinks; i++) {
+ // support only one sink if connection to a mix or across HW modules
+ if ((patch->sinks[i].type == AUDIO_PORT_TYPE_MIX ||
+ patch->sinks[i].ext.mix.hw_module != srcModule) &&
+ patch->num_sinks > 1) {
+ status = INVALID_OPERATION;
+ goto exit;
+ }
// reject connection to different sink types
if (patch->sinks[i].type != patch->sinks[0].type) {
ALOGW("createAudioPatch() different sink types in same patch not supported");
@@ -194,7 +199,7 @@
goto exit;
}
// limit to connections between devices and input streams for HAL before 3.0
- if (patch->sinks[i].ext.mix.hw_module == src_module &&
+ if (patch->sinks[i].ext.mix.hw_module == srcModule &&
(audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) &&
(patch->sinks[i].type != AUDIO_PORT_TYPE_MIX)) {
ALOGW("createAudioPatch() invalid sink type %d for device source",
@@ -204,7 +209,7 @@
}
}
- if (patch->sinks[0].ext.device.hw_module != src_module) {
+ if (patch->sinks[0].ext.device.hw_module != srcModule) {
// limit to device to device connection if not on same hw module
if (patch->sinks[0].type != AUDIO_PORT_TYPE_DEVICE) {
ALOGW("createAudioPatch() invalid sink type for cross hw module");
@@ -258,7 +263,7 @@
config.channel_mask = inChannelMask;
config.format = newPatch->mPlaybackThread->format();
audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
- newPatch->mRecordThread = audioflinger->openInput_l(src_module,
+ newPatch->mRecordThread = audioflinger->openInput_l(srcModule,
&input,
&config,
device,
@@ -279,10 +284,10 @@
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);
+ patch->sinks[0].ext.mix.handle);
if (thread == 0) {
ALOGW("createAudioPatch() bad capture I/O handle %d",
- patch->sinks[0].ext.mix.handle);
+ patch->sinks[0].ext.mix.handle);
status = BAD_VALUE;
goto exit;
}
@@ -298,10 +303,10 @@
}
} else {
sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
- patch->sinks[0].ext.mix.handle);
+ patch->sinks[0].ext.mix.handle);
if (thread == 0) {
ALOGW("createAudioPatch() bad capture I/O handle %d",
- patch->sinks[0].ext.mix.handle);
+ patch->sinks[0].ext.mix.handle);
status = BAD_VALUE;
goto exit;
}
@@ -326,10 +331,10 @@
}
} 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);
+ audio_module_handle_t srcModule = patch->sources[0].ext.mix.hw_module;
+ ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
if (index < 0) {
- ALOGW("createAudioPatch() bad src hw module %d", src_module);
+ ALOGW("createAudioPatch() bad src hw module %d", srcModule);
status = BAD_VALUE;
goto exit;
}
@@ -342,7 +347,7 @@
goto exit;
}
// limit to connections between sinks and sources on same HW module
- if (patch->sinks[i].ext.device.hw_module != src_module) {
+ if (patch->sinks[i].ext.device.hw_module != srcModule) {
status = BAD_VALUE;
goto exit;
}
@@ -365,6 +370,7 @@
}
char *address;
if (strcmp(patch->sinks[0].ext.device.address, "") != 0) {
+ //FIXME: we only support address on first sink with HAL version < 3.0
address = audio_device_address_to_parameter(
patch->sinks[0].ext.device.type,
patch->sinks[0].ext.device.address);
@@ -562,16 +568,16 @@
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);
+ audio_module_handle_t srcModule = patch->sources[0].ext.device.hw_module;
+ ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
if (index < 0) {
- ALOGW("releaseAudioPatch() bad src hw module %d", src_module);
+ ALOGW("releaseAudioPatch() bad src hw module %d", srcModule);
status = BAD_VALUE;
break;
}
if (patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE &&
- patch->sinks[0].ext.device.hw_module != src_module) {
+ patch->sinks[0].ext.device.hw_module != srcModule) {
clearPatchConnections(removedPatch);
break;
}
@@ -609,10 +615,10 @@
}
} 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);
+ audio_module_handle_t srcModule = patch->sources[0].ext.mix.hw_module;
+ ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
if (index < 0) {
- ALOGW("releaseAudioPatch() bad src hw module %d", src_module);
+ ALOGW("releaseAudioPatch() bad src hw module %d", srcModule);
status = BAD_VALUE;
break;
}