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