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 #ifndef CHRE_CORE_AUDIO_REQUEST_MANAGER_H_
18 #define CHRE_CORE_AUDIO_REQUEST_MANAGER_H_
19 
20 #include <cstdint>
21 
22 #include "chre/core/nanoapp.h"
23 #include "chre/core/settings.h"
24 #include "chre/platform/platform_audio.h"
25 #include "chre/util/dynamic_vector.h"
26 #include "chre/util/non_copyable.h"
27 #include "chre_api/chre/audio.h"
28 
29 namespace chre {
30 
31 /**
32  * Manages requests for audio resources from nanoapps and multiplexes these
33  * requests into the platform-specific implementation of the audio subsystem.
34  */
35 class AudioRequestManager : public NonCopyable {
36  public:
37   /**
38    * Initializes the platform-specific audio module. Must be called prior to
39    * invoking any other methods in this class.
40    *
41    * Sets up the initial condition for the audio request manager including
42    * initial allocation of requests managers.
43    */
44   void init();
45 
46   /**
47    * Obtains an audio source from the platform audio implementation.
48    *
49    * @param handle The audio source to query for.
50    * @param audioSource The audio source to populate with the details of this
51    *        handle, if found.
52    * @return true if the query was successful.
53    */
getAudioSource(uint32_t handle,struct chreAudioSource * audioSource)54   bool getAudioSource(uint32_t handle, struct chreAudioSource *audioSource) {
55     return mPlatformAudio.getAudioSource(handle, audioSource);
56   }
57 
58   /**
59    * Updates the current request for audio from a nanoapp for a given audio
60    * source.
61    *
62    * @param nanoapp A non-null pointer to the nanoapp requesting this change.
63    * @param handle The audio source handle for which this request is directed
64    *        toward.
65    * @param enable true if enabling the source, false if disabling.
66    * @param bufferDuration The amount of data to deliver to the nanoapp.
67    * @param deliveryInterval How frequently to deliver this data.
68    * @return true if the request was successful, false otherwise. When enabling,
69    *         the bufferDuration must be less than or equal to deliveryInterval.
70    *
71    * @see chreAudioConfigureSource()
72    */
73   bool configureSource(const Nanoapp *nanoapp, uint32_t handle, bool enable,
74                        uint64_t bufferDuration, uint64_t deliveryInterval);
75 
76   /**
77    * Handles a new batch of audio from the PlatformAudio interface.
78    *
79    * @param event The audio data event provided to the audio request manager.
80    *        Ownership of this event is transferred to the CHRE runtime until it
81    *        is released via the PlatformAudio::releaseAudioDataEvent platform
82    *        API.
83    */
84   void handleAudioDataEvent(const struct chreAudioDataEvent *event);
85 
86   /**
87    * Handles events from the platform related to whether or not audio is
88    * available.
89    *
90    * @param handle The handle for which audio data availability has changed.
91    * @param available true if requests for audio data will be processed and
92    *        data events posted, false otherwise.
93    */
94   void handleAudioAvailability(uint32_t handle, bool available);
95 
96   /**
97    * Prints state in a string buffer. Must only be called from the context of
98    * the main CHRE thread.
99    *
100    * @param debugDump The debug dump wrapper where a string can be printed
101    *     into one of the buffers.
102    */
103   void logStateToBuffer(DebugDumpWrapper &debugDump) const;
104 
105   /**
106    * Invoked when the host notifies CHRE that microphone access has been
107    * disabled via the user settings.
108    *
109    * @param setting The setting that changed.
110    * @param state The new setting state.
111    */
112   void onSettingChanged(Setting setting, SettingState state);
113 
114   /**
115    * @return the instance of platform audio to allow platform-specific
116    * funtionality to call it. Example: handling host awake events.
117    */
getPlatformAudio()118   PlatformAudio &getPlatformAudio() {
119     return mPlatformAudio;
120   }
121 
122  private:
123   /**
124    * One instance of an audio request from a nanoapp.
125    */
126   struct AudioRequest {
AudioRequestAudioRequest127     AudioRequest(uint32_t numSamples, Nanoseconds deliveryInterval,
128                  Nanoseconds nextEventTimestamp)
129         : numSamples(numSamples),
130           deliveryInterval(deliveryInterval),
131           nextEventTimestamp(nextEventTimestamp) {}
132 
133     //! The nanoapp instance IDs that own this request.
134     DynamicVector<uint32_t> instanceIds;
135 
136     //! The number of samples requested for this request.
137     uint32_t numSamples;
138 
139     //! The delivery interval for this request.
140     Nanoseconds deliveryInterval;
141 
142     //! The expected timestamp of the next event delivery.
143     Nanoseconds nextEventTimestamp;
144   };
145 
146   /**
147    * A list of audio requests for a given source. Note that each nanoapp may
148    * have at most one open request for a given source. When the source is
149    * disabled it is removed from this list.
150    */
151   struct AudioRequestList {
152     //! Whether or not the source is available. It is unavailable by default.
153     bool available = false;
154 
155     //! The timestamp when the last audio data event was received.
156     Nanoseconds lastEventTimestamp;
157 
158     //! The request to post the next event to.
159     AudioRequest *nextAudioRequest = nullptr;
160 
161     //! The list of requests for this source that are currently open.
162     DynamicVector<AudioRequest> requests;
163   };
164 
165   /**
166    * Keep track of the number of times an audio data event is published to a
167    * nanoapp.
168    *
169    * TODO: Add support for multicast events to the core event loop to avoid this
170    * kind of logic from appearing in the AudioRequestManager.
171    */
172   struct AudioDataEventRefCount {
173     /**
174      * Constructs an AudioDataEventRefCount object with an uninitialized
175      * refCount to allow searching in a list using the equality comparison
176      * below.
177      *
178      * @param event The event that this object tracks.
179      */
AudioDataEventRefCountAudioDataEventRefCount180     explicit AudioDataEventRefCount(struct chreAudioDataEvent *event)
181         : event(event) {}
182 
AudioDataEventRefCountAudioDataEventRefCount183     AudioDataEventRefCount(struct chreAudioDataEvent *event, uint32_t refCount)
184         : event(event), refCount(refCount) {}
185 
186     /**
187      * @param audioDataEventRefCount The other object to perform an equality
188      *        comparison against.
189      * @return true if the supplied AudioDataEventRefCount is tracking the same
190      *         published event as current object.
191      */
192     bool operator==(const AudioDataEventRefCount &other) const {
193       return (event == other.event);
194     }
195 
196     //! The event that is ref counted here.
197     struct chreAudioDataEvent *event;
198 
199     //! The number of outstanding published events.
200     uint32_t refCount;
201   };
202 
203   //! Maps published audio data events to a refcount that is used to determine
204   //! when to let the platform audio implementation know that this audio data
205   //! event no longer needed.
206   DynamicVector<AudioDataEventRefCount> mAudioDataEventRefCounts;
207 
208   //! Maps audio handles to requests from multiple nanoapps for an audio source.
209   //! The array index implies the audio handle which is being managed.
210   DynamicVector<AudioRequestList> mAudioRequestLists;
211 
212   //! The instance of platform audio that is managed by this AudioRequestManager
213   //! and used to service requests for audio data.
214   PlatformAudio mPlatformAudio;
215 
216   /**
217    * Validates the arguments provided to configureSource to ensure that the
218    * handle is valid and enable, bufferDuration and deliveryInterval are in a
219    * valid configuration.
220    *
221    * @see configureSource for paramater documentation.
222    *
223    * @param numSamples Assigned the number of samples for this request if the
224    *        return value is true.
225    * @return true if the arguments are configured in a valid arrangement.
226    */
227   bool validateConfigureSourceArguments(uint32_t handle, bool enable,
228                                         uint64_t bufferDuration,
229                                         uint64_t deliveryInterval,
230                                         uint32_t *numSamples);
231 
232   /**
233    * Performs the configuration of an audio source with validated arguments. See
234    * configureSource for more details.
235    *
236    * @param instanceId The instanceId of the nanoapp making the request.
237    * @param handle The audio source that is being configured.
238    * @param enable true if enabling the source, false if disabling.
239    * @param numSamples The number of samples being requested.
240    * @param deliveryInterval When to deliver the samples.
241    * @return true if successful, false otherwise.
242    */
243   bool doConfigureSource(uint32_t instanceId, uint32_t handle, bool enable,
244                          uint32_t numSamples, Nanoseconds deliveryInterval);
245 
246   /**
247    * Notify the platform if a given handle has been enabled or disabled.
248    *
249    * @param handle The handle that may have changed enabled state.
250    * @param lastNumRequests The last number of requests for a handle before it
251    *        was reconfigured.
252    */
253   void updatePlatformHandleEnabled(uint32_t handle, size_t lastNumRequests);
254 
255   /**
256    * Creates an audio request given a configuration and instance ID for a given
257    * handle.
258    *
259    * @param handle The handle to create a request for.
260    * @param instanceId The instance ID that will own this request.
261    * @param numSamples The number of samples requested.
262    * @param deliveryInterval When to deliver the samples.
263    * @return true if successful, false otherwise.
264    */
265   bool createAudioRequest(uint32_t handle, uint32_t instanceId,
266                           uint32_t numSamples, Nanoseconds deliveryInterval);
267 
268   /**
269    * Finds an audio request for a given audio handle and nanoapp instance ID. If
270    * no existing request is available, nullptr is returned.
271    *
272    * @param handle The audio handle to query for. This must be guaranteed by the
273    *     caller to be less than the size of the mAudioRequestLists member.
274    * @param instanceId The nanoapp instance ID that owns the existing request
275    *     for this handle.
276    * @param index Populated with the index of the request if it was found.
277    * @param instanceIdIndex Populated with the index of the instance ID within
278    *        the returned audio request if it was found.
279    * @return The AudioRequest for this handle and instanceId, nullptr if not
280    *     found.
281    */
282   AudioRequest *findAudioRequestByInstanceId(uint32_t handle,
283                                              uint32_t instanceId, size_t *index,
284                                              size_t *instanceIdIndex);
285 
286   /**
287    * Finds an audio request for a given handle and configuration. If no existing
288    * request is available, nullptr is returned.
289    *
290    * @param handle The audio handle to query for. This must be guaranteed by the
291    *        caller to be less than the size of the mAudioRequestLists member.
292    * @param numSamples The number of samples to match for.
293    * @param deliveryInterval The delivery interval to match for.
294    * @param index Populated with the index of the request if it was found.
295    * @return The AudioRequest for this handle and configuration, nullptr if not
296    *     found.
297    */
298   AudioRequest *findAudioRequestByConfiguration(uint32_t handle,
299                                                 uint32_t numSamples,
300                                                 Nanoseconds deliveryInterval,
301                                                 size_t *index);
302 
303   /**
304    * Finds the next expiring request for audio data for a given handle.
305    *
306    * @param handle the handle to determine the next request to service for
307    * @return The audio request for this handle that expires next. If no requests
308    *         are bound to this handle, nullptr is returned.
309    */
310   AudioRequest *findNextAudioRequest(uint32_t handle);
311 
312   /**
313    * Handles an audio data event from the platform synchronously. This is
314    * invoked on the CHRE thread through a scheduled callback.
315    *
316    * @param event The event to provide to nanoapps containg audio data.
317    */
318   void handleAudioDataEventSync(struct chreAudioDataEvent *event);
319 
320   /**
321    * Handles audio availability from the platform synchronously. This is
322    * invoked on the CHRE thread through a deferred callback. Refer to
323    * handleAudioAvailability for details on these supplied parameters.
324    */
325   void handleAudioAvailabilitySync(uint32_t handle, bool available);
326 
327   /**
328    * Iterates the list of outstanding requests for the provided handle and
329    * schedules the next request to the platform.
330    *
331    * @param handle the audio source for which to schedule a request.
332    */
333   void scheduleNextAudioDataEvent(uint32_t handle);
334 
335   /**
336    * Posts CHRE_EVENT_AUDIO_SAMPLING_CHANGE events to all nanoapps subscribed to
337    * the supplied handle with the current availability of the source.
338    *
339    * @param handle The handle for the audio source that is changing.
340    * @param suspended Boolean value that indicates if the source is suspended
341    */
342   void postAudioSamplingChangeEvents(uint32_t handle, bool suspended);
343 
344   /**
345    * Posts a CHRE_EVENT_AUDIO_SAMPLING_CHANGE event to the specified nanoapp.
346    *
347    * @param instanceId The instance ID of the nanoapp to post to.
348    * @param handle The handle for the audio source that is changing.
349    * @param available true if audio is available for the supplied handle, false
350    *        otherwise.
351    * @param suspended Boolean value that indicates if the source is suspended
352    */
353   void postAudioSamplingChangeEvent(uint32_t instanceId, uint32_t handle,
354                                     bool available, bool suspended);
355 
356   /**
357    * Posts the provided audio data event to a nanoapp with the given instance ID
358    * and fails fatally if the event is not posted. Fatal error is an acceptable
359    * error handling mechanism here because there is no way to satisfy the
360    * requirements of the API without posting an event.
361    *
362    * @param audioDataEvent The audio data event to send to a nanoapp.
363    * @param instanceIds The list of nanoapp instance IDs to direct the event to.
364    */
365   void postAudioDataEventFatal(struct chreAudioDataEvent *event,
366                                const DynamicVector<uint32_t> &instanceIds);
367 
368   /**
369    * Invoked by the freeAudioDataEventCallback to decrement the reference count
370    * of the most recently published event and free it if unreferenced.
371    *
372    * @param audioDataEvent the audio data event to process.
373    */
374   void handleFreeAudioDataEvent(struct chreAudioDataEvent *audioDataEvent);
375 
376   /**
377    * Releases an audio data event after nanoapps have consumed it.
378    *
379    * @param eventType the type of event being freed.
380    * @param eventData a pointer to the scan event to release.
381    */
382   static void freeAudioDataEventCallback(uint16_t eventType, void *eventData);
383 };
384 
385 }  // namespace chre
386 
387 #endif  // CHRE_CORE_AUDIO_REQUEST_MANAGER_H_
388