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