xref: /aosp_15_r20/system/chre/core/audio_request_manager.cc (revision 84e339476a462649f82315436d70fd732297a399)
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifdef CHRE_AUDIO_SUPPORT_ENABLED
18 
19 #include "chre/core/audio_request_manager.h"
20 
21 #include "chre/core/audio_util.h"
22 #include "chre/core/event_loop_manager.h"
23 #include "chre/platform/fatal_error.h"
24 #include "chre/platform/system_time.h"
25 #include "chre/util/nested_data_ptr.h"
26 #include "chre/util/system/debug_dump.h"
27 #include "chre/util/system/event_callbacks.h"
28 #include "chre/util/time.h"
29 
30 /*
31  * TODO(P1-62e045): Evict pending audio events from the event queue as needed.
32  *
33  * Under the following conditions, an audio data event may be posted to the
34  * CHRE event queue when it should not be.
35  *
36  * 1. Nanoapp changes request
37  * 2. Nanoapp removes request
38  *
39  * A previously scheduled audio data event may be residing in the event queue
40  * and will be dispatched to the nanoapp after it has cancelled the request.
41  *
42  * The solution is to evict any audio events for a given audio handle that are
43  * directed to a nanoapp before scheduling the next request to the platform.
44  */
45 
46 namespace chre {
47 
init()48 void AudioRequestManager::init() {
49   mPlatformAudio.init();
50 
51   size_t sourceCount = mPlatformAudio.getSourceCount();
52   if (!mAudioRequestLists.reserve(sourceCount)) {
53     FATAL_ERROR_OOM();
54   }
55 
56   for (size_t i = 0; i < sourceCount; i++) {
57     mAudioRequestLists.emplace_back();
58   }
59 }
60 
configureSource(const Nanoapp * nanoapp,uint32_t handle,bool enable,uint64_t bufferDuration,uint64_t deliveryInterval)61 bool AudioRequestManager::configureSource(const Nanoapp *nanoapp,
62                                           uint32_t handle, bool enable,
63                                           uint64_t bufferDuration,
64                                           uint64_t deliveryInterval) {
65   uint32_t numSamples = 0;
66   return validateConfigureSourceArguments(handle, enable, bufferDuration,
67                                           deliveryInterval, &numSamples) &&
68          doConfigureSource(nanoapp->getInstanceId(), handle, enable, numSamples,
69                            Nanoseconds(deliveryInterval));
70 }
71 
handleAudioDataEvent(const struct chreAudioDataEvent * audioDataEvent)72 void AudioRequestManager::handleAudioDataEvent(
73     const struct chreAudioDataEvent *audioDataEvent) {
74   uint32_t handle = audioDataEvent->handle;
75   if (handle >= mAudioRequestLists.size()) {
76     LOGE("Received audio event for unknown handle %" PRIu32, handle);
77   } else {
78     mAudioRequestLists[handle].lastEventTimestamp =
79         SystemTime::getMonotonicTime();
80   }
81 
82   auto callback = [](uint16_t /*type*/, void *data, void * /*extraData*/) {
83     auto *event = static_cast<struct chreAudioDataEvent *>(data);
84     EventLoopManagerSingleton::get()
85         ->getAudioRequestManager()
86         .handleAudioDataEventSync(event);
87   };
88 
89   // Cast off the event const so that it can be provided to the callback as
90   // non-const. The event is provided to nanoapps as const and the runtime
91   // itself will not modify this memory so this is safe.
92   struct chreAudioDataEvent *event =
93       const_cast<struct chreAudioDataEvent *>(audioDataEvent);
94   if (!EventLoopManagerSingleton::get()->deferCallback(
95           SystemCallbackType::AudioHandleDataEvent, event, callback)) {
96     EventLoopManagerSingleton::get()
97         ->getAudioRequestManager()
98         .handleFreeAudioDataEvent(event);
99   }
100 }
101 
handleAudioAvailability(uint32_t handle,bool available)102 void AudioRequestManager::handleAudioAvailability(uint32_t handle,
103                                                   bool available) {
104   auto callback = [](uint16_t /*type*/, void *data, void *extraData) {
105     uint32_t cbHandle = NestedDataPtr<uint32_t>(data);
106     bool cbAvailable = NestedDataPtr<bool>(extraData);
107     EventLoopManagerSingleton::get()
108         ->getAudioRequestManager()
109         .handleAudioAvailabilitySync(cbHandle, cbAvailable);
110   };
111 
112   EventLoopManagerSingleton::get()->deferCallback(
113       SystemCallbackType::AudioAvailabilityChange,
114       NestedDataPtr<uint32_t>(handle), callback,
115       NestedDataPtr<bool>(available));
116 }
117 
logStateToBuffer(DebugDumpWrapper & debugDump) const118 void AudioRequestManager::logStateToBuffer(DebugDumpWrapper &debugDump) const {
119   debugDump.print("\nAudio:\n");
120   for (size_t i = 0; i < mAudioRequestLists.size(); i++) {
121     uint32_t handle = static_cast<uint32_t>(i);
122     struct chreAudioSource source;
123     mPlatformAudio.getAudioSource(handle, &source);
124 
125     Nanoseconds timeSinceLastAudioEvent =
126         SystemTime::getMonotonicTime() -
127         mAudioRequestLists[i].lastEventTimestamp;
128     debugDump.print(
129         " handle=%" PRIu32 ", name=\"%s\", available=%d, sampleRate=%" PRIu32
130         ", buffer(ms)=[%" PRIu64 ",%" PRIu64 "], format=%" PRIu8
131         ", timeSinceLastAudioEvent(ms)=%" PRIu64 "\n",
132         handle, source.name, mAudioRequestLists[i].available, source.sampleRate,
133         Milliseconds(Nanoseconds(source.minBufferDuration)).getMilliseconds(),
134         Milliseconds(Nanoseconds(source.maxBufferDuration)).getMilliseconds(),
135         source.format, Milliseconds(timeSinceLastAudioEvent).getMilliseconds());
136 
137     for (const auto &request : mAudioRequestLists[i].requests) {
138       for (const auto &instanceId : request.instanceIds) {
139         debugDump.print("  nanoappId=%" PRIu16 ", numSamples=%" PRIu32
140                         ", interval(ms)=%" PRIu64 "\n",
141                         instanceId, request.numSamples,
142                         Milliseconds(Nanoseconds(request.deliveryInterval))
143                             .getMilliseconds());
144       }
145     }
146   }
147 }
148 
validateConfigureSourceArguments(uint32_t handle,bool enable,uint64_t bufferDuration,uint64_t deliveryInterval,uint32_t * numSamples)149 bool AudioRequestManager::validateConfigureSourceArguments(
150     uint32_t handle, bool enable, uint64_t bufferDuration,
151     uint64_t deliveryInterval, uint32_t *numSamples) {
152   bool success = false;
153   if (handle >= mAudioRequestLists.size()) {
154     LOGE("Provided audio handle out of range");
155   } else if (enable) {
156     chreAudioSource audioSource;
157     if (!mPlatformAudio.getAudioSource(handle, &audioSource)) {
158       LOGE("Failed to query for audio source");
159     } else if (bufferDuration > deliveryInterval) {
160       LOGE("Buffer duration must be less than or equal to delivery interval");
161     } else if (bufferDuration < audioSource.minBufferDuration ||
162                bufferDuration > audioSource.maxBufferDuration) {
163       LOGE("Invalid buffer duration %" PRIu64 " not in range [%" PRIu64
164            ",%" PRIu64 "]",
165            bufferDuration, audioSource.minBufferDuration,
166            audioSource.maxBufferDuration);
167     } else {
168       *numSamples = AudioUtil::getSampleCountFromRateAndDuration(
169           audioSource.sampleRate, Nanoseconds(bufferDuration));
170       success = true;
171     }
172   } else {
173     // Disabling the request, no need to validate bufferDuration or
174     // deliveryInterval.
175     success = true;
176   }
177   return success;
178 }
179 
doConfigureSource(uint16_t instanceId,uint32_t handle,bool enable,uint32_t numSamples,Nanoseconds deliveryInterval)180 bool AudioRequestManager::doConfigureSource(uint16_t instanceId,
181                                             uint32_t handle, bool enable,
182                                             uint32_t numSamples,
183                                             Nanoseconds deliveryInterval) {
184   size_t requestIndex;
185   size_t requestInstanceIdIndex;
186   auto *audioRequest = findAudioRequestByInstanceId(
187       handle, instanceId, &requestIndex, &requestInstanceIdIndex);
188 
189   AudioRequestList &requestList = mAudioRequestLists[handle];
190   size_t lastNumRequests = requestList.requests.size();
191 
192   bool success = false;
193   if (audioRequest == nullptr) {
194     if (enable) {
195       success =
196           createAudioRequest(handle, instanceId, numSamples, deliveryInterval);
197     } else {
198       LOGW("Nanoapp disabling nonexistent audio request");
199     }
200   } else {
201     if (audioRequest->instanceIds.size() > 1) {
202       // If there are other clients listening in this configuration, remove
203       // just the instance ID.
204       audioRequest->instanceIds.erase(requestInstanceIdIndex);
205     } else {
206       // If this is the last client listening in this configuration, remove
207       // the entire request.
208       requestList.requests.erase(requestIndex);
209     }
210 
211     // If the client is disabling, there is nothing to do, otherwise a
212     // request must be created successfully.
213     if (!enable) {
214       success = true;
215     } else {
216       success =
217           createAudioRequest(handle, instanceId, numSamples, deliveryInterval);
218     }
219   }
220 
221   if (success &&
222       (EventLoopManagerSingleton::get()->getSettingManager().getSettingEnabled(
223           Setting::MICROPHONE))) {
224     scheduleNextAudioDataEvent(handle);
225     updatePlatformHandleEnabled(handle, lastNumRequests);
226   }
227 
228   return success;
229 }
230 
updatePlatformHandleEnabled(uint32_t handle,size_t lastNumRequests)231 void AudioRequestManager::updatePlatformHandleEnabled(uint32_t handle,
232                                                       size_t lastNumRequests) {
233   size_t numRequests = mAudioRequestLists[handle].requests.size();
234   if (lastNumRequests == 0 && numRequests > 0) {
235     mPlatformAudio.setHandleEnabled(handle, true /* enabled */);
236   } else if (lastNumRequests > 0 && numRequests == 0) {
237     mPlatformAudio.setHandleEnabled(handle, false /* enabled */);
238   }
239 }
240 
createAudioRequest(uint32_t handle,uint16_t instanceId,uint32_t numSamples,Nanoseconds deliveryInterval)241 bool AudioRequestManager::createAudioRequest(uint32_t handle,
242                                              uint16_t instanceId,
243                                              uint32_t numSamples,
244                                              Nanoseconds deliveryInterval) {
245   AudioRequestList &requestList = mAudioRequestLists[handle];
246 
247   size_t matchingRequestIndex;
248   auto *matchingAudioRequest = findAudioRequestByConfiguration(
249       handle, numSamples, deliveryInterval, &matchingRequestIndex);
250 
251   bool success = false;
252   if (matchingAudioRequest != nullptr) {
253     if (!matchingAudioRequest->instanceIds.push_back(instanceId)) {
254       LOG_OOM();
255     } else {
256       success = true;
257     }
258   } else {
259     Nanoseconds timeNow = SystemTime::getMonotonicTime();
260     Nanoseconds nextEventTimestamp = timeNow + deliveryInterval;
261     if (!requestList.requests.emplace_back(numSamples, deliveryInterval,
262                                            nextEventTimestamp)) {
263       LOG_OOM();
264     } else if (!requestList.requests.back().instanceIds.push_back(instanceId)) {
265       requestList.requests.pop_back();
266       LOG_OOM();
267     } else {
268       success = true;
269     }
270   }
271 
272   if (success) {
273     bool suspended = !EventLoopManagerSingleton::get()
274                           ->getSettingManager()
275                           .getSettingEnabled(Setting::MICROPHONE);
276     postAudioSamplingChangeEvent(instanceId, handle, requestList.available,
277                                  suspended);
278   }
279 
280   return success;
281 }
282 
disableAllAudioRequests(const Nanoapp * nanoapp)283 uint32_t AudioRequestManager::disableAllAudioRequests(const Nanoapp *nanoapp) {
284   uint32_t numRequestDisabled = 0;
285 
286   const uint32_t numRequests = static_cast<uint32_t>(mAudioRequestLists.size());
287   for (uint32_t handle = 0; handle < numRequests; ++handle) {
288     AudioRequest *audioRequest = findAudioRequestByInstanceId(
289         handle, nanoapp->getInstanceId(), nullptr /*index*/, nullptr
290         /*instanceIdIndex*/);
291 
292     if (audioRequest != nullptr) {
293       numRequestDisabled++;
294       doConfigureSource(nanoapp->getInstanceId(), handle, false /*enable*/,
295                         0 /*numSamples*/, Nanoseconds() /*deliveryInterval*/);
296     }
297   }
298 
299   return numRequestDisabled;
300 }
301 
302 AudioRequestManager::AudioRequest *
findAudioRequestByInstanceId(uint32_t handle,uint16_t instanceId,size_t * index,size_t * instanceIdIndex)303 AudioRequestManager::findAudioRequestByInstanceId(uint32_t handle,
304                                                   uint16_t instanceId,
305                                                   size_t *index,
306                                                   size_t *instanceIdIndex) {
307   AudioRequest *foundAudioRequest = nullptr;
308   auto &requests = mAudioRequestLists[handle].requests;
309   for (size_t i = 0; i < requests.size(); i++) {
310     auto &audioRequest = requests[i];
311     size_t foundInstanceIdIndex = audioRequest.instanceIds.find(instanceId);
312     if (foundInstanceIdIndex != audioRequest.instanceIds.size()) {
313       foundAudioRequest = &audioRequest;
314       if (index != nullptr) {
315         *index = i;
316       }
317       if (instanceIdIndex != nullptr) {
318         *instanceIdIndex = foundInstanceIdIndex;
319       }
320       break;
321     }
322   }
323 
324   return foundAudioRequest;
325 }
326 
327 AudioRequestManager::AudioRequest *
findAudioRequestByConfiguration(uint32_t handle,uint32_t numSamples,Nanoseconds deliveryInterval,size_t * index)328 AudioRequestManager::findAudioRequestByConfiguration(
329     uint32_t handle, uint32_t numSamples, Nanoseconds deliveryInterval,
330     size_t *index) {
331   AudioRequest *foundAudioRequest = nullptr;
332   auto &requests = mAudioRequestLists[handle].requests;
333   for (size_t i = 0; i < requests.size(); i++) {
334     auto &audioRequest = requests[i];
335     if (audioRequest.numSamples == numSamples &&
336         audioRequest.deliveryInterval == deliveryInterval) {
337       foundAudioRequest = &audioRequest;
338       *index = i;
339       break;
340     }
341   }
342 
343   return foundAudioRequest;
344 }
345 
findNextAudioRequest(uint32_t handle)346 AudioRequestManager::AudioRequest *AudioRequestManager::findNextAudioRequest(
347     uint32_t handle) {
348   Nanoseconds earliestNextEventTimestamp = Nanoseconds(UINT64_MAX);
349   AudioRequest *nextRequest = nullptr;
350 
351   auto &reqList = mAudioRequestLists[handle];
352   for (auto &req : reqList.requests) {
353     if (req.nextEventTimestamp < earliestNextEventTimestamp) {
354       earliestNextEventTimestamp = req.nextEventTimestamp;
355       nextRequest = &req;
356     }
357   }
358 
359   return nextRequest;
360 }
361 
handleAudioDataEventSync(struct chreAudioDataEvent * event)362 void AudioRequestManager::handleAudioDataEventSync(
363     struct chreAudioDataEvent *event) {
364   uint32_t handle = event->handle;
365   if (handle < mAudioRequestLists.size()) {
366     auto &reqList = mAudioRequestLists[handle];
367     AudioRequest *nextAudioRequest = reqList.nextAudioRequest;
368     if (nextAudioRequest != nullptr) {
369       postAudioDataEventFatal(event, nextAudioRequest->instanceIds);
370       nextAudioRequest->nextEventTimestamp =
371           SystemTime::getMonotonicTime() + nextAudioRequest->deliveryInterval;
372     } else {
373       LOGW("Received audio data event with no pending audio request");
374       mPlatformAudio.releaseAudioDataEvent(event);
375     }
376 
377     scheduleNextAudioDataEvent(handle);
378   } else {
379     LOGE("Audio data event handle out of range: %" PRIu32, handle);
380   }
381 }
382 
handleAudioAvailabilitySync(uint32_t handle,bool available)383 void AudioRequestManager::handleAudioAvailabilitySync(uint32_t handle,
384                                                       bool available) {
385   if (handle < mAudioRequestLists.size()) {
386     if (mAudioRequestLists[handle].available != available) {
387       bool suspended = !EventLoopManagerSingleton::get()
388                             ->getSettingManager()
389                             .getSettingEnabled(Setting::MICROPHONE);
390       mAudioRequestLists[handle].available = available;
391       postAudioSamplingChangeEvents(handle, suspended);
392     }
393 
394     scheduleNextAudioDataEvent(handle);
395   } else {
396     LOGE("Audio availability handle out of range: %" PRIu32, handle);
397   }
398 }
399 
scheduleNextAudioDataEvent(uint32_t handle)400 void AudioRequestManager::scheduleNextAudioDataEvent(uint32_t handle) {
401   if (!EventLoopManagerSingleton::get()->getSettingManager().getSettingEnabled(
402           Setting::MICROPHONE)) {
403     LOGD("Mic access disabled, doing nothing");
404     return;
405   }
406 
407   auto &reqList = mAudioRequestLists[handle];
408   AudioRequest *nextRequest = findNextAudioRequest(handle);
409 
410   // Clear the next request and it will be reset below if needed.
411   reqList.nextAudioRequest = nullptr;
412   if (reqList.available && (nextRequest != nullptr)) {
413     Nanoseconds curTime = SystemTime::getMonotonicTime();
414     Nanoseconds eventDelay = Nanoseconds(0);
415     if (nextRequest->nextEventTimestamp > curTime) {
416       eventDelay = nextRequest->nextEventTimestamp - curTime;
417     }
418     reqList.nextAudioRequest = nextRequest;
419     mPlatformAudio.requestAudioDataEvent(handle, nextRequest->numSamples,
420                                          eventDelay);
421   } else {
422     mPlatformAudio.cancelAudioDataEventRequest(handle);
423   }
424 }
425 
postAudioSamplingChangeEvents(uint32_t handle,bool suspended)426 void AudioRequestManager::postAudioSamplingChangeEvents(uint32_t handle,
427                                                         bool suspended) {
428   const auto &requestList = mAudioRequestLists[handle];
429   for (const auto &request : requestList.requests) {
430     for (const auto &instanceId : request.instanceIds) {
431       postAudioSamplingChangeEvent(instanceId, handle, requestList.available,
432                                    suspended);
433     }
434   }
435 }
436 
postAudioSamplingChangeEvent(uint16_t instanceId,uint32_t handle,bool available,bool suspended)437 void AudioRequestManager::postAudioSamplingChangeEvent(uint16_t instanceId,
438                                                        uint32_t handle,
439                                                        bool available,
440                                                        bool suspended) {
441   auto *event = memoryAlloc<struct chreAudioSourceStatusEvent>();
442   event->handle = handle;
443   event->status.enabled = true;
444   event->status.suspended = !available || suspended;
445 
446   EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
447       CHRE_EVENT_AUDIO_SAMPLING_CHANGE, event, freeEventDataCallback,
448       instanceId);
449 }
450 
postAudioDataEventFatal(struct chreAudioDataEvent * event,const DynamicVector<uint16_t> & instanceIds)451 void AudioRequestManager::postAudioDataEventFatal(
452     struct chreAudioDataEvent *event,
453     const DynamicVector<uint16_t> &instanceIds) {
454   if (instanceIds.empty()) {
455     LOGW("Received audio data event for no clients");
456     mPlatformAudio.releaseAudioDataEvent(event);
457   } else {
458     for (const auto &instanceId : instanceIds) {
459       EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
460           CHRE_EVENT_AUDIO_DATA, event, freeAudioDataEventCallback, instanceId);
461     }
462 
463     mAudioDataEventRefCounts.emplace_back(
464         event, static_cast<uint32_t>(instanceIds.size()));
465   }
466 }
467 
handleFreeAudioDataEvent(struct chreAudioDataEvent * audioDataEvent)468 void AudioRequestManager::handleFreeAudioDataEvent(
469     struct chreAudioDataEvent *audioDataEvent) {
470   size_t audioDataEventRefCountIndex =
471       mAudioDataEventRefCounts.find(AudioDataEventRefCount(audioDataEvent));
472   if (audioDataEventRefCountIndex == mAudioDataEventRefCounts.size()) {
473     LOGE("Freeing invalid audio data event");
474   } else {
475     auto &audioDataEventRefCount =
476         mAudioDataEventRefCounts[audioDataEventRefCountIndex];
477     if (audioDataEventRefCount.refCount == 0) {
478       LOGE("Attempting to free an event with zero published events");
479     } else {
480       audioDataEventRefCount.refCount--;
481       if (audioDataEventRefCount.refCount == 0) {
482         mAudioDataEventRefCounts.erase(audioDataEventRefCountIndex);
483         mPlatformAudio.releaseAudioDataEvent(audioDataEvent);
484       }
485     }
486   }
487 }
488 
freeAudioDataEventCallback(uint16_t eventType,void * eventData)489 void AudioRequestManager::freeAudioDataEventCallback(uint16_t eventType,
490                                                      void *eventData) {
491   UNUSED_VAR(eventType);
492   auto *event = static_cast<struct chreAudioDataEvent *>(eventData);
493   EventLoopManagerSingleton::get()
494       ->getAudioRequestManager()
495       .handleFreeAudioDataEvent(event);
496 }
497 
onSettingChanged(Setting setting,bool enabled)498 void AudioRequestManager::onSettingChanged(Setting setting, bool enabled) {
499   if (setting == Setting::MICROPHONE) {
500     for (size_t i = 0; i < mAudioRequestLists.size(); ++i) {
501       uint32_t handle = static_cast<uint32_t>(i);
502       if (mAudioRequestLists[i].available) {
503         if (!enabled) {
504           LOGD("Canceling data event request for handle %" PRIu32, handle);
505           postAudioSamplingChangeEvents(handle, true /* suspended */);
506           mPlatformAudio.cancelAudioDataEventRequest(handle);
507         } else {
508           LOGD("Scheduling data event for handle %" PRIu32, handle);
509           postAudioSamplingChangeEvents(handle, false /* suspended */);
510           scheduleNextAudioDataEvent(handle);
511         }
512       }
513     }
514   }
515 }
516 
517 }  // namespace chre
518 
519 #endif  // CHRE_AUDIO_SUPPORT_ENABLED
520