blob: c3259f131db39da87cabb5dab2f7fd0187fa34b1 [file] [log] [blame]
Vlad Popa5161f8a2022-10-10 16:17:20 +02001/*
2**
3** Copyright 2022, 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#define LOG_TAG "AudioFlinger::PatchCommandThread"
19//#define LOG_NDEBUG 0
20
Andy Hung57091702023-07-18 18:31:50 -070021#include "PatchCommandThread.h"
22
23#include <utils/Log.h>
Vlad Popa5161f8a2022-10-10 16:17:20 +020024
25namespace android {
26
27constexpr char kPatchCommandThreadName[] = "AudioFlinger_PatchCommandThread";
28
Andy Hungc8904852023-07-13 19:33:17 -070029PatchCommandThread::~PatchCommandThread() {
Vlad Popa5161f8a2022-10-10 16:17:20 +020030 exit();
31
32 std::lock_guard _l(mLock);
33 mCommands.clear();
34}
35
Andy Hungc8904852023-07-13 19:33:17 -070036void PatchCommandThread::onFirstRef() {
Vlad Popa5161f8a2022-10-10 16:17:20 +020037 run(kPatchCommandThreadName, ANDROID_PRIORITY_AUDIO);
38}
39
Andy Hungc8904852023-07-13 19:33:17 -070040void PatchCommandThread::addListener(const sp<PatchCommandListener>& listener) {
Vlad Popa5161f8a2022-10-10 16:17:20 +020041 ALOGV("%s add listener %p", __func__, static_cast<void*>(listener.get()));
42 std::lock_guard _l(mListenerLock);
43 mListeners.emplace_back(listener);
44}
45
Andy Hungc8904852023-07-13 19:33:17 -070046void PatchCommandThread::createAudioPatch(audio_patch_handle_t handle,
Andy Hung07434ef2023-07-13 18:11:33 -070047 const IAfPatchPanel::Patch& patch) {
Vlad Popa5161f8a2022-10-10 16:17:20 +020048 ALOGV("%s handle %d mHalHandle %d num sinks %d device sink %08x",
49 __func__, handle, patch.mHalHandle,
50 patch.mAudioPatch.num_sinks,
51 patch.mAudioPatch.num_sinks > 0 ? patch.mAudioPatch.sinks[0].ext.device.type : 0);
52
53 createAudioPatchCommand(handle, patch);
54}
55
Andy Hungc8904852023-07-13 19:33:17 -070056void PatchCommandThread::releaseAudioPatch(audio_patch_handle_t handle) {
Vlad Popa5161f8a2022-10-10 16:17:20 +020057 ALOGV("%s", __func__);
58 releaseAudioPatchCommand(handle);
59}
60
Andy Hungc8904852023-07-13 19:33:17 -070061bool PatchCommandThread::threadLoop()
Andy Hung920f6572022-10-06 12:09:49 -070062NO_THREAD_SAFETY_ANALYSIS // bug in clang compiler.
63{
Vlad Popa5161f8a2022-10-10 16:17:20 +020064 std::unique_lock _l(mLock);
65
66 while (!exitPending()) {
67 while (!mCommands.empty() && !exitPending()) {
68 const sp<Command> command = mCommands.front();
69 mCommands.pop_front();
70 _l.unlock();
71
72 std::vector<wp<PatchCommandListener>> listenersCopy;
73 {
74 std::lock_guard _ll(mListenerLock);
75 listenersCopy = mListeners;
76 }
77
78 switch (command->mCommand) {
79 case CREATE_AUDIO_PATCH: {
80 const auto data = (CreateAudioPatchData*) command->mData.get();
81 ALOGV("%s processing create audio patch handle %d",
82 __func__,
83 data->mHandle);
84
85 for (const auto& listener : listenersCopy) {
86 auto spListener = listener.promote();
87 if (spListener) {
88 spListener->onCreateAudioPatch(data->mHandle, data->mPatch);
89 }
90 }
91 }
92 break;
93 case RELEASE_AUDIO_PATCH: {
94 const auto data = (ReleaseAudioPatchData*) command->mData.get();
95 ALOGV("%s processing release audio patch handle %d",
96 __func__,
97 data->mHandle);
98
99 for (const auto& listener : listenersCopy) {
100 auto spListener = listener.promote();
101 if (spListener) {
102 spListener->onReleaseAudioPatch(data->mHandle);
103 }
104 }
105 }
106 break;
107 default:
108 ALOGW("%s unknown command %d", __func__, command->mCommand);
109 break;
110 }
111 _l.lock();
112 }
113
114 // At this stage we have either an empty command queue or the first command in the queue
115 // has a finite delay. So unless we are exiting it is safe to wait.
116 if (!exitPending()) {
117 ALOGV("%s going to sleep", __func__);
118 mWaitWorkCV.wait(_l);
119 }
120 }
121 return false;
122}
123
Andy Hungc8904852023-07-13 19:33:17 -0700124void PatchCommandThread::sendCommand(const sp<Command>& command) {
Vlad Popa5161f8a2022-10-10 16:17:20 +0200125 std::lock_guard _l(mLock);
126 mCommands.emplace_back(command);
127 mWaitWorkCV.notify_one();
128}
129
Andy Hungc8904852023-07-13 19:33:17 -0700130void PatchCommandThread::createAudioPatchCommand(
Andy Hung07434ef2023-07-13 18:11:33 -0700131 audio_patch_handle_t handle, const IAfPatchPanel::Patch& patch) {
Vlad Popa5161f8a2022-10-10 16:17:20 +0200132 auto command = sp<Command>::make(CREATE_AUDIO_PATCH,
133 new CreateAudioPatchData(handle, patch));
134 ALOGV("%s adding create patch handle %d mHalHandle %d.",
135 __func__,
136 handle,
137 patch.mHalHandle);
138 sendCommand(command);
139}
140
Andy Hungc8904852023-07-13 19:33:17 -0700141void PatchCommandThread::releaseAudioPatchCommand(audio_patch_handle_t handle) {
Vlad Popa5161f8a2022-10-10 16:17:20 +0200142 sp<Command> command =
143 sp<Command>::make(RELEASE_AUDIO_PATCH, new ReleaseAudioPatchData(handle));
144 ALOGV("%s adding release patch", __func__);
145 sendCommand(command);
146}
147
Andy Hungc8904852023-07-13 19:33:17 -0700148void PatchCommandThread::exit() {
Vlad Popa5161f8a2022-10-10 16:17:20 +0200149 ALOGV("%s", __func__);
150 {
151 std::lock_guard _l(mLock);
152 requestExit();
153 mWaitWorkCV.notify_one();
154 }
155 // Note that we can call it from the thread loop if all other references have been released
156 // but it will safely return WOULD_BLOCK in this case
157 requestExitAndWait();
158}
159
160} // namespace android