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