PatchPanel.cpp revision f27ce4051c81a90f8f937a1b381e9e6ffa2bfa6b
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];
17183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                mPatches.removeAt(index);
172d8cd47792bac11a44096ef8233bb5268a6674becsoon                delete removedPatch;
17383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                break;
17483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            }
175951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        }
176951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
177951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
17883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    Patch *newPatch = new Patch(patch);
17983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
180951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    switch (patch->sources[0].type) {
181951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        case AUDIO_PORT_TYPE_DEVICE: {
182874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent            audio_module_handle_t srcModule = patch->sources[0].ext.device.hw_module;
183874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent            ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
184951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            if (index < 0) {
185874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                ALOGW("createAudioPatch() bad src hw module %d", srcModule);
18683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                status = BAD_VALUE;
18783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                goto exit;
188951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
1896a94d69dc4f32abb53c466a96f905bb199be6417Eric Laurent            AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
190951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            for (unsigned int i = 0; i < patch->num_sinks; i++) {
191874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                // support only one sink if connection to a mix or across HW modules
192874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                if ((patch->sinks[i].type == AUDIO_PORT_TYPE_MIX ||
193874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                        patch->sinks[i].ext.mix.hw_module != srcModule) &&
194874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                        patch->num_sinks > 1) {
195874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                    status = INVALID_OPERATION;
196874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                    goto exit;
197874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                }
1986a94d69dc4f32abb53c466a96f905bb199be6417Eric Laurent                // reject connection to different sink types
1996a94d69dc4f32abb53c466a96f905bb199be6417Eric Laurent                if (patch->sinks[i].type != patch->sinks[0].type) {
2006a94d69dc4f32abb53c466a96f905bb199be6417Eric Laurent                    ALOGW("createAudioPatch() different sink types in same patch not supported");
20183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    status = BAD_VALUE;
20283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    goto exit;
203951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                }
204951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
205951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
2063bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent            // manage patches requiring a software bridge
207d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent            // - special patch request with 2 sources (reuse one existing output mix) OR
2083bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent            // - Device to device AND
2093bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent            //    - source HW module != destination HW module OR
2103bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent            //    - audio HAL version < 3.0
211d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent            if ((patch->num_sources == 2) ||
212d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent                ((patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) &&
213d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent                 ((patch->sinks[0].ext.device.hw_module != srcModule) ||
214d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent                  (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0)))) {
21583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                if (patch->num_sources == 2) {
21683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    if (patch->sources[1].type != AUDIO_PORT_TYPE_MIX ||
217d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent                            (patch->num_sinks != 0 && patch->sinks[0].ext.device.hw_module !=
218d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent                                    patch->sources[1].ext.mix.hw_module)) {
21983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        ALOGW("createAudioPatch() invalid source combination");
22083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        status = INVALID_OPERATION;
22183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        goto exit;
22283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    }
22383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
22483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    sp<ThreadBase> thread =
22583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                            audioflinger->checkPlaybackThread_l(patch->sources[1].ext.mix.handle);
22683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    newPatch->mPlaybackThread = (MixerThread *)thread.get();
227951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                    if (thread == 0) {
22883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        ALOGW("createAudioPatch() cannot get playback thread");
22983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        status = INVALID_OPERATION;
23083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        goto exit;
231951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                    }
232951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                } else {
233cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    audio_config_t config = AUDIO_CONFIG_INITIALIZER;
234cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    audio_devices_t device = patch->sinks[0].ext.device.type;
235cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    String8 address = String8(patch->sinks[0].ext.device.address);
236cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
23783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    newPatch->mPlaybackThread = audioflinger->openOutput_l(
23883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                             patch->sinks[0].ext.device.hw_module,
239cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                             &output,
24083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                             &config,
241cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                             device,
242cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                             address,
24383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                             AUDIO_OUTPUT_FLAG_NONE);
24483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    ALOGV("audioflinger->openOutput_l() returned %p",
24583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                          newPatch->mPlaybackThread.get());
24683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    if (newPatch->mPlaybackThread == 0) {
24783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        status = NO_MEMORY;
24883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        goto exit;
24983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    }
25083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                }
25183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                uint32_t channelCount = newPatch->mPlaybackThread->channelCount();
25283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                audio_devices_t device = patch->sources[0].ext.device.type;
253cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                String8 address = String8(patch->sources[0].ext.device.address);
254cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                audio_config_t config = AUDIO_CONFIG_INITIALIZER;
25583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                audio_channel_mask_t inChannelMask = audio_channel_in_mask_from_count(channelCount);
25683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                config.sample_rate = newPatch->mPlaybackThread->sampleRate();
25783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                config.channel_mask = inChannelMask;
25883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                config.format = newPatch->mPlaybackThread->format();
259cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
260874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                newPatch->mRecordThread = audioflinger->openInput_l(srcModule,
261cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                                    &input,
26283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                                    &config,
263cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                                    device,
264cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                                    address,
265cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                                    AUDIO_SOURCE_MIC,
26683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                                    AUDIO_INPUT_FLAG_NONE);
26783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                ALOGV("audioflinger->openInput_l() returned %p inChannelMask %08x",
26883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                      newPatch->mRecordThread.get(), inChannelMask);
26983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                if (newPatch->mRecordThread == 0) {
27083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    status = NO_MEMORY;
27183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    goto exit;
27283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                }
27383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                status = createPatchConnections(newPatch, patch);
27483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                if (status != NO_ERROR) {
27583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    goto exit;
276951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                }
277951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            } else {
278054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
27983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
280054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                                                              patch->sinks[0].ext.mix.handle);
28183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    if (thread == 0) {
28283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        ALOGW("createAudioPatch() bad capture I/O handle %d",
283054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                                                              patch->sinks[0].ext.mix.handle);
28483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        status = BAD_VALUE;
28583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        goto exit;
28683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    }
287054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                    status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
288054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                } else {
289054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                    if (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) {
290054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                        status = INVALID_OPERATION;
291054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                        goto exit;
292cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    }
293054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent
294054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                    audio_hw_device_t *hwDevice = audioHwDevice->hwDevice();
295054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                    status = hwDevice->create_audio_patch(hwDevice,
296054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                                                           patch->num_sources,
297054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                                                           patch->sources,
298054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                                                           patch->num_sinks,
299054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                                                           patch->sinks,
300054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                                                           &halHandle);
301951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                }
302951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
303951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        } break;
304951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        case AUDIO_PORT_TYPE_MIX: {
305874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent            audio_module_handle_t srcModule =  patch->sources[0].ext.mix.hw_module;
306874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent            ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
307951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            if (index < 0) {
308874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                ALOGW("createAudioPatch() bad src hw module %d", srcModule);
30983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                status = BAD_VALUE;
31083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                goto exit;
311951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
312951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            // limit to connections between devices and output streams
313054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent            audio_devices_t type = AUDIO_DEVICE_NONE;
314951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            for (unsigned int i = 0; i < patch->num_sinks; i++) {
315951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) {
31683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    ALOGW("createAudioPatch() invalid sink type %d for mix source",
317951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                          patch->sinks[i].type);
31883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    status = BAD_VALUE;
31983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    goto exit;
320951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                }
321951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                // limit to connections between sinks and sources on same HW module
322874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                if (patch->sinks[i].ext.device.hw_module != srcModule) {
32383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    status = BAD_VALUE;
32483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    goto exit;
325951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                }
326054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                type |= patch->sinks[i].ext.device.type;
327951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
328951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            sp<ThreadBase> thread =
329951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                            audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
330951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            if (thread == 0) {
331951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                ALOGW("createAudioPatch() bad playback I/O handle %d",
332951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                          patch->sources[0].ext.mix.handle);
33383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                status = BAD_VALUE;
33483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                goto exit;
335951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
336054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent            if (thread == audioflinger->primaryPlaybackThread_l()) {
337054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                AudioParameter param = AudioParameter();
338cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), (int)type);
339054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent
340054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                audioflinger->broacastParametersToRecordThreads_l(param.toString());
341951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
342951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
343054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent            status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
344951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        } break;
345951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        default:
34683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            status = BAD_VALUE;
34783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            goto exit;
348951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
34983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurentexit:
350951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    ALOGV("createAudioPatch() status %d", status);
351951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    if (status == NO_ERROR) {
352eeecb980ff4c202d0a3c4b0bfe040dce2f73336dGlenn Kasten        *handle = audioflinger->nextUniqueId(AUDIO_UNIQUE_ID_USE_PATCH);
353951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        newPatch->mHandle = *handle;
354951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        newPatch->mHalHandle = halHandle;
355951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        mPatches.add(newPatch);
356951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        ALOGV("createAudioPatch() added new patch handle %d halHandle %d", *handle, halHandle);
35783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    } else {
35883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        clearPatchConnections(newPatch);
35983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        delete newPatch;
36083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
36183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    return status;
36283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent}
36383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
36483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurentstatus_t AudioFlinger::PatchPanel::createPatchConnections(Patch *patch,
36583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                          const struct audio_patch *audioPatch)
36683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent{
36783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // create patch from source device to record thread input
36883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    struct audio_patch subPatch;
36983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    subPatch.num_sources = 1;
37083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    subPatch.sources[0] = audioPatch->sources[0];
37183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    subPatch.num_sinks = 1;
37283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
37383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mRecordThread->getAudioPortConfig(&subPatch.sinks[0]);
37483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    subPatch.sinks[0].ext.mix.usecase.source = AUDIO_SOURCE_MIC;
37583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
37683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    status_t status = createAudioPatch(&subPatch, &patch->mRecordPatchHandle);
37783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (status != NO_ERROR) {
37883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        patch->mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE;
37983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        return status;
38083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
38183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
38283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // create patch from playback thread output to sink device
383d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent    if (audioPatch->num_sinks != 0) {
384d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent        patch->mPlaybackThread->getAudioPortConfig(&subPatch.sources[0]);
385d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent        subPatch.sinks[0] = audioPatch->sinks[0];
386d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent        status = createAudioPatch(&subPatch, &patch->mPlaybackPatchHandle);
387d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent        if (status != NO_ERROR) {
388d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent            patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
389d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent            return status;
390d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent        }
391d60560af7cb559762593161c8202459cc01fb0f5Eric Laurent    } else {
39283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
39383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
39483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
39583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // use a pseudo LCM between input and output framecount
39683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    size_t playbackFrameCount = patch->mPlaybackThread->frameCount();
39783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    int playbackShift = __builtin_ctz(playbackFrameCount);
39883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    size_t recordFramecount = patch->mRecordThread->frameCount();
39983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    int shift = __builtin_ctz(recordFramecount);
40083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (playbackShift < shift) {
40183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        shift = playbackShift;
40283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
40383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    size_t frameCount = (playbackFrameCount * recordFramecount) >> shift;
40483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    ALOGV("createPatchConnections() playframeCount %d recordFramecount %d frameCount %d ",
40583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent          playbackFrameCount, recordFramecount, frameCount);
40683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
40783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // create a special record track to capture from record thread
40883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    uint32_t channelCount = patch->mPlaybackThread->channelCount();
40983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    audio_channel_mask_t inChannelMask = audio_channel_in_mask_from_count(channelCount);
41083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    audio_channel_mask_t outChannelMask = patch->mPlaybackThread->channelMask();
41183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    uint32_t sampleRate = patch->mPlaybackThread->sampleRate();
41283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    audio_format_t format = patch->mPlaybackThread->format();
41383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
41483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPatchRecord = new RecordThread::PatchRecord(
41583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                             patch->mRecordThread.get(),
41683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                             sampleRate,
41783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                             inChannelMask,
41883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                             format,
41983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                             frameCount,
42083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                             NULL,
42183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                             IAudioFlinger::TRACK_DEFAULT);
42283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mPatchRecord == 0) {
42383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        return NO_MEMORY;
42483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
42583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    status = patch->mPatchRecord->initCheck();
42683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (status != NO_ERROR) {
42783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        return status;
428951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
42983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mRecordThread->addPatchRecord(patch->mPatchRecord);
43083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
43183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // create a special playback track to render to playback thread.
43283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // this track is given the same buffer as the PatchRecord buffer
43383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPatchTrack = new PlaybackThread::PatchTrack(
43483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                           patch->mPlaybackThread.get(),
4353bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent                                           audioPatch->sources[1].ext.mix.usecase.stream,
43683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                           sampleRate,
43783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                           outChannelMask,
43883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                           format,
43983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                           frameCount,
44083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                           patch->mPatchRecord->buffer(),
44183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                           IAudioFlinger::TRACK_DEFAULT);
44283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mPatchTrack == 0) {
44383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        return NO_MEMORY;
44483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
44583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    status = patch->mPatchTrack->initCheck();
44683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (status != NO_ERROR) {
44783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        return status;
44883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
44983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPlaybackThread->addPatchTrack(patch->mPatchTrack);
45083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
45183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // tie playback and record tracks together
45283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPatchRecord->setPeerProxy(patch->mPatchTrack.get());
45383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPatchTrack->setPeerProxy(patch->mPatchRecord.get());
45483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
45583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // start capture and playback
45683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPatchRecord->start(AudioSystem::SYNC_EVENT_NONE, 0);
45783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPatchTrack->start();
45883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
459951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    return status;
460951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent}
461951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
46283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurentvoid AudioFlinger::PatchPanel::clearPatchConnections(Patch *patch)
46383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent{
46483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
46583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (audioflinger == 0) {
46683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        return;
46783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
46883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
46983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    ALOGV("clearPatchConnections() patch->mRecordPatchHandle %d patch->mPlaybackPatchHandle %d",
47083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent          patch->mRecordPatchHandle, patch->mPlaybackPatchHandle);
47183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
47283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mPatchRecord != 0) {
47383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        patch->mPatchRecord->stop();
47483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
47583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mPatchTrack != 0) {
47683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        patch->mPatchTrack->stop();
47783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
47883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mRecordPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
47983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        releaseAudioPatch(patch->mRecordPatchHandle);
48083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        patch->mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE;
48183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
48283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mPlaybackPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
48383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        releaseAudioPatch(patch->mPlaybackPatchHandle);
48483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
48583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
48683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mRecordThread != 0) {
48783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        if (patch->mPatchRecord != 0) {
48883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            patch->mRecordThread->deletePatchRecord(patch->mPatchRecord);
48983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        }
49083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        audioflinger->closeInputInternal_l(patch->mRecordThread);
49183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
49283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mPlaybackThread != 0) {
49383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        if (patch->mPatchTrack != 0) {
49483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            patch->mPlaybackThread->deletePatchTrack(patch->mPatchTrack);
49583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        }
49683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        // if num sources == 2 we are reusing an existing playback thread so we do not close it
49783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        if (patch->mAudioPatch.num_sources != 2) {
49883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            audioflinger->closeOutputInternal_l(patch->mPlaybackThread);
49983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        }
500a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent    }
501a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent    if (patch->mRecordThread != 0) {
502a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent        if (patch->mPatchRecord != 0) {
503a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent            patch->mPatchRecord.clear();
504a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent        }
505a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent        patch->mRecordThread.clear();
506a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent    }
507a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent    if (patch->mPlaybackThread != 0) {
508a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent        if (patch->mPatchTrack != 0) {
509a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent            patch->mPatchTrack.clear();
510a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent        }
51183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        patch->mPlaybackThread.clear();
51283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
513a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent
51483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent}
51583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
516951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent/* Disconnect a patch */
517951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurentstatus_t AudioFlinger::PatchPanel::releaseAudioPatch(audio_patch_handle_t handle)
518951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{
519951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    ALOGV("releaseAudioPatch handle %d", handle);
520951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    status_t status = NO_ERROR;
521951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    size_t index;
522951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
523951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
524951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    if (audioflinger == 0) {
525951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        return NO_INIT;
526951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
527951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
528951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    for (index = 0; index < mPatches.size(); index++) {
529951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        if (handle == mPatches[index]->mHandle) {
530951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            break;
531951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        }
532951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
533951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    if (index == mPatches.size()) {
534951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        return BAD_VALUE;
535951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
53683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    Patch *removedPatch = mPatches[index];
53783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    mPatches.removeAt(index);
538951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
53983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    struct audio_patch *patch = &removedPatch->mAudioPatch;
540951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
541951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    switch (patch->sources[0].type) {
542951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        case AUDIO_PORT_TYPE_DEVICE: {
543874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent            audio_module_handle_t srcModule = patch->sources[0].ext.device.hw_module;
544874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent            ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
545951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            if (index < 0) {
546874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                ALOGW("releaseAudioPatch() bad src hw module %d", srcModule);
547951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                status = BAD_VALUE;
548951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                break;
549951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
55083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
5513bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent            if (removedPatch->mRecordPatchHandle != AUDIO_PATCH_HANDLE_NONE ||
5523bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent                    removedPatch->mPlaybackPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
55383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                clearPatchConnections(removedPatch);
55483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                break;
55583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            }
55683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
557054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent            if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
558951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
559054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                                                                patch->sinks[0].ext.mix.handle);
560951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                if (thread == 0) {
561951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                    ALOGW("releaseAudioPatch() bad capture I/O handle %d",
562054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                                                              patch->sinks[0].ext.mix.handle);
563951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                    status = BAD_VALUE;
564951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                    break;
565951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                }
566054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle);
567054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent            } else {
568054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
569054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                if (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) {
570054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                    status = INVALID_OPERATION;
571054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                    break;
572054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                }
573054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                audio_hw_device_t *hwDevice = audioHwDevice->hwDevice();
574054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                status = hwDevice->release_audio_patch(hwDevice, removedPatch->mHalHandle);
575951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
576951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        } break;
577951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        case AUDIO_PORT_TYPE_MIX: {
578874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent            audio_module_handle_t srcModule =  patch->sources[0].ext.mix.hw_module;
579874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent            ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
580951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            if (index < 0) {
581874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                ALOGW("releaseAudioPatch() bad src hw module %d", srcModule);
582951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                status = BAD_VALUE;
583951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                break;
584951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
585951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            sp<ThreadBase> thread =
586951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                            audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
587951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            if (thread == 0) {
588951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                ALOGW("releaseAudioPatch() bad playback I/O handle %d",
589951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                                                              patch->sources[0].ext.mix.handle);
590951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                status = BAD_VALUE;
591951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                break;
592951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
593054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent            status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle);
594951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        } break;
595951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        default:
596951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            status = BAD_VALUE;
597951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            break;
598951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
599951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
60083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    delete removedPatch;
601951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    return status;
602951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent}
603951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
604951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
605951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent/* List connected audio ports and they attributes */
606951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurentstatus_t AudioFlinger::PatchPanel::listAudioPatches(unsigned int *num_patches __unused,
607951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                                  struct audio_patch *patches __unused)
608951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{
609951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    ALOGV("listAudioPatches");
610951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    return NO_ERROR;
611951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent}
612951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
613951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent/* Set audio port configuration */
614e1715a465a29db625da9d0ea365edf371e39e201Eric Laurentstatus_t AudioFlinger::PatchPanel::setAudioPortConfig(const struct audio_port_config *config)
615951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{
616951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    ALOGV("setAudioPortConfig");
617e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    status_t status = NO_ERROR;
618e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent
619e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
620e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    if (audioflinger == 0) {
621e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        return NO_INIT;
622e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    }
623e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent
624e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    audio_module_handle_t module;
625e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    if (config->type == AUDIO_PORT_TYPE_DEVICE) {
626e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        module = config->ext.device.hw_module;
627e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    } else {
628e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        module = config->ext.mix.hw_module;
629e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    }
630e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent
631e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(module);
632e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    if (index < 0) {
633e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        ALOGW("setAudioPortConfig() bad hw module %d", module);
634e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        return BAD_VALUE;
635e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    }
636e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent
637e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
638e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
639e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        audio_hw_device_t *hwDevice = audioHwDevice->hwDevice();
640e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        return hwDevice->set_audio_port_config(hwDevice, config);
641e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    } else {
642e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        return INVALID_OPERATION;
643e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    }
644951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    return NO_ERROR;
645951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent}
646951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
64763238efb0d674758902918e3cdaac322126484b7Glenn Kasten} // namespace android
648