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