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/event_loop_manager.h"
20 #include "chre/platform/fatal_error.h"
21 #include "chre/platform/system_time.h"
22 #include "chre/util/system/debug_dump.h"
23 
24 /*
25  * TODO(P1-62e045): Evict pending audio events from the event queue as needed.
26  *
27  * Under the following conditions, an audio data event may be posted to the
28  * CHRE event queue when it should not be.
29  *
30  * 1. Nanoapp changes request
31  * 2. Nanoapp removes request
32  *
33  * A previously scheduled audio data event may be residing in the event queue
34  * and will be dispatched to the nanoapp after it has cancelled the request.
35  *
36  * The solution is to evict any audio events for a given audio handle that are
37  * directed to a nanoapp before scheduling the next request to the platform.
38  */
39 
40 namespace chre {
41 
42 void AudioRequestManager::init() {
43   mPlatformAudio.init();
44 
45   size_t sourceCount = mPlatformAudio.getSourceCount();
46   if (!mAudioRequestLists.reserve(sourceCount)) {
47     FATAL_ERROR_OOM();
48   }
49 
50   for (size_t i = 0; i < sourceCount; i++) {
51     mAudioRequestLists.emplace_back();
52   }
53 }
54 
55 bool AudioRequestManager::configureSource(const Nanoapp *nanoapp,
56                                           uint32_t handle, bool enable,
57                                           uint64_t bufferDuration,
58                                           uint64_t deliveryInterval) {
59   uint32_t numSamples;
60   return validateConfigureSourceArguments(handle, enable, bufferDuration,
61                                           deliveryInterval, &numSamples) &&
62          doConfigureSource(nanoapp->getInstanceId(), handle, enable, numSamples,
63                            Nanoseconds(deliveryInterval));
64 }
65 
66 void AudioRequestManager::handleAudioDataEvent(
67     const struct chreAudioDataEvent *audioDataEvent) {
68   uint32_t handle = audioDataEvent->handle;
69   if (handle >= mAudioRequestLists.size()) {
70     LOGE("Received audio event for unknown handle %" PRIu32, handle);
71   } else {
72     mAudioRequestLists[handle].lastEventTimestamp =
73         SystemTime::getMonotonicTime();
74   }
75 
76   auto callback = [](uint16_t /* eventType */, void *eventData) {
77     auto *event = static_cast<struct chreAudioDataEvent *>(eventData);
78     EventLoopManagerSingleton::get()
79         ->getAudioRequestManager()
80         .handleAudioDataEventSync(event);
81   };
82 
83   // Cast off the event const so that it can be provided to the free callback as
84   // non-const. The event is provided to nanoapps as const and the runtime
85   // itself will not modify this memory so this is safe.
86   EventLoopManagerSingleton::get()->deferCallback(
87       SystemCallbackType::AudioHandleDataEvent,
88       const_cast<struct chreAudioDataEvent *>(audioDataEvent), callback);
89 }
90 
91 void AudioRequestManager::handleAudioAvailability(uint32_t handle,
92                                                   bool available) {
93   struct CallbackState {
94     uint32_t handle;
95     bool available;
96   };
97 
98   auto *cbState = memoryAlloc<CallbackState>();
99   if (cbState == nullptr) {
100     LOG_OOM();
101   } else {
102     cbState->handle = handle;
103     cbState->available = available;
104 
105     auto callback = [](uint16_t /* eventType */, void *eventData) {
106       auto *state = static_cast<CallbackState *>(eventData);
107       EventLoopManagerSingleton::get()
108           ->getAudioRequestManager()
109           .handleAudioAvailabilitySync(state->handle, state->available);
110       memoryFree(state);
111     };
112 
113     EventLoopManagerSingleton::get()->deferCallback(
114         SystemCallbackType::AudioAvailabilityChange, cbState, callback);
115   }
116 }
117 
118 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=%" PRIu32 ", numSamples=%" PRIu32
140                         ", interval(ms)=%" PRIu64 "\n",
141                         instanceId, request.numSamples,
142                         Milliseconds(Nanoseconds(request.deliveryInterval))
143                             .getMilliseconds());
144       }
145     }
146   }
147 }
148 
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 = 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 
180 bool AudioRequestManager::doConfigureSource(uint32_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 request
212     // must be created successfully.
213     success = (!enable || createAudioRequest(handle, instanceId, numSamples,
214                                              deliveryInterval));
215   }
216 
217   if (success) {
218     scheduleNextAudioDataEvent(handle);
219     updatePlatformHandleEnabled(handle, lastNumRequests);
220   }
221 
222   return success;
223 }
224 
225 void AudioRequestManager::updatePlatformHandleEnabled(uint32_t handle,
226                                                       size_t lastNumRequests) {
227   size_t numRequests = mAudioRequestLists[handle].requests.size();
228   if (lastNumRequests == 0 && numRequests > 0) {
229     mPlatformAudio.setHandleEnabled(handle, true /* enabled */);
230   } else if (lastNumRequests > 0 && numRequests == 0) {
231     mPlatformAudio.setHandleEnabled(handle, false /* enabled */);
232   }
233 }
234 
235 bool AudioRequestManager::createAudioRequest(uint32_t handle,
236                                              uint32_t instanceId,
237                                              uint32_t numSamples,
238                                              Nanoseconds deliveryInterval) {
239   AudioRequestList &requestList = mAudioRequestLists[handle];
240 
241   size_t matchingRequestIndex;
242   auto *matchingAudioRequest = findAudioRequestByConfiguration(
243       handle, numSamples, deliveryInterval, &matchingRequestIndex);
244 
245   bool success = false;
246   if (matchingAudioRequest != nullptr) {
247     if (!matchingAudioRequest->instanceIds.push_back(instanceId)) {
248       LOG_OOM();
249     } else {
250       success = true;
251     }
252   } else {
253     Nanoseconds timeNow = SystemTime::getMonotonicTime();
254     Nanoseconds nextEventTimestamp = timeNow + deliveryInterval;
255     if (!requestList.requests.emplace_back(numSamples, deliveryInterval,
256                                            nextEventTimestamp)) {
257       LOG_OOM();
258     } else if (!requestList.requests.back().instanceIds.push_back(instanceId)) {
259       requestList.requests.pop_back();
260       LOG_OOM();
261     } else {
262       success = true;
263     }
264   }
265 
266   if (success) {
267     postAudioSamplingChangeEvent(instanceId, handle, requestList.available);
268   }
269 
270   return success;
271 }
272 
273 AudioRequestManager::AudioRequest *
274 AudioRequestManager::findAudioRequestByInstanceId(uint32_t handle,
275                                                   uint32_t instanceId,
276                                                   size_t *index,
277                                                   size_t *instanceIdIndex) {
278   AudioRequest *foundAudioRequest = nullptr;
279   auto &requests = mAudioRequestLists[handle].requests;
280   for (size_t i = 0; i < requests.size(); i++) {
281     auto &audioRequest = requests[i];
282     size_t foundInstanceIdIndex = audioRequest.instanceIds.find(instanceId);
283     if (foundInstanceIdIndex != audioRequest.instanceIds.size()) {
284       foundAudioRequest = &audioRequest;
285       *index = i;
286       *instanceIdIndex = foundInstanceIdIndex;
287       break;
288     }
289   }
290 
291   return foundAudioRequest;
292 }
293 
294 AudioRequestManager::AudioRequest *
295 AudioRequestManager::findAudioRequestByConfiguration(
296     uint32_t handle, uint32_t numSamples, Nanoseconds deliveryInterval,
297     size_t *index) {
298   AudioRequest *foundAudioRequest = nullptr;
299   auto &requests = mAudioRequestLists[handle].requests;
300   for (size_t i = 0; i < requests.size(); i++) {
301     auto &audioRequest = requests[i];
302     if (audioRequest.numSamples == numSamples &&
303         audioRequest.deliveryInterval == deliveryInterval) {
304       foundAudioRequest = &audioRequest;
305       *index = i;
306       break;
307     }
308   }
309 
310   return foundAudioRequest;
311 }
312 
313 AudioRequestManager::AudioRequest *AudioRequestManager::findNextAudioRequest(
314     uint32_t handle) {
315   Nanoseconds earliestNextEventTimestamp = Nanoseconds(UINT64_MAX);
316   AudioRequest *nextRequest = nullptr;
317 
318   auto &reqList = mAudioRequestLists[handle];
319   for (auto &req : reqList.requests) {
320     if (req.nextEventTimestamp < earliestNextEventTimestamp) {
321       earliestNextEventTimestamp = req.nextEventTimestamp;
322       nextRequest = &req;
323     }
324   }
325 
326   return nextRequest;
327 }
328 
329 void AudioRequestManager::handleAudioDataEventSync(
330     struct chreAudioDataEvent *event) {
331   uint32_t handle = event->handle;
332   if (handle < mAudioRequestLists.size()) {
333     auto &reqList = mAudioRequestLists[handle];
334     AudioRequest *nextAudioRequest = reqList.nextAudioRequest;
335     if (nextAudioRequest != nullptr) {
336       postAudioDataEventFatal(event, nextAudioRequest->instanceIds);
337       nextAudioRequest->nextEventTimestamp =
338           SystemTime::getMonotonicTime() + nextAudioRequest->deliveryInterval;
339     } else {
340       LOGW("Received audio data event with no pending audio request");
341       mPlatformAudio.releaseAudioDataEvent(event);
342     }
343 
344     scheduleNextAudioDataEvent(handle);
345   } else {
346     LOGE("Audio data event handle out of range: %" PRIu32, handle);
347   }
348 }
349 
350 void AudioRequestManager::handleAudioAvailabilitySync(uint32_t handle,
351                                                       bool available) {
352   if (handle < mAudioRequestLists.size()) {
353     if (mAudioRequestLists[handle].available != available) {
354       mAudioRequestLists[handle].available = available;
355       postAudioSamplingChangeEvents(handle);
356     }
357 
358     scheduleNextAudioDataEvent(handle);
359   } else {
360     LOGE("Audio availability handle out of range: %" PRIu32, handle);
361   }
362 }
363 
364 void AudioRequestManager::scheduleNextAudioDataEvent(uint32_t handle) {
365   auto &reqList = mAudioRequestLists[handle];
366   AudioRequest *nextRequest = findNextAudioRequest(handle);
367 
368   // Clear the next request and it will be reset below if needed.
369   reqList.nextAudioRequest = nullptr;
370   if (reqList.available && nextRequest != nullptr) {
371     Nanoseconds curTime = SystemTime::getMonotonicTime();
372     Nanoseconds eventDelay = Nanoseconds(0);
373     if (nextRequest->nextEventTimestamp > curTime) {
374       eventDelay = nextRequest->nextEventTimestamp - curTime;
375     }
376     reqList.nextAudioRequest = nextRequest;
377     mPlatformAudio.requestAudioDataEvent(handle, nextRequest->numSamples,
378                                          eventDelay);
379   } else {
380     mPlatformAudio.cancelAudioDataEventRequest(handle);
381   }
382 }
383 
384 void AudioRequestManager::postAudioSamplingChangeEvents(uint32_t handle) {
385   const auto &requestList = mAudioRequestLists[handle];
386   for (const auto &request : requestList.requests) {
387     for (const auto &instanceId : request.instanceIds) {
388       postAudioSamplingChangeEvent(instanceId, handle, requestList.available);
389     }
390   }
391 }
392 
393 void AudioRequestManager::postAudioSamplingChangeEvent(uint32_t instanceId,
394                                                        uint32_t handle,
395                                                        bool available) {
396   auto *event = memoryAlloc<struct chreAudioSourceStatusEvent>();
397   event->handle = handle;
398   event->status.enabled = true;
399   event->status.suspended = !available;
400 
401   EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
402       CHRE_EVENT_AUDIO_SAMPLING_CHANGE, event, freeEventDataCallback,
403       instanceId);
404 }
405 
406 void AudioRequestManager::postAudioDataEventFatal(
407     struct chreAudioDataEvent *event,
408     const DynamicVector<uint32_t> &instanceIds) {
409   if (instanceIds.empty()) {
410     LOGW("Received audio data event for no clients");
411     mPlatformAudio.releaseAudioDataEvent(event);
412   } else {
413     for (const auto &instanceId : instanceIds) {
414       EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
415           CHRE_EVENT_AUDIO_DATA, event, freeAudioDataEventCallback, instanceId);
416     }
417 
418     mAudioDataEventRefCounts.emplace_back(
419         event, static_cast<uint32_t>(instanceIds.size()));
420   }
421 }
422 
423 void AudioRequestManager::handleFreeAudioDataEvent(
424     struct chreAudioDataEvent *audioDataEvent) {
425   size_t audioDataEventRefCountIndex =
426       mAudioDataEventRefCounts.find(AudioDataEventRefCount(audioDataEvent));
427   if (audioDataEventRefCountIndex == mAudioDataEventRefCounts.size()) {
428     LOGE("Freeing invalid audio data event");
429   } else {
430     auto &audioDataEventRefCount =
431         mAudioDataEventRefCounts[audioDataEventRefCountIndex];
432     if (audioDataEventRefCount.refCount == 0) {
433       LOGE("Attempting to free an event with zero published events");
434     } else {
435       audioDataEventRefCount.refCount--;
436       if (audioDataEventRefCount.refCount == 0) {
437         mAudioDataEventRefCounts.erase(audioDataEventRefCountIndex);
438         mPlatformAudio.releaseAudioDataEvent(audioDataEvent);
439       }
440     }
441   }
442 }
443 
444 void AudioRequestManager::freeAudioDataEventCallback(uint16_t eventType,
445                                                      void *eventData) {
446   auto *event = static_cast<struct chreAudioDataEvent *>(eventData);
447   EventLoopManagerSingleton::get()
448       ->getAudioRequestManager()
449       .handleFreeAudioDataEvent(event);
450 }
451 
452 }  // namespace chre
453