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 Patch *removedPatch = mPatches[index]; 170 mPatches.removeAt(index); 171 delete removedPatch; 172 break; 173 } 174 } 175 } 176 177 Patch *newPatch = new Patch(patch); 178 179 switch (patch->sources[0].type) { 180 case AUDIO_PORT_TYPE_DEVICE: { 181 audio_module_handle_t srcModule = patch->sources[0].ext.device.hw_module; 182 ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule); 183 if (index < 0) { 184 ALOGW("createAudioPatch() bad src hw module %d", srcModule); 185 status = BAD_VALUE; 186 goto exit; 187 } 188 AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); 189 for (unsigned int i = 0; i < patch->num_sinks; i++) { 190 // support only one sink if connection to a mix or across HW modules 191 if ((patch->sinks[i].type == AUDIO_PORT_TYPE_MIX || 192 patch->sinks[i].ext.mix.hw_module != srcModule) && 193 patch->num_sinks > 1) { 194 status = INVALID_OPERATION; 195 goto exit; 196 } 197 // reject connection to different sink types 198 if (patch->sinks[i].type != patch->sinks[0].type) { 199 ALOGW("createAudioPatch() different sink types in same patch not supported"); 200 status = BAD_VALUE; 201 goto exit; 202 } 203 // limit to connections between devices and input streams for HAL before 3.0 204 if (patch->sinks[i].ext.mix.hw_module == srcModule && 205 (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) && 206 (patch->sinks[i].type != AUDIO_PORT_TYPE_MIX)) { 207 ALOGW("createAudioPatch() invalid sink type %d for device source", 208 patch->sinks[i].type); 209 status = BAD_VALUE; 210 goto exit; 211 } 212 } 213 214 if (patch->sinks[0].ext.device.hw_module != srcModule) { 215 // limit to device to device connection if not on same hw module 216 if (patch->sinks[0].type != AUDIO_PORT_TYPE_DEVICE) { 217 ALOGW("createAudioPatch() invalid sink type for cross hw module"); 218 status = INVALID_OPERATION; 219 goto exit; 220 } 221 // special case num sources == 2 -=> reuse an exiting output mix to connect to the 222 // sink 223 if (patch->num_sources == 2) { 224 if (patch->sources[1].type != AUDIO_PORT_TYPE_MIX || 225 patch->sinks[0].ext.device.hw_module != 226 patch->sources[1].ext.mix.hw_module) { 227 ALOGW("createAudioPatch() invalid source combination"); 228 status = INVALID_OPERATION; 229 goto exit; 230 } 231 232 sp<ThreadBase> thread = 233 audioflinger->checkPlaybackThread_l(patch->sources[1].ext.mix.handle); 234 newPatch->mPlaybackThread = (MixerThread *)thread.get(); 235 if (thread == 0) { 236 ALOGW("createAudioPatch() cannot get playback thread"); 237 status = INVALID_OPERATION; 238 goto exit; 239 } 240 } else { 241 audio_config_t config = AUDIO_CONFIG_INITIALIZER; 242 audio_devices_t device = patch->sinks[0].ext.device.type; 243 String8 address = String8(patch->sinks[0].ext.device.address); 244 audio_io_handle_t output = AUDIO_IO_HANDLE_NONE; 245 newPatch->mPlaybackThread = audioflinger->openOutput_l( 246 patch->sinks[0].ext.device.hw_module, 247 &output, 248 &config, 249 device, 250 address, 251 AUDIO_OUTPUT_FLAG_NONE); 252 ALOGV("audioflinger->openOutput_l() returned %p", 253 newPatch->mPlaybackThread.get()); 254 if (newPatch->mPlaybackThread == 0) { 255 status = NO_MEMORY; 256 goto exit; 257 } 258 } 259 uint32_t channelCount = newPatch->mPlaybackThread->channelCount(); 260 audio_devices_t device = patch->sources[0].ext.device.type; 261 String8 address = String8(patch->sources[0].ext.device.address); 262 audio_config_t config = AUDIO_CONFIG_INITIALIZER; 263 audio_channel_mask_t inChannelMask = audio_channel_in_mask_from_count(channelCount); 264 config.sample_rate = newPatch->mPlaybackThread->sampleRate(); 265 config.channel_mask = inChannelMask; 266 config.format = newPatch->mPlaybackThread->format(); 267 audio_io_handle_t input = AUDIO_IO_HANDLE_NONE; 268 newPatch->mRecordThread = audioflinger->openInput_l(srcModule, 269 &input, 270 &config, 271 device, 272 address, 273 AUDIO_SOURCE_MIC, 274 AUDIO_INPUT_FLAG_NONE); 275 ALOGV("audioflinger->openInput_l() returned %p inChannelMask %08x", 276 newPatch->mRecordThread.get(), inChannelMask); 277 if (newPatch->mRecordThread == 0) { 278 status = NO_MEMORY; 279 goto exit; 280 } 281 status = createPatchConnections(newPatch, patch); 282 if (status != NO_ERROR) { 283 goto exit; 284 } 285 } else { 286 if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { 287 if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) { 288 sp<ThreadBase> thread = audioflinger->checkRecordThread_l( 289 patch->sinks[0].ext.mix.handle); 290 if (thread == 0) { 291 ALOGW("createAudioPatch() bad capture I/O handle %d", 292 patch->sinks[0].ext.mix.handle); 293 status = BAD_VALUE; 294 goto exit; 295 } 296 status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle); 297 } else { 298 audio_hw_device_t *hwDevice = audioHwDevice->hwDevice(); 299 status = hwDevice->create_audio_patch(hwDevice, 300 patch->num_sources, 301 patch->sources, 302 patch->num_sinks, 303 patch->sinks, 304 &halHandle); 305 } 306 } else { 307 sp<ThreadBase> thread = audioflinger->checkRecordThread_l( 308 patch->sinks[0].ext.mix.handle); 309 if (thread == 0) { 310 ALOGW("createAudioPatch() bad capture I/O handle %d", 311 patch->sinks[0].ext.mix.handle); 312 status = BAD_VALUE; 313 goto exit; 314 } 315 char *address; 316 if (strcmp(patch->sources[0].ext.device.address, "") != 0) { 317 address = audio_device_address_to_parameter( 318 patch->sources[0].ext.device.type, 319 patch->sources[0].ext.device.address); 320 } else { 321 address = (char *)calloc(1, 1); 322 } 323 AudioParameter param = AudioParameter(String8(address)); 324 free(address); 325 param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), 326 (int)patch->sources[0].ext.device.type); 327 param.addInt(String8(AUDIO_PARAMETER_STREAM_INPUT_SOURCE), 328 (int)patch->sinks[0].ext.mix.usecase.source); 329 ALOGV("createAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s", 330 param.toString().string()); 331 status = thread->setParameters(param.toString()); 332 } 333 } 334 } break; 335 case AUDIO_PORT_TYPE_MIX: { 336 audio_module_handle_t srcModule = patch->sources[0].ext.mix.hw_module; 337 ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule); 338 if (index < 0) { 339 ALOGW("createAudioPatch() bad src hw module %d", srcModule); 340 status = BAD_VALUE; 341 goto exit; 342 } 343 // limit to connections between devices and output streams 344 for (unsigned int i = 0; i < patch->num_sinks; i++) { 345 if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) { 346 ALOGW("createAudioPatch() invalid sink type %d for mix source", 347 patch->sinks[i].type); 348 status = BAD_VALUE; 349 goto exit; 350 } 351 // limit to connections between sinks and sources on same HW module 352 if (patch->sinks[i].ext.device.hw_module != srcModule) { 353 status = BAD_VALUE; 354 goto exit; 355 } 356 } 357 AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); 358 sp<ThreadBase> thread = 359 audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle); 360 if (thread == 0) { 361 ALOGW("createAudioPatch() bad playback I/O handle %d", 362 patch->sources[0].ext.mix.handle); 363 status = BAD_VALUE; 364 goto exit; 365 } 366 if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { 367 status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle); 368 } else { 369 audio_devices_t type = AUDIO_DEVICE_NONE; 370 for (unsigned int i = 0; i < patch->num_sinks; i++) { 371 type |= patch->sinks[i].ext.device.type; 372 } 373 char *address; 374 if (strcmp(patch->sinks[0].ext.device.address, "") != 0) { 375 //FIXME: we only support address on first sink with HAL version < 3.0 376 address = audio_device_address_to_parameter( 377 patch->sinks[0].ext.device.type, 378 patch->sinks[0].ext.device.address); 379 } else { 380 address = (char *)calloc(1, 1); 381 } 382 AudioParameter param = AudioParameter(String8(address)); 383 free(address); 384 param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), (int)type); 385 status = thread->setParameters(param.toString()); 386 } 387 388 } break; 389 default: 390 status = BAD_VALUE; 391 goto exit; 392 } 393 exit: 394 ALOGV("createAudioPatch() status %d", status); 395 if (status == NO_ERROR) { 396 *handle = audioflinger->nextUniqueId(); 397 newPatch->mHandle = *handle; 398 newPatch->mHalHandle = halHandle; 399 mPatches.add(newPatch); 400 ALOGV("createAudioPatch() added new patch handle %d halHandle %d", *handle, halHandle); 401 } else { 402 clearPatchConnections(newPatch); 403 delete newPatch; 404 } 405 return status; 406 } 407 408 status_t AudioFlinger::PatchPanel::createPatchConnections(Patch *patch, 409 const struct audio_patch *audioPatch) 410 { 411 // create patch from source device to record thread input 412 struct audio_patch subPatch; 413 subPatch.num_sources = 1; 414 subPatch.sources[0] = audioPatch->sources[0]; 415 subPatch.num_sinks = 1; 416 417 patch->mRecordThread->getAudioPortConfig(&subPatch.sinks[0]); 418 subPatch.sinks[0].ext.mix.usecase.source = AUDIO_SOURCE_MIC; 419 420 status_t status = createAudioPatch(&subPatch, &patch->mRecordPatchHandle); 421 if (status != NO_ERROR) { 422 patch->mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE; 423 return status; 424 } 425 426 // create patch from playback thread output to sink device 427 patch->mPlaybackThread->getAudioPortConfig(&subPatch.sources[0]); 428 subPatch.sinks[0] = audioPatch->sinks[0]; 429 status = createAudioPatch(&subPatch, &patch->mPlaybackPatchHandle); 430 if (status != NO_ERROR) { 431 patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE; 432 return status; 433 } 434 435 // use a pseudo LCM between input and output framecount 436 size_t playbackFrameCount = patch->mPlaybackThread->frameCount(); 437 int playbackShift = __builtin_ctz(playbackFrameCount); 438 size_t recordFramecount = patch->mRecordThread->frameCount(); 439 int shift = __builtin_ctz(recordFramecount); 440 if (playbackShift < shift) { 441 shift = playbackShift; 442 } 443 size_t frameCount = (playbackFrameCount * recordFramecount) >> shift; 444 ALOGV("createPatchConnections() playframeCount %d recordFramecount %d frameCount %d ", 445 playbackFrameCount, recordFramecount, frameCount); 446 447 // create a special record track to capture from record thread 448 uint32_t channelCount = patch->mPlaybackThread->channelCount(); 449 audio_channel_mask_t inChannelMask = audio_channel_in_mask_from_count(channelCount); 450 audio_channel_mask_t outChannelMask = patch->mPlaybackThread->channelMask(); 451 uint32_t sampleRate = patch->mPlaybackThread->sampleRate(); 452 audio_format_t format = patch->mPlaybackThread->format(); 453 454 patch->mPatchRecord = new RecordThread::PatchRecord( 455 patch->mRecordThread.get(), 456 sampleRate, 457 inChannelMask, 458 format, 459 frameCount, 460 NULL, 461 IAudioFlinger::TRACK_DEFAULT); 462 if (patch->mPatchRecord == 0) { 463 return NO_MEMORY; 464 } 465 status = patch->mPatchRecord->initCheck(); 466 if (status != NO_ERROR) { 467 return status; 468 } 469 patch->mRecordThread->addPatchRecord(patch->mPatchRecord); 470 471 // create a special playback track to render to playback thread. 472 // this track is given the same buffer as the PatchRecord buffer 473 patch->mPatchTrack = new PlaybackThread::PatchTrack( 474 patch->mPlaybackThread.get(), 475 sampleRate, 476 outChannelMask, 477 format, 478 frameCount, 479 patch->mPatchRecord->buffer(), 480 IAudioFlinger::TRACK_DEFAULT); 481 if (patch->mPatchTrack == 0) { 482 return NO_MEMORY; 483 } 484 status = patch->mPatchTrack->initCheck(); 485 if (status != NO_ERROR) { 486 return status; 487 } 488 patch->mPlaybackThread->addPatchTrack(patch->mPatchTrack); 489 490 // tie playback and record tracks together 491 patch->mPatchRecord->setPeerProxy(patch->mPatchTrack.get()); 492 patch->mPatchTrack->setPeerProxy(patch->mPatchRecord.get()); 493 494 // start capture and playback 495 patch->mPatchRecord->start(AudioSystem::SYNC_EVENT_NONE, 0); 496 patch->mPatchTrack->start(); 497 498 return status; 499 } 500 501 void AudioFlinger::PatchPanel::clearPatchConnections(Patch *patch) 502 { 503 sp<AudioFlinger> audioflinger = mAudioFlinger.promote(); 504 if (audioflinger == 0) { 505 return; 506 } 507 508 ALOGV("clearPatchConnections() patch->mRecordPatchHandle %d patch->mPlaybackPatchHandle %d", 509 patch->mRecordPatchHandle, patch->mPlaybackPatchHandle); 510 511 if (patch->mPatchRecord != 0) { 512 patch->mPatchRecord->stop(); 513 } 514 if (patch->mPatchTrack != 0) { 515 patch->mPatchTrack->stop(); 516 } 517 if (patch->mRecordPatchHandle != AUDIO_PATCH_HANDLE_NONE) { 518 releaseAudioPatch(patch->mRecordPatchHandle); 519 patch->mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE; 520 } 521 if (patch->mPlaybackPatchHandle != AUDIO_PATCH_HANDLE_NONE) { 522 releaseAudioPatch(patch->mPlaybackPatchHandle); 523 patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE; 524 } 525 if (patch->mRecordThread != 0) { 526 if (patch->mPatchRecord != 0) { 527 patch->mRecordThread->deletePatchRecord(patch->mPatchRecord); 528 patch->mPatchRecord.clear(); 529 } 530 audioflinger->closeInputInternal_l(patch->mRecordThread); 531 patch->mRecordThread.clear(); 532 } 533 if (patch->mPlaybackThread != 0) { 534 if (patch->mPatchTrack != 0) { 535 patch->mPlaybackThread->deletePatchTrack(patch->mPatchTrack); 536 patch->mPatchTrack.clear(); 537 } 538 // if num sources == 2 we are reusing an existing playback thread so we do not close it 539 if (patch->mAudioPatch.num_sources != 2) { 540 audioflinger->closeOutputInternal_l(patch->mPlaybackThread); 541 } 542 patch->mPlaybackThread.clear(); 543 } 544 } 545 546 /* Disconnect a patch */ 547 status_t AudioFlinger::PatchPanel::releaseAudioPatch(audio_patch_handle_t handle) 548 { 549 ALOGV("releaseAudioPatch handle %d", handle); 550 status_t status = NO_ERROR; 551 size_t index; 552 553 sp<AudioFlinger> audioflinger = mAudioFlinger.promote(); 554 if (audioflinger == 0) { 555 return NO_INIT; 556 } 557 558 for (index = 0; index < mPatches.size(); index++) { 559 if (handle == mPatches[index]->mHandle) { 560 break; 561 } 562 } 563 if (index == mPatches.size()) { 564 return BAD_VALUE; 565 } 566 Patch *removedPatch = mPatches[index]; 567 mPatches.removeAt(index); 568 569 struct audio_patch *patch = &removedPatch->mAudioPatch; 570 571 switch (patch->sources[0].type) { 572 case AUDIO_PORT_TYPE_DEVICE: { 573 audio_module_handle_t srcModule = patch->sources[0].ext.device.hw_module; 574 ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule); 575 if (index < 0) { 576 ALOGW("releaseAudioPatch() bad src hw module %d", srcModule); 577 status = BAD_VALUE; 578 break; 579 } 580 581 if (patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE && 582 patch->sinks[0].ext.device.hw_module != srcModule) { 583 clearPatchConnections(removedPatch); 584 break; 585 } 586 587 AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); 588 if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { 589 if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) { 590 sp<ThreadBase> thread = audioflinger->checkRecordThread_l( 591 patch->sinks[0].ext.mix.handle); 592 if (thread == 0) { 593 ALOGW("releaseAudioPatch() bad capture I/O handle %d", 594 patch->sinks[0].ext.mix.handle); 595 status = BAD_VALUE; 596 break; 597 } 598 status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle); 599 } else { 600 audio_hw_device_t *hwDevice = audioHwDevice->hwDevice(); 601 status = hwDevice->release_audio_patch(hwDevice, removedPatch->mHalHandle); 602 } 603 } else { 604 sp<ThreadBase> thread = audioflinger->checkRecordThread_l( 605 patch->sinks[0].ext.mix.handle); 606 if (thread == 0) { 607 ALOGW("releaseAudioPatch() bad capture I/O handle %d", 608 patch->sinks[0].ext.mix.handle); 609 status = BAD_VALUE; 610 break; 611 } 612 AudioParameter param; 613 param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), 0); 614 ALOGV("releaseAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s", 615 param.toString().string()); 616 status = thread->setParameters(param.toString()); 617 } 618 } break; 619 case AUDIO_PORT_TYPE_MIX: { 620 audio_module_handle_t srcModule = patch->sources[0].ext.mix.hw_module; 621 ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule); 622 if (index < 0) { 623 ALOGW("releaseAudioPatch() bad src hw module %d", srcModule); 624 status = BAD_VALUE; 625 break; 626 } 627 sp<ThreadBase> thread = 628 audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle); 629 if (thread == 0) { 630 ALOGW("releaseAudioPatch() bad playback I/O handle %d", 631 patch->sources[0].ext.mix.handle); 632 status = BAD_VALUE; 633 break; 634 } 635 AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); 636 if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { 637 status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle); 638 } else { 639 AudioParameter param; 640 param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), 0); 641 status = thread->setParameters(param.toString()); 642 } 643 } break; 644 default: 645 status = BAD_VALUE; 646 break; 647 } 648 649 delete removedPatch; 650 return status; 651 } 652 653 654 /* List connected audio ports and they attributes */ 655 status_t AudioFlinger::PatchPanel::listAudioPatches(unsigned int *num_patches __unused, 656 struct audio_patch *patches __unused) 657 { 658 ALOGV("listAudioPatches"); 659 return NO_ERROR; 660 } 661 662 /* Set audio port configuration */ 663 status_t AudioFlinger::PatchPanel::setAudioPortConfig(const struct audio_port_config *config) 664 { 665 ALOGV("setAudioPortConfig"); 666 status_t status = NO_ERROR; 667 668 sp<AudioFlinger> audioflinger = mAudioFlinger.promote(); 669 if (audioflinger == 0) { 670 return NO_INIT; 671 } 672 673 audio_module_handle_t module; 674 if (config->type == AUDIO_PORT_TYPE_DEVICE) { 675 module = config->ext.device.hw_module; 676 } else { 677 module = config->ext.mix.hw_module; 678 } 679 680 ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(module); 681 if (index < 0) { 682 ALOGW("setAudioPortConfig() bad hw module %d", module); 683 return BAD_VALUE; 684 } 685 686 AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); 687 if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { 688 audio_hw_device_t *hwDevice = audioHwDevice->hwDevice(); 689 return hwDevice->set_audio_port_config(hwDevice, config); 690 } else { 691 return INVALID_OPERATION; 692 } 693 return NO_ERROR; 694 } 695 696 697 }; // namespace android 698