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