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