• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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