• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
21 #include <cstdint>
22 
23 #include "chre_api/chre/audio.h"
24 #include "chre/core/nanoapp.h"
25 #include "chre/platform/platform_audio.h"
26 #include "chre/util/dynamic_vector.h"
27 #include "chre/util/non_copyable.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 buffer Pointer to the start of the buffer.
101    * @param bufferPos Pointer to buffer position to start the print (in-out).
102    * @param size Size of the buffer in bytes.
103    */
104   void logStateToBuffer(char *buffer, size_t *bufferPos,
105                         size_t bufferSize) const;
106 
107   /**
108    * A convenience function to convert sample count and sample rate into a time
109    * duration. It is illegal to call this function with a rate of zero.
110    *
111    * @param sampleCount The number of samples to convert to time at the provided
112    *        rate.
113    * @param sampleRate The rate to perform the time conversion at.
114    * @return The duration of time for these two parameters.
115    */
getDurationFromSampleCountAndRate(uint32_t sampleCount,uint32_t sampleRate)116   static constexpr Nanoseconds getDurationFromSampleCountAndRate(
117       uint32_t sampleCount, uint32_t sampleRate) {
118     // This function will overflow with high sample counts but does work for
119     // reasonable expected values.
120     //
121     // Example: 22050 * 1000000000 / 44100 = 500000000ns
122     return Nanoseconds((sampleCount * kOneSecondInNanoseconds) / sampleRate);
123   }
124 
125   /**
126    * A convenience function to convert sample rate and duration into a sample
127    * count. This can be used by platform implementations to ensure that the
128    * computed buffer sizes match those expected by CHRE.
129    *
130    * @param sampleRate The sample rate of the audio source.
131    * @param duration The duration of the buffer delivered.
132    * @return The number of samples given this configuration.
133    */
getSampleCountFromRateAndDuration(uint32_t sampleRate,Nanoseconds duration)134   static constexpr uint32_t getSampleCountFromRateAndDuration(
135       uint32_t sampleRate, Nanoseconds duration) {
136     // This function will overflow at high sample rates or extremely high
137     // durations, but does work for reasonable expected values.
138     //
139     // Example: 44100 * 60 seconds (in nanoseconds) fits into a uint64_t as an
140     // intermediate value before casting to uint32_t.
141     return static_cast<uint32_t>((sampleRate * duration.toRawNanoseconds())
142         / kOneSecondInNanoseconds);
143   }
144 
145   /**
146    * @return the instance of platform audio to allow platform-specific
147    * funtionality to call it. Example: handling host awake events.
148    */
getPlatformAudio()149   PlatformAudio& getPlatformAudio() {
150     return mPlatformAudio;
151   }
152 
153  private:
154   /**
155    * One instance of an audio request from a nanoapp.
156    */
157   struct AudioRequest {
AudioRequestAudioRequest158     AudioRequest(uint32_t numSamples, Nanoseconds deliveryInterval,
159                  Nanoseconds nextEventTimestamp)
160         : numSamples(numSamples),
161           deliveryInterval(deliveryInterval),
162           nextEventTimestamp(nextEventTimestamp) {}
163 
164     //! The nanoapp instance IDs that own this request.
165     DynamicVector<uint32_t> instanceIds;
166 
167     //! The number of samples requested for this request.
168     uint32_t numSamples;
169 
170     //! The delivery interval for this request.
171     Nanoseconds deliveryInterval;
172 
173     //! The expected timestamp of the next event delivery.
174     Nanoseconds nextEventTimestamp;
175   };
176 
177   /**
178    * A list of audio requests for a given source. Note that each nanoapp may
179    * have at most one open request for a given source. When the source is
180    * disabled it is removed from this list.
181    */
182   struct AudioRequestList {
183     //! Whether or not the source is available. It is unavailable by default.
184     bool available = false;
185 
186     //! The request to post the next event to.
187     AudioRequest *nextAudioRequest = nullptr;
188 
189     //! The list of requests for this source that are currently open.
190     DynamicVector<AudioRequest> requests;
191   };
192 
193   /**
194    * Keep track of the number of times an audio data event is published to a
195    * nanoapp.
196    *
197    * TODO: Add support for multicast events to the core event loop to avoid this
198    * kind of logic from appearing in the AudioRequestManager.
199    */
200   struct AudioDataEventRefCount {
201     /**
202      * Constructs an AudioDataEventRefCount object with an uninitialized
203      * refCount to allow searching in a list using the equality comparison
204      * below.
205      *
206      * @param event The event that this object tracks.
207      */
AudioDataEventRefCountAudioDataEventRefCount208     explicit AudioDataEventRefCount(struct chreAudioDataEvent *event)
209         : event(event) {}
210 
AudioDataEventRefCountAudioDataEventRefCount211     AudioDataEventRefCount(struct chreAudioDataEvent *event, uint32_t refCount)
212         : event(event), refCount(refCount) {}
213 
214     /**
215      * @param audioDataEventRefCount The other object to perform an equality
216      *        comparison against.
217      * @return true if the supplied AudioDataEventRefCount is tracking the same
218      *         published event as current object.
219      */
220     bool operator==(const AudioDataEventRefCount& other) const {
221       return (event == other.event);
222     }
223 
224     //! The event that is ref counted here.
225     struct chreAudioDataEvent *event;
226 
227     //! The number of outstanding published events.
228     uint32_t refCount;
229   };
230 
231   //! Maps published audio data events to a refcount that is used to determine
232   //! when to let the platform audio implementation know that this audio data
233   //! event no longer needed.
234   DynamicVector<AudioDataEventRefCount> mAudioDataEventRefCounts;
235 
236   //! Maps audio handles to requests from multiple nanoapps for an audio source.
237   //! The array index implies the audio handle which is being managed.
238   DynamicVector<AudioRequestList> mAudioRequestLists;
239 
240   //! The instance of platform audio that is managed by this AudioRequestManager
241   //! and used to service requests for audio data.
242   PlatformAudio mPlatformAudio;
243 
244   /**
245    * Validates the arguments provided to configureSource to ensure that the
246    * handle is valid and enable, bufferDuration and deliveryInterval are in a
247    * valid configuration.
248    *
249    * @see configureSource for paramater documentation.
250    *
251    * @param numSamples Assigned the number of samples for this request if the
252    *        return value is true.
253    * @return true if the arguments are configured in a valid arrangement.
254    */
255   bool validateConfigureSourceArguments(uint32_t handle, bool enable,
256       uint64_t bufferDuration, uint64_t deliveryInterval, uint32_t *numSamples);
257 
258   /**
259    * Performs the configuration of an audio source with validated arguments. See
260    * configureSource for more details.
261    *
262    * @param instanceId The instanceId of the nanoapp making the request.
263    * @param handle The audio source that is being configured.
264    * @param enable true if enabling the source, false if disabling.
265    * @param numSamples The number of samples being requested.
266    * @param deliveryInterval When to deliver the samples.
267    * @return true if successful, false otherwise.
268    */
269   bool doConfigureSource(uint32_t instanceId, uint32_t handle, bool enable,
270                          uint32_t numSamples, Nanoseconds deliveryInterval);
271 
272   /**
273    * Notify the platform if a given handle has been enabled or disabled.
274    *
275    * @param handle The handle that may have changed enabled state.
276    * @param lastNumRequests The last number of requests for a handle before it
277    *        was reconfigured.
278    */
279   void updatePlatformHandleEnabled(uint32_t handle, size_t lastNumRequests);
280 
281   /**
282    * Creates an audio request given a configuration and instance ID for a given
283    * handle.
284    *
285    * @param handle The handle to create a request for.
286    * @param instanceId The instance ID that will own this request.
287    * @param numSamples The number of samples requested.
288    * @param deliveryInterval When to deliver the samples.
289    * @return true if successful, false otherwise.
290    */
291   bool createAudioRequest(
292       uint32_t handle, uint32_t instanceId, uint32_t numSamples,
293       Nanoseconds deliveryInterval);
294 
295   /**
296    * Finds an audio request for a given audio handle and nanoapp instance ID. If
297    * no existing request is available, nullptr is returned.
298    *
299    * @param handle The audio handle to query for. This must be guaranteed by the
300    *     caller to be less than the size of the mAudioRequestLists member.
301    * @param instanceId The nanoapp instance ID that owns the existing request
302    *     for this handle.
303    * @param index Populated with the index of the request if it was found.
304    * @param instanceIdIndex Populated with the index of the instance ID within
305    *        the returned audio request if it was found.
306    * @return The AudioRequest for this handle and instanceId, nullptr if not
307    *     found.
308    */
309   AudioRequest *findAudioRequestByInstanceId(
310       uint32_t handle, uint32_t instanceId, size_t *index,
311       size_t *instanceIdIndex);
312 
313   /**
314    * Finds an audio request for a given handle and configuration. If no existing
315    * request is available, nullptr is returned.
316    *
317    * @param handle The audio handle to query for. This must be guaranteed by the
318    *        caller to be less than the size of the mAudioRequestLists member.
319    * @param numSamples The number of samples to match for.
320    * @param deliveryInterval The delivery interval to match for.
321    * @param index Populated with the index of the request if it was found.
322    * @return The AudioRequest for this handle and configuration, nullptr if not
323    *     found.
324    */
325   AudioRequest *findAudioRequestByConfiguration(
326       uint32_t handle, uint32_t numSamples, Nanoseconds deliveryInterval,
327       size_t *index);
328 
329   /**
330    * Finds the next expiring request for audio data for a given handle.
331    *
332    * @param handle the handle to determine the next request to service for
333    * @return The audio request for this handle that expires next. If no requests
334    *         are bound to this handle, nullptr is returned.
335    */
336   AudioRequest *findNextAudioRequest(uint32_t handle);
337 
338   /**
339    * Handles an audio data event from the platform synchronously. This is
340    * invoked on the CHRE thread through a scheduled callback.
341    *
342    * @param event The event to provide to nanoapps containg audio data.
343    */
344   void handleAudioDataEventSync(struct chreAudioDataEvent *event);
345 
346   /**
347    * Handles audio availability from the platform synchronously. This is
348    * invoked on the CHRE thread through a deferred callback. Refer to
349    * handleAudioAvailability for details on these supplied parameters.
350    */
351   void handleAudioAvailabilitySync(uint32_t handle, bool available);
352 
353   /**
354    * Iterates the list of outstanding requests for the provided handle and
355    * schedules the next request to the platform.
356    *
357    * @param handle the audio source for which to schedule a request.
358    */
359   void scheduleNextAudioDataEvent(uint32_t handle);
360 
361   /**
362    * Posts CHRE_EVENT_AUDIO_SAMPLING_CHANGE events to all nanoapps subscribed to
363    * the supplied handle with the current availability of the source.
364    *
365    * @param handle The handle for the audio source that is changing.
366    */
367   void postAudioSamplingChangeEvents(uint32_t handle);
368 
369   /**
370    * Posts a CHRE_EVENT_AUDIO_SAMPLING_CHANGE event to the specified nanoapp.
371    *
372    * @param instanceId The instance ID of the nanoapp to post to.
373    * @param handle The handle for the audio source that is changing.
374    * @param available true if audio is available for the supplied handle, false
375    *        otherwise.
376    */
377   void postAudioSamplingChangeEvent(uint32_t instanceId, uint32_t handle,
378                                     bool available);
379 
380   /**
381    * Posts the provided audio data event to a nanoapp with the given instance ID
382    * and fails fatally if the event is not posted. Fatal error is an acceptable
383    * error handling mechanism here because there is no way to satisfy the
384    * requirements of the API without posting an event.
385    *
386    * @param audioDataEvent The audio data event to send to a nanoapp.
387    * @param instanceIds The list of nanoapp instance IDs to direct the event to.
388    */
389   void postAudioDataEventFatal(struct chreAudioDataEvent *event,
390                                const DynamicVector<uint32_t>& instanceIds);
391 
392   /**
393    * Invoked by the freeAudioDataEventCallback to decrement the reference count
394    * of the most recently published event and free it if unreferenced.
395    *
396    * @param audioDataEvent the audio data event to process.
397    */
398   void handleFreeAudioDataEvent(struct chreAudioDataEvent *audioDataEvent);
399 
400   /**
401    * Releases an audio data event after nanoapps have consumed it.
402    *
403    * @param eventType the type of event being freed.
404    * @param eventData a pointer to the scan event to release.
405    */
406   static void freeAudioDataEventCallback(uint16_t eventType, void *eventData);
407 };
408 
409 }  // namespace chre
410 
411 #endif  // CHRE_CORE_AUDIO_REQUEST_MANAGER_H_
412