PatchPanel.cpp revision 951f455566775e5f01e67c5ee26863d7d19209d7
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 for (unsigned int i = 0; i < patch->num_sinks; i++) { 183 // limit to connections between devices and output streams 184 if (patch->sinks[i].type != AUDIO_PORT_TYPE_MIX) { 185 ALOGW("createAudioPatch() invalid sink type %d for device source", 186 patch->sinks[i].type); 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 197 AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); 198 if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { 199 if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) { 200 sp<ThreadBase> thread = audioflinger->checkRecordThread_l( 201 patch->sinks[0].ext.mix.handle); 202 if (thread == 0) { 203 ALOGW("createAudioPatch() bad capture I/O handle %d", 204 patch->sinks[0].ext.mix.handle); 205 return BAD_VALUE; 206 } 207 status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle); 208 } else { 209 audio_hw_device_t *hwDevice = audioHwDevice->hwDevice(); 210 status = hwDevice->create_audio_patch(hwDevice, 211 patch->num_sources, 212 patch->sources, 213 patch->num_sinks, 214 patch->sinks, 215 &halHandle); 216 } 217 } else { 218 sp<ThreadBase> thread = audioflinger->checkRecordThread_l( 219 patch->sinks[0].ext.mix.handle); 220 if (thread == 0) { 221 ALOGW("createAudioPatch() bad capture I/O handle %d", 222 patch->sinks[0].ext.mix.handle); 223 return BAD_VALUE; 224 } 225 AudioParameter param; 226 param.addInt(String8(AudioParameter::keyRouting), 227 (int)patch->sources[0].ext.device.type); 228 param.addInt(String8(AudioParameter::keyInputSource), 229 (int)patch->sinks[0].ext.mix.usecase.source); 230 231 ALOGW("createAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s", 232 param.toString().string()); 233 status = thread->setParameters(param.toString()); 234 } 235 } break; 236 case AUDIO_PORT_TYPE_MIX: { 237 audio_module_handle_t src_module = patch->sources[0].ext.mix.hw_module; 238 ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(src_module); 239 if (index < 0) { 240 ALOGW("createAudioPatch() bad src hw module %d", src_module); 241 return BAD_VALUE; 242 } 243 // limit to connections between devices and output streams 244 for (unsigned int i = 0; i < patch->num_sinks; i++) { 245 if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) { 246 ALOGW("createAudioPatch() invalid sink type %d for bus source", 247 patch->sinks[i].type); 248 return BAD_VALUE; 249 } 250 // limit to connections between sinks and sources on same HW module 251 if (patch->sinks[i].ext.device.hw_module != src_module) { 252 return BAD_VALUE; 253 } 254 } 255 AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); 256 sp<ThreadBase> thread = 257 audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle); 258 if (thread == 0) { 259 ALOGW("createAudioPatch() bad playback I/O handle %d", 260 patch->sources[0].ext.mix.handle); 261 return BAD_VALUE; 262 } 263 if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { 264 status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle); 265 } else { 266 audio_devices_t type = AUDIO_DEVICE_NONE; 267 for (unsigned int i = 0; i < patch->num_sinks; i++) { 268 type |= patch->sinks[i].ext.device.type; 269 } 270 AudioParameter param; 271 param.addInt(String8(AudioParameter::keyRouting), (int)type); 272 status = thread->setParameters(param.toString()); 273 } 274 275 } break; 276 default: 277 return BAD_VALUE; 278 } 279 ALOGV("createAudioPatch() status %d", status); 280 if (status == NO_ERROR) { 281 *handle = audioflinger->nextUniqueId(); 282 Patch *newPatch = new Patch(patch); 283 newPatch->mHandle = *handle; 284 newPatch->mHalHandle = halHandle; 285 mPatches.add(newPatch); 286 ALOGV("createAudioPatch() added new patch handle %d halHandle %d", *handle, halHandle); 287 } 288 return status; 289} 290 291/* Disconnect a patch */ 292status_t AudioFlinger::PatchPanel::releaseAudioPatch(audio_patch_handle_t handle) 293{ 294 ALOGV("releaseAudioPatch handle %d", handle); 295 status_t status = NO_ERROR; 296 size_t index; 297 298 sp<AudioFlinger> audioflinger = mAudioFlinger.promote(); 299 if (audioflinger == 0) { 300 return NO_INIT; 301 } 302 303 for (index = 0; index < mPatches.size(); index++) { 304 if (handle == mPatches[index]->mHandle) { 305 break; 306 } 307 } 308 if (index == mPatches.size()) { 309 return BAD_VALUE; 310 } 311 312 struct audio_patch *patch = &mPatches[index]->mAudioPatch; 313 314 switch (patch->sources[0].type) { 315 case AUDIO_PORT_TYPE_DEVICE: { 316 audio_module_handle_t src_module = patch->sources[0].ext.device.hw_module; 317 ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(src_module); 318 if (index < 0) { 319 ALOGW("releaseAudioPatch() bad src hw module %d", src_module); 320 status = BAD_VALUE; 321 break; 322 } 323 AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); 324 if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { 325 if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) { 326 sp<ThreadBase> thread = audioflinger->checkRecordThread_l( 327 patch->sinks[0].ext.mix.handle); 328 if (thread == 0) { 329 ALOGW("createAudioPatch() bad capture I/O handle %d", 330 patch->sinks[0].ext.mix.handle); 331 status = BAD_VALUE; 332 break; 333 } 334 status = thread->sendReleaseAudioPatchConfigEvent(mPatches[index]->mHalHandle); 335 } else { 336 audio_hw_device_t *hwDevice = audioHwDevice->hwDevice(); 337 status = hwDevice->release_audio_patch(hwDevice, mPatches[index]->mHalHandle); 338 } 339 } else { 340 sp<ThreadBase> thread = audioflinger->checkRecordThread_l( 341 patch->sinks[0].ext.mix.handle); 342 if (thread == 0) { 343 ALOGW("releaseAudioPatch() bad capture I/O handle %d", 344 patch->sinks[0].ext.mix.handle); 345 status = BAD_VALUE; 346 break; 347 } 348 AudioParameter param; 349 param.addInt(String8(AudioParameter::keyRouting), 0); 350 ALOGW("releaseAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s", 351 param.toString().string()); 352 status = thread->setParameters(param.toString()); 353 } 354 } break; 355 case AUDIO_PORT_TYPE_MIX: { 356 audio_module_handle_t src_module = patch->sources[0].ext.mix.hw_module; 357 ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(src_module); 358 if (index < 0) { 359 ALOGW("releaseAudioPatch() bad src hw module %d", src_module); 360 status = BAD_VALUE; 361 break; 362 } 363 sp<ThreadBase> thread = 364 audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle); 365 if (thread == 0) { 366 ALOGW("releaseAudioPatch() bad playback I/O handle %d", 367 patch->sources[0].ext.mix.handle); 368 status = BAD_VALUE; 369 break; 370 } 371 AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); 372 if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { 373 status = thread->sendReleaseAudioPatchConfigEvent(mPatches[index]->mHalHandle); 374 } else { 375 AudioParameter param; 376 param.addInt(String8(AudioParameter::keyRouting), (int)0); 377 status = thread->setParameters(param.toString()); 378 } 379 } break; 380 default: 381 status = BAD_VALUE; 382 break; 383 } 384 385 delete (mPatches[index]); 386 mPatches.removeAt(index); 387 return status; 388} 389 390 391/* List connected audio ports and they attributes */ 392status_t AudioFlinger::PatchPanel::listAudioPatches(unsigned int *num_patches __unused, 393 struct audio_patch *patches __unused) 394{ 395 ALOGV("listAudioPatches"); 396 return NO_ERROR; 397} 398 399/* Set audio port configuration */ 400status_t AudioFlinger::PatchPanel::setAudioPortConfig( 401 const struct audio_port_config *config __unused) 402{ 403 ALOGV("setAudioPortConfig"); 404 return NO_ERROR; 405} 406 407 408 409}; // namespace android 410