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 
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 
52 void AudioRequestManager::init() {
53   mPlatformAudio.init();
54 }
55 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
292 void AudioRequestManager::handleFreeAudioDataEvent(
293     struct chreAudioDataEvent *audioDataEvent) {
294   mPlatformAudio.releaseAudioDataEvent(audioDataEvent);
295 }
296 
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