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