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