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