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 */
listAudioPorts(unsigned int * num_ports,struct audio_port * ports)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 */
getAudioPort(struct audio_port * 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 */
createAudioPatch(const struct audio_patch * patch,audio_patch_handle_t * handle)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 */
releaseAudioPatch(audio_patch_handle_t handle)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 */
listAudioPatches(unsigned int * num_patches,struct audio_patch * patches)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 */
setAudioPortConfig(const struct audio_port_config * config)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 
PatchPanel(const sp<AudioFlinger> & audioFlinger)113 AudioFlinger::PatchPanel::PatchPanel(const sp<AudioFlinger>& audioFlinger)
114                                    : mAudioFlinger(audioFlinger)
115 {
116 }
117 
~PatchPanel()118 AudioFlinger::PatchPanel::~PatchPanel()
119 {
120 }
121 
122 /* List connected audio ports and their attributes */
listAudioPorts(unsigned int * num_ports __unused,struct audio_port * ports __unused)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 */
getAudioPort(struct audio_port * port __unused)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 */
createAudioPatch(const struct audio_patch * patch,audio_patch_handle_t * handle)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 
createPatchConnections(Patch * patch,const struct audio_patch * audioPatch)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 
clearPatchConnections(Patch * patch)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 */
releaseAudioPatch(audio_patch_handle_t handle)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 */
listAudioPatches(unsigned int * num_patches __unused,struct audio_patch * patches __unused)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 */
setAudioPortConfig(const struct audio_port_config * config)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