1 /* 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 45 namespace android { 46 47 /* List connected audio ports and their attributes */ 48 status_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 */ 59 status_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 */ 70 status_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 */ 81 status_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 */ 92 status_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 */ 103 status_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 113 AudioFlinger::PatchPanel::PatchPanel(const sp<AudioFlinger>& audioFlinger) 114 : mAudioFlinger(audioFlinger) 115 { 116 } 117 118 AudioFlinger::PatchPanel::~PatchPanel() 119 { 120 } 121 122 /* List connected audio ports and their attributes */ 123 status_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 */ 131 status_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 */ 139 status_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; 145 audio_patch_handle_t halHandle = AUDIO_PATCH_HANDLE_NONE; 146 sp<AudioFlinger> audioflinger = mAudioFlinger.promote(); 147 if (audioflinger == 0) { 148 return NO_INIT; 149 } 150 151 if (handle == NULL || patch == NULL) { 152 return BAD_VALUE; 153 } 154 if (patch->num_sources == 0 || patch->num_sources > AUDIO_PATCH_PORTS_MAX || 155 patch->num_sinks == 0 || patch->num_sinks > AUDIO_PATCH_PORTS_MAX) { 156 return BAD_VALUE; 157 } 158 // 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 } 163 164 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 } 172 } 173 } 174 175 Patch *newPatch = new Patch(patch); 176 177 switch (patch->sources[0].type) { 178 case AUDIO_PORT_TYPE_DEVICE: { 179 audio_module_handle_t srcModule = patch->sources[0].ext.device.hw_module; 180 ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule); 181 if (index < 0) { 182 ALOGW("createAudioPatch() bad src hw module %d", srcModule); 183 status = BAD_VALUE; 184 goto exit; 185 } 186 AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); 187 for (unsigned int i = 0; i < patch->num_sinks; i++) { 188 // 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 } 195 // 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"); 198 status = BAD_VALUE; 199 goto exit; 200 } 201 // limit to connections between devices and input streams for HAL before 3.0 202 if (patch->sinks[i].ext.mix.hw_module == srcModule && 203 (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) && 204 (patch->sinks[i].type != AUDIO_PORT_TYPE_MIX)) { 205 ALOGW("createAudioPatch() invalid sink type %d for device source", 206 patch->sinks[i].type); 207 status = BAD_VALUE; 208 goto exit; 209 } 210 } 211 212 if (patch->sinks[0].ext.device.hw_module != srcModule) { 213 // 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; 228 } 229 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 } 238 } else { 239 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; 243 newPatch->mPlaybackThread = audioflinger->openOutput_l( 244 patch->sinks[0].ext.device.hw_module, 245 &output, 246 &config, 247 device, 248 address, 249 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; 259 String8 address = String8(patch->sources[0].ext.device.address); 260 audio_config_t config = AUDIO_CONFIG_INITIALIZER; 261 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(); 265 audio_io_handle_t input = AUDIO_IO_HANDLE_NONE; 266 newPatch->mRecordThread = audioflinger->openInput_l(srcModule, 267 &input, 268 &config, 269 device, 270 address, 271 AUDIO_SOURCE_MIC, 272 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; 282 } 283 } else { 284 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( 287 patch->sinks[0].ext.mix.handle); 288 if (thread == 0) { 289 ALOGW("createAudioPatch() bad capture I/O handle %d", 290 patch->sinks[0].ext.mix.handle); 291 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( 306 patch->sinks[0].ext.mix.handle); 307 if (thread == 0) { 308 ALOGW("createAudioPatch() bad capture I/O handle %d", 309 patch->sinks[0].ext.mix.handle); 310 status = BAD_VALUE; 311 goto exit; 312 } 313 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), 324 (int)patch->sources[0].ext.device.type); 325 param.addInt(String8(AUDIO_PARAMETER_STREAM_INPUT_SOURCE), 326 (int)patch->sinks[0].ext.mix.usecase.source); 327 ALOGV("createAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s", 328 param.toString().string()); 329 status = thread->setParameters(param.toString()); 330 } 331 } 332 } break; 333 case AUDIO_PORT_TYPE_MIX: { 334 audio_module_handle_t srcModule = patch->sources[0].ext.mix.hw_module; 335 ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule); 336 if (index < 0) { 337 ALOGW("createAudioPatch() bad src hw module %d", srcModule); 338 status = BAD_VALUE; 339 goto exit; 340 } 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) { 344 ALOGW("createAudioPatch() invalid sink type %d for mix source", 345 patch->sinks[i].type); 346 status = BAD_VALUE; 347 goto exit; 348 } 349 // limit to connections between sinks and sources on same HW module 350 if (patch->sinks[i].ext.device.hw_module != srcModule) { 351 status = BAD_VALUE; 352 goto exit; 353 } 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); 361 status = BAD_VALUE; 362 goto exit; 363 } 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 } 371 char *address; 372 if (strcmp(patch->sinks[0].ext.device.address, "") != 0) { 373 //FIXME: we only support address on first sink with HAL version < 3.0 374 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); 383 status = thread->setParameters(param.toString()); 384 } 385 386 } break; 387 default: 388 status = BAD_VALUE; 389 goto exit; 390 } 391 exit: 392 ALOGV("createAudioPatch() status %d", status); 393 if (status == NO_ERROR) { 394 *handle = audioflinger->nextUniqueId(); 395 newPatch->mHandle = *handle; 396 newPatch->mHalHandle = halHandle; 397 mPatches.add(newPatch); 398 ALOGV("createAudioPatch() added new patch handle %d halHandle %d", *handle, halHandle); 399 } else { 400 clearPatchConnections(newPatch); 401 delete newPatch; 402 } 403 return status; 404 } 405 406 status_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 499 void 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 544 /* Disconnect a patch */ 545 status_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 } 564 Patch *removedPatch = mPatches[index]; 565 mPatches.removeAt(index); 566 567 struct audio_patch *patch = &removedPatch->mAudioPatch; 568 569 switch (patch->sources[0].type) { 570 case AUDIO_PORT_TYPE_DEVICE: { 571 audio_module_handle_t srcModule = patch->sources[0].ext.device.hw_module; 572 ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule); 573 if (index < 0) { 574 ALOGW("releaseAudioPatch() bad src hw module %d", srcModule); 575 status = BAD_VALUE; 576 break; 577 } 578 579 if (patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE && 580 patch->sinks[0].ext.device.hw_module != srcModule) { 581 clearPatchConnections(removedPatch); 582 break; 583 } 584 585 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) { 591 ALOGW("releaseAudioPatch() bad capture I/O handle %d", 592 patch->sinks[0].ext.mix.handle); 593 status = BAD_VALUE; 594 break; 595 } 596 status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle); 597 } else { 598 audio_hw_device_t *hwDevice = audioHwDevice->hwDevice(); 599 status = hwDevice->release_audio_patch(hwDevice, removedPatch->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; 611 param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), 0); 612 ALOGV("releaseAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s", 613 param.toString().string()); 614 status = thread->setParameters(param.toString()); 615 } 616 } break; 617 case AUDIO_PORT_TYPE_MIX: { 618 audio_module_handle_t srcModule = patch->sources[0].ext.mix.hw_module; 619 ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule); 620 if (index < 0) { 621 ALOGW("releaseAudioPatch() bad src hw module %d", srcModule); 622 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(removedPatch->mHalHandle); 636 } else { 637 AudioParameter param; 638 param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), 0); 639 status = thread->setParameters(param.toString()); 640 } 641 } break; 642 default: 643 status = BAD_VALUE; 644 break; 645 } 646 647 delete removedPatch; 648 return status; 649 } 650 651 652 /* List connected audio ports and they attributes */ 653 status_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 */ 661 status_t AudioFlinger::PatchPanel::setAudioPortConfig(const struct audio_port_config *config) 662 { 663 ALOGV("setAudioPortConfig"); 664 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 } 691 return NO_ERROR; 692 } 693 694 695 }; // namespace android 696