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 "MelReporter"
20
21 #include "MelReporter.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 MelReporter::activateHalSoundDoseComputation(const std::string& module,
32 const sp<DeviceHalInterface>& device) {
33 if (mSoundDoseManager->isFrameworkMelForced()) {
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 MelReporter::activateInternalSoundDoseComputation() {
64 {
65 audio_utils::lock_guard _l(mutex());
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 MelReporter::onFirstRef() {
78 mAfMelReporterCallback->getPatchCommandThread()->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 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 audio_utils::lock_guard _laf(mAfMelReporterCallback->mutex()); // AudioFlinger_Mutex
91 audio_utils::lock_guard _l(mutex());
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
resetReferencesForTest()120 void MelReporter::resetReferencesForTest() {
121 mAfMelReporterCallback.clear();
122 mSoundDoseManager->resetReferencesForTest();
123 }
124
onCreateAudioPatch(audio_patch_handle_t handle,const IAfPatchPanel::Patch & patch)125 void MelReporter::onCreateAudioPatch(audio_patch_handle_t handle,
126 const IAfPatchPanel::Patch& patch) {
127 if (!mSoundDoseManager->isCsdEnabled()) {
128 ALOGV("%s csd is disabled", __func__);
129 return;
130 }
131
132 ALOGV("%s: handle %d mHalHandle %d device sink %08x",
133 __func__, handle, patch.mHalHandle,
134 patch.mAudioPatch.num_sinks > 0 ? patch.mAudioPatch.sinks[0].ext.device.type : 0);
135 if (patch.mAudioPatch.num_sources == 0
136 || patch.mAudioPatch.sources[0].type != AUDIO_PORT_TYPE_MIX) {
137 ALOGV("%s: patch does not contain any mix sources", __func__);
138 return;
139 }
140
141 audio_io_handle_t streamHandle = patch.mAudioPatch.sources[0].ext.mix.handle;
142 ActiveMelPatch newPatch;
143 newPatch.streamHandle = streamHandle;
144 newPatch.csdActive = false;
145 for (size_t i = 0; i < patch.mAudioPatch.num_sinks; ++i) {
146 if (patch.mAudioPatch.sinks[i].type == AUDIO_PORT_TYPE_DEVICE &&
147 mSoundDoseManager->shouldComputeCsdForDeviceType(
148 patch.mAudioPatch.sinks[i].ext.device.type)) {
149 audio_port_handle_t deviceId = patch.mAudioPatch.sinks[i].id;
150 bool shouldComputeCsd = mSoundDoseManager->shouldComputeCsdForDeviceWithAddress(
151 patch.mAudioPatch.sinks[i].ext.device.type,
152 patch.mAudioPatch.sinks[i].ext.device.address);
153 newPatch.deviceStates.push_back({deviceId, shouldComputeCsd});
154 newPatch.csdActive |= shouldComputeCsd;
155 AudioDeviceTypeAddr adt{patch.mAudioPatch.sinks[i].ext.device.type,
156 patch.mAudioPatch.sinks[i].ext.device.address};
157 mSoundDoseManager->mapAddressToDeviceId(adt, deviceId);
158 }
159 }
160
161 if (!newPatch.deviceStates.empty() && newPatch.csdActive) {
162 audio_utils::lock_guard _afl(mAfMelReporterCallback->mutex()); // AudioFlinger_Mutex
163 audio_utils::lock_guard _l(mutex());
164 ALOGV("%s add patch handle %d to active devices", __func__, handle);
165 startMelComputationForActivePatch_l(newPatch);
166 mActiveMelPatches[handle] = newPatch;
167 }
168 }
169
startMelComputationForActivePatch_l(const ActiveMelPatch & patch)170 void MelReporter::startMelComputationForActivePatch_l(const ActiveMelPatch& patch)
171 NO_THREAD_SAFETY_ANALYSIS // access of AudioFlinger::checkOutputThread_l
172 {
173 auto outputThread = mAfMelReporterCallback->checkOutputThread_l(patch.streamHandle);
174 if (outputThread == nullptr) {
175 ALOGE("%s cannot find thread for stream handle %d", __func__, patch.streamHandle);
176 return;
177 }
178
179 for (const auto& device : patch.deviceStates) {
180 if (device.second) {
181 ++mActiveDevices[device.first];
182 ALOGI("%s add stream %d that uses device %d for CSD, nr of streams: %d", __func__,
183 patch.streamHandle, device.first, mActiveDevices[device.first]);
184
185 if (outputThread != nullptr && !useHalSoundDoseInterface_l()) {
186 outputThread->startMelComputation_l(
187 mSoundDoseManager->getOrCreateProcessorForDevice(
188 device.first,
189 patch.streamHandle,
190 outputThread->sampleRate(),
191 outputThread->channelCount(),
192 outputThread->format()));
193 }
194 }
195 }
196 }
197
startMelComputationForDeviceId(audio_port_handle_t deviceId)198 void MelReporter::startMelComputationForDeviceId(audio_port_handle_t deviceId) {
199 ALOGV("%s(%d)", __func__, deviceId);
200 audio_utils::lock_guard _laf(mAfMelReporterCallback->mutex());
201 audio_utils::lock_guard _l(mutex());
202
203 for (auto& activeMelPatch : mActiveMelPatches) {
204 bool csdActive = false;
205 for (auto& device: activeMelPatch.second.deviceStates) {
206 if (device.first == deviceId && !device.second) {
207 device.second = true;
208 }
209 csdActive |= device.second;
210 }
211 if (csdActive && !activeMelPatch.second.csdActive) {
212 activeMelPatch.second.csdActive = csdActive;
213 startMelComputationForActivePatch_l(activeMelPatch.second);
214 }
215 }
216 }
217
onReleaseAudioPatch(audio_patch_handle_t handle)218 void MelReporter::onReleaseAudioPatch(audio_patch_handle_t handle) {
219 if (!mSoundDoseManager->isCsdEnabled()) {
220 ALOGV("%s csd is disabled", __func__);
221 return;
222 }
223
224 ActiveMelPatch melPatch;
225 {
226 audio_utils::lock_guard _l(mutex());
227
228 auto patchIt = mActiveMelPatches.find(handle);
229 if (patchIt == mActiveMelPatches.end()) {
230 ALOGV("%s patch handle %d does not contain any mix sources with active MEL calculation",
231 __func__, handle);
232 return;
233 }
234
235 melPatch = patchIt->second;
236 mActiveMelPatches.erase(patchIt);
237 }
238
239 audio_utils::lock_guard _afl(mAfMelReporterCallback->mutex()); // AudioFlinger_Mutex
240 audio_utils::lock_guard _l(mutex());
241 if (melPatch.csdActive) {
242 // only need to stop if patch was active
243 melPatch.csdActive = false;
244 stopMelComputationForPatch_l(melPatch);
245 }
246 }
247
onUpdateAudioPatch(audio_patch_handle_t oldHandle,audio_patch_handle_t newHandle,const IAfPatchPanel::Patch & patch)248 void MelReporter::onUpdateAudioPatch(audio_patch_handle_t oldHandle,
249 audio_patch_handle_t newHandle, const IAfPatchPanel::Patch& patch) {
250 onReleaseAudioPatch(oldHandle);
251 onCreateAudioPatch(newHandle, patch);
252 }
253
getSoundDoseInterface(const sp<media::ISoundDoseCallback> & callback)254 sp<media::ISoundDose> MelReporter::getSoundDoseInterface(
255 const sp<media::ISoundDoseCallback>& callback) {
256 // no need to lock since getSoundDoseInterface is synchronized
257 return mSoundDoseManager->getSoundDoseInterface(callback);
258 }
259
stopInternalMelComputation()260 void MelReporter::stopInternalMelComputation() {
261 ALOGV("%s", __func__);
262 audio_utils::lock_guard _l(mutex());
263 if (mUseHalSoundDoseInterface) {
264 return;
265 }
266 mActiveMelPatches.clear();
267 mUseHalSoundDoseInterface = true;
268 }
269
stopMelComputationForPatch_l(const ActiveMelPatch & patch)270 void MelReporter::stopMelComputationForPatch_l(const ActiveMelPatch& patch)
271 NO_THREAD_SAFETY_ANALYSIS // access of AudioFlinger::checkOutputThread_l
272 {
273 auto outputThread = mAfMelReporterCallback->checkOutputThread_l(patch.streamHandle);
274
275 ALOGV("%s: stop MEL for stream id: %d", __func__, patch.streamHandle);
276 for (const auto& device : patch.deviceStates) {
277 if (mActiveDevices[device.first] > 0) {
278 --mActiveDevices[device.first];
279 if (mActiveDevices[device.first] == 0) {
280 // no stream is using deviceId anymore
281 ALOGI("%s removing device %d from active CSD devices", __func__, device.first);
282 mSoundDoseManager->clearMapDeviceIdEntries(device.first);
283 }
284 }
285 }
286
287 mSoundDoseManager->removeStreamProcessor(patch.streamHandle);
288 if (outputThread != nullptr && !useHalSoundDoseInterface_l()) {
289 outputThread->stopMelComputation_l();
290 }
291 }
292
stopMelComputationForDeviceId(audio_port_handle_t deviceId)293 void MelReporter::stopMelComputationForDeviceId(audio_port_handle_t deviceId) {
294 ALOGV("%s(%d)", __func__, deviceId);
295 audio_utils::lock_guard _laf(mAfMelReporterCallback->mutex());
296 audio_utils::lock_guard _l(mutex());
297
298 for (auto& activeMelPatch : mActiveMelPatches) {
299 bool csdActive = false;
300 for (auto& device: activeMelPatch.second.deviceStates) {
301 if (device.first == deviceId && device.second) {
302 device.second = false;
303 }
304 csdActive |= device.second;
305 }
306
307 if (!csdActive && activeMelPatch.second.csdActive) {
308 activeMelPatch.second.csdActive = csdActive;
309 stopMelComputationForPatch_l(activeMelPatch.second);
310 }
311 }
312
313 }
314
applyAllAudioPatches()315 void MelReporter::applyAllAudioPatches() {
316 ALOGV("%s", __func__);
317
318 std::vector<IAfPatchPanel::Patch> patchesCopy;
319 {
320 audio_utils::lock_guard _laf(mAfMelReporterCallback->mutex());
321 for (const auto& patch : mAfPatchPanel->patches_l()) {
322 patchesCopy.emplace_back(patch.second);
323 }
324 }
325
326 for (const auto& patch : patchesCopy) {
327 onCreateAudioPatch(patch.mHalHandle, patch);
328 }
329 }
330
activePatchStreamHandle_l(audio_io_handle_t streamHandle)331 std::optional<audio_patch_handle_t> MelReporter::activePatchStreamHandle_l(
332 audio_io_handle_t streamHandle) {
333 for(const auto& patchIt : mActiveMelPatches) {
334 if (patchIt.second.streamHandle == streamHandle) {
335 return patchIt.first;
336 }
337 }
338 return std::nullopt;
339 }
340
useHalSoundDoseInterface_l()341 bool MelReporter::useHalSoundDoseInterface_l() {
342 return !mSoundDoseManager->isFrameworkMelForced() & mUseHalSoundDoseInterface;
343 }
344
dump()345 std::string MelReporter::dump() {
346 audio_utils::lock_guard _l(mutex());
347 std::string output("\nSound Dose:\n");
348 output.append(mSoundDoseManager->dump());
349 return output;
350 }
351
352 } // namespace android
353