1 /*
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
21 #include "AudioFlinger.h"
22
23 namespace android {
24
25 constexpr char kPatchCommandThreadName[] = "AudioFlinger_PatchCommandThread";
26
~PatchCommandThread()27 AudioFlinger::PatchCommandThread::~PatchCommandThread() {
28 exit();
29
30 std::lock_guard _l(mLock);
31 mCommands.clear();
32 }
33
onFirstRef()34 void AudioFlinger::PatchCommandThread::onFirstRef() {
35 run(kPatchCommandThreadName, ANDROID_PRIORITY_AUDIO);
36 }
37
addListener(const sp<PatchCommandListener> & listener)38 void AudioFlinger::PatchCommandThread::addListener(const sp<PatchCommandListener>& listener) {
39 ALOGV("%s add listener %p", __func__, static_cast<void*>(listener.get()));
40 std::lock_guard _l(mListenerLock);
41 mListeners.emplace_back(listener);
42 }
43
createAudioPatch(audio_patch_handle_t handle,const PatchPanel::Patch & patch)44 void AudioFlinger::PatchCommandThread::createAudioPatch(audio_patch_handle_t handle,
45 const PatchPanel::Patch& patch) {
46 ALOGV("%s handle %d mHalHandle %d num sinks %d device sink %08x",
47 __func__, handle, patch.mHalHandle,
48 patch.mAudioPatch.num_sinks,
49 patch.mAudioPatch.num_sinks > 0 ? patch.mAudioPatch.sinks[0].ext.device.type : 0);
50
51 createAudioPatchCommand(handle, patch);
52 }
53
releaseAudioPatch(audio_patch_handle_t handle)54 void AudioFlinger::PatchCommandThread::releaseAudioPatch(audio_patch_handle_t handle) {
55 ALOGV("%s", __func__);
56 releaseAudioPatchCommand(handle);
57 }
58
threadLoop()59 bool AudioFlinger::PatchCommandThread::threadLoop()
60 NO_THREAD_SAFETY_ANALYSIS // bug in clang compiler.
61 {
62 std::unique_lock _l(mLock);
63
64 while (!exitPending()) {
65 while (!mCommands.empty() && !exitPending()) {
66 const sp<Command> command = mCommands.front();
67 mCommands.pop_front();
68 _l.unlock();
69
70 std::vector<wp<PatchCommandListener>> listenersCopy;
71 {
72 std::lock_guard _ll(mListenerLock);
73 listenersCopy = mListeners;
74 }
75
76 switch (command->mCommand) {
77 case CREATE_AUDIO_PATCH: {
78 const auto data = (CreateAudioPatchData*) command->mData.get();
79 ALOGV("%s processing create audio patch handle %d",
80 __func__,
81 data->mHandle);
82
83 for (const auto& listener : listenersCopy) {
84 auto spListener = listener.promote();
85 if (spListener) {
86 spListener->onCreateAudioPatch(data->mHandle, data->mPatch);
87 }
88 }
89 }
90 break;
91 case RELEASE_AUDIO_PATCH: {
92 const auto data = (ReleaseAudioPatchData*) command->mData.get();
93 ALOGV("%s processing release audio patch handle %d",
94 __func__,
95 data->mHandle);
96
97 for (const auto& listener : listenersCopy) {
98 auto spListener = listener.promote();
99 if (spListener) {
100 spListener->onReleaseAudioPatch(data->mHandle);
101 }
102 }
103 }
104 break;
105 default:
106 ALOGW("%s unknown command %d", __func__, command->mCommand);
107 break;
108 }
109 _l.lock();
110 }
111
112 // At this stage we have either an empty command queue or the first command in the queue
113 // has a finite delay. So unless we are exiting it is safe to wait.
114 if (!exitPending()) {
115 ALOGV("%s going to sleep", __func__);
116 mWaitWorkCV.wait(_l);
117 }
118 }
119 return false;
120 }
121
sendCommand(const sp<Command> & command)122 void AudioFlinger::PatchCommandThread::sendCommand(const sp<Command>& command) {
123 std::lock_guard _l(mLock);
124 mCommands.emplace_back(command);
125 mWaitWorkCV.notify_one();
126 }
127
createAudioPatchCommand(audio_patch_handle_t handle,const PatchPanel::Patch & patch)128 void AudioFlinger::PatchCommandThread::createAudioPatchCommand(
129 audio_patch_handle_t handle, const PatchPanel::Patch& patch) {
130 auto command = sp<Command>::make(CREATE_AUDIO_PATCH,
131 new CreateAudioPatchData(handle, patch));
132 ALOGV("%s adding create patch handle %d mHalHandle %d.",
133 __func__,
134 handle,
135 patch.mHalHandle);
136 sendCommand(command);
137 }
138
releaseAudioPatchCommand(audio_patch_handle_t handle)139 void AudioFlinger::PatchCommandThread::releaseAudioPatchCommand(audio_patch_handle_t handle) {
140 sp<Command> command =
141 sp<Command>::make(RELEASE_AUDIO_PATCH, new ReleaseAudioPatchData(handle));
142 ALOGV("%s adding release patch", __func__);
143 sendCommand(command);
144 }
145
exit()146 void AudioFlinger::PatchCommandThread::exit() {
147 ALOGV("%s", __func__);
148 {
149 std::lock_guard _l(mLock);
150 requestExit();
151 mWaitWorkCV.notify_one();
152 }
153 // Note that we can call it from the thread loop if all other references have been released
154 // but it will safely return WOULD_BLOCK in this case
155 requestExitAndWait();
156 }
157
158 } // namespace android
159