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 
init()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 
configureSource(const Nanoapp * nanoapp,uint32_t handle,bool enable,uint64_t bufferDuration,uint64_t deliveryInterval)55 bool AudioRequestManager::configureSource(const Nanoapp *nanoapp,
56                                           uint32_t handle,
57                                           bool enable,
58                                           uint64_t bufferDuration,
59                                           uint64_t deliveryInterval) {
60   uint32_t numSamples;
61   return validateConfigureSourceArguments(handle, enable, bufferDuration,
62                                           deliveryInterval, &numSamples)
63       && doConfigureSource(nanoapp->getInstanceId(), handle, enable, numSamples,
64                            Nanoseconds(deliveryInterval));
65 }
66 
handleAudioDataEvent(const struct chreAudioDataEvent * audioDataEvent)67 void AudioRequestManager::handleAudioDataEvent(
68     const struct chreAudioDataEvent *audioDataEvent) {
69   uint32_t handle = audioDataEvent->handle;
70   if (handle >= mAudioRequestLists.size()) {
71     LOGE("Received audio event for unknown handle %" PRIu32, handle);
72   } else {
73     mAudioRequestLists[handle].lastEventTimestamp
74         = SystemTime::getMonotonicTime();
75   }
76 
77   auto callback = [](uint16_t /* eventType */, void *eventData) {
78     auto *event = static_cast<struct chreAudioDataEvent *>(eventData);
79     EventLoopManagerSingleton::get()->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 
handleAudioAvailability(uint32_t handle,bool available)91 void AudioRequestManager::handleAudioAvailability(uint32_t handle, bool available) {
92   struct CallbackState {
93     uint32_t handle;
94     bool available;
95   };
96 
97   auto *cbState = memoryAlloc<CallbackState>();
98   if (cbState == nullptr) {
99     LOG_OOM();
100   } else {
101     cbState->handle = handle;
102     cbState->available = available;
103 
104     auto callback = [](uint16_t /* eventType */, void *eventData) {
105       auto *state = static_cast<CallbackState *>(eventData);
106       EventLoopManagerSingleton::get()->getAudioRequestManager()
107           .handleAudioAvailabilitySync(state->handle, state->available);
108       memoryFree(state);
109     };
110 
111     EventLoopManagerSingleton::get()->deferCallback(
112         SystemCallbackType::AudioAvailabilityChange, cbState, callback);
113   }
114 }
115 
logStateToBuffer(char * buffer,size_t * bufferPos,size_t bufferSize) const116 void AudioRequestManager::logStateToBuffer(char *buffer, size_t *bufferPos,
117                                            size_t bufferSize) const {
118   debugDumpPrint(buffer, bufferPos, bufferSize, "\nAudio:\n");
119   for (size_t i = 0; i < mAudioRequestLists.size(); i++) {
120     uint32_t handle = static_cast<uint32_t>(i);
121     struct chreAudioSource source;
122     mPlatformAudio.getAudioSource(handle, &source);
123 
124     Nanoseconds timeSinceLastAudioEvent = SystemTime::getMonotonicTime()
125         - mAudioRequestLists[i].lastEventTimestamp;
126     debugDumpPrint(buffer, bufferPos, bufferSize,
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         debugDumpPrint(buffer, bufferPos, bufferSize,
138             "  nanoappId=%" PRIu32 ", numSamples=%" PRIu32
139             ", interval(ms)=%" PRIu64 "\n", 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 "]", bufferDuration, audioSource.minBufferDuration,
163            audioSource.maxBufferDuration);
164     } else {
165       *numSamples = getSampleCountFromRateAndDuration(
166           audioSource.sampleRate, Nanoseconds(bufferDuration));
167       success = true;
168     }
169   } else {
170     // Disabling the request, no need to validate bufferDuration or
171     // deliveryInterval.
172     success = true;
173   }
174   return success;
175 }
176 
doConfigureSource(uint32_t instanceId,uint32_t handle,bool enable,uint32_t numSamples,Nanoseconds deliveryInterval)177 bool AudioRequestManager::doConfigureSource(
178     uint32_t instanceId, uint32_t handle, bool enable, uint32_t numSamples,
179     Nanoseconds deliveryInterval) {
180   size_t requestIndex;
181   size_t requestInstanceIdIndex;
182   auto *audioRequest = findAudioRequestByInstanceId(
183       handle, instanceId, &requestIndex, &requestInstanceIdIndex);
184 
185   AudioRequestList& requestList = mAudioRequestLists[handle];
186   size_t lastNumRequests = requestList.requests.size();
187 
188   bool success = false;
189   if (audioRequest == nullptr) {
190     if (enable) {
191       success = createAudioRequest(handle, instanceId, numSamples,
192                                    deliveryInterval);
193     } else {
194       LOGW("Nanoapp disabling nonexistent audio request");
195     }
196   } else {
197     if (audioRequest->instanceIds.size() > 1) {
198       // If there are other clients listening in this configuration, remove
199       // just the instance ID.
200       audioRequest->instanceIds.erase(requestInstanceIdIndex);
201     } else {
202       // If this is the last client listening in this configuration, remove
203       // the entire request.
204       requestList.requests.erase(requestIndex);
205     }
206 
207     // If the client is disabling, there is nothing to do, otherwise a request
208     // must be created successfully.
209     success = (!enable || createAudioRequest(handle, instanceId, numSamples,
210                                              deliveryInterval));
211   }
212 
213   if (success) {
214     scheduleNextAudioDataEvent(handle);
215     updatePlatformHandleEnabled(handle, lastNumRequests);
216   }
217 
218   return success;
219 }
220 
updatePlatformHandleEnabled(uint32_t handle,size_t lastNumRequests)221 void AudioRequestManager::updatePlatformHandleEnabled(
222     uint32_t handle, size_t lastNumRequests) {
223   size_t numRequests = mAudioRequestLists[handle].requests.size();
224   if (lastNumRequests == 0 && numRequests > 0) {
225     mPlatformAudio.setHandleEnabled(handle, true /* enabled */);
226   } else if (lastNumRequests > 0 && numRequests == 0) {
227     mPlatformAudio.setHandleEnabled(handle, false /* enabled */);
228   }
229 }
230 
createAudioRequest(uint32_t handle,uint32_t instanceId,uint32_t numSamples,Nanoseconds deliveryInterval)231 bool AudioRequestManager::createAudioRequest(
232     uint32_t handle, uint32_t instanceId, uint32_t numSamples,
233     Nanoseconds deliveryInterval) {
234   AudioRequestList& requestList = mAudioRequestLists[handle];
235 
236   size_t matchingRequestIndex;
237   auto *matchingAudioRequest = findAudioRequestByConfiguration(
238       handle, numSamples, deliveryInterval, &matchingRequestIndex);
239 
240   bool success = false;
241   if (matchingAudioRequest != nullptr) {
242     if (!matchingAudioRequest->instanceIds.push_back(instanceId)) {
243       LOG_OOM();
244     } else {
245       success = true;
246     }
247   } else {
248     Nanoseconds timeNow = SystemTime::getMonotonicTime();
249     Nanoseconds nextEventTimestamp = timeNow + deliveryInterval;
250     if (!requestList.requests.emplace_back(numSamples, deliveryInterval,
251                                            nextEventTimestamp)) {
252       LOG_OOM();
253     } else if (!requestList.requests.back().instanceIds.push_back(instanceId)) {
254       requestList.requests.pop_back();
255       LOG_OOM();
256     } else {
257       success = true;
258     }
259   }
260 
261   if (success) {
262     postAudioSamplingChangeEvent(instanceId, handle, requestList.available);
263   }
264 
265   return success;
266 }
267 
268 AudioRequestManager::AudioRequest *AudioRequestManager::
findAudioRequestByInstanceId(uint32_t handle,uint32_t instanceId,size_t * index,size_t * instanceIdIndex)269     findAudioRequestByInstanceId(
270         uint32_t handle, uint32_t instanceId, size_t *index,
271         size_t *instanceIdIndex) {
272   AudioRequest *foundAudioRequest = nullptr;
273   auto& requests = mAudioRequestLists[handle].requests;
274   for (size_t i = 0; i < requests.size(); i++) {
275     auto& audioRequest = requests[i];
276     size_t foundInstanceIdIndex = audioRequest.instanceIds.find(instanceId);
277     if (foundInstanceIdIndex != audioRequest.instanceIds.size()) {
278       foundAudioRequest = &audioRequest;
279       *index = i;
280       *instanceIdIndex = foundInstanceIdIndex;
281       break;
282     }
283   }
284 
285   return foundAudioRequest;
286 }
287 
288 AudioRequestManager::AudioRequest *AudioRequestManager::
findAudioRequestByConfiguration(uint32_t handle,uint32_t numSamples,Nanoseconds deliveryInterval,size_t * index)289     findAudioRequestByConfiguration(
290         uint32_t handle, uint32_t numSamples, Nanoseconds deliveryInterval,
291         size_t *index) {
292   AudioRequest *foundAudioRequest = nullptr;
293   auto& requests = mAudioRequestLists[handle].requests;
294   for (size_t i = 0; i < requests.size(); i++) {
295     auto& audioRequest = requests[i];
296     if (audioRequest.numSamples == numSamples
297         && audioRequest.deliveryInterval == deliveryInterval) {
298       foundAudioRequest = &audioRequest;
299       *index = i;
300       break;
301     }
302   }
303 
304   return foundAudioRequest;
305 }
306 
findNextAudioRequest(uint32_t handle)307 AudioRequestManager::AudioRequest *AudioRequestManager::findNextAudioRequest(
308     uint32_t handle) {
309   Nanoseconds earliestNextEventTimestamp = Nanoseconds(UINT64_MAX);
310   AudioRequest *nextRequest = nullptr;
311 
312   auto& reqList = mAudioRequestLists[handle];
313   for (auto& req : reqList.requests) {
314     if (req.nextEventTimestamp < earliestNextEventTimestamp) {
315       earliestNextEventTimestamp = req.nextEventTimestamp;
316       nextRequest = &req;
317     }
318   }
319 
320   return nextRequest;
321 }
322 
handleAudioDataEventSync(struct chreAudioDataEvent * event)323 void AudioRequestManager::handleAudioDataEventSync(
324     struct chreAudioDataEvent *event) {
325   uint32_t handle = event->handle;
326   if (handle < mAudioRequestLists.size()) {
327     auto& reqList = mAudioRequestLists[handle];
328     AudioRequest *nextAudioRequest = reqList.nextAudioRequest;
329     if (nextAudioRequest != nullptr) {
330       postAudioDataEventFatal(event, nextAudioRequest->instanceIds);
331       nextAudioRequest->nextEventTimestamp = SystemTime::getMonotonicTime()
332           + nextAudioRequest->deliveryInterval;
333     } else {
334       LOGW("Received audio data event with no pending audio request");
335       mPlatformAudio.releaseAudioDataEvent(event);
336     }
337 
338     scheduleNextAudioDataEvent(handle);
339   } else {
340     LOGE("Audio data event handle out of range: %" PRIu32, handle);
341   }
342 }
343 
handleAudioAvailabilitySync(uint32_t handle,bool available)344 void AudioRequestManager::handleAudioAvailabilitySync(uint32_t handle,
345                                                       bool available) {
346   if (handle < mAudioRequestLists.size()) {
347     if (mAudioRequestLists[handle].available != available) {
348       mAudioRequestLists[handle].available = available;
349       postAudioSamplingChangeEvents(handle);
350     }
351 
352     scheduleNextAudioDataEvent(handle);
353   } else {
354     LOGE("Audio availability handle out of range: %" PRIu32, handle);
355   }
356 }
357 
scheduleNextAudioDataEvent(uint32_t handle)358 void AudioRequestManager::scheduleNextAudioDataEvent(uint32_t handle) {
359   auto& reqList = mAudioRequestLists[handle];
360   AudioRequest *nextRequest = findNextAudioRequest(handle);
361 
362   // Clear the next request and it will be reset below if needed.
363   reqList.nextAudioRequest = nullptr;
364   if (reqList.available && nextRequest != nullptr) {
365     Nanoseconds curTime = SystemTime::getMonotonicTime();
366     Nanoseconds eventDelay = Nanoseconds(0);
367     if (nextRequest->nextEventTimestamp > curTime) {
368       eventDelay = nextRequest->nextEventTimestamp - curTime;
369     }
370     reqList.nextAudioRequest = nextRequest;
371     mPlatformAudio.requestAudioDataEvent(
372         handle, nextRequest->numSamples, eventDelay);
373   } else {
374     mPlatformAudio.cancelAudioDataEventRequest(handle);
375   }
376 }
377 
postAudioSamplingChangeEvents(uint32_t handle)378 void AudioRequestManager::postAudioSamplingChangeEvents(uint32_t handle) {
379   const auto& requestList = mAudioRequestLists[handle];
380   for (const auto& request : requestList.requests) {
381     for (const auto& instanceId : request.instanceIds) {
382       postAudioSamplingChangeEvent(instanceId, handle, requestList.available);
383     }
384   }
385 }
386 
postAudioSamplingChangeEvent(uint32_t instanceId,uint32_t handle,bool available)387 void AudioRequestManager::postAudioSamplingChangeEvent(uint32_t instanceId,
388                                                        uint32_t handle,
389                                                        bool available) {
390   auto *event = memoryAlloc<struct chreAudioSourceStatusEvent>();
391   event->handle = handle;
392   event->status.enabled = true;
393   event->status.suspended = !available;
394 
395   EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
396       CHRE_EVENT_AUDIO_SAMPLING_CHANGE, event, freeEventDataCallback,
397       instanceId);
398 }
399 
postAudioDataEventFatal(struct chreAudioDataEvent * event,const DynamicVector<uint32_t> & instanceIds)400 void AudioRequestManager::postAudioDataEventFatal(
401     struct chreAudioDataEvent *event,
402     const DynamicVector<uint32_t>& instanceIds) {
403   if (instanceIds.empty()) {
404     LOGW("Received audio data event for no clients");
405     mPlatformAudio.releaseAudioDataEvent(event);
406   } else {
407     for (const auto &instanceId : instanceIds) {
408       EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
409           CHRE_EVENT_AUDIO_DATA, event, freeAudioDataEventCallback, instanceId);
410     }
411 
412     mAudioDataEventRefCounts.emplace_back(
413         event, static_cast<uint32_t>(instanceIds.size()));
414   }
415 }
416 
handleFreeAudioDataEvent(struct chreAudioDataEvent * audioDataEvent)417 void AudioRequestManager::handleFreeAudioDataEvent(
418     struct chreAudioDataEvent *audioDataEvent) {
419   size_t audioDataEventRefCountIndex =
420       mAudioDataEventRefCounts.find(AudioDataEventRefCount(audioDataEvent));
421   if (audioDataEventRefCountIndex == mAudioDataEventRefCounts.size()) {
422     LOGE("Freeing invalid audio data event");
423   } else {
424     auto& audioDataEventRefCount =
425         mAudioDataEventRefCounts[audioDataEventRefCountIndex];
426     if (audioDataEventRefCount.refCount == 0) {
427       LOGE("Attempting to free an event with zero published events");
428     } else {
429       audioDataEventRefCount.refCount--;
430       if (audioDataEventRefCount.refCount == 0) {
431         mAudioDataEventRefCounts.erase(audioDataEventRefCountIndex);
432         mPlatformAudio.releaseAudioDataEvent(audioDataEvent);
433       }
434     }
435   }
436 }
437 
freeAudioDataEventCallback(uint16_t eventType,void * eventData)438 void AudioRequestManager::freeAudioDataEventCallback(uint16_t eventType,
439                                                      void *eventData) {
440   auto *event = static_cast<struct chreAudioDataEvent *>(eventData);
441   EventLoopManagerSingleton::get()->getAudioRequestManager()
442       .handleFreeAudioDataEvent(event);
443 }
444 
445 }  // namespace chre
446