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_NDEBUG 0
19 #define LOG_TAG "AudioFlinger::MelReporter"
20
21 #include "AudioFlinger.h"
22
23 #include <android/media/ISoundDoseCallback.h>
24 #include <audio_utils/power.h>
25 #include <utils/Log.h>
26
27 using aidl::android::hardware::audio::core::sounddose::ISoundDose;
28
29 namespace android {
30
activateHalSoundDoseComputation(const std::string & module,const sp<DeviceHalInterface> & device)31 bool AudioFlinger::MelReporter::activateHalSoundDoseComputation(const std::string& module,
32 const sp<DeviceHalInterface>& device) {
33 if (mSoundDoseManager->forceUseFrameworkMel()) {
34 ALOGD("%s: Forcing use of internal MEL computation.", __func__);
35 activateInternalSoundDoseComputation();
36 return false;
37 }
38
39 ndk::SpAIBinder soundDoseBinder;
40 if (device->getSoundDoseInterface(module, &soundDoseBinder) != OK) {
41 ALOGW("%s: HAL cannot provide sound dose interface for module %s",
42 __func__, module.c_str());
43 return false;
44 }
45
46 if (soundDoseBinder == nullptr) {
47 ALOGW("%s: HAL doesn't implement a sound dose interface for module %s",
48 __func__, module.c_str());
49 return false;
50 }
51
52 std::shared_ptr<ISoundDose> soundDoseInterface = ISoundDose::fromBinder(soundDoseBinder);
53
54 if (!mSoundDoseManager->setHalSoundDoseInterface(module, soundDoseInterface)) {
55 ALOGW("%s: cannot activate HAL MEL reporting for module %s", __func__, module.c_str());
56 return false;
57 }
58
59 stopInternalMelComputation();
60 return true;
61 }
62
activateInternalSoundDoseComputation()63 void AudioFlinger::MelReporter::activateInternalSoundDoseComputation() {
64 {
65 std::lock_guard _l(mLock);
66 if (!mUseHalSoundDoseInterface) {
67 // no need to start internal MEL on active patches
68 return;
69 }
70 mUseHalSoundDoseInterface = false;
71 }
72
73 // reset the HAL interfaces and use internal MELs
74 mSoundDoseManager->resetHalSoundDoseInterfaces();
75 }
76
onFirstRef()77 void AudioFlinger::MelReporter::onFirstRef() {
78 mAudioFlinger.mPatchCommandThread->addListener(this);
79
80 mSoundDoseManager = sp<SoundDoseManager>::make(sp<IMelReporterCallback>::fromExisting(this));
81 }
82
updateMetadataForCsd(audio_io_handle_t streamHandle,const std::vector<playback_track_metadata_v7_t> & metadataVec)83 void AudioFlinger::MelReporter::updateMetadataForCsd(audio_io_handle_t streamHandle,
84 const std::vector<playback_track_metadata_v7_t>& metadataVec) {
85 if (!mSoundDoseManager->isCsdEnabled()) {
86 ALOGV("%s csd is disabled", __func__);
87 return;
88 }
89
90 std::lock_guard _laf(mAudioFlinger.mLock);
91 std::lock_guard _l(mLock);
92 auto activeMelPatchId = activePatchStreamHandle_l(streamHandle);
93 if (!activeMelPatchId) {
94 ALOGV("%s stream handle %d does not have an active patch", __func__, streamHandle);
95 return;
96 }
97
98 bool shouldActivateCsd = false;
99 for (const auto& metadata : metadataVec) {
100 if (metadata.base.usage == AUDIO_USAGE_GAME || metadata.base.usage == AUDIO_USAGE_MEDIA) {
101 shouldActivateCsd = true;
102 }
103 }
104
105 auto activeMelPatchIt = mActiveMelPatches.find(activeMelPatchId.value());
106 if (activeMelPatchIt != mActiveMelPatches.end()) {
107 if (shouldActivateCsd != activeMelPatchIt->second.csdActive) {
108 if (activeMelPatchIt->second.csdActive) {
109 ALOGV("%s should not compute CSD for stream handle %d", __func__, streamHandle);
110 stopMelComputationForPatch_l(activeMelPatchIt->second);
111 } else {
112 ALOGV("%s should compute CSD for stream handle %d", __func__, streamHandle);
113 startMelComputationForActivePatch_l(activeMelPatchIt->second);
114 }
115 activeMelPatchIt->second.csdActive = shouldActivateCsd;
116 }
117 }
118 }
119
onCreateAudioPatch(audio_patch_handle_t handle,const PatchPanel::Patch & patch)120 void AudioFlinger::MelReporter::onCreateAudioPatch(audio_patch_handle_t handle,
121 const PatchPanel::Patch& patch) {
122 if (!mSoundDoseManager->isCsdEnabled()) {
123 ALOGV("%s csd is disabled", __func__);
124 return;
125 }
126
127 ALOGV("%s: handle %d mHalHandle %d device sink %08x",
128 __func__, handle, patch.mHalHandle,
129 patch.mAudioPatch.num_sinks > 0 ? patch.mAudioPatch.sinks[0].ext.device.type : 0);
130 if (patch.mAudioPatch.num_sources == 0
131 || patch.mAudioPatch.sources[0].type != AUDIO_PORT_TYPE_MIX) {
132 ALOGV("%s: patch does not contain any mix sources", __func__);
133 return;
134 }
135
136 audio_io_handle_t streamHandle = patch.mAudioPatch.sources[0].ext.mix.handle;
137 ActiveMelPatch newPatch;
138 newPatch.streamHandle = streamHandle;
139 newPatch.csdActive = false;
140 for (size_t i = 0; i < patch.mAudioPatch.num_sinks; ++i) {
141 if (patch.mAudioPatch.sinks[i].type == AUDIO_PORT_TYPE_DEVICE &&
142 mSoundDoseManager->shouldComputeCsdForDeviceType(
143 patch.mAudioPatch.sinks[i].ext.device.type)) {
144 audio_port_handle_t deviceId = patch.mAudioPatch.sinks[i].id;
145 bool shouldComputeCsd = mSoundDoseManager->shouldComputeCsdForDeviceWithAddress(
146 patch.mAudioPatch.sinks[i].ext.device.type,
147 patch.mAudioPatch.sinks[i].ext.device.address);
148 newPatch.deviceStates.push_back({deviceId, shouldComputeCsd});
149 newPatch.csdActive |= shouldComputeCsd;
150 AudioDeviceTypeAddr adt{patch.mAudioPatch.sinks[i].ext.device.type,
151 patch.mAudioPatch.sinks[i].ext.device.address};
152 mSoundDoseManager->mapAddressToDeviceId(adt, deviceId);
153 }
154 }
155
156 if (!newPatch.deviceStates.empty() && newPatch.csdActive) {
157 std::lock_guard _afl(mAudioFlinger.mLock);
158 std::lock_guard _l(mLock);
159 ALOGV("%s add patch handle %d to active devices", __func__, handle);
160 startMelComputationForActivePatch_l(newPatch);
161 mActiveMelPatches[handle] = newPatch;
162 }
163 }
164
startMelComputationForActivePatch_l(const ActiveMelPatch & patch)165 void AudioFlinger::MelReporter::startMelComputationForActivePatch_l(const ActiveMelPatch& patch)
166 NO_THREAD_SAFETY_ANALYSIS // access of AudioFlinger::checkOutputThread_l
167 {
168 auto outputThread = mAudioFlinger.checkOutputThread_l(patch.streamHandle);
169 if (outputThread == nullptr) {
170 ALOGE("%s cannot find thread for stream handle %d", __func__, patch.streamHandle);
171 return;
172 }
173
174 for (const auto& device : patch.deviceStates) {
175 if (device.second) {
176 ++mActiveDevices[device.first];
177 ALOGI("%s add stream %d that uses device %d for CSD, nr of streams: %d", __func__,
178 patch.streamHandle, device.first, mActiveDevices[device.first]);
179
180 if (outputThread != nullptr && !useHalSoundDoseInterface_l()) {
181 outputThread->startMelComputation_l(
182 mSoundDoseManager->getOrCreateProcessorForDevice(
183 device.first,
184 patch.streamHandle,
185 outputThread->mSampleRate,
186 outputThread->mChannelCount,
187 outputThread->mFormat));
188 }
189 }
190 }
191 }
192
startMelComputationForDeviceId(audio_port_handle_t deviceId)193 void AudioFlinger::MelReporter::startMelComputationForDeviceId(audio_port_handle_t deviceId) {
194 ALOGV("%s(%d)", __func__, deviceId);
195 std::lock_guard _laf(mAudioFlinger.mLock);
196 std::lock_guard _l(mLock);
197
198 for (auto& activeMelPatch : mActiveMelPatches) {
199 bool csdActive = false;
200 for (auto& device: activeMelPatch.second.deviceStates) {
201 if (device.first == deviceId && !device.second) {
202 device.second = true;
203 }
204 csdActive |= device.second;
205 }
206 if (csdActive && !activeMelPatch.second.csdActive) {
207 activeMelPatch.second.csdActive = csdActive;
208 startMelComputationForActivePatch_l(activeMelPatch.second);
209 }
210 }
211 }
212
onReleaseAudioPatch(audio_patch_handle_t handle)213 void AudioFlinger::MelReporter::onReleaseAudioPatch(audio_patch_handle_t handle) {
214 if (!mSoundDoseManager->isCsdEnabled()) {
215 ALOGV("%s csd is disabled", __func__);
216 return;
217 }
218
219 ActiveMelPatch melPatch;
220 {
221 std::lock_guard _l(mLock);
222
223 auto patchIt = mActiveMelPatches.find(handle);
224 if (patchIt == mActiveMelPatches.end()) {
225 ALOGV("%s patch handle %d does not contain any mix sources with active MEL calculation",
226 __func__, handle);
227 return;
228 }
229
230 melPatch = patchIt->second;
231 mActiveMelPatches.erase(patchIt);
232 }
233
234 std::lock_guard _afl(mAudioFlinger.mLock);
235 std::lock_guard _l(mLock);
236 if (melPatch.csdActive) {
237 // only need to stop if patch was active
238 melPatch.csdActive = false;
239 stopMelComputationForPatch_l(melPatch);
240 }
241 }
242
getSoundDoseInterface(const sp<media::ISoundDoseCallback> & callback)243 sp<media::ISoundDose> AudioFlinger::MelReporter::getSoundDoseInterface(
244 const sp<media::ISoundDoseCallback>& callback) {
245 // no need to lock since getSoundDoseInterface is synchronized
246 return mSoundDoseManager->getSoundDoseInterface(callback);
247 }
248
stopInternalMelComputation()249 void AudioFlinger::MelReporter::stopInternalMelComputation() {
250 ALOGV("%s", __func__);
251 std::lock_guard _l(mLock);
252 if (mUseHalSoundDoseInterface) {
253 return;
254 }
255 mActiveMelPatches.clear();
256 mUseHalSoundDoseInterface = true;
257 }
258
stopMelComputationForPatch_l(const ActiveMelPatch & patch)259 void AudioFlinger::MelReporter::stopMelComputationForPatch_l(const ActiveMelPatch& patch)
260 NO_THREAD_SAFETY_ANALYSIS // access of AudioFlinger::checkOutputThread_l
261 {
262 auto outputThread = mAudioFlinger.checkOutputThread_l(patch.streamHandle);
263
264 ALOGV("%s: stop MEL for stream id: %d", __func__, patch.streamHandle);
265 for (const auto& device : patch.deviceStates) {
266 if (mActiveDevices[device.first] > 0) {
267 --mActiveDevices[device.first];
268 if (mActiveDevices[device.first] == 0) {
269 // no stream is using deviceId anymore
270 ALOGI("%s removing device %d from active CSD devices", __func__, device.first);
271 mSoundDoseManager->clearMapDeviceIdEntries(device.first);
272 }
273 }
274 }
275
276 mSoundDoseManager->removeStreamProcessor(patch.streamHandle);
277 if (outputThread != nullptr && !useHalSoundDoseInterface_l()) {
278 outputThread->stopMelComputation_l();
279 }
280 }
281
stopMelComputationForDeviceId(audio_port_handle_t deviceId)282 void AudioFlinger::MelReporter::stopMelComputationForDeviceId(audio_port_handle_t deviceId) {
283 ALOGV("%s(%d)", __func__, deviceId);
284 std::lock_guard _laf(mAudioFlinger.mLock);
285 std::lock_guard _l(mLock);
286
287 for (auto& activeMelPatch : mActiveMelPatches) {
288 bool csdActive = false;
289 for (auto& device: activeMelPatch.second.deviceStates) {
290 if (device.first == deviceId && device.second) {
291 device.second = false;
292 }
293 csdActive |= device.second;
294 }
295
296 if (!csdActive && activeMelPatch.second.csdActive) {
297 activeMelPatch.second.csdActive = csdActive;
298 stopMelComputationForPatch_l(activeMelPatch.second);
299 }
300 }
301
302 }
303
activePatchStreamHandle_l(audio_io_handle_t streamHandle)304 std::optional<audio_patch_handle_t> AudioFlinger::MelReporter::activePatchStreamHandle_l(
305 audio_io_handle_t streamHandle) {
306 for(const auto& patchIt : mActiveMelPatches) {
307 if (patchIt.second.streamHandle == streamHandle) {
308 return patchIt.first;
309 }
310 }
311 return std::nullopt;
312 }
313
useHalSoundDoseInterface_l()314 bool AudioFlinger::MelReporter::useHalSoundDoseInterface_l() {
315 return !mSoundDoseManager->forceUseFrameworkMel() & mUseHalSoundDoseInterface;
316 }
317
dump()318 std::string AudioFlinger::MelReporter::dump() {
319 std::lock_guard _l(mLock);
320 std::string output("\nSound Dose:\n");
321 output.append(mSoundDoseManager->dump());
322 return output;
323 }
324
325 } // namespace android
326