PatchPanel.cpp revision e1715a465a29db625da9d0ea365edf371e39e201
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 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; 145 146 audio_patch_handle_t halHandle = AUDIO_PATCH_HANDLE_NONE; 147 148 sp<AudioFlinger> audioflinger = mAudioFlinger.promote(); 149 if (audioflinger == 0) { 150 return NO_INIT; 151 } 152 if (handle == NULL || patch == NULL) { 153 return BAD_VALUE; 154 } 155 // limit number of sources to 1 for now 156 if (patch->num_sources == 0 || patch->num_sources > 1 || 157 patch->num_sinks == 0 || patch->num_sinks > AUDIO_PATCH_PORTS_MAX) { 158 return BAD_VALUE; 159 } 160 161 for (size_t index = 0; *handle != 0 && index < mPatches.size(); index++) { 162 if (*handle == mPatches[index]->mHandle) { 163 ALOGV("createAudioPatch() removing patch handle %d", *handle); 164 halHandle = mPatches[index]->mHalHandle; 165 mPatches.removeAt(index); 166 break; 167 } 168 } 169 170 switch (patch->sources[0].type) { 171 case AUDIO_PORT_TYPE_DEVICE: { 172 // limit number of sinks to 1 for now 173 if (patch->num_sinks > 1) { 174 return BAD_VALUE; 175 } 176 audio_module_handle_t src_module = patch->sources[0].ext.device.hw_module; 177 ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(src_module); 178 if (index < 0) { 179 ALOGW("createAudioPatch() bad src hw module %d", src_module); 180 return BAD_VALUE; 181 } 182 AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); 183 for (unsigned int i = 0; i < patch->num_sinks; i++) { 184 // reject connection to different sink types 185 if (patch->sinks[i].type != patch->sinks[0].type) { 186 ALOGW("createAudioPatch() different sink types in same patch not supported"); 187 return BAD_VALUE; 188 } 189 // limit to connections between sinks and sources on same HW module 190 if (patch->sinks[i].ext.mix.hw_module != src_module) { 191 ALOGW("createAudioPatch() cannot connect source on module %d to" 192 "sink on module %d", src_module, patch->sinks[i].ext.mix.hw_module); 193 return BAD_VALUE; 194 } 195 196 // limit to connections between devices and output streams for HAL before 3.0 197 if ((audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) && 198 (patch->sinks[i].type != AUDIO_PORT_TYPE_MIX)) { 199 ALOGW("createAudioPatch() invalid sink type %d for device source", 200 patch->sinks[i].type); 201 return BAD_VALUE; 202 } 203 } 204 205 if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { 206 if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) { 207 sp<ThreadBase> thread = audioflinger->checkRecordThread_l( 208 patch->sinks[0].ext.mix.handle); 209 if (thread == 0) { 210 ALOGW("createAudioPatch() bad capture I/O handle %d", 211 patch->sinks[0].ext.mix.handle); 212 return BAD_VALUE; 213 } 214 status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle); 215 } else { 216 audio_hw_device_t *hwDevice = audioHwDevice->hwDevice(); 217 status = hwDevice->create_audio_patch(hwDevice, 218 patch->num_sources, 219 patch->sources, 220 patch->num_sinks, 221 patch->sinks, 222 &halHandle); 223 } 224 } else { 225 sp<ThreadBase> thread = audioflinger->checkRecordThread_l( 226 patch->sinks[0].ext.mix.handle); 227 if (thread == 0) { 228 ALOGW("createAudioPatch() bad capture I/O handle %d", 229 patch->sinks[0].ext.mix.handle); 230 return BAD_VALUE; 231 } 232 AudioParameter param; 233 param.addInt(String8(AudioParameter::keyRouting), 234 (int)patch->sources[0].ext.device.type); 235 param.addInt(String8(AudioParameter::keyInputSource), 236 (int)patch->sinks[0].ext.mix.usecase.source); 237 238 ALOGW("createAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s", 239 param.toString().string()); 240 status = thread->setParameters(param.toString()); 241 } 242 } break; 243 case AUDIO_PORT_TYPE_MIX: { 244 audio_module_handle_t src_module = patch->sources[0].ext.mix.hw_module; 245 ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(src_module); 246 if (index < 0) { 247 ALOGW("createAudioPatch() bad src hw module %d", src_module); 248 return BAD_VALUE; 249 } 250 // limit to connections between devices and output streams 251 for (unsigned int i = 0; i < patch->num_sinks; i++) { 252 if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) { 253 ALOGW("createAudioPatch() invalid sink type %d for bus source", 254 patch->sinks[i].type); 255 return BAD_VALUE; 256 } 257 // limit to connections between sinks and sources on same HW module 258 if (patch->sinks[i].ext.device.hw_module != src_module) { 259 return BAD_VALUE; 260 } 261 } 262 AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); 263 sp<ThreadBase> thread = 264 audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle); 265 if (thread == 0) { 266 ALOGW("createAudioPatch() bad playback I/O handle %d", 267 patch->sources[0].ext.mix.handle); 268 return BAD_VALUE; 269 } 270 if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { 271 status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle); 272 } else { 273 audio_devices_t type = AUDIO_DEVICE_NONE; 274 for (unsigned int i = 0; i < patch->num_sinks; i++) { 275 type |= patch->sinks[i].ext.device.type; 276 } 277 AudioParameter param; 278 param.addInt(String8(AudioParameter::keyRouting), (int)type); 279 status = thread->setParameters(param.toString()); 280 } 281 282 } break; 283 default: 284 return BAD_VALUE; 285 } 286 ALOGV("createAudioPatch() status %d", status); 287 if (status == NO_ERROR) { 288 *handle = audioflinger->nextUniqueId(); 289 Patch *newPatch = new Patch(patch); 290 newPatch->mHandle = *handle; 291 newPatch->mHalHandle = halHandle; 292 mPatches.add(newPatch); 293 ALOGV("createAudioPatch() added new patch handle %d halHandle %d", *handle, halHandle); 294 } 295 return status; 296} 297 298/* Disconnect a patch */ 299status_t AudioFlinger::PatchPanel::releaseAudioPatch(audio_patch_handle_t handle) 300{ 301 ALOGV("releaseAudioPatch handle %d", handle); 302 status_t status = NO_ERROR; 303 size_t index; 304 305 sp<AudioFlinger> audioflinger = mAudioFlinger.promote(); 306 if (audioflinger == 0) { 307 return NO_INIT; 308 } 309 310 for (index = 0; index < mPatches.size(); index++) { 311 if (handle == mPatches[index]->mHandle) { 312 break; 313 } 314 } 315 if (index == mPatches.size()) { 316 return BAD_VALUE; 317 } 318 319 struct audio_patch *patch = &mPatches[index]->mAudioPatch; 320 321 switch (patch->sources[0].type) { 322 case AUDIO_PORT_TYPE_DEVICE: { 323 audio_module_handle_t src_module = patch->sources[0].ext.device.hw_module; 324 ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(src_module); 325 if (index < 0) { 326 ALOGW("releaseAudioPatch() bad src hw module %d", src_module); 327 status = BAD_VALUE; 328 break; 329 } 330 AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); 331 if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { 332 if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) { 333 sp<ThreadBase> thread = audioflinger->checkRecordThread_l( 334 patch->sinks[0].ext.mix.handle); 335 if (thread == 0) { 336 ALOGW("createAudioPatch() bad capture I/O handle %d", 337 patch->sinks[0].ext.mix.handle); 338 status = BAD_VALUE; 339 break; 340 } 341 status = thread->sendReleaseAudioPatchConfigEvent(mPatches[index]->mHalHandle); 342 } else { 343 audio_hw_device_t *hwDevice = audioHwDevice->hwDevice(); 344 status = hwDevice->release_audio_patch(hwDevice, mPatches[index]->mHalHandle); 345 } 346 } else { 347 sp<ThreadBase> thread = audioflinger->checkRecordThread_l( 348 patch->sinks[0].ext.mix.handle); 349 if (thread == 0) { 350 ALOGW("releaseAudioPatch() bad capture I/O handle %d", 351 patch->sinks[0].ext.mix.handle); 352 status = BAD_VALUE; 353 break; 354 } 355 AudioParameter param; 356 param.addInt(String8(AudioParameter::keyRouting), 0); 357 ALOGW("releaseAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s", 358 param.toString().string()); 359 status = thread->setParameters(param.toString()); 360 } 361 } break; 362 case AUDIO_PORT_TYPE_MIX: { 363 audio_module_handle_t src_module = patch->sources[0].ext.mix.hw_module; 364 ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(src_module); 365 if (index < 0) { 366 ALOGW("releaseAudioPatch() bad src hw module %d", src_module); 367 status = BAD_VALUE; 368 break; 369 } 370 sp<ThreadBase> thread = 371 audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle); 372 if (thread == 0) { 373 ALOGW("releaseAudioPatch() bad playback I/O handle %d", 374 patch->sources[0].ext.mix.handle); 375 status = BAD_VALUE; 376 break; 377 } 378 AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); 379 if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { 380 status = thread->sendReleaseAudioPatchConfigEvent(mPatches[index]->mHalHandle); 381 } else { 382 AudioParameter param; 383 param.addInt(String8(AudioParameter::keyRouting), (int)0); 384 status = thread->setParameters(param.toString()); 385 } 386 } break; 387 default: 388 status = BAD_VALUE; 389 break; 390 } 391 392 delete (mPatches[index]); 393 mPatches.removeAt(index); 394 return status; 395} 396 397 398/* List connected audio ports and they attributes */ 399status_t AudioFlinger::PatchPanel::listAudioPatches(unsigned int *num_patches __unused, 400 struct audio_patch *patches __unused) 401{ 402 ALOGV("listAudioPatches"); 403 return NO_ERROR; 404} 405 406/* Set audio port configuration */ 407status_t AudioFlinger::PatchPanel::setAudioPortConfig(const struct audio_port_config *config) 408{ 409 ALOGV("setAudioPortConfig"); 410 status_t status = NO_ERROR; 411 412 sp<AudioFlinger> audioflinger = mAudioFlinger.promote(); 413 if (audioflinger == 0) { 414 return NO_INIT; 415 } 416 417 audio_module_handle_t module; 418 if (config->type == AUDIO_PORT_TYPE_DEVICE) { 419 module = config->ext.device.hw_module; 420 } else { 421 module = config->ext.mix.hw_module; 422 } 423 424 ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(module); 425 if (index < 0) { 426 ALOGW("setAudioPortConfig() bad hw module %d", module); 427 return BAD_VALUE; 428 } 429 430 AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); 431 if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { 432 audio_hw_device_t *hwDevice = audioHwDevice->hwDevice(); 433 return hwDevice->set_audio_port_config(hwDevice, config); 434 } else { 435 return INVALID_OPERATION; 436 } 437 return NO_ERROR; 438} 439 440 441}; // namespace android 442