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
23 /*
24 * TODO(P1-62e045): Evict pending audio events from the event queue as needed.
25 *
26 * Under the following conditions, an audio data event may be posted to the
27 * CHRE event queue when it should not be.
28 *
29 * 1. Nanoapp changes request
30 * 2. Nanoapp removes request
31 *
32 * A previously scheduled audio data event may be residing in the event queue
33 * and will be dispatched to the nanoapp after it has cancelled the request.
34 *
35 * The solution is to evict any audio events for a given audio handle that are
36 * directed to a nanoapp before scheduling the next request to the platform.
37 */
38
39 namespace chre {
40
AudioRequestManager()41 AudioRequestManager::AudioRequestManager() {
42 size_t sourceCount = mPlatformAudio.getSourceCount();
43 if (!mAudioRequestLists.reserve(sourceCount)) {
44 FATAL_ERROR_OOM();
45 }
46
47 for (size_t i = 0; i < sourceCount; i++) {
48 mAudioRequestLists.emplace_back();
49 }
50 }
51
init()52 void AudioRequestManager::init() {
53 mPlatformAudio.init();
54 }
55
configureSource(const Nanoapp * nanoapp,uint32_t handle,bool enable,uint64_t bufferDuration,uint64_t deliveryInterval)56 bool AudioRequestManager::configureSource(const Nanoapp *nanoapp,
57 uint32_t handle,
58 bool enable,
59 uint64_t bufferDuration,
60 uint64_t deliveryInterval) {
61 uint32_t numSamples;
62 bool success = validateConfigureSourceArguments(
63 handle, enable, bufferDuration, deliveryInterval, &numSamples);
64 if (success) {
65 size_t requestIndex;
66 auto *audioRequest = findAudioRequest(handle, nanoapp->getInstanceId(),
67 &requestIndex);
68 Nanoseconds nextEventTimestamp = SystemTime::getMonotonicTime()
69 + Nanoseconds(deliveryInterval);
70 size_t lastNumRequests = mAudioRequestLists[handle].requests.size();
71 if (audioRequest == nullptr) {
72 // The nanoapp is making a new request for audio data.
73 if (enable) {
74 mAudioRequestLists[handle].requests.emplace_back(
75 nanoapp->getInstanceId(), numSamples,
76 Nanoseconds(deliveryInterval), nextEventTimestamp);
77 postAudioSamplingChangeEvent(nanoapp->getInstanceId(), handle,
78 mAudioRequestLists[handle].available);
79 scheduleNextAudioDataEvent(handle);
80 } else {
81 LOGW("Nanoapp disabling nonexistent audio request");
82 }
83 } else {
84 // The nanoapp is modifying an existing request for audio.
85 if (enable) {
86 audioRequest->numSamples = numSamples;
87 audioRequest->deliveryInterval = Nanoseconds(deliveryInterval);
88 audioRequest->nextEventTimestamp = nextEventTimestamp;
89 } else {
90 mAudioRequestLists[handle].requests.erase(requestIndex);
91 }
92
93 // Note that if the next request did not change, this call is not strictly
94 // necessary. The expectation is that the platform will gracefully handle
95 // rescheduling the same request.
96 scheduleNextAudioDataEvent(handle);
97 }
98
99 size_t numRequests = mAudioRequestLists[handle].requests.size();
100 if (lastNumRequests == 0 && numRequests > 0) {
101 mPlatformAudio.setHandleEnabled(handle, true);
102 } else if (lastNumRequests > 0 && numRequests == 0) {
103 mPlatformAudio.setHandleEnabled(handle, false);
104 }
105 }
106
107 return success;
108 }
109
handleAudioDataEvent(const struct chreAudioDataEvent * audioDataEvent)110 void AudioRequestManager::handleAudioDataEvent(
111 const struct chreAudioDataEvent *audioDataEvent) {
112 auto callback = [](uint16_t /* eventType */, void *eventData) {
113 auto *event = static_cast<struct chreAudioDataEvent *>(eventData);
114 EventLoopManagerSingleton::get()->getAudioRequestManager()
115 .handleAudioDataEventSync(event);
116 };
117
118 // Cast off the event const so that it can be provided to the free callback as
119 // non-const. The event is provided to nanoapps as const and the runtime
120 // itself will not modify this memory so this is safe.
121 EventLoopManagerSingleton::get()->deferCallback(
122 SystemCallbackType::AudioHandleDataEvent,
123 const_cast<struct chreAudioDataEvent *>(audioDataEvent), callback);
124 }
125
handleAudioAvailability(uint32_t handle,bool available)126 void AudioRequestManager::handleAudioAvailability(uint32_t handle, bool available) {
127 struct CallbackState {
128 uint32_t handle;
129 bool available;
130 };
131
132 auto *cbState = memoryAlloc<CallbackState>();
133 if (cbState == nullptr) {
134 LOG_OOM();
135 } else {
136 cbState->handle = handle;
137 cbState->available = available;
138
139 auto callback = [](uint16_t /* eventType */, void *eventData) {
140 auto *state = static_cast<CallbackState *>(eventData);
141 EventLoopManagerSingleton::get()->getAudioRequestManager()
142 .handleAudioAvailabilitySync(state->handle, state->available);
143 memoryFree(state);
144 };
145
146 EventLoopManagerSingleton::get()->deferCallback(
147 SystemCallbackType::AudioAvailabilityChange, cbState, callback);
148 }
149 }
150
validateConfigureSourceArguments(uint32_t handle,bool enable,uint64_t bufferDuration,uint64_t deliveryInterval,uint32_t * numSamples)151 bool AudioRequestManager::validateConfigureSourceArguments(
152 uint32_t handle, bool enable, uint64_t bufferDuration,
153 uint64_t deliveryInterval, uint32_t *numSamples) {
154 bool success = false;
155 if (handle >= mAudioRequestLists.size()) {
156 LOGE("Provided audio handle out of range");
157 } else if (enable) {
158 chreAudioSource audioSource;
159 if (!mPlatformAudio.getAudioSource(handle, &audioSource)) {
160 LOGE("Failed to query for audio source");
161 } else if (bufferDuration > deliveryInterval) {
162 LOGE("Buffer duration must be less than or equal to delivery interval");
163 } else if (bufferDuration < audioSource.minBufferDuration
164 || bufferDuration > audioSource.maxBufferDuration) {
165 LOGE("Invalid buffer duration %" PRIu64 " not in range [%" PRIu64
166 ",%" PRIu64 "]", bufferDuration, audioSource.minBufferDuration,
167 audioSource.maxBufferDuration);
168 } else {
169 *numSamples = getSampleCountFromRateAndDuration(
170 audioSource.sampleRate, Nanoseconds(bufferDuration));
171 success = true;
172 }
173 } else {
174 // Disabling the request, no need to validate bufferDuration or
175 // deliveryInterval.
176 success = true;
177 }
178 return success;
179 }
180
findAudioRequest(uint32_t handle,uint32_t instanceId,size_t * index)181 AudioRequestManager::AudioRequest *AudioRequestManager::findAudioRequest(
182 uint32_t handle, uint32_t instanceId, size_t *index) {
183 AudioRequest *foundAudioRequest = nullptr;
184 auto& requests = mAudioRequestLists[handle].requests;
185 for (size_t i = 0; i < requests.size(); i++) {
186 auto& audioRequest = requests[i];
187 if (audioRequest.instanceId == instanceId) {
188 foundAudioRequest = &audioRequest;
189 *index = i;
190 break;
191 }
192 }
193
194 return foundAudioRequest;
195 }
196
findNextAudioRequest(uint32_t handle)197 AudioRequestManager::AudioRequest *AudioRequestManager::findNextAudioRequest(
198 uint32_t handle) {
199 Nanoseconds earliestNextEventTimestamp = Nanoseconds(UINT64_MAX);
200 AudioRequest *nextRequest = nullptr;
201
202 auto& reqList = mAudioRequestLists[handle];
203 for (auto& req : reqList.requests) {
204 if (req.nextEventTimestamp < earliestNextEventTimestamp) {
205 earliestNextEventTimestamp = req.nextEventTimestamp;
206 nextRequest = &req;
207 }
208 }
209
210 return nextRequest;
211 }
212
handleAudioDataEventSync(struct chreAudioDataEvent * event)213 void AudioRequestManager::handleAudioDataEventSync(
214 struct chreAudioDataEvent *event) {
215 uint32_t handle = event->handle;
216 if (handle < mAudioRequestLists.size()) {
217 auto& reqList = mAudioRequestLists[handle];
218 AudioRequest *nextAudioRequest = reqList.nextAudioRequest;
219
220 if (reqList.nextAudioRequest != nullptr) {
221 postAudioDataEventFatal(event, nextAudioRequest->instanceId);
222 nextAudioRequest->nextEventTimestamp = SystemTime::getMonotonicTime()
223 + nextAudioRequest->deliveryInterval;
224 reqList.nextAudioRequest = nullptr;
225 } else {
226 LOGW("Received audio data event with no pending audio request");
227 }
228
229 scheduleNextAudioDataEvent(handle);
230 } else {
231 LOGE("Audio data event handle out of range: %" PRIu32, handle);
232 }
233 }
234
handleAudioAvailabilitySync(uint32_t handle,bool available)235 void AudioRequestManager::handleAudioAvailabilitySync(uint32_t handle,
236 bool available) {
237 if (handle < mAudioRequestLists.size()) {
238 mAudioRequestLists[handle].available = available;
239 postAudioSamplingChangeEvents(handle, available);
240 scheduleNextAudioDataEvent(handle);
241 } else {
242 LOGE("Audio availability handle out of range: %" PRIu32, handle);
243 }
244 }
245
scheduleNextAudioDataEvent(uint32_t handle)246 void AudioRequestManager::scheduleNextAudioDataEvent(uint32_t handle) {
247 auto& reqList = mAudioRequestLists[handle];
248 AudioRequest *nextRequest = findNextAudioRequest(handle);
249
250 if (reqList.available && nextRequest != nullptr) {
251 Nanoseconds curTime = SystemTime::getMonotonicTime();
252 Nanoseconds eventDelay = Nanoseconds(0);
253 if (nextRequest->nextEventTimestamp > curTime) {
254 eventDelay = nextRequest->nextEventTimestamp - curTime;
255 }
256 reqList.nextAudioRequest = nextRequest;
257 mPlatformAudio.requestAudioDataEvent(
258 handle, nextRequest->numSamples, eventDelay);
259 } else {
260 mPlatformAudio.cancelAudioDataEventRequest(handle);
261 }
262 }
263
postAudioSamplingChangeEvents(uint32_t handle,bool available)264 void AudioRequestManager::postAudioSamplingChangeEvents(uint32_t handle,
265 bool available) {
266 for (const auto& request : mAudioRequestLists[handle].requests) {
267 postAudioSamplingChangeEvent(request.instanceId, handle, available);
268 }
269 }
270
postAudioSamplingChangeEvent(uint32_t instanceId,uint32_t handle,bool available)271 void AudioRequestManager::postAudioSamplingChangeEvent(uint32_t instanceId,
272 uint32_t handle,
273 bool available) {
274 auto *event = memoryAlloc<struct chreAudioSourceStatusEvent>();
275 event->handle = handle;
276 event->status.enabled = true;
277 event->status.suspended = !available;
278
279 EventLoopManagerSingleton::get()->getEventLoop()
280 .postEvent(CHRE_EVENT_AUDIO_SAMPLING_CHANGE, event,
281 freeEventDataCallback, kSystemInstanceId, instanceId);
282 }
283
postAudioDataEventFatal(struct chreAudioDataEvent * event,uint32_t instanceId)284 void AudioRequestManager::postAudioDataEventFatal(
285 struct chreAudioDataEvent *event, uint32_t instanceId) {
286 EventLoopManagerSingleton::get()->getEventLoop()
287 .postEvent(CHRE_EVENT_AUDIO_DATA, event,
288 freeAudioDataEventCallback,
289 kSystemInstanceId, instanceId);
290 }
291
handleFreeAudioDataEvent(struct chreAudioDataEvent * audioDataEvent)292 void AudioRequestManager::handleFreeAudioDataEvent(
293 struct chreAudioDataEvent *audioDataEvent) {
294 mPlatformAudio.releaseAudioDataEvent(audioDataEvent);
295 }
296
freeAudioDataEventCallback(uint16_t eventType,void * eventData)297 void AudioRequestManager::freeAudioDataEventCallback(uint16_t eventType,
298 void *eventData) {
299 auto *event = static_cast<struct chreAudioDataEvent *>(eventData);
300 EventLoopManagerSingleton::get()->getAudioRequestManager()
301 .handleFreeAudioDataEvent(event);
302 }
303
304 } // namespace chre
305