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