1951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent/* 2951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent** 3951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent** Copyright 2014, The Android Open Source Project 4951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent** 5951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent** Licensed under the Apache License, Version 2.0 (the "License"); 6951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent** you may not use this file except in compliance with the License. 7951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent** You may obtain a copy of the License at 8951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent** 9951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent** http://www.apache.org/licenses/LICENSE-2.0 10951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent** 11951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent** Unless required by applicable law or agreed to in writing, software 12951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent** distributed under the License is distributed on an "AS IS" BASIS, 13951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent** See the License for the specific language governing permissions and 15951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent** limitations under the License. 16951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent*/ 17951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 18951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 19951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent#define LOG_TAG "AudioFlinger::PatchPanel" 20951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent//#define LOG_NDEBUG 0 21951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 22951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent#include "Configuration.h" 23951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent#include <utils/Log.h> 24951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent#include <audio_utils/primitives.h> 25951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 26951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent#include "AudioFlinger.h" 27951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent#include "ServiceUtilities.h" 28951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent#include <media/AudioParameter.h> 29951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 30951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent// ---------------------------------------------------------------------------- 31951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 32951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent// Note: the following macro is used for extremely verbose logging message. In 33951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent// order to run with ALOG_ASSERT turned on, we need to have LOG_NDEBUG set to 34951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent// 0; but one side effect of this is to turn all LOGV's as well. Some messages 35951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent// are so verbose that we want to suppress them even when we have ALOG_ASSERT 36951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent// turned on. Do not uncomment the #def below unless you really know what you 37951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent// are doing and want to see all of the extremely verbose messages. 38951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent//#define VERY_VERY_VERBOSE_LOGGING 39951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent#ifdef VERY_VERY_VERBOSE_LOGGING 40951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent#define ALOGVV ALOGV 41951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent#else 42951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent#define ALOGVV(a...) do { } while(0) 43951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent#endif 44951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 45951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurentnamespace android { 46951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 47951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent/* List connected audio ports and their attributes */ 48951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurentstatus_t AudioFlinger::listAudioPorts(unsigned int *num_ports, 49951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent struct audio_port *ports) 50951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{ 51951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent Mutex::Autolock _l(mLock); 52951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent if (mPatchPanel != 0) { 53951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent return mPatchPanel->listAudioPorts(num_ports, ports); 54951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 55951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent return NO_INIT; 56951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent} 57951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 58951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent/* Get supported attributes for a given audio port */ 59951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurentstatus_t AudioFlinger::getAudioPort(struct audio_port *port) 60951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{ 61951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent Mutex::Autolock _l(mLock); 62951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent if (mPatchPanel != 0) { 63951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent return mPatchPanel->getAudioPort(port); 64951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 65951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent return NO_INIT; 66951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent} 67951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 68951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 69951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent/* Connect a patch between several source and sink ports */ 70951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurentstatus_t AudioFlinger::createAudioPatch(const struct audio_patch *patch, 71951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent audio_patch_handle_t *handle) 72951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{ 73951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent Mutex::Autolock _l(mLock); 74951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent if (mPatchPanel != 0) { 75951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent return mPatchPanel->createAudioPatch(patch, handle); 76951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 77951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent return NO_INIT; 78951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent} 79951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 80951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent/* Disconnect a patch */ 81951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurentstatus_t AudioFlinger::releaseAudioPatch(audio_patch_handle_t handle) 82951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{ 83951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent Mutex::Autolock _l(mLock); 84951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent if (mPatchPanel != 0) { 85951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent return mPatchPanel->releaseAudioPatch(handle); 86951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 87951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent return NO_INIT; 88951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent} 89951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 90951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 91951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent/* List connected audio ports and they attributes */ 92951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurentstatus_t AudioFlinger::listAudioPatches(unsigned int *num_patches, 93951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent struct audio_patch *patches) 94951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{ 95951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent Mutex::Autolock _l(mLock); 96951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent if (mPatchPanel != 0) { 97951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent return mPatchPanel->listAudioPatches(num_patches, patches); 98951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 99951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent return NO_INIT; 100951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent} 101951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 102951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent/* Set audio port configuration */ 103951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurentstatus_t AudioFlinger::setAudioPortConfig(const struct audio_port_config *config) 104951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{ 105951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent Mutex::Autolock _l(mLock); 106951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent if (mPatchPanel != 0) { 107951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent return mPatchPanel->setAudioPortConfig(config); 108951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 109951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent return NO_INIT; 110951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent} 111951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 112951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 113951f455566775e5f01e67c5ee26863d7d19209d7Eric LaurentAudioFlinger::PatchPanel::PatchPanel(const sp<AudioFlinger>& audioFlinger) 114951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent : mAudioFlinger(audioFlinger) 115951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{ 116951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent} 117951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 118951f455566775e5f01e67c5ee26863d7d19209d7Eric LaurentAudioFlinger::PatchPanel::~PatchPanel() 119951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{ 120951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent} 121951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 122951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent/* List connected audio ports and their attributes */ 123951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurentstatus_t AudioFlinger::PatchPanel::listAudioPorts(unsigned int *num_ports __unused, 124951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent struct audio_port *ports __unused) 125951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{ 126951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent ALOGV("listAudioPorts"); 127951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent return NO_ERROR; 128951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent} 129951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 130951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent/* Get supported attributes for a given audio port */ 131951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurentstatus_t AudioFlinger::PatchPanel::getAudioPort(struct audio_port *port __unused) 132951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{ 133951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent ALOGV("getAudioPort"); 134951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent return NO_ERROR; 135951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent} 136951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 137951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 138951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent/* Connect a patch between several source and sink ports */ 139951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurentstatus_t AudioFlinger::PatchPanel::createAudioPatch(const struct audio_patch *patch, 140951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent audio_patch_handle_t *handle) 141951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{ 142951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent status_t status = NO_ERROR; 143951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent audio_patch_handle_t halHandle = AUDIO_PATCH_HANDLE_NONE; 144951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent sp<AudioFlinger> audioflinger = mAudioFlinger.promote(); 145f27ce4051c81a90f8f937a1b381e9e6ffa2bfa6bGreg Kaiser if (handle == NULL || patch == NULL) { 146f27ce4051c81a90f8f937a1b381e9e6ffa2bfa6bGreg Kaiser return BAD_VALUE; 147f27ce4051c81a90f8f937a1b381e9e6ffa2bfa6bGreg Kaiser } 148f27ce4051c81a90f8f937a1b381e9e6ffa2bfa6bGreg Kaiser ALOGV("createAudioPatch() num_sources %d num_sinks %d handle %d", 149f27ce4051c81a90f8f937a1b381e9e6ffa2bfa6bGreg Kaiser patch->num_sources, patch->num_sinks, *handle); 150951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent if (audioflinger == 0) { 151951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent return NO_INIT; 152951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 15383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent 154874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent if (patch->num_sources == 0 || patch->num_sources > AUDIO_PATCH_PORTS_MAX || 155d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent (patch->num_sinks == 0 && patch->num_sources != 2) || 156d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent patch->num_sinks > AUDIO_PATCH_PORTS_MAX) { 157951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent return BAD_VALUE; 158951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 159874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent // limit number of sources to 1 for now or 2 sources for special cross hw module case. 160874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent // only the audio policy manager can request a patch creation with 2 sources. 161874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent if (patch->num_sources > 2) { 162874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent return INVALID_OPERATION; 163874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent } 164951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 16583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (*handle != AUDIO_PATCH_HANDLE_NONE) { 16683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent for (size_t index = 0; *handle != 0 && index < mPatches.size(); index++) { 16783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (*handle == mPatches[index]->mHandle) { 16883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent ALOGV("createAudioPatch() removing patch handle %d", *handle); 16983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent halHandle = mPatches[index]->mHalHandle; 170d8cd47792bac11a44096ef8233bb5268a6674becsoon Patch *removedPatch = mPatches[index]; 1710666cc5b6b430cc5a815dab0bcba3dd73da8061aEric Laurent if ((removedPatch->mRecordPatchHandle 1720666cc5b6b430cc5a815dab0bcba3dd73da8061aEric Laurent != AUDIO_PATCH_HANDLE_NONE) || 1730666cc5b6b430cc5a815dab0bcba3dd73da8061aEric Laurent (removedPatch->mPlaybackPatchHandle != 1740666cc5b6b430cc5a815dab0bcba3dd73da8061aEric Laurent AUDIO_PATCH_HANDLE_NONE)) { 1750666cc5b6b430cc5a815dab0bcba3dd73da8061aEric Laurent clearPatchConnections(removedPatch); 1760666cc5b6b430cc5a815dab0bcba3dd73da8061aEric Laurent } 17783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent mPatches.removeAt(index); 178d8cd47792bac11a44096ef8233bb5268a6674becsoon delete removedPatch; 17983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent break; 18083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 181951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 182951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 183951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 18483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent Patch *newPatch = new Patch(patch); 18583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent 186951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent switch (patch->sources[0].type) { 187951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent case AUDIO_PORT_TYPE_DEVICE: { 188874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent audio_module_handle_t srcModule = patch->sources[0].ext.device.hw_module; 189874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule); 190951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent if (index < 0) { 191874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent ALOGW("createAudioPatch() bad src hw module %d", srcModule); 19283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent status = BAD_VALUE; 19383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent goto exit; 194951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 1956a94d69dc4f32abb53c466a96f905bb199be6417Eric Laurent AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); 196951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent for (unsigned int i = 0; i < patch->num_sinks; i++) { 197874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent // support only one sink if connection to a mix or across HW modules 198874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent if ((patch->sinks[i].type == AUDIO_PORT_TYPE_MIX || 199874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent patch->sinks[i].ext.mix.hw_module != srcModule) && 200874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent patch->num_sinks > 1) { 201874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent status = INVALID_OPERATION; 202874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent goto exit; 203874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent } 2046a94d69dc4f32abb53c466a96f905bb199be6417Eric Laurent // reject connection to different sink types 2056a94d69dc4f32abb53c466a96f905bb199be6417Eric Laurent if (patch->sinks[i].type != patch->sinks[0].type) { 2066a94d69dc4f32abb53c466a96f905bb199be6417Eric Laurent ALOGW("createAudioPatch() different sink types in same patch not supported"); 20783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent status = BAD_VALUE; 20883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent goto exit; 209951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 210951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 211951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 2123bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent // manage patches requiring a software bridge 213d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent // - special patch request with 2 sources (reuse one existing output mix) OR 2143bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent // - Device to device AND 2153bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent // - source HW module != destination HW module OR 2163bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent // - audio HAL version < 3.0 217d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent if ((patch->num_sources == 2) || 218d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent ((patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) && 219d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent ((patch->sinks[0].ext.device.hw_module != srcModule) || 220d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0)))) { 22183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (patch->num_sources == 2) { 22283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (patch->sources[1].type != AUDIO_PORT_TYPE_MIX || 223d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent (patch->num_sinks != 0 && patch->sinks[0].ext.device.hw_module != 224d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent patch->sources[1].ext.mix.hw_module)) { 22583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent ALOGW("createAudioPatch() invalid source combination"); 22683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent status = INVALID_OPERATION; 22783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent goto exit; 22883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 22983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent 23083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent sp<ThreadBase> thread = 23183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent audioflinger->checkPlaybackThread_l(patch->sources[1].ext.mix.handle); 23283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent newPatch->mPlaybackThread = (MixerThread *)thread.get(); 233951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent if (thread == 0) { 23483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent ALOGW("createAudioPatch() cannot get playback thread"); 23583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent status = INVALID_OPERATION; 23683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent goto exit; 237951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 238951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } else { 239cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent audio_config_t config = AUDIO_CONFIG_INITIALIZER; 240cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent audio_devices_t device = patch->sinks[0].ext.device.type; 241cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent String8 address = String8(patch->sinks[0].ext.device.address); 242cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent audio_io_handle_t output = AUDIO_IO_HANDLE_NONE; 24383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent newPatch->mPlaybackThread = audioflinger->openOutput_l( 24483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent patch->sinks[0].ext.device.hw_module, 245cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent &output, 24683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent &config, 247cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent device, 248cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent address, 24983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent AUDIO_OUTPUT_FLAG_NONE); 25083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent ALOGV("audioflinger->openOutput_l() returned %p", 25183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent newPatch->mPlaybackThread.get()); 25283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (newPatch->mPlaybackThread == 0) { 25383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent status = NO_MEMORY; 25483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent goto exit; 25583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 25683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 25783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent audio_devices_t device = patch->sources[0].ext.device.type; 258cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent String8 address = String8(patch->sources[0].ext.device.address); 259cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent audio_config_t config = AUDIO_CONFIG_INITIALIZER; 2608ae73129e7e79d826b293238c2f037f723d0e6e8Eric Laurent // open input stream with source device audio properties if provided or 2618ae73129e7e79d826b293238c2f037f723d0e6e8Eric Laurent // default to peer output stream properties otherwise. 2628ae73129e7e79d826b293238c2f037f723d0e6e8Eric Laurent if (patch->sources[0].config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) { 2638ae73129e7e79d826b293238c2f037f723d0e6e8Eric Laurent config.sample_rate = patch->sources[0].sample_rate; 2648ae73129e7e79d826b293238c2f037f723d0e6e8Eric Laurent } else { 2658ae73129e7e79d826b293238c2f037f723d0e6e8Eric Laurent config.sample_rate = newPatch->mPlaybackThread->sampleRate(); 2668ae73129e7e79d826b293238c2f037f723d0e6e8Eric Laurent } 2678ae73129e7e79d826b293238c2f037f723d0e6e8Eric Laurent if (patch->sources[0].config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) { 2688ae73129e7e79d826b293238c2f037f723d0e6e8Eric Laurent config.channel_mask = patch->sources[0].channel_mask; 2698ae73129e7e79d826b293238c2f037f723d0e6e8Eric Laurent } else { 2708ae73129e7e79d826b293238c2f037f723d0e6e8Eric Laurent config.channel_mask = 2718ae73129e7e79d826b293238c2f037f723d0e6e8Eric Laurent audio_channel_in_mask_from_count(newPatch->mPlaybackThread->channelCount()); 2728ae73129e7e79d826b293238c2f037f723d0e6e8Eric Laurent } 2738ae73129e7e79d826b293238c2f037f723d0e6e8Eric Laurent if (patch->sources[0].config_mask & AUDIO_PORT_CONFIG_FORMAT) { 2748ae73129e7e79d826b293238c2f037f723d0e6e8Eric Laurent config.format = patch->sources[0].format; 2758ae73129e7e79d826b293238c2f037f723d0e6e8Eric Laurent } else { 2768ae73129e7e79d826b293238c2f037f723d0e6e8Eric Laurent config.format = newPatch->mPlaybackThread->format(); 2778ae73129e7e79d826b293238c2f037f723d0e6e8Eric Laurent } 278cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent audio_io_handle_t input = AUDIO_IO_HANDLE_NONE; 279874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent newPatch->mRecordThread = audioflinger->openInput_l(srcModule, 280cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent &input, 28183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent &config, 282cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent device, 283cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent address, 284cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent AUDIO_SOURCE_MIC, 28583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent AUDIO_INPUT_FLAG_NONE); 28683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent ALOGV("audioflinger->openInput_l() returned %p inChannelMask %08x", 2878ae73129e7e79d826b293238c2f037f723d0e6e8Eric Laurent newPatch->mRecordThread.get(), config.channel_mask); 28883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (newPatch->mRecordThread == 0) { 28983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent status = NO_MEMORY; 29083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent goto exit; 29183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 29283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent status = createPatchConnections(newPatch, patch); 29383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (status != NO_ERROR) { 29483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent goto exit; 295951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 296951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } else { 297054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) { 29883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent sp<ThreadBase> thread = audioflinger->checkRecordThread_l( 299054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent patch->sinks[0].ext.mix.handle); 30083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (thread == 0) { 30183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent ALOGW("createAudioPatch() bad capture I/O handle %d", 302054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent patch->sinks[0].ext.mix.handle); 30383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent status = BAD_VALUE; 30483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent goto exit; 30583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 306054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle); 307054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent } else { 308054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent if (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) { 309054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent status = INVALID_OPERATION; 310054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent goto exit; 311cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent } 312054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent 313054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent audio_hw_device_t *hwDevice = audioHwDevice->hwDevice(); 314054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent status = hwDevice->create_audio_patch(hwDevice, 315054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent patch->num_sources, 316054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent patch->sources, 317054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent patch->num_sinks, 318054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent patch->sinks, 319054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent &halHandle); 320951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 321951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 322951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } break; 323951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent case AUDIO_PORT_TYPE_MIX: { 324874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent audio_module_handle_t srcModule = patch->sources[0].ext.mix.hw_module; 325874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule); 326951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent if (index < 0) { 327874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent ALOGW("createAudioPatch() bad src hw module %d", srcModule); 32883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent status = BAD_VALUE; 32983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent goto exit; 330951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 331951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent // limit to connections between devices and output streams 332054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent audio_devices_t type = AUDIO_DEVICE_NONE; 333951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent for (unsigned int i = 0; i < patch->num_sinks; i++) { 334951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) { 33583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent ALOGW("createAudioPatch() invalid sink type %d for mix source", 336951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent patch->sinks[i].type); 33783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent status = BAD_VALUE; 33883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent goto exit; 339951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 340951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent // limit to connections between sinks and sources on same HW module 341874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent if (patch->sinks[i].ext.device.hw_module != srcModule) { 34283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent status = BAD_VALUE; 34383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent goto exit; 344951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 345054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent type |= patch->sinks[i].ext.device.type; 346951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 347951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent sp<ThreadBase> thread = 348951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle); 349951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent if (thread == 0) { 350951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent ALOGW("createAudioPatch() bad playback I/O handle %d", 351951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent patch->sources[0].ext.mix.handle); 35283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent status = BAD_VALUE; 35383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent goto exit; 354951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 355054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent if (thread == audioflinger->primaryPlaybackThread_l()) { 356054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent AudioParameter param = AudioParameter(); 357cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), (int)type); 358054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent 359054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent audioflinger->broacastParametersToRecordThreads_l(param.toString()); 360951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 361951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 362054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle); 363951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } break; 364951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent default: 36583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent status = BAD_VALUE; 36683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent goto exit; 367951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 36883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurentexit: 369951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent ALOGV("createAudioPatch() status %d", status); 370951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent if (status == NO_ERROR) { 371a13cde98a880341f0a56d91da6364b093fb5d24eGlenn Kasten *handle = (audio_patch_handle_t) audioflinger->nextUniqueId(AUDIO_UNIQUE_ID_USE_PATCH); 372951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent newPatch->mHandle = *handle; 373951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent newPatch->mHalHandle = halHandle; 374951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent mPatches.add(newPatch); 375951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent ALOGV("createAudioPatch() added new patch handle %d halHandle %d", *handle, halHandle); 37683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } else { 37783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent clearPatchConnections(newPatch); 37883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent delete newPatch; 37983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 38083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent return status; 38183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent} 38283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent 38383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurentstatus_t AudioFlinger::PatchPanel::createPatchConnections(Patch *patch, 38483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent const struct audio_patch *audioPatch) 38583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent{ 38683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent // create patch from source device to record thread input 38783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent struct audio_patch subPatch; 38883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent subPatch.num_sources = 1; 38983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent subPatch.sources[0] = audioPatch->sources[0]; 39083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent subPatch.num_sinks = 1; 39183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent 39283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent patch->mRecordThread->getAudioPortConfig(&subPatch.sinks[0]); 39383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent subPatch.sinks[0].ext.mix.usecase.source = AUDIO_SOURCE_MIC; 39483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent 39583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent status_t status = createAudioPatch(&subPatch, &patch->mRecordPatchHandle); 39683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (status != NO_ERROR) { 39783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent patch->mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE; 39883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent return status; 39983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 40083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent 40183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent // create patch from playback thread output to sink device 402d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent if (audioPatch->num_sinks != 0) { 403d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent patch->mPlaybackThread->getAudioPortConfig(&subPatch.sources[0]); 404d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent subPatch.sinks[0] = audioPatch->sinks[0]; 405d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent status = createAudioPatch(&subPatch, &patch->mPlaybackPatchHandle); 406d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent if (status != NO_ERROR) { 407d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE; 408d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent return status; 409d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent } 410d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent } else { 41183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE; 41283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 41383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent 41483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent // use a pseudo LCM between input and output framecount 41583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent size_t playbackFrameCount = patch->mPlaybackThread->frameCount(); 41683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent int playbackShift = __builtin_ctz(playbackFrameCount); 41783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent size_t recordFramecount = patch->mRecordThread->frameCount(); 41883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent int shift = __builtin_ctz(recordFramecount); 41983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (playbackShift < shift) { 42083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent shift = playbackShift; 42183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 42283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent size_t frameCount = (playbackFrameCount * recordFramecount) >> shift; 423c42e9b462661673dff480ee71757a58b0f806370Glenn Kasten ALOGV("createPatchConnections() playframeCount %zu recordFramecount %zu frameCount %zu", 42483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent playbackFrameCount, recordFramecount, frameCount); 42583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent 42683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent // create a special record track to capture from record thread 42783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent uint32_t channelCount = patch->mPlaybackThread->channelCount(); 42883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent audio_channel_mask_t inChannelMask = audio_channel_in_mask_from_count(channelCount); 42983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent audio_channel_mask_t outChannelMask = patch->mPlaybackThread->channelMask(); 43083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent uint32_t sampleRate = patch->mPlaybackThread->sampleRate(); 43183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent audio_format_t format = patch->mPlaybackThread->format(); 43283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent 43383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent patch->mPatchRecord = new RecordThread::PatchRecord( 43483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent patch->mRecordThread.get(), 43583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent sampleRate, 43683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent inChannelMask, 43783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent format, 43883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent frameCount, 43983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent NULL, 44083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent IAudioFlinger::TRACK_DEFAULT); 44183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (patch->mPatchRecord == 0) { 44283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent return NO_MEMORY; 44383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 44483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent status = patch->mPatchRecord->initCheck(); 44583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (status != NO_ERROR) { 44683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent return status; 447951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 44883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent patch->mRecordThread->addPatchRecord(patch->mPatchRecord); 44983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent 45083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent // create a special playback track to render to playback thread. 45183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent // this track is given the same buffer as the PatchRecord buffer 45283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent patch->mPatchTrack = new PlaybackThread::PatchTrack( 45383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent patch->mPlaybackThread.get(), 4543bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent audioPatch->sources[1].ext.mix.usecase.stream, 45583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent sampleRate, 45683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent outChannelMask, 45783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent format, 45883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent frameCount, 45983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent patch->mPatchRecord->buffer(), 46083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent IAudioFlinger::TRACK_DEFAULT); 46183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (patch->mPatchTrack == 0) { 46283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent return NO_MEMORY; 46383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 46483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent status = patch->mPatchTrack->initCheck(); 46583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (status != NO_ERROR) { 46683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent return status; 46783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 46883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent patch->mPlaybackThread->addPatchTrack(patch->mPatchTrack); 46983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent 47083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent // tie playback and record tracks together 47183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent patch->mPatchRecord->setPeerProxy(patch->mPatchTrack.get()); 47283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent patch->mPatchTrack->setPeerProxy(patch->mPatchRecord.get()); 47383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent 47483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent // start capture and playback 475d848eb48c121c119e8ba7583efc75415fe102570Glenn Kasten patch->mPatchRecord->start(AudioSystem::SYNC_EVENT_NONE, AUDIO_SESSION_NONE); 47683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent patch->mPatchTrack->start(); 47783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent 478951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent return status; 479951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent} 480951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 48183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurentvoid AudioFlinger::PatchPanel::clearPatchConnections(Patch *patch) 48283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent{ 48383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent sp<AudioFlinger> audioflinger = mAudioFlinger.promote(); 48483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (audioflinger == 0) { 48583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent return; 48683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 48783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent 48883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent ALOGV("clearPatchConnections() patch->mRecordPatchHandle %d patch->mPlaybackPatchHandle %d", 48983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent patch->mRecordPatchHandle, patch->mPlaybackPatchHandle); 49083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent 49183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (patch->mPatchRecord != 0) { 49283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent patch->mPatchRecord->stop(); 49383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 49483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (patch->mPatchTrack != 0) { 49583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent patch->mPatchTrack->stop(); 49683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 49783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (patch->mRecordPatchHandle != AUDIO_PATCH_HANDLE_NONE) { 49883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent releaseAudioPatch(patch->mRecordPatchHandle); 49983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent patch->mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE; 50083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 50183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (patch->mPlaybackPatchHandle != AUDIO_PATCH_HANDLE_NONE) { 50283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent releaseAudioPatch(patch->mPlaybackPatchHandle); 50383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE; 50483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 50583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (patch->mRecordThread != 0) { 50683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (patch->mPatchRecord != 0) { 50783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent patch->mRecordThread->deletePatchRecord(patch->mPatchRecord); 50883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 50983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent audioflinger->closeInputInternal_l(patch->mRecordThread); 51083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 51183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (patch->mPlaybackThread != 0) { 51283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (patch->mPatchTrack != 0) { 51383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent patch->mPlaybackThread->deletePatchTrack(patch->mPatchTrack); 51483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 51583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent // if num sources == 2 we are reusing an existing playback thread so we do not close it 51683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent if (patch->mAudioPatch.num_sources != 2) { 51783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent audioflinger->closeOutputInternal_l(patch->mPlaybackThread); 51883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 519a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent } 520a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent if (patch->mRecordThread != 0) { 521a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent if (patch->mPatchRecord != 0) { 522a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent patch->mPatchRecord.clear(); 523a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent } 524a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent patch->mRecordThread.clear(); 525a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent } 526a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent if (patch->mPlaybackThread != 0) { 527a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent if (patch->mPatchTrack != 0) { 528a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent patch->mPatchTrack.clear(); 529a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent } 53083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent patch->mPlaybackThread.clear(); 53183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 532a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent 53383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent} 53483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent 535951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent/* Disconnect a patch */ 536951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurentstatus_t AudioFlinger::PatchPanel::releaseAudioPatch(audio_patch_handle_t handle) 537951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{ 538951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent ALOGV("releaseAudioPatch handle %d", handle); 539951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent status_t status = NO_ERROR; 540951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent size_t index; 541951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 542951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent sp<AudioFlinger> audioflinger = mAudioFlinger.promote(); 543951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent if (audioflinger == 0) { 544951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent return NO_INIT; 545951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 546951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 547951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent for (index = 0; index < mPatches.size(); index++) { 548951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent if (handle == mPatches[index]->mHandle) { 549951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent break; 550951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 551951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 552951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent if (index == mPatches.size()) { 553951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent return BAD_VALUE; 554951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 55583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent Patch *removedPatch = mPatches[index]; 55683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent mPatches.removeAt(index); 557951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 55883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent struct audio_patch *patch = &removedPatch->mAudioPatch; 559951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 560951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent switch (patch->sources[0].type) { 561951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent case AUDIO_PORT_TYPE_DEVICE: { 562874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent audio_module_handle_t srcModule = patch->sources[0].ext.device.hw_module; 563874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule); 564951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent if (index < 0) { 565874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent ALOGW("releaseAudioPatch() bad src hw module %d", srcModule); 566951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent status = BAD_VALUE; 567951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent break; 568951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 56983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent 5703bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent if (removedPatch->mRecordPatchHandle != AUDIO_PATCH_HANDLE_NONE || 5713bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent removedPatch->mPlaybackPatchHandle != AUDIO_PATCH_HANDLE_NONE) { 57283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent clearPatchConnections(removedPatch); 57383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent break; 57483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent } 57583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent 576054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) { 577951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent sp<ThreadBase> thread = audioflinger->checkRecordThread_l( 578054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent patch->sinks[0].ext.mix.handle); 579951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent if (thread == 0) { 580951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent ALOGW("releaseAudioPatch() bad capture I/O handle %d", 581054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent patch->sinks[0].ext.mix.handle); 582951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent status = BAD_VALUE; 583951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent break; 584951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 585054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle); 586054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent } else { 587054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); 588054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent if (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) { 589054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent status = INVALID_OPERATION; 590054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent break; 591054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent } 592054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent audio_hw_device_t *hwDevice = audioHwDevice->hwDevice(); 593054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent status = hwDevice->release_audio_patch(hwDevice, removedPatch->mHalHandle); 594951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 595951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } break; 596951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent case AUDIO_PORT_TYPE_MIX: { 597874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent audio_module_handle_t srcModule = patch->sources[0].ext.mix.hw_module; 598874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule); 599951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent if (index < 0) { 600874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent ALOGW("releaseAudioPatch() bad src hw module %d", srcModule); 601951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent status = BAD_VALUE; 602951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent break; 603951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 604951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent sp<ThreadBase> thread = 605951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle); 606951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent if (thread == 0) { 607951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent ALOGW("releaseAudioPatch() bad playback I/O handle %d", 608951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent patch->sources[0].ext.mix.handle); 609951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent status = BAD_VALUE; 610951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent break; 611951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 612054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle); 613951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } break; 614951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent default: 615951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent status = BAD_VALUE; 616951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent break; 617951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent } 618951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 61983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent delete removedPatch; 620951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent return status; 621951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent} 622951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 623951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 624951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent/* List connected audio ports and they attributes */ 625951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurentstatus_t AudioFlinger::PatchPanel::listAudioPatches(unsigned int *num_patches __unused, 626951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent struct audio_patch *patches __unused) 627951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{ 628951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent ALOGV("listAudioPatches"); 629951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent return NO_ERROR; 630951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent} 631951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 632951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent/* Set audio port configuration */ 633e1715a465a29db625da9d0ea365edf371e39e201Eric Laurentstatus_t AudioFlinger::PatchPanel::setAudioPortConfig(const struct audio_port_config *config) 634951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{ 635951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent ALOGV("setAudioPortConfig"); 636e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent 637e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent sp<AudioFlinger> audioflinger = mAudioFlinger.promote(); 638e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent if (audioflinger == 0) { 639e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent return NO_INIT; 640e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent } 641e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent 642e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent audio_module_handle_t module; 643e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent if (config->type == AUDIO_PORT_TYPE_DEVICE) { 644e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent module = config->ext.device.hw_module; 645e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent } else { 646e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent module = config->ext.mix.hw_module; 647e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent } 648e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent 649e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(module); 650e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent if (index < 0) { 651e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent ALOGW("setAudioPortConfig() bad hw module %d", module); 652e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent return BAD_VALUE; 653e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent } 654e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent 655e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); 656e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { 657e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent audio_hw_device_t *hwDevice = audioHwDevice->hwDevice(); 658e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent return hwDevice->set_audio_port_config(hwDevice, config); 659e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent } else { 660e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent return INVALID_OPERATION; 661e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent } 662951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent return NO_ERROR; 663951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent} 664951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent 66563238efb0d674758902918e3cdaac322126484b7Glenn Kasten} // namespace android 666