PatchPanel.cpp revision d8cd47792bac11a44096ef8233bb5268a6674bec
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    ALOGV("createAudioPatch() num_sources %d num_sinks %d handle %d",
143951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent          patch->num_sources, patch->num_sinks, *handle);
144951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    status_t status = NO_ERROR;
145951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    audio_patch_handle_t halHandle = AUDIO_PATCH_HANDLE_NONE;
146951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
147951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    if (audioflinger == 0) {
148951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        return NO_INIT;
149951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
15083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
151951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    if (handle == NULL || patch == NULL) {
152951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        return BAD_VALUE;
153951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
154874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent    if (patch->num_sources == 0 || patch->num_sources > AUDIO_PATCH_PORTS_MAX ||
155951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            patch->num_sinks == 0 || patch->num_sinks > AUDIO_PATCH_PORTS_MAX) {
156951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        return BAD_VALUE;
157951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
158874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent    // limit number of sources to 1 for now or 2 sources for special cross hw module case.
159874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent    // only the audio policy manager can request a patch creation with 2 sources.
160874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent    if (patch->num_sources > 2) {
161874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent        return INVALID_OPERATION;
162874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent    }
163951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
16483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (*handle != AUDIO_PATCH_HANDLE_NONE) {
16583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        for (size_t index = 0; *handle != 0 && index < mPatches.size(); index++) {
16683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            if (*handle == mPatches[index]->mHandle) {
16783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                ALOGV("createAudioPatch() removing patch handle %d", *handle);
16883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                halHandle = mPatches[index]->mHalHandle;
169d8cd47792bac11a44096ef8233bb5268a6674becsoon                Patch *removedPatch = mPatches[index];
17083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                mPatches.removeAt(index);
171d8cd47792bac11a44096ef8233bb5268a6674becsoon                delete removedPatch;
17283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                break;
17383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            }
174951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        }
175951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
176951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
17783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    Patch *newPatch = new Patch(patch);
17883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
179951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    switch (patch->sources[0].type) {
180951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        case AUDIO_PORT_TYPE_DEVICE: {
181874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent            audio_module_handle_t srcModule = patch->sources[0].ext.device.hw_module;
182874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent            ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
183951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            if (index < 0) {
184874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                ALOGW("createAudioPatch() bad src hw module %d", srcModule);
18583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                status = BAD_VALUE;
18683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                goto exit;
187951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
1886a94d69dc4f32abb53c466a96f905bb199be6417Eric Laurent            AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
189951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            for (unsigned int i = 0; i < patch->num_sinks; i++) {
190874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                // support only one sink if connection to a mix or across HW modules
191874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                if ((patch->sinks[i].type == AUDIO_PORT_TYPE_MIX ||
192874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                        patch->sinks[i].ext.mix.hw_module != srcModule) &&
193874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                        patch->num_sinks > 1) {
194874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                    status = INVALID_OPERATION;
195874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                    goto exit;
196874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                }
1976a94d69dc4f32abb53c466a96f905bb199be6417Eric Laurent                // reject connection to different sink types
1986a94d69dc4f32abb53c466a96f905bb199be6417Eric Laurent                if (patch->sinks[i].type != patch->sinks[0].type) {
1996a94d69dc4f32abb53c466a96f905bb199be6417Eric Laurent                    ALOGW("createAudioPatch() different sink types in same patch not supported");
20083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    status = BAD_VALUE;
20183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    goto exit;
202951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                }
20383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                // limit to connections between devices and input streams for HAL before 3.0
204874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                if (patch->sinks[i].ext.mix.hw_module == srcModule &&
20583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) &&
2066a94d69dc4f32abb53c466a96f905bb199be6417Eric Laurent                        (patch->sinks[i].type != AUDIO_PORT_TYPE_MIX)) {
2076a94d69dc4f32abb53c466a96f905bb199be6417Eric Laurent                    ALOGW("createAudioPatch() invalid sink type %d for device source",
2086a94d69dc4f32abb53c466a96f905bb199be6417Eric Laurent                          patch->sinks[i].type);
20983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    status = BAD_VALUE;
21083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    goto exit;
2116a94d69dc4f32abb53c466a96f905bb199be6417Eric Laurent                }
212951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
213951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
214874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent            if (patch->sinks[0].ext.device.hw_module != srcModule) {
21583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                // limit to device to device connection if not on same hw module
21683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                if (patch->sinks[0].type != AUDIO_PORT_TYPE_DEVICE) {
21783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    ALOGW("createAudioPatch() invalid sink type for cross hw module");
21883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    status = INVALID_OPERATION;
21983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    goto exit;
22083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                }
22183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                // special case num sources == 2 -=> reuse an exiting output mix to connect to the
22283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                // sink
22383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                if (patch->num_sources == 2) {
22483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    if (patch->sources[1].type != AUDIO_PORT_TYPE_MIX ||
22583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                            patch->sinks[0].ext.device.hw_module !=
22683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                    patch->sources[1].ext.mix.hw_module) {
22783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        ALOGW("createAudioPatch() invalid source combination");
22883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        status = INVALID_OPERATION;
22983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        goto exit;
23083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    }
23183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
23283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    sp<ThreadBase> thread =
23383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                            audioflinger->checkPlaybackThread_l(patch->sources[1].ext.mix.handle);
23483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    newPatch->mPlaybackThread = (MixerThread *)thread.get();
235951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                    if (thread == 0) {
23683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        ALOGW("createAudioPatch() cannot get playback thread");
23783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        status = INVALID_OPERATION;
23883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        goto exit;
239951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                    }
240951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                } else {
241cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    audio_config_t config = AUDIO_CONFIG_INITIALIZER;
242cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    audio_devices_t device = patch->sinks[0].ext.device.type;
243cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    String8 address = String8(patch->sinks[0].ext.device.address);
244cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
24583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    newPatch->mPlaybackThread = audioflinger->openOutput_l(
24683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                             patch->sinks[0].ext.device.hw_module,
247cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                             &output,
24883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                             &config,
249cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                             device,
250cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                             address,
25183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                             AUDIO_OUTPUT_FLAG_NONE);
25283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    ALOGV("audioflinger->openOutput_l() returned %p",
25383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                          newPatch->mPlaybackThread.get());
25483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    if (newPatch->mPlaybackThread == 0) {
25583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        status = NO_MEMORY;
25683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        goto exit;
25783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    }
25883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                }
25983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                uint32_t channelCount = newPatch->mPlaybackThread->channelCount();
26083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                audio_devices_t device = patch->sources[0].ext.device.type;
261cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                String8 address = String8(patch->sources[0].ext.device.address);
262cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                audio_config_t config = AUDIO_CONFIG_INITIALIZER;
26383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                audio_channel_mask_t inChannelMask = audio_channel_in_mask_from_count(channelCount);
26483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                config.sample_rate = newPatch->mPlaybackThread->sampleRate();
26583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                config.channel_mask = inChannelMask;
26683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                config.format = newPatch->mPlaybackThread->format();
267cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
268874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                newPatch->mRecordThread = audioflinger->openInput_l(srcModule,
269cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                                    &input,
27083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                                    &config,
271cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                                    device,
272cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                                    address,
273cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                                    AUDIO_SOURCE_MIC,
27483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                                    AUDIO_INPUT_FLAG_NONE);
27583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                ALOGV("audioflinger->openInput_l() returned %p inChannelMask %08x",
27683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                      newPatch->mRecordThread.get(), inChannelMask);
27783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                if (newPatch->mRecordThread == 0) {
27883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    status = NO_MEMORY;
27983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    goto exit;
28083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                }
28183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                status = createPatchConnections(newPatch, patch);
28283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                if (status != NO_ERROR) {
28383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    goto exit;
284951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                }
285951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            } else {
28683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
28783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
28883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
289874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                                                                  patch->sinks[0].ext.mix.handle);
29083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        if (thread == 0) {
29183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                            ALOGW("createAudioPatch() bad capture I/O handle %d",
292874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                                                                  patch->sinks[0].ext.mix.handle);
29383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                            status = BAD_VALUE;
29483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                            goto exit;
29583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        }
29683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
29783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    } else {
29883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        audio_hw_device_t *hwDevice = audioHwDevice->hwDevice();
29983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        status = hwDevice->create_audio_patch(hwDevice,
30083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                               patch->num_sources,
30183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                               patch->sources,
30283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                               patch->num_sinks,
30383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                               patch->sinks,
30483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                               &halHandle);
30583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    }
30683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                } else {
30783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
308874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                                                                    patch->sinks[0].ext.mix.handle);
30983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    if (thread == 0) {
31083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        ALOGW("createAudioPatch() bad capture I/O handle %d",
311874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                                                                    patch->sinks[0].ext.mix.handle);
31283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        status = BAD_VALUE;
31383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        goto exit;
31483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    }
315cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    char *address;
316cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    if (strcmp(patch->sources[0].ext.device.address, "") != 0) {
317cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                        address = audio_device_address_to_parameter(
318cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                            patch->sources[0].ext.device.type,
319cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                            patch->sources[0].ext.device.address);
320cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    } else {
321cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                        address = (char *)calloc(1, 1);
322cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    }
323cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    AudioParameter param = AudioParameter(String8(address));
324cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    free(address);
325cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING),
32683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                 (int)patch->sources[0].ext.device.type);
327cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    param.addInt(String8(AUDIO_PARAMETER_STREAM_INPUT_SOURCE),
328cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                     (int)patch->sinks[0].ext.mix.usecase.source);
32983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    ALOGV("createAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s",
330cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                                      param.toString().string());
33183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    status = thread->setParameters(param.toString());
332951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                }
333951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
334951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        } break;
335951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        case AUDIO_PORT_TYPE_MIX: {
336874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent            audio_module_handle_t srcModule =  patch->sources[0].ext.mix.hw_module;
337874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent            ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
338951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            if (index < 0) {
339874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                ALOGW("createAudioPatch() bad src hw module %d", srcModule);
34083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                status = BAD_VALUE;
34183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                goto exit;
342951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
343951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            // limit to connections between devices and output streams
344951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            for (unsigned int i = 0; i < patch->num_sinks; i++) {
345951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) {
34683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    ALOGW("createAudioPatch() invalid sink type %d for mix source",
347951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                          patch->sinks[i].type);
34883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    status = BAD_VALUE;
34983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    goto exit;
350951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                }
351951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                // limit to connections between sinks and sources on same HW module
352874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                if (patch->sinks[i].ext.device.hw_module != srcModule) {
35383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    status = BAD_VALUE;
35483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    goto exit;
355951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                }
356951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
357951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
358951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            sp<ThreadBase> thread =
359951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                            audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
360951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            if (thread == 0) {
361951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                ALOGW("createAudioPatch() bad playback I/O handle %d",
362951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                          patch->sources[0].ext.mix.handle);
36383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                status = BAD_VALUE;
36483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                goto exit;
365951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
366951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
367951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
368951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            } else {
369951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                audio_devices_t type = AUDIO_DEVICE_NONE;
370951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                for (unsigned int i = 0; i < patch->num_sinks; i++) {
371951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                    type |= patch->sinks[i].ext.device.type;
372951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                }
373cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                char *address;
374cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                if (strcmp(patch->sinks[0].ext.device.address, "") != 0) {
375874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                    //FIXME: we only support address on first sink with HAL version < 3.0
376cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    address = audio_device_address_to_parameter(
377cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                                patch->sinks[0].ext.device.type,
378cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                                patch->sinks[0].ext.device.address);
379cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                } else {
380cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    address = (char *)calloc(1, 1);
381cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                }
382cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                AudioParameter param = AudioParameter(String8(address));
383cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                free(address);
384cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), (int)type);
385951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                status = thread->setParameters(param.toString());
386951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
387951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
388951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        } break;
389951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        default:
39083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            status = BAD_VALUE;
39183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            goto exit;
392951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
39383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurentexit:
394951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    ALOGV("createAudioPatch() status %d", status);
395951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    if (status == NO_ERROR) {
396951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        *handle = audioflinger->nextUniqueId();
397951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        newPatch->mHandle = *handle;
398951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        newPatch->mHalHandle = halHandle;
399951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        mPatches.add(newPatch);
400951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        ALOGV("createAudioPatch() added new patch handle %d halHandle %d", *handle, halHandle);
40183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    } else {
40283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        clearPatchConnections(newPatch);
40383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        delete newPatch;
40483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
40583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    return status;
40683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent}
40783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
40883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurentstatus_t AudioFlinger::PatchPanel::createPatchConnections(Patch *patch,
40983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                          const struct audio_patch *audioPatch)
41083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent{
41183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // create patch from source device to record thread input
41283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    struct audio_patch subPatch;
41383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    subPatch.num_sources = 1;
41483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    subPatch.sources[0] = audioPatch->sources[0];
41583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    subPatch.num_sinks = 1;
41683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
41783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mRecordThread->getAudioPortConfig(&subPatch.sinks[0]);
41883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    subPatch.sinks[0].ext.mix.usecase.source = AUDIO_SOURCE_MIC;
41983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
42083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    status_t status = createAudioPatch(&subPatch, &patch->mRecordPatchHandle);
42183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (status != NO_ERROR) {
42283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        patch->mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE;
42383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        return status;
42483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
42583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
42683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // create patch from playback thread output to sink device
42783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPlaybackThread->getAudioPortConfig(&subPatch.sources[0]);
42883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    subPatch.sinks[0] = audioPatch->sinks[0];
42983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    status = createAudioPatch(&subPatch, &patch->mPlaybackPatchHandle);
43083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (status != NO_ERROR) {
43183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
43283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        return status;
43383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
43483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
43583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // use a pseudo LCM between input and output framecount
43683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    size_t playbackFrameCount = patch->mPlaybackThread->frameCount();
43783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    int playbackShift = __builtin_ctz(playbackFrameCount);
43883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    size_t recordFramecount = patch->mRecordThread->frameCount();
43983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    int shift = __builtin_ctz(recordFramecount);
44083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (playbackShift < shift) {
44183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        shift = playbackShift;
44283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
44383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    size_t frameCount = (playbackFrameCount * recordFramecount) >> shift;
44483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    ALOGV("createPatchConnections() playframeCount %d recordFramecount %d frameCount %d ",
44583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent          playbackFrameCount, recordFramecount, frameCount);
44683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
44783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // create a special record track to capture from record thread
44883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    uint32_t channelCount = patch->mPlaybackThread->channelCount();
44983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    audio_channel_mask_t inChannelMask = audio_channel_in_mask_from_count(channelCount);
45083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    audio_channel_mask_t outChannelMask = patch->mPlaybackThread->channelMask();
45183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    uint32_t sampleRate = patch->mPlaybackThread->sampleRate();
45283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    audio_format_t format = patch->mPlaybackThread->format();
45383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
45483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPatchRecord = new RecordThread::PatchRecord(
45583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                             patch->mRecordThread.get(),
45683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                             sampleRate,
45783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                             inChannelMask,
45883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                             format,
45983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                             frameCount,
46083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                             NULL,
46183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                             IAudioFlinger::TRACK_DEFAULT);
46283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mPatchRecord == 0) {
46383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        return NO_MEMORY;
46483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
46583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    status = patch->mPatchRecord->initCheck();
46683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (status != NO_ERROR) {
46783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        return status;
468951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
46983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mRecordThread->addPatchRecord(patch->mPatchRecord);
47083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
47183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // create a special playback track to render to playback thread.
47283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // this track is given the same buffer as the PatchRecord buffer
47383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPatchTrack = new PlaybackThread::PatchTrack(
47483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                           patch->mPlaybackThread.get(),
47583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                           sampleRate,
47683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                           outChannelMask,
47783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                           format,
47883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                           frameCount,
47983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                           patch->mPatchRecord->buffer(),
48083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                           IAudioFlinger::TRACK_DEFAULT);
48183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mPatchTrack == 0) {
48283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        return NO_MEMORY;
48383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
48483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    status = patch->mPatchTrack->initCheck();
48583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (status != NO_ERROR) {
48683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        return status;
48783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
48883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPlaybackThread->addPatchTrack(patch->mPatchTrack);
48983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
49083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // tie playback and record tracks together
49183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPatchRecord->setPeerProxy(patch->mPatchTrack.get());
49283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPatchTrack->setPeerProxy(patch->mPatchRecord.get());
49383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
49483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // start capture and playback
49583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPatchRecord->start(AudioSystem::SYNC_EVENT_NONE, 0);
49683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPatchTrack->start();
49783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
498951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    return status;
499951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent}
500951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
50183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurentvoid AudioFlinger::PatchPanel::clearPatchConnections(Patch *patch)
50283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent{
50383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
50483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (audioflinger == 0) {
50583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        return;
50683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
50783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
50883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    ALOGV("clearPatchConnections() patch->mRecordPatchHandle %d patch->mPlaybackPatchHandle %d",
50983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent          patch->mRecordPatchHandle, patch->mPlaybackPatchHandle);
51083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
51183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mPatchRecord != 0) {
51283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        patch->mPatchRecord->stop();
51383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
51483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mPatchTrack != 0) {
51583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        patch->mPatchTrack->stop();
51683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
51783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mRecordPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
51883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        releaseAudioPatch(patch->mRecordPatchHandle);
51983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        patch->mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE;
52083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
52183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mPlaybackPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
52283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        releaseAudioPatch(patch->mPlaybackPatchHandle);
52383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
52483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
52583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mRecordThread != 0) {
52683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        if (patch->mPatchRecord != 0) {
52783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            patch->mRecordThread->deletePatchRecord(patch->mPatchRecord);
52883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            patch->mPatchRecord.clear();
52983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        }
53083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        audioflinger->closeInputInternal_l(patch->mRecordThread);
53183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        patch->mRecordThread.clear();
53283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
53383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mPlaybackThread != 0) {
53483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        if (patch->mPatchTrack != 0) {
53583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            patch->mPlaybackThread->deletePatchTrack(patch->mPatchTrack);
53683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            patch->mPatchTrack.clear();
53783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        }
53883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        // if num sources == 2 we are reusing an existing playback thread so we do not close it
53983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        if (patch->mAudioPatch.num_sources != 2) {
54083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            audioflinger->closeOutputInternal_l(patch->mPlaybackThread);
54183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        }
54283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        patch->mPlaybackThread.clear();
54383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
54483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent}
54583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
546951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent/* Disconnect a patch */
547951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurentstatus_t AudioFlinger::PatchPanel::releaseAudioPatch(audio_patch_handle_t handle)
548951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{
549951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    ALOGV("releaseAudioPatch handle %d", handle);
550951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    status_t status = NO_ERROR;
551951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    size_t index;
552951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
553951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
554951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    if (audioflinger == 0) {
555951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        return NO_INIT;
556951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
557951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
558951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    for (index = 0; index < mPatches.size(); index++) {
559951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        if (handle == mPatches[index]->mHandle) {
560951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            break;
561951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        }
562951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
563951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    if (index == mPatches.size()) {
564951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        return BAD_VALUE;
565951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
56683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    Patch *removedPatch = mPatches[index];
56783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    mPatches.removeAt(index);
568951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
56983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    struct audio_patch *patch = &removedPatch->mAudioPatch;
570951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
571951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    switch (patch->sources[0].type) {
572951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        case AUDIO_PORT_TYPE_DEVICE: {
573874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent            audio_module_handle_t srcModule = patch->sources[0].ext.device.hw_module;
574874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent            ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
575951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            if (index < 0) {
576874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                ALOGW("releaseAudioPatch() bad src hw module %d", srcModule);
577951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                status = BAD_VALUE;
578951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                break;
579951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
58083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
58183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            if (patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE &&
582874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                    patch->sinks[0].ext.device.hw_module != srcModule) {
58383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                clearPatchConnections(removedPatch);
58483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                break;
58583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            }
58683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
587951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
588951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
589951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
590951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                    sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
591951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                                                                    patch->sinks[0].ext.mix.handle);
592951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                    if (thread == 0) {
59383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        ALOGW("releaseAudioPatch() bad capture I/O handle %d",
594951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                                                                  patch->sinks[0].ext.mix.handle);
595951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                        status = BAD_VALUE;
596951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                        break;
597951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                    }
598f8fd8d6daab5ced86ce950be68070d27c24d487fEric Laurent                    status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle);
599951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                } else {
600951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                    audio_hw_device_t *hwDevice = audioHwDevice->hwDevice();
601f8fd8d6daab5ced86ce950be68070d27c24d487fEric Laurent                    status = hwDevice->release_audio_patch(hwDevice, removedPatch->mHalHandle);
602951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                }
603951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            } else {
604951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
605951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                                                                    patch->sinks[0].ext.mix.handle);
606951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                if (thread == 0) {
607951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                    ALOGW("releaseAudioPatch() bad capture I/O handle %d",
608951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                                                                  patch->sinks[0].ext.mix.handle);
609951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                    status = BAD_VALUE;
610951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                    break;
611951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                }
612951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                AudioParameter param;
613cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), 0);
61424478d47fc631ab33208f4dd9d034abb6839c992Eric Laurent                ALOGV("releaseAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s",
615951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                                                                      param.toString().string());
616951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                status = thread->setParameters(param.toString());
617951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
618951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        } break;
619951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        case AUDIO_PORT_TYPE_MIX: {
620874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent            audio_module_handle_t srcModule =  patch->sources[0].ext.mix.hw_module;
621874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent            ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
622951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            if (index < 0) {
623874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                ALOGW("releaseAudioPatch() bad src hw module %d", srcModule);
624951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                status = BAD_VALUE;
625951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                break;
626951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
627951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            sp<ThreadBase> thread =
628951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                            audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
629951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            if (thread == 0) {
630951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                ALOGW("releaseAudioPatch() bad playback I/O handle %d",
631951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                                                              patch->sources[0].ext.mix.handle);
632951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                status = BAD_VALUE;
633951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                break;
634951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
635951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
636951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
637f8fd8d6daab5ced86ce950be68070d27c24d487fEric Laurent                status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle);
638951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            } else {
639951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                AudioParameter param;
640cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), 0);
641951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                status = thread->setParameters(param.toString());
642951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
643951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        } break;
644951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        default:
645951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            status = BAD_VALUE;
646951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            break;
647951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
648951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
64983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    delete removedPatch;
650951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    return status;
651951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent}
652951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
653951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
654951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent/* List connected audio ports and they attributes */
655951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurentstatus_t AudioFlinger::PatchPanel::listAudioPatches(unsigned int *num_patches __unused,
656951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                                  struct audio_patch *patches __unused)
657951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{
658951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    ALOGV("listAudioPatches");
659951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    return NO_ERROR;
660951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent}
661951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
662951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent/* Set audio port configuration */
663e1715a465a29db625da9d0ea365edf371e39e201Eric Laurentstatus_t AudioFlinger::PatchPanel::setAudioPortConfig(const struct audio_port_config *config)
664951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{
665951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    ALOGV("setAudioPortConfig");
666e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    status_t status = NO_ERROR;
667e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent
668e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
669e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    if (audioflinger == 0) {
670e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        return NO_INIT;
671e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    }
672e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent
673e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    audio_module_handle_t module;
674e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    if (config->type == AUDIO_PORT_TYPE_DEVICE) {
675e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        module = config->ext.device.hw_module;
676e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    } else {
677e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        module = config->ext.mix.hw_module;
678e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    }
679e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent
680e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(module);
681e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    if (index < 0) {
682e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        ALOGW("setAudioPortConfig() bad hw module %d", module);
683e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        return BAD_VALUE;
684e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    }
685e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent
686e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
687e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
688e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        audio_hw_device_t *hwDevice = audioHwDevice->hwDevice();
689e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        return hwDevice->set_audio_port_config(hwDevice, config);
690e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    } else {
691e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        return INVALID_OPERATION;
692e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    }
693951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    return NO_ERROR;
694951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent}
695951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
696951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
697951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent}; // namespace android
698