blob: 2d0a25f7bc3eab104baa1b7614968ca6cd23aa22 [file] [log] [blame]
Eric Laurent951f4552014-05-20 10:48:17 -07001/*
2**
3** Copyright 2014, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18
19#define LOG_TAG "AudioFlinger::PatchPanel"
20//#define LOG_NDEBUG 0
21
22#include "Configuration.h"
23#include <utils/Log.h>
24#include <audio_utils/primitives.h>
25
26#include "AudioFlinger.h"
27#include "ServiceUtilities.h"
28#include <media/AudioParameter.h>
29
30// ----------------------------------------------------------------------------
31
32// Note: the following macro is used for extremely verbose logging message. In
33// order to run with ALOG_ASSERT turned on, we need to have LOG_NDEBUG set to
34// 0; but one side effect of this is to turn all LOGV's as well. Some messages
35// are so verbose that we want to suppress them even when we have ALOG_ASSERT
36// turned on. Do not uncomment the #def below unless you really know what you
37// are doing and want to see all of the extremely verbose messages.
38//#define VERY_VERY_VERBOSE_LOGGING
39#ifdef VERY_VERY_VERBOSE_LOGGING
40#define ALOGVV ALOGV
41#else
42#define ALOGVV(a...) do { } while(0)
43#endif
44
45namespace android {
46
47/* List connected audio ports and their attributes */
48status_t AudioFlinger::listAudioPorts(unsigned int *num_ports,
49 struct audio_port *ports)
50{
51 Mutex::Autolock _l(mLock);
52 if (mPatchPanel != 0) {
53 return mPatchPanel->listAudioPorts(num_ports, ports);
54 }
55 return NO_INIT;
56}
57
58/* Get supported attributes for a given audio port */
59status_t AudioFlinger::getAudioPort(struct audio_port *port)
60{
61 Mutex::Autolock _l(mLock);
62 if (mPatchPanel != 0) {
63 return mPatchPanel->getAudioPort(port);
64 }
65 return NO_INIT;
66}
67
68
69/* Connect a patch between several source and sink ports */
70status_t AudioFlinger::createAudioPatch(const struct audio_patch *patch,
71 audio_patch_handle_t *handle)
72{
73 Mutex::Autolock _l(mLock);
74 if (mPatchPanel != 0) {
75 return mPatchPanel->createAudioPatch(patch, handle);
76 }
77 return NO_INIT;
78}
79
80/* Disconnect a patch */
81status_t AudioFlinger::releaseAudioPatch(audio_patch_handle_t handle)
82{
83 Mutex::Autolock _l(mLock);
84 if (mPatchPanel != 0) {
85 return mPatchPanel->releaseAudioPatch(handle);
86 }
87 return NO_INIT;
88}
89
90
91/* List connected audio ports and they attributes */
92status_t AudioFlinger::listAudioPatches(unsigned int *num_patches,
93 struct audio_patch *patches)
94{
95 Mutex::Autolock _l(mLock);
96 if (mPatchPanel != 0) {
97 return mPatchPanel->listAudioPatches(num_patches, patches);
98 }
99 return NO_INIT;
100}
101
102/* Set audio port configuration */
103status_t AudioFlinger::setAudioPortConfig(const struct audio_port_config *config)
104{
105 Mutex::Autolock _l(mLock);
106 if (mPatchPanel != 0) {
107 return mPatchPanel->setAudioPortConfig(config);
108 }
109 return NO_INIT;
110}
111
112
113AudioFlinger::PatchPanel::PatchPanel(const sp<AudioFlinger>& audioFlinger)
114 : mAudioFlinger(audioFlinger)
115{
116}
117
118AudioFlinger::PatchPanel::~PatchPanel()
119{
120}
121
122/* List connected audio ports and their attributes */
123status_t AudioFlinger::PatchPanel::listAudioPorts(unsigned int *num_ports __unused,
124 struct audio_port *ports __unused)
125{
126 ALOGV("listAudioPorts");
127 return NO_ERROR;
128}
129
130/* Get supported attributes for a given audio port */
131status_t AudioFlinger::PatchPanel::getAudioPort(struct audio_port *port __unused)
132{
133 ALOGV("getAudioPort");
134 return NO_ERROR;
135}
136
137
138/* Connect a patch between several source and sink ports */
139status_t AudioFlinger::PatchPanel::createAudioPatch(const struct audio_patch *patch,
140 audio_patch_handle_t *handle)
141{
142 ALOGV("createAudioPatch() num_sources %d num_sinks %d handle %d",
143 patch->num_sources, patch->num_sinks, *handle);
144 status_t status = NO_ERROR;
Eric Laurent951f4552014-05-20 10:48:17 -0700145 audio_patch_handle_t halHandle = AUDIO_PATCH_HANDLE_NONE;
Eric Laurent951f4552014-05-20 10:48:17 -0700146 sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
147 if (audioflinger == 0) {
148 return NO_INIT;
149 }
Eric Laurent83b88082014-06-20 18:31:16 -0700150
Eric Laurent951f4552014-05-20 10:48:17 -0700151 if (handle == NULL || patch == NULL) {
152 return BAD_VALUE;
153 }
Eric Laurent874c42872014-08-08 15:13:39 -0700154 if (patch->num_sources == 0 || patch->num_sources > AUDIO_PATCH_PORTS_MAX ||
Eric Laurent951f4552014-05-20 10:48:17 -0700155 patch->num_sinks == 0 || patch->num_sinks > AUDIO_PATCH_PORTS_MAX) {
156 return BAD_VALUE;
157 }
Eric Laurent874c42872014-08-08 15:13:39 -0700158 // limit number of sources to 1 for now or 2 sources for special cross hw module case.
159 // only the audio policy manager can request a patch creation with 2 sources.
160 if (patch->num_sources > 2) {
161 return INVALID_OPERATION;
162 }
Eric Laurent951f4552014-05-20 10:48:17 -0700163
Eric Laurent83b88082014-06-20 18:31:16 -0700164 if (*handle != AUDIO_PATCH_HANDLE_NONE) {
165 for (size_t index = 0; *handle != 0 && index < mPatches.size(); index++) {
166 if (*handle == mPatches[index]->mHandle) {
167 ALOGV("createAudioPatch() removing patch handle %d", *handle);
168 halHandle = mPatches[index]->mHalHandle;
169 mPatches.removeAt(index);
170 break;
171 }
Eric Laurent951f4552014-05-20 10:48:17 -0700172 }
173 }
174
Eric Laurent83b88082014-06-20 18:31:16 -0700175 Patch *newPatch = new Patch(patch);
176
Eric Laurent951f4552014-05-20 10:48:17 -0700177 switch (patch->sources[0].type) {
178 case AUDIO_PORT_TYPE_DEVICE: {
Eric Laurent874c42872014-08-08 15:13:39 -0700179 audio_module_handle_t srcModule = patch->sources[0].ext.device.hw_module;
180 ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
Eric Laurent951f4552014-05-20 10:48:17 -0700181 if (index < 0) {
Eric Laurent874c42872014-08-08 15:13:39 -0700182 ALOGW("createAudioPatch() bad src hw module %d", srcModule);
Eric Laurent83b88082014-06-20 18:31:16 -0700183 status = BAD_VALUE;
184 goto exit;
Eric Laurent951f4552014-05-20 10:48:17 -0700185 }
Eric Laurent6a94d692014-05-20 11:18:06 -0700186 AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
Eric Laurent951f4552014-05-20 10:48:17 -0700187 for (unsigned int i = 0; i < patch->num_sinks; i++) {
Eric Laurent874c42872014-08-08 15:13:39 -0700188 // support only one sink if connection to a mix or across HW modules
189 if ((patch->sinks[i].type == AUDIO_PORT_TYPE_MIX ||
190 patch->sinks[i].ext.mix.hw_module != srcModule) &&
191 patch->num_sinks > 1) {
192 status = INVALID_OPERATION;
193 goto exit;
194 }
Eric Laurent6a94d692014-05-20 11:18:06 -0700195 // reject connection to different sink types
196 if (patch->sinks[i].type != patch->sinks[0].type) {
197 ALOGW("createAudioPatch() different sink types in same patch not supported");
Eric Laurent83b88082014-06-20 18:31:16 -0700198 status = BAD_VALUE;
199 goto exit;
Eric Laurent951f4552014-05-20 10:48:17 -0700200 }
Eric Laurent83b88082014-06-20 18:31:16 -0700201 // limit to connections between devices and input streams for HAL before 3.0
Eric Laurent874c42872014-08-08 15:13:39 -0700202 if (patch->sinks[i].ext.mix.hw_module == srcModule &&
Eric Laurent83b88082014-06-20 18:31:16 -0700203 (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) &&
Eric Laurent6a94d692014-05-20 11:18:06 -0700204 (patch->sinks[i].type != AUDIO_PORT_TYPE_MIX)) {
205 ALOGW("createAudioPatch() invalid sink type %d for device source",
206 patch->sinks[i].type);
Eric Laurent83b88082014-06-20 18:31:16 -0700207 status = BAD_VALUE;
208 goto exit;
Eric Laurent6a94d692014-05-20 11:18:06 -0700209 }
Eric Laurent951f4552014-05-20 10:48:17 -0700210 }
211
Eric Laurent874c42872014-08-08 15:13:39 -0700212 if (patch->sinks[0].ext.device.hw_module != srcModule) {
Eric Laurent83b88082014-06-20 18:31:16 -0700213 // limit to device to device connection if not on same hw module
214 if (patch->sinks[0].type != AUDIO_PORT_TYPE_DEVICE) {
215 ALOGW("createAudioPatch() invalid sink type for cross hw module");
216 status = INVALID_OPERATION;
217 goto exit;
218 }
219 // special case num sources == 2 -=> reuse an exiting output mix to connect to the
220 // sink
221 if (patch->num_sources == 2) {
222 if (patch->sources[1].type != AUDIO_PORT_TYPE_MIX ||
223 patch->sinks[0].ext.device.hw_module !=
224 patch->sources[1].ext.mix.hw_module) {
225 ALOGW("createAudioPatch() invalid source combination");
226 status = INVALID_OPERATION;
227 goto exit;
Eric Laurent951f4552014-05-20 10:48:17 -0700228 }
Eric Laurent83b88082014-06-20 18:31:16 -0700229
230 sp<ThreadBase> thread =
231 audioflinger->checkPlaybackThread_l(patch->sources[1].ext.mix.handle);
232 newPatch->mPlaybackThread = (MixerThread *)thread.get();
233 if (thread == 0) {
234 ALOGW("createAudioPatch() cannot get playback thread");
235 status = INVALID_OPERATION;
236 goto exit;
237 }
Eric Laurent951f4552014-05-20 10:48:17 -0700238 } else {
Eric Laurentcf2c0212014-07-25 16:20:43 -0700239 audio_config_t config = AUDIO_CONFIG_INITIALIZER;
240 audio_devices_t device = patch->sinks[0].ext.device.type;
241 String8 address = String8(patch->sinks[0].ext.device.address);
242 audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
Eric Laurent83b88082014-06-20 18:31:16 -0700243 newPatch->mPlaybackThread = audioflinger->openOutput_l(
244 patch->sinks[0].ext.device.hw_module,
Eric Laurentcf2c0212014-07-25 16:20:43 -0700245 &output,
Eric Laurent83b88082014-06-20 18:31:16 -0700246 &config,
Eric Laurentcf2c0212014-07-25 16:20:43 -0700247 device,
248 address,
Eric Laurent83b88082014-06-20 18:31:16 -0700249 AUDIO_OUTPUT_FLAG_NONE);
250 ALOGV("audioflinger->openOutput_l() returned %p",
251 newPatch->mPlaybackThread.get());
252 if (newPatch->mPlaybackThread == 0) {
253 status = NO_MEMORY;
254 goto exit;
255 }
256 }
257 uint32_t channelCount = newPatch->mPlaybackThread->channelCount();
258 audio_devices_t device = patch->sources[0].ext.device.type;
Eric Laurentcf2c0212014-07-25 16:20:43 -0700259 String8 address = String8(patch->sources[0].ext.device.address);
260 audio_config_t config = AUDIO_CONFIG_INITIALIZER;
Eric Laurent83b88082014-06-20 18:31:16 -0700261 audio_channel_mask_t inChannelMask = audio_channel_in_mask_from_count(channelCount);
262 config.sample_rate = newPatch->mPlaybackThread->sampleRate();
263 config.channel_mask = inChannelMask;
264 config.format = newPatch->mPlaybackThread->format();
Eric Laurentcf2c0212014-07-25 16:20:43 -0700265 audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
Eric Laurent874c42872014-08-08 15:13:39 -0700266 newPatch->mRecordThread = audioflinger->openInput_l(srcModule,
Eric Laurentcf2c0212014-07-25 16:20:43 -0700267 &input,
Eric Laurent83b88082014-06-20 18:31:16 -0700268 &config,
Eric Laurentcf2c0212014-07-25 16:20:43 -0700269 device,
270 address,
271 AUDIO_SOURCE_MIC,
Eric Laurent83b88082014-06-20 18:31:16 -0700272 AUDIO_INPUT_FLAG_NONE);
273 ALOGV("audioflinger->openInput_l() returned %p inChannelMask %08x",
274 newPatch->mRecordThread.get(), inChannelMask);
275 if (newPatch->mRecordThread == 0) {
276 status = NO_MEMORY;
277 goto exit;
278 }
279 status = createPatchConnections(newPatch, patch);
280 if (status != NO_ERROR) {
281 goto exit;
Eric Laurent951f4552014-05-20 10:48:17 -0700282 }
283 } else {
Eric Laurent83b88082014-06-20 18:31:16 -0700284 if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
285 if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
286 sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
Eric Laurent874c42872014-08-08 15:13:39 -0700287 patch->sinks[0].ext.mix.handle);
Eric Laurent83b88082014-06-20 18:31:16 -0700288 if (thread == 0) {
289 ALOGW("createAudioPatch() bad capture I/O handle %d",
Eric Laurent874c42872014-08-08 15:13:39 -0700290 patch->sinks[0].ext.mix.handle);
Eric Laurent83b88082014-06-20 18:31:16 -0700291 status = BAD_VALUE;
292 goto exit;
293 }
294 status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
295 } else {
296 audio_hw_device_t *hwDevice = audioHwDevice->hwDevice();
297 status = hwDevice->create_audio_patch(hwDevice,
298 patch->num_sources,
299 patch->sources,
300 patch->num_sinks,
301 patch->sinks,
302 &halHandle);
303 }
304 } else {
305 sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
Eric Laurent874c42872014-08-08 15:13:39 -0700306 patch->sinks[0].ext.mix.handle);
Eric Laurent83b88082014-06-20 18:31:16 -0700307 if (thread == 0) {
308 ALOGW("createAudioPatch() bad capture I/O handle %d",
Eric Laurent874c42872014-08-08 15:13:39 -0700309 patch->sinks[0].ext.mix.handle);
Eric Laurent83b88082014-06-20 18:31:16 -0700310 status = BAD_VALUE;
311 goto exit;
312 }
Eric Laurentcf2c0212014-07-25 16:20:43 -0700313 char *address;
314 if (strcmp(patch->sources[0].ext.device.address, "") != 0) {
315 address = audio_device_address_to_parameter(
316 patch->sources[0].ext.device.type,
317 patch->sources[0].ext.device.address);
318 } else {
319 address = (char *)calloc(1, 1);
320 }
321 AudioParameter param = AudioParameter(String8(address));
322 free(address);
323 param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING),
Eric Laurent83b88082014-06-20 18:31:16 -0700324 (int)patch->sources[0].ext.device.type);
Eric Laurentcf2c0212014-07-25 16:20:43 -0700325 param.addInt(String8(AUDIO_PARAMETER_STREAM_INPUT_SOURCE),
326 (int)patch->sinks[0].ext.mix.usecase.source);
Eric Laurent83b88082014-06-20 18:31:16 -0700327 ALOGV("createAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s",
Eric Laurentcf2c0212014-07-25 16:20:43 -0700328 param.toString().string());
Eric Laurent83b88082014-06-20 18:31:16 -0700329 status = thread->setParameters(param.toString());
330 }
Eric Laurent951f4552014-05-20 10:48:17 -0700331 }
332 } break;
333 case AUDIO_PORT_TYPE_MIX: {
Eric Laurent874c42872014-08-08 15:13:39 -0700334 audio_module_handle_t srcModule = patch->sources[0].ext.mix.hw_module;
335 ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
Eric Laurent951f4552014-05-20 10:48:17 -0700336 if (index < 0) {
Eric Laurent874c42872014-08-08 15:13:39 -0700337 ALOGW("createAudioPatch() bad src hw module %d", srcModule);
Eric Laurent83b88082014-06-20 18:31:16 -0700338 status = BAD_VALUE;
339 goto exit;
Eric Laurent951f4552014-05-20 10:48:17 -0700340 }
341 // limit to connections between devices and output streams
342 for (unsigned int i = 0; i < patch->num_sinks; i++) {
343 if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) {
Eric Laurent83b88082014-06-20 18:31:16 -0700344 ALOGW("createAudioPatch() invalid sink type %d for mix source",
Eric Laurent951f4552014-05-20 10:48:17 -0700345 patch->sinks[i].type);
Eric Laurent83b88082014-06-20 18:31:16 -0700346 status = BAD_VALUE;
347 goto exit;
Eric Laurent951f4552014-05-20 10:48:17 -0700348 }
349 // limit to connections between sinks and sources on same HW module
Eric Laurent874c42872014-08-08 15:13:39 -0700350 if (patch->sinks[i].ext.device.hw_module != srcModule) {
Eric Laurent83b88082014-06-20 18:31:16 -0700351 status = BAD_VALUE;
352 goto exit;
Eric Laurent951f4552014-05-20 10:48:17 -0700353 }
354 }
355 AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
356 sp<ThreadBase> thread =
357 audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
358 if (thread == 0) {
359 ALOGW("createAudioPatch() bad playback I/O handle %d",
360 patch->sources[0].ext.mix.handle);
Eric Laurent83b88082014-06-20 18:31:16 -0700361 status = BAD_VALUE;
362 goto exit;
Eric Laurent951f4552014-05-20 10:48:17 -0700363 }
364 if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
365 status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
366 } else {
367 audio_devices_t type = AUDIO_DEVICE_NONE;
368 for (unsigned int i = 0; i < patch->num_sinks; i++) {
369 type |= patch->sinks[i].ext.device.type;
370 }
Eric Laurentcf2c0212014-07-25 16:20:43 -0700371 char *address;
372 if (strcmp(patch->sinks[0].ext.device.address, "") != 0) {
Eric Laurent874c42872014-08-08 15:13:39 -0700373 //FIXME: we only support address on first sink with HAL version < 3.0
Eric Laurentcf2c0212014-07-25 16:20:43 -0700374 address = audio_device_address_to_parameter(
375 patch->sinks[0].ext.device.type,
376 patch->sinks[0].ext.device.address);
377 } else {
378 address = (char *)calloc(1, 1);
379 }
380 AudioParameter param = AudioParameter(String8(address));
381 free(address);
382 param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), (int)type);
Eric Laurent951f4552014-05-20 10:48:17 -0700383 status = thread->setParameters(param.toString());
384 }
385
386 } break;
387 default:
Eric Laurent83b88082014-06-20 18:31:16 -0700388 status = BAD_VALUE;
389 goto exit;
Eric Laurent951f4552014-05-20 10:48:17 -0700390 }
Eric Laurent83b88082014-06-20 18:31:16 -0700391exit:
Eric Laurent951f4552014-05-20 10:48:17 -0700392 ALOGV("createAudioPatch() status %d", status);
393 if (status == NO_ERROR) {
394 *handle = audioflinger->nextUniqueId();
Eric Laurent951f4552014-05-20 10:48:17 -0700395 newPatch->mHandle = *handle;
396 newPatch->mHalHandle = halHandle;
397 mPatches.add(newPatch);
398 ALOGV("createAudioPatch() added new patch handle %d halHandle %d", *handle, halHandle);
Eric Laurent83b88082014-06-20 18:31:16 -0700399 } else {
400 clearPatchConnections(newPatch);
401 delete newPatch;
Eric Laurent951f4552014-05-20 10:48:17 -0700402 }
403 return status;
404}
405
Eric Laurent83b88082014-06-20 18:31:16 -0700406status_t AudioFlinger::PatchPanel::createPatchConnections(Patch *patch,
407 const struct audio_patch *audioPatch)
408{
409 // create patch from source device to record thread input
410 struct audio_patch subPatch;
411 subPatch.num_sources = 1;
412 subPatch.sources[0] = audioPatch->sources[0];
413 subPatch.num_sinks = 1;
414
415 patch->mRecordThread->getAudioPortConfig(&subPatch.sinks[0]);
416 subPatch.sinks[0].ext.mix.usecase.source = AUDIO_SOURCE_MIC;
417
418 status_t status = createAudioPatch(&subPatch, &patch->mRecordPatchHandle);
419 if (status != NO_ERROR) {
420 patch->mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE;
421 return status;
422 }
423
424 // create patch from playback thread output to sink device
425 patch->mPlaybackThread->getAudioPortConfig(&subPatch.sources[0]);
426 subPatch.sinks[0] = audioPatch->sinks[0];
427 status = createAudioPatch(&subPatch, &patch->mPlaybackPatchHandle);
428 if (status != NO_ERROR) {
429 patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
430 return status;
431 }
432
433 // use a pseudo LCM between input and output framecount
434 size_t playbackFrameCount = patch->mPlaybackThread->frameCount();
435 int playbackShift = __builtin_ctz(playbackFrameCount);
436 size_t recordFramecount = patch->mRecordThread->frameCount();
437 int shift = __builtin_ctz(recordFramecount);
438 if (playbackShift < shift) {
439 shift = playbackShift;
440 }
441 size_t frameCount = (playbackFrameCount * recordFramecount) >> shift;
442 ALOGV("createPatchConnections() playframeCount %d recordFramecount %d frameCount %d ",
443 playbackFrameCount, recordFramecount, frameCount);
444
445 // create a special record track to capture from record thread
446 uint32_t channelCount = patch->mPlaybackThread->channelCount();
447 audio_channel_mask_t inChannelMask = audio_channel_in_mask_from_count(channelCount);
448 audio_channel_mask_t outChannelMask = patch->mPlaybackThread->channelMask();
449 uint32_t sampleRate = patch->mPlaybackThread->sampleRate();
450 audio_format_t format = patch->mPlaybackThread->format();
451
452 patch->mPatchRecord = new RecordThread::PatchRecord(
453 patch->mRecordThread.get(),
454 sampleRate,
455 inChannelMask,
456 format,
457 frameCount,
458 NULL,
459 IAudioFlinger::TRACK_DEFAULT);
460 if (patch->mPatchRecord == 0) {
461 return NO_MEMORY;
462 }
463 status = patch->mPatchRecord->initCheck();
464 if (status != NO_ERROR) {
465 return status;
466 }
467 patch->mRecordThread->addPatchRecord(patch->mPatchRecord);
468
469 // create a special playback track to render to playback thread.
470 // this track is given the same buffer as the PatchRecord buffer
471 patch->mPatchTrack = new PlaybackThread::PatchTrack(
472 patch->mPlaybackThread.get(),
473 sampleRate,
474 outChannelMask,
475 format,
476 frameCount,
477 patch->mPatchRecord->buffer(),
478 IAudioFlinger::TRACK_DEFAULT);
479 if (patch->mPatchTrack == 0) {
480 return NO_MEMORY;
481 }
482 status = patch->mPatchTrack->initCheck();
483 if (status != NO_ERROR) {
484 return status;
485 }
486 patch->mPlaybackThread->addPatchTrack(patch->mPatchTrack);
487
488 // tie playback and record tracks together
489 patch->mPatchRecord->setPeerProxy(patch->mPatchTrack.get());
490 patch->mPatchTrack->setPeerProxy(patch->mPatchRecord.get());
491
492 // start capture and playback
493 patch->mPatchRecord->start(AudioSystem::SYNC_EVENT_NONE, 0);
494 patch->mPatchTrack->start();
495
496 return status;
497}
498
499void AudioFlinger::PatchPanel::clearPatchConnections(Patch *patch)
500{
501 sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
502 if (audioflinger == 0) {
503 return;
504 }
505
506 ALOGV("clearPatchConnections() patch->mRecordPatchHandle %d patch->mPlaybackPatchHandle %d",
507 patch->mRecordPatchHandle, patch->mPlaybackPatchHandle);
508
509 if (patch->mPatchRecord != 0) {
510 patch->mPatchRecord->stop();
511 }
512 if (patch->mPatchTrack != 0) {
513 patch->mPatchTrack->stop();
514 }
515 if (patch->mRecordPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
516 releaseAudioPatch(patch->mRecordPatchHandle);
517 patch->mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE;
518 }
519 if (patch->mPlaybackPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
520 releaseAudioPatch(patch->mPlaybackPatchHandle);
521 patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
522 }
523 if (patch->mRecordThread != 0) {
524 if (patch->mPatchRecord != 0) {
525 patch->mRecordThread->deletePatchRecord(patch->mPatchRecord);
526 patch->mPatchRecord.clear();
527 }
528 audioflinger->closeInputInternal_l(patch->mRecordThread);
529 patch->mRecordThread.clear();
530 }
531 if (patch->mPlaybackThread != 0) {
532 if (patch->mPatchTrack != 0) {
533 patch->mPlaybackThread->deletePatchTrack(patch->mPatchTrack);
534 patch->mPatchTrack.clear();
535 }
536 // if num sources == 2 we are reusing an existing playback thread so we do not close it
537 if (patch->mAudioPatch.num_sources != 2) {
538 audioflinger->closeOutputInternal_l(patch->mPlaybackThread);
539 }
540 patch->mPlaybackThread.clear();
541 }
542}
543
Eric Laurent951f4552014-05-20 10:48:17 -0700544/* Disconnect a patch */
545status_t AudioFlinger::PatchPanel::releaseAudioPatch(audio_patch_handle_t handle)
546{
547 ALOGV("releaseAudioPatch handle %d", handle);
548 status_t status = NO_ERROR;
549 size_t index;
550
551 sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
552 if (audioflinger == 0) {
553 return NO_INIT;
554 }
555
556 for (index = 0; index < mPatches.size(); index++) {
557 if (handle == mPatches[index]->mHandle) {
558 break;
559 }
560 }
561 if (index == mPatches.size()) {
562 return BAD_VALUE;
563 }
Eric Laurent83b88082014-06-20 18:31:16 -0700564 Patch *removedPatch = mPatches[index];
565 mPatches.removeAt(index);
Eric Laurent951f4552014-05-20 10:48:17 -0700566
Eric Laurent83b88082014-06-20 18:31:16 -0700567 struct audio_patch *patch = &removedPatch->mAudioPatch;
Eric Laurent951f4552014-05-20 10:48:17 -0700568
569 switch (patch->sources[0].type) {
570 case AUDIO_PORT_TYPE_DEVICE: {
Eric Laurent874c42872014-08-08 15:13:39 -0700571 audio_module_handle_t srcModule = patch->sources[0].ext.device.hw_module;
572 ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
Eric Laurent951f4552014-05-20 10:48:17 -0700573 if (index < 0) {
Eric Laurent874c42872014-08-08 15:13:39 -0700574 ALOGW("releaseAudioPatch() bad src hw module %d", srcModule);
Eric Laurent951f4552014-05-20 10:48:17 -0700575 status = BAD_VALUE;
576 break;
577 }
Eric Laurent83b88082014-06-20 18:31:16 -0700578
579 if (patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE &&
Eric Laurent874c42872014-08-08 15:13:39 -0700580 patch->sinks[0].ext.device.hw_module != srcModule) {
Eric Laurent83b88082014-06-20 18:31:16 -0700581 clearPatchConnections(removedPatch);
582 break;
583 }
584
Eric Laurent951f4552014-05-20 10:48:17 -0700585 AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
586 if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
587 if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
588 sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
589 patch->sinks[0].ext.mix.handle);
590 if (thread == 0) {
Eric Laurent83b88082014-06-20 18:31:16 -0700591 ALOGW("releaseAudioPatch() bad capture I/O handle %d",
Eric Laurent951f4552014-05-20 10:48:17 -0700592 patch->sinks[0].ext.mix.handle);
593 status = BAD_VALUE;
594 break;
595 }
596 status = thread->sendReleaseAudioPatchConfigEvent(mPatches[index]->mHalHandle);
597 } else {
598 audio_hw_device_t *hwDevice = audioHwDevice->hwDevice();
599 status = hwDevice->release_audio_patch(hwDevice, mPatches[index]->mHalHandle);
600 }
601 } else {
602 sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
603 patch->sinks[0].ext.mix.handle);
604 if (thread == 0) {
605 ALOGW("releaseAudioPatch() bad capture I/O handle %d",
606 patch->sinks[0].ext.mix.handle);
607 status = BAD_VALUE;
608 break;
609 }
610 AudioParameter param;
Eric Laurentcf2c0212014-07-25 16:20:43 -0700611 param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), 0);
Eric Laurent24478d42014-06-04 20:02:57 -0700612 ALOGV("releaseAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s",
Eric Laurent951f4552014-05-20 10:48:17 -0700613 param.toString().string());
614 status = thread->setParameters(param.toString());
615 }
616 } break;
617 case AUDIO_PORT_TYPE_MIX: {
Eric Laurent874c42872014-08-08 15:13:39 -0700618 audio_module_handle_t srcModule = patch->sources[0].ext.mix.hw_module;
619 ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
Eric Laurent951f4552014-05-20 10:48:17 -0700620 if (index < 0) {
Eric Laurent874c42872014-08-08 15:13:39 -0700621 ALOGW("releaseAudioPatch() bad src hw module %d", srcModule);
Eric Laurent951f4552014-05-20 10:48:17 -0700622 status = BAD_VALUE;
623 break;
624 }
625 sp<ThreadBase> thread =
626 audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
627 if (thread == 0) {
628 ALOGW("releaseAudioPatch() bad playback I/O handle %d",
629 patch->sources[0].ext.mix.handle);
630 status = BAD_VALUE;
631 break;
632 }
633 AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
634 if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
635 status = thread->sendReleaseAudioPatchConfigEvent(mPatches[index]->mHalHandle);
636 } else {
637 AudioParameter param;
Eric Laurentcf2c0212014-07-25 16:20:43 -0700638 param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), 0);
Eric Laurent951f4552014-05-20 10:48:17 -0700639 status = thread->setParameters(param.toString());
640 }
641 } break;
642 default:
643 status = BAD_VALUE;
644 break;
645 }
646
Eric Laurent83b88082014-06-20 18:31:16 -0700647 delete removedPatch;
Eric Laurent951f4552014-05-20 10:48:17 -0700648 return status;
649}
650
651
652/* List connected audio ports and they attributes */
653status_t AudioFlinger::PatchPanel::listAudioPatches(unsigned int *num_patches __unused,
654 struct audio_patch *patches __unused)
655{
656 ALOGV("listAudioPatches");
657 return NO_ERROR;
658}
659
660/* Set audio port configuration */
Eric Laurente1715a42014-05-20 11:30:42 -0700661status_t AudioFlinger::PatchPanel::setAudioPortConfig(const struct audio_port_config *config)
Eric Laurent951f4552014-05-20 10:48:17 -0700662{
663 ALOGV("setAudioPortConfig");
Eric Laurente1715a42014-05-20 11:30:42 -0700664 status_t status = NO_ERROR;
665
666 sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
667 if (audioflinger == 0) {
668 return NO_INIT;
669 }
670
671 audio_module_handle_t module;
672 if (config->type == AUDIO_PORT_TYPE_DEVICE) {
673 module = config->ext.device.hw_module;
674 } else {
675 module = config->ext.mix.hw_module;
676 }
677
678 ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(module);
679 if (index < 0) {
680 ALOGW("setAudioPortConfig() bad hw module %d", module);
681 return BAD_VALUE;
682 }
683
684 AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
685 if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
686 audio_hw_device_t *hwDevice = audioHwDevice->hwDevice();
687 return hwDevice->set_audio_port_config(hwDevice, config);
688 } else {
689 return INVALID_OPERATION;
690 }
Eric Laurent951f4552014-05-20 10:48:17 -0700691 return NO_ERROR;
692}
693
694
Eric Laurent951f4552014-05-20 10:48:17 -0700695}; // namespace android