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