PatchPanel.cpp revision a0169a073d88efefbfb35fa0ea8e94f7b31d7469
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                }
203951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
204951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
2053bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent            // manage patches requiring a software bridge
2063bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent            // - Device to device AND
2073bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent            //    - source HW module != destination HW module OR
2083bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent            //    - audio HAL version < 3.0
2093bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent            //    - special patch request with 2 sources (reuse one existing output mix)
2103bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent            if ((patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) &&
2113bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent                    ((patch->sinks[0].ext.device.hw_module != srcModule) ||
2123bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent                    (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) ||
2133bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent                    (patch->num_sources == 2))) {
21483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                if (patch->num_sources == 2) {
21583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    if (patch->sources[1].type != AUDIO_PORT_TYPE_MIX ||
21683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                            patch->sinks[0].ext.device.hw_module !=
21783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                    patch->sources[1].ext.mix.hw_module) {
21883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        ALOGW("createAudioPatch() invalid source combination");
21983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        status = INVALID_OPERATION;
22083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        goto exit;
22183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    }
22283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
22383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    sp<ThreadBase> thread =
22483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                            audioflinger->checkPlaybackThread_l(patch->sources[1].ext.mix.handle);
22583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    newPatch->mPlaybackThread = (MixerThread *)thread.get();
226951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                    if (thread == 0) {
22783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        ALOGW("createAudioPatch() cannot get playback thread");
22883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        status = INVALID_OPERATION;
22983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        goto exit;
230951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                    }
231951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                } else {
232cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    audio_config_t config = AUDIO_CONFIG_INITIALIZER;
233cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    audio_devices_t device = patch->sinks[0].ext.device.type;
234cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    String8 address = String8(patch->sinks[0].ext.device.address);
235cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
23683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    newPatch->mPlaybackThread = audioflinger->openOutput_l(
23783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                             patch->sinks[0].ext.device.hw_module,
238cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                             &output,
23983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                             &config,
240cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                             device,
241cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                             address,
24283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                             AUDIO_OUTPUT_FLAG_NONE);
24383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    ALOGV("audioflinger->openOutput_l() returned %p",
24483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                          newPatch->mPlaybackThread.get());
24583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    if (newPatch->mPlaybackThread == 0) {
24683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        status = NO_MEMORY;
24783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        goto exit;
24883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    }
24983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                }
25083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                uint32_t channelCount = newPatch->mPlaybackThread->channelCount();
25183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                audio_devices_t device = patch->sources[0].ext.device.type;
252cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                String8 address = String8(patch->sources[0].ext.device.address);
253cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                audio_config_t config = AUDIO_CONFIG_INITIALIZER;
25483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                audio_channel_mask_t inChannelMask = audio_channel_in_mask_from_count(channelCount);
25583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                config.sample_rate = newPatch->mPlaybackThread->sampleRate();
25683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                config.channel_mask = inChannelMask;
25783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                config.format = newPatch->mPlaybackThread->format();
258cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
259874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                newPatch->mRecordThread = audioflinger->openInput_l(srcModule,
260cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                                    &input,
26183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                                    &config,
262cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                                    device,
263cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                                    address,
264cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                                                                    AUDIO_SOURCE_MIC,
26583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                                    AUDIO_INPUT_FLAG_NONE);
26683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                ALOGV("audioflinger->openInput_l() returned %p inChannelMask %08x",
26783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                      newPatch->mRecordThread.get(), inChannelMask);
26883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                if (newPatch->mRecordThread == 0) {
26983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    status = NO_MEMORY;
27083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    goto exit;
27183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                }
27283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                status = createPatchConnections(newPatch, patch);
27383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                if (status != NO_ERROR) {
27483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    goto exit;
275951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                }
276951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            } else {
277054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
27883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
279054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                                                              patch->sinks[0].ext.mix.handle);
28083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    if (thread == 0) {
28183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        ALOGW("createAudioPatch() bad capture I/O handle %d",
282054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                                                              patch->sinks[0].ext.mix.handle);
28383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        status = BAD_VALUE;
28483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                        goto exit;
28583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    }
286054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                    status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
287054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                } else {
288054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                    if (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) {
289054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                        status = INVALID_OPERATION;
290054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                        goto exit;
291cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                    }
292054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent
293054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                    audio_hw_device_t *hwDevice = audioHwDevice->hwDevice();
294054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                    status = hwDevice->create_audio_patch(hwDevice,
295054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                                                           patch->num_sources,
296054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                                                           patch->sources,
297054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                                                           patch->num_sinks,
298054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                                                           patch->sinks,
299054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                                                           &halHandle);
300951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                }
301951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
302951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        } break;
303951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        case AUDIO_PORT_TYPE_MIX: {
304874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent            audio_module_handle_t srcModule =  patch->sources[0].ext.mix.hw_module;
305874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent            ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
306951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            if (index < 0) {
307874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                ALOGW("createAudioPatch() bad src hw module %d", srcModule);
30883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                status = BAD_VALUE;
30983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                goto exit;
310951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
311951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            // limit to connections between devices and output streams
312054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent            audio_devices_t type = AUDIO_DEVICE_NONE;
313951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            for (unsigned int i = 0; i < patch->num_sinks; i++) {
314951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) {
31583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    ALOGW("createAudioPatch() invalid sink type %d for mix source",
316951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                          patch->sinks[i].type);
31783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    status = BAD_VALUE;
31883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    goto exit;
319951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                }
320951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                // limit to connections between sinks and sources on same HW module
321874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                if (patch->sinks[i].ext.device.hw_module != srcModule) {
32283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    status = BAD_VALUE;
32383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                    goto exit;
324951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                }
325054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                type |= patch->sinks[i].ext.device.type;
326951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
327951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            sp<ThreadBase> thread =
328951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                            audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
329951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            if (thread == 0) {
330951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                ALOGW("createAudioPatch() bad playback I/O handle %d",
331951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                          patch->sources[0].ext.mix.handle);
33283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                status = BAD_VALUE;
33383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                goto exit;
334951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
335054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent            if (thread == audioflinger->primaryPlaybackThread_l()) {
336054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                AudioParameter param = AudioParameter();
337cf2c0210c8afbe7d0661ccbbae3835b5ce73c0bfEric Laurent                param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), (int)type);
338054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent
339054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                audioflinger->broacastParametersToRecordThreads_l(param.toString());
340951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
341951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
342054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent            status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
343951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        } break;
344951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        default:
34583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            status = BAD_VALUE;
34683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            goto exit;
347951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
34883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurentexit:
349951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    ALOGV("createAudioPatch() status %d", status);
350951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    if (status == NO_ERROR) {
351951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        *handle = audioflinger->nextUniqueId();
352951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        newPatch->mHandle = *handle;
353951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        newPatch->mHalHandle = halHandle;
354951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        mPatches.add(newPatch);
355951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        ALOGV("createAudioPatch() added new patch handle %d halHandle %d", *handle, halHandle);
35683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    } else {
35783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        clearPatchConnections(newPatch);
35883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        delete newPatch;
35983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
36083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    return status;
36183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent}
36283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
36383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurentstatus_t AudioFlinger::PatchPanel::createPatchConnections(Patch *patch,
36483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                                          const struct audio_patch *audioPatch)
36583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent{
36683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // create patch from source device to record thread input
36783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    struct audio_patch subPatch;
36883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    subPatch.num_sources = 1;
36983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    subPatch.sources[0] = audioPatch->sources[0];
37083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    subPatch.num_sinks = 1;
37183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
37283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mRecordThread->getAudioPortConfig(&subPatch.sinks[0]);
37383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    subPatch.sinks[0].ext.mix.usecase.source = AUDIO_SOURCE_MIC;
37483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
37583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    status_t status = createAudioPatch(&subPatch, &patch->mRecordPatchHandle);
37683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (status != NO_ERROR) {
37783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        patch->mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE;
37883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        return status;
37983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
38083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
38183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // create patch from playback thread output to sink device
38283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPlaybackThread->getAudioPortConfig(&subPatch.sources[0]);
38383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    subPatch.sinks[0] = audioPatch->sinks[0];
38483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    status = createAudioPatch(&subPatch, &patch->mPlaybackPatchHandle);
38583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (status != NO_ERROR) {
38683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
38783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        return status;
38883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
38983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
39083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // use a pseudo LCM between input and output framecount
39183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    size_t playbackFrameCount = patch->mPlaybackThread->frameCount();
39283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    int playbackShift = __builtin_ctz(playbackFrameCount);
39383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    size_t recordFramecount = patch->mRecordThread->frameCount();
39483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    int shift = __builtin_ctz(recordFramecount);
39583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (playbackShift < shift) {
39683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        shift = playbackShift;
39783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
39883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    size_t frameCount = (playbackFrameCount * recordFramecount) >> shift;
39983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    ALOGV("createPatchConnections() playframeCount %d recordFramecount %d frameCount %d ",
40083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent          playbackFrameCount, recordFramecount, frameCount);
40183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
40283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // create a special record track to capture from record thread
40383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    uint32_t channelCount = patch->mPlaybackThread->channelCount();
40483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    audio_channel_mask_t inChannelMask = audio_channel_in_mask_from_count(channelCount);
40583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    audio_channel_mask_t outChannelMask = patch->mPlaybackThread->channelMask();
40683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    uint32_t sampleRate = patch->mPlaybackThread->sampleRate();
40783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    audio_format_t format = patch->mPlaybackThread->format();
40883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
40983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPatchRecord = new RecordThread::PatchRecord(
41083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                             patch->mRecordThread.get(),
41183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                             sampleRate,
41283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                             inChannelMask,
41383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                             format,
41483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                             frameCount,
41583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                             NULL,
41683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                             IAudioFlinger::TRACK_DEFAULT);
41783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mPatchRecord == 0) {
41883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        return NO_MEMORY;
41983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
42083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    status = patch->mPatchRecord->initCheck();
42183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (status != NO_ERROR) {
42283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        return status;
423951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
42483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mRecordThread->addPatchRecord(patch->mPatchRecord);
42583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
42683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // create a special playback track to render to playback thread.
42783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // this track is given the same buffer as the PatchRecord buffer
42883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPatchTrack = new PlaybackThread::PatchTrack(
42983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                           patch->mPlaybackThread.get(),
4303bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent                                           audioPatch->sources[1].ext.mix.usecase.stream,
43183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                           sampleRate,
43283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                           outChannelMask,
43383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                           format,
43483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                           frameCount,
43583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                           patch->mPatchRecord->buffer(),
43683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                                           IAudioFlinger::TRACK_DEFAULT);
43783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mPatchTrack == 0) {
43883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        return NO_MEMORY;
43983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
44083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    status = patch->mPatchTrack->initCheck();
44183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (status != NO_ERROR) {
44283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        return status;
44383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
44483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPlaybackThread->addPatchTrack(patch->mPatchTrack);
44583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
44683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // tie playback and record tracks together
44783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPatchRecord->setPeerProxy(patch->mPatchTrack.get());
44883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPatchTrack->setPeerProxy(patch->mPatchRecord.get());
44983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
45083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    // start capture and playback
45183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPatchRecord->start(AudioSystem::SYNC_EVENT_NONE, 0);
45283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    patch->mPatchTrack->start();
45383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
454951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    return status;
455951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent}
456951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
45783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurentvoid AudioFlinger::PatchPanel::clearPatchConnections(Patch *patch)
45883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent{
45983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
46083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (audioflinger == 0) {
46183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        return;
46283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
46383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
46483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    ALOGV("clearPatchConnections() patch->mRecordPatchHandle %d patch->mPlaybackPatchHandle %d",
46583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent          patch->mRecordPatchHandle, patch->mPlaybackPatchHandle);
46683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
46783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mPatchRecord != 0) {
46883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        patch->mPatchRecord->stop();
46983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
47083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mPatchTrack != 0) {
47183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        patch->mPatchTrack->stop();
47283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
47383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mRecordPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
47483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        releaseAudioPatch(patch->mRecordPatchHandle);
47583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        patch->mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE;
47683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
47783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mPlaybackPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
47883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        releaseAudioPatch(patch->mPlaybackPatchHandle);
47983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
48083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
48183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mRecordThread != 0) {
48283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        if (patch->mPatchRecord != 0) {
48383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            patch->mRecordThread->deletePatchRecord(patch->mPatchRecord);
48483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        }
48583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        audioflinger->closeInputInternal_l(patch->mRecordThread);
48683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
48783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    if (patch->mPlaybackThread != 0) {
48883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        if (patch->mPatchTrack != 0) {
48983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            patch->mPlaybackThread->deletePatchTrack(patch->mPatchTrack);
49083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        }
49183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        // if num sources == 2 we are reusing an existing playback thread so we do not close it
49283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        if (patch->mAudioPatch.num_sources != 2) {
49383b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            audioflinger->closeOutputInternal_l(patch->mPlaybackThread);
49483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        }
495a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent    }
496a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent    if (patch->mRecordThread != 0) {
497a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent        if (patch->mPatchRecord != 0) {
498a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent            patch->mPatchRecord.clear();
499a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent        }
500a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent        patch->mRecordThread.clear();
501a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent    }
502a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent    if (patch->mPlaybackThread != 0) {
503a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent        if (patch->mPatchTrack != 0) {
504a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent            patch->mPatchTrack.clear();
505a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent        }
50683b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent        patch->mPlaybackThread.clear();
50783b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    }
508a0169a073d88efefbfb35fa0ea8e94f7b31d7469Eric Laurent
50983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent}
51083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
511951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent/* Disconnect a patch */
512951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurentstatus_t AudioFlinger::PatchPanel::releaseAudioPatch(audio_patch_handle_t handle)
513951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{
514951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    ALOGV("releaseAudioPatch handle %d", handle);
515951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    status_t status = NO_ERROR;
516951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    size_t index;
517951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
518951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
519951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    if (audioflinger == 0) {
520951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        return NO_INIT;
521951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
522951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
523951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    for (index = 0; index < mPatches.size(); index++) {
524951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        if (handle == mPatches[index]->mHandle) {
525951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            break;
526951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        }
527951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
528951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    if (index == mPatches.size()) {
529951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        return BAD_VALUE;
530951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
53183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    Patch *removedPatch = mPatches[index];
53283b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    mPatches.removeAt(index);
533951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
53483b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    struct audio_patch *patch = &removedPatch->mAudioPatch;
535951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
536951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    switch (patch->sources[0].type) {
537951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        case AUDIO_PORT_TYPE_DEVICE: {
538874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent            audio_module_handle_t srcModule = patch->sources[0].ext.device.hw_module;
539874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent            ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
540951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            if (index < 0) {
541874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent                ALOGW("releaseAudioPatch() bad src hw module %d", srcModule);
542951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                status = BAD_VALUE;
543951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                break;
544951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
54583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
5463bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent            if (removedPatch->mRecordPatchHandle != AUDIO_PATCH_HANDLE_NONE ||
5473bcf8597189c592713675ec58326ecbef0ac4ae9Eric Laurent                    removedPatch->mPlaybackPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
54883b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                clearPatchConnections(removedPatch);
54983b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent                break;
55083b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent            }
55183b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent
552054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent            if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
553951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
554054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                                                                patch->sinks[0].ext.mix.handle);
555951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                if (thread == 0) {
556951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                    ALOGW("releaseAudioPatch() bad capture I/O handle %d",
557054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                                                              patch->sinks[0].ext.mix.handle);
558951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                    status = BAD_VALUE;
559951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                    break;
560951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                }
561054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle);
562054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent            } else {
563054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
564054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                if (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) {
565054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                    status = INVALID_OPERATION;
566054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                    break;
567054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                }
568054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                audio_hw_device_t *hwDevice = audioHwDevice->hwDevice();
569054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent                status = hwDevice->release_audio_patch(hwDevice, removedPatch->mHalHandle);
570951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
571951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        } break;
572951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        case AUDIO_PORT_TYPE_MIX: {
573874c4287a4e49c59ac88767751dce00fcd3edb73Eric Laurent            audio_module_handle_t srcModule =  patch->sources[0].ext.mix.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            }
580951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            sp<ThreadBase> thread =
581951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                            audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
582951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            if (thread == 0) {
583951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                ALOGW("releaseAudioPatch() bad playback I/O handle %d",
584951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                                                              patch->sources[0].ext.mix.handle);
585951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                status = BAD_VALUE;
586951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                break;
587951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            }
588054d9d3dea1390294650ac704acb4aa0a0731217Eric Laurent            status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle);
589951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        } break;
590951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent        default:
591951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            status = BAD_VALUE;
592951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent            break;
593951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    }
594951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
59583b8808faad1e91690c64d7007348be8d9ebde73Eric Laurent    delete removedPatch;
596951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    return status;
597951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent}
598951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
599951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
600951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent/* List connected audio ports and they attributes */
601951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurentstatus_t AudioFlinger::PatchPanel::listAudioPatches(unsigned int *num_patches __unused,
602951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent                                  struct audio_patch *patches __unused)
603951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{
604951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    ALOGV("listAudioPatches");
605951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    return NO_ERROR;
606951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent}
607951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
608951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent/* Set audio port configuration */
609e1715a465a29db625da9d0ea365edf371e39e201Eric Laurentstatus_t AudioFlinger::PatchPanel::setAudioPortConfig(const struct audio_port_config *config)
610951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent{
611951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    ALOGV("setAudioPortConfig");
612e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    status_t status = NO_ERROR;
613e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent
614e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
615e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    if (audioflinger == 0) {
616e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        return NO_INIT;
617e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    }
618e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent
619e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    audio_module_handle_t module;
620e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    if (config->type == AUDIO_PORT_TYPE_DEVICE) {
621e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        module = config->ext.device.hw_module;
622e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    } else {
623e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        module = config->ext.mix.hw_module;
624e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    }
625e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent
626e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(module);
627e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    if (index < 0) {
628e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        ALOGW("setAudioPortConfig() bad hw module %d", module);
629e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        return BAD_VALUE;
630e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    }
631e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent
632e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
633e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
634e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        audio_hw_device_t *hwDevice = audioHwDevice->hwDevice();
635e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        return hwDevice->set_audio_port_config(hwDevice, config);
636e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    } else {
637e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent        return INVALID_OPERATION;
638e1715a465a29db625da9d0ea365edf371e39e201Eric Laurent    }
639951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent    return NO_ERROR;
640951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent}
641951f455566775e5f01e67c5ee26863d7d19209d7Eric Laurent
64263238efb0d674758902918e3cdaac322126484b7Glenn Kasten} // namespace android
643