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