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 #include "chre/util/system/debug_dump.h" 23 24 /* 25 * TODO(P1-62e045): Evict pending audio events from the event queue as needed. 26 * 27 * Under the following conditions, an audio data event may be posted to the 28 * CHRE event queue when it should not be. 29 * 30 * 1. Nanoapp changes request 31 * 2. Nanoapp removes request 32 * 33 * A previously scheduled audio data event may be residing in the event queue 34 * and will be dispatched to the nanoapp after it has cancelled the request. 35 * 36 * The solution is to evict any audio events for a given audio handle that are 37 * directed to a nanoapp before scheduling the next request to the platform. 38 */ 39 40 namespace chre { 41 42 void AudioRequestManager::init() { 43 mPlatformAudio.init(); 44 45 size_t sourceCount = mPlatformAudio.getSourceCount(); 46 if (!mAudioRequestLists.reserve(sourceCount)) { 47 FATAL_ERROR_OOM(); 48 } 49 50 for (size_t i = 0; i < sourceCount; i++) { 51 mAudioRequestLists.emplace_back(); 52 } 53 } 54 55 bool AudioRequestManager::configureSource(const Nanoapp *nanoapp, 56 uint32_t handle, bool enable, 57 uint64_t bufferDuration, 58 uint64_t deliveryInterval) { 59 uint32_t numSamples; 60 return validateConfigureSourceArguments(handle, enable, bufferDuration, 61 deliveryInterval, &numSamples) && 62 doConfigureSource(nanoapp->getInstanceId(), handle, enable, numSamples, 63 Nanoseconds(deliveryInterval)); 64 } 65 66 void AudioRequestManager::handleAudioDataEvent( 67 const struct chreAudioDataEvent *audioDataEvent) { 68 uint32_t handle = audioDataEvent->handle; 69 if (handle >= mAudioRequestLists.size()) { 70 LOGE("Received audio event for unknown handle %" PRIu32, handle); 71 } else { 72 mAudioRequestLists[handle].lastEventTimestamp = 73 SystemTime::getMonotonicTime(); 74 } 75 76 auto callback = [](uint16_t /* eventType */, void *eventData) { 77 auto *event = static_cast<struct chreAudioDataEvent *>(eventData); 78 EventLoopManagerSingleton::get() 79 ->getAudioRequestManager() 80 .handleAudioDataEventSync(event); 81 }; 82 83 // Cast off the event const so that it can be provided to the free callback as 84 // non-const. The event is provided to nanoapps as const and the runtime 85 // itself will not modify this memory so this is safe. 86 EventLoopManagerSingleton::get()->deferCallback( 87 SystemCallbackType::AudioHandleDataEvent, 88 const_cast<struct chreAudioDataEvent *>(audioDataEvent), callback); 89 } 90 91 void AudioRequestManager::handleAudioAvailability(uint32_t handle, 92 bool available) { 93 struct CallbackState { 94 uint32_t handle; 95 bool available; 96 }; 97 98 auto *cbState = memoryAlloc<CallbackState>(); 99 if (cbState == nullptr) { 100 LOG_OOM(); 101 } else { 102 cbState->handle = handle; 103 cbState->available = available; 104 105 auto callback = [](uint16_t /* eventType */, void *eventData) { 106 auto *state = static_cast<CallbackState *>(eventData); 107 EventLoopManagerSingleton::get() 108 ->getAudioRequestManager() 109 .handleAudioAvailabilitySync(state->handle, state->available); 110 memoryFree(state); 111 }; 112 113 EventLoopManagerSingleton::get()->deferCallback( 114 SystemCallbackType::AudioAvailabilityChange, cbState, callback); 115 } 116 } 117 118 void AudioRequestManager::logStateToBuffer(DebugDumpWrapper &debugDump) const { 119 debugDump.print("\nAudio:\n"); 120 for (size_t i = 0; i < mAudioRequestLists.size(); i++) { 121 uint32_t handle = static_cast<uint32_t>(i); 122 struct chreAudioSource source; 123 mPlatformAudio.getAudioSource(handle, &source); 124 125 Nanoseconds timeSinceLastAudioEvent = 126 SystemTime::getMonotonicTime() - 127 mAudioRequestLists[i].lastEventTimestamp; 128 debugDump.print( 129 " handle=%" PRIu32 ", name=\"%s\", available=%d, sampleRate=%" PRIu32 130 ", buffer(ms)=[%" PRIu64 ",%" PRIu64 "], format=%" PRIu8 131 ", timeSinceLastAudioEvent(ms)=%" PRIu64 "\n", 132 handle, source.name, mAudioRequestLists[i].available, source.sampleRate, 133 Milliseconds(Nanoseconds(source.minBufferDuration)).getMilliseconds(), 134 Milliseconds(Nanoseconds(source.maxBufferDuration)).getMilliseconds(), 135 source.format, Milliseconds(timeSinceLastAudioEvent).getMilliseconds()); 136 137 for (const auto &request : mAudioRequestLists[i].requests) { 138 for (const auto &instanceId : request.instanceIds) { 139 debugDump.print(" nanoappId=%" PRIu32 ", numSamples=%" PRIu32 140 ", interval(ms)=%" PRIu64 "\n", 141 instanceId, request.numSamples, 142 Milliseconds(Nanoseconds(request.deliveryInterval)) 143 .getMilliseconds()); 144 } 145 } 146 } 147 } 148 149 bool AudioRequestManager::validateConfigureSourceArguments( 150 uint32_t handle, bool enable, uint64_t bufferDuration, 151 uint64_t deliveryInterval, uint32_t *numSamples) { 152 bool success = false; 153 if (handle >= mAudioRequestLists.size()) { 154 LOGE("Provided audio handle out of range"); 155 } else if (enable) { 156 chreAudioSource audioSource; 157 if (!mPlatformAudio.getAudioSource(handle, &audioSource)) { 158 LOGE("Failed to query for audio source"); 159 } else if (bufferDuration > deliveryInterval) { 160 LOGE("Buffer duration must be less than or equal to delivery interval"); 161 } else if (bufferDuration < audioSource.minBufferDuration || 162 bufferDuration > audioSource.maxBufferDuration) { 163 LOGE("Invalid buffer duration %" PRIu64 " not in range [%" PRIu64 164 ",%" PRIu64 "]", 165 bufferDuration, audioSource.minBufferDuration, 166 audioSource.maxBufferDuration); 167 } else { 168 *numSamples = getSampleCountFromRateAndDuration( 169 audioSource.sampleRate, Nanoseconds(bufferDuration)); 170 success = true; 171 } 172 } else { 173 // Disabling the request, no need to validate bufferDuration or 174 // deliveryInterval. 175 success = true; 176 } 177 return success; 178 } 179 180 bool AudioRequestManager::doConfigureSource(uint32_t instanceId, 181 uint32_t handle, bool enable, 182 uint32_t numSamples, 183 Nanoseconds deliveryInterval) { 184 size_t requestIndex; 185 size_t requestInstanceIdIndex; 186 auto *audioRequest = findAudioRequestByInstanceId( 187 handle, instanceId, &requestIndex, &requestInstanceIdIndex); 188 189 AudioRequestList &requestList = mAudioRequestLists[handle]; 190 size_t lastNumRequests = requestList.requests.size(); 191 192 bool success = false; 193 if (audioRequest == nullptr) { 194 if (enable) { 195 success = 196 createAudioRequest(handle, instanceId, numSamples, deliveryInterval); 197 } else { 198 LOGW("Nanoapp disabling nonexistent audio request"); 199 } 200 } else { 201 if (audioRequest->instanceIds.size() > 1) { 202 // If there are other clients listening in this configuration, remove 203 // just the instance ID. 204 audioRequest->instanceIds.erase(requestInstanceIdIndex); 205 } else { 206 // If this is the last client listening in this configuration, remove 207 // the entire request. 208 requestList.requests.erase(requestIndex); 209 } 210 211 // If the client is disabling, there is nothing to do, otherwise a request 212 // must be created successfully. 213 success = (!enable || createAudioRequest(handle, instanceId, numSamples, 214 deliveryInterval)); 215 } 216 217 if (success) { 218 scheduleNextAudioDataEvent(handle); 219 updatePlatformHandleEnabled(handle, lastNumRequests); 220 } 221 222 return success; 223 } 224 225 void AudioRequestManager::updatePlatformHandleEnabled(uint32_t handle, 226 size_t lastNumRequests) { 227 size_t numRequests = mAudioRequestLists[handle].requests.size(); 228 if (lastNumRequests == 0 && numRequests > 0) { 229 mPlatformAudio.setHandleEnabled(handle, true /* enabled */); 230 } else if (lastNumRequests > 0 && numRequests == 0) { 231 mPlatformAudio.setHandleEnabled(handle, false /* enabled */); 232 } 233 } 234 235 bool AudioRequestManager::createAudioRequest(uint32_t handle, 236 uint32_t instanceId, 237 uint32_t numSamples, 238 Nanoseconds deliveryInterval) { 239 AudioRequestList &requestList = mAudioRequestLists[handle]; 240 241 size_t matchingRequestIndex; 242 auto *matchingAudioRequest = findAudioRequestByConfiguration( 243 handle, numSamples, deliveryInterval, &matchingRequestIndex); 244 245 bool success = false; 246 if (matchingAudioRequest != nullptr) { 247 if (!matchingAudioRequest->instanceIds.push_back(instanceId)) { 248 LOG_OOM(); 249 } else { 250 success = true; 251 } 252 } else { 253 Nanoseconds timeNow = SystemTime::getMonotonicTime(); 254 Nanoseconds nextEventTimestamp = timeNow + deliveryInterval; 255 if (!requestList.requests.emplace_back(numSamples, deliveryInterval, 256 nextEventTimestamp)) { 257 LOG_OOM(); 258 } else if (!requestList.requests.back().instanceIds.push_back(instanceId)) { 259 requestList.requests.pop_back(); 260 LOG_OOM(); 261 } else { 262 success = true; 263 } 264 } 265 266 if (success) { 267 postAudioSamplingChangeEvent(instanceId, handle, requestList.available); 268 } 269 270 return success; 271 } 272 273 AudioRequestManager::AudioRequest * 274 AudioRequestManager::findAudioRequestByInstanceId(uint32_t handle, 275 uint32_t instanceId, 276 size_t *index, 277 size_t *instanceIdIndex) { 278 AudioRequest *foundAudioRequest = nullptr; 279 auto &requests = mAudioRequestLists[handle].requests; 280 for (size_t i = 0; i < requests.size(); i++) { 281 auto &audioRequest = requests[i]; 282 size_t foundInstanceIdIndex = audioRequest.instanceIds.find(instanceId); 283 if (foundInstanceIdIndex != audioRequest.instanceIds.size()) { 284 foundAudioRequest = &audioRequest; 285 *index = i; 286 *instanceIdIndex = foundInstanceIdIndex; 287 break; 288 } 289 } 290 291 return foundAudioRequest; 292 } 293 294 AudioRequestManager::AudioRequest * 295 AudioRequestManager::findAudioRequestByConfiguration( 296 uint32_t handle, uint32_t numSamples, Nanoseconds deliveryInterval, 297 size_t *index) { 298 AudioRequest *foundAudioRequest = nullptr; 299 auto &requests = mAudioRequestLists[handle].requests; 300 for (size_t i = 0; i < requests.size(); i++) { 301 auto &audioRequest = requests[i]; 302 if (audioRequest.numSamples == numSamples && 303 audioRequest.deliveryInterval == deliveryInterval) { 304 foundAudioRequest = &audioRequest; 305 *index = i; 306 break; 307 } 308 } 309 310 return foundAudioRequest; 311 } 312 313 AudioRequestManager::AudioRequest *AudioRequestManager::findNextAudioRequest( 314 uint32_t handle) { 315 Nanoseconds earliestNextEventTimestamp = Nanoseconds(UINT64_MAX); 316 AudioRequest *nextRequest = nullptr; 317 318 auto &reqList = mAudioRequestLists[handle]; 319 for (auto &req : reqList.requests) { 320 if (req.nextEventTimestamp < earliestNextEventTimestamp) { 321 earliestNextEventTimestamp = req.nextEventTimestamp; 322 nextRequest = &req; 323 } 324 } 325 326 return nextRequest; 327 } 328 329 void AudioRequestManager::handleAudioDataEventSync( 330 struct chreAudioDataEvent *event) { 331 uint32_t handle = event->handle; 332 if (handle < mAudioRequestLists.size()) { 333 auto &reqList = mAudioRequestLists[handle]; 334 AudioRequest *nextAudioRequest = reqList.nextAudioRequest; 335 if (nextAudioRequest != nullptr) { 336 postAudioDataEventFatal(event, nextAudioRequest->instanceIds); 337 nextAudioRequest->nextEventTimestamp = 338 SystemTime::getMonotonicTime() + nextAudioRequest->deliveryInterval; 339 } else { 340 LOGW("Received audio data event with no pending audio request"); 341 mPlatformAudio.releaseAudioDataEvent(event); 342 } 343 344 scheduleNextAudioDataEvent(handle); 345 } else { 346 LOGE("Audio data event handle out of range: %" PRIu32, handle); 347 } 348 } 349 350 void AudioRequestManager::handleAudioAvailabilitySync(uint32_t handle, 351 bool available) { 352 if (handle < mAudioRequestLists.size()) { 353 if (mAudioRequestLists[handle].available != available) { 354 mAudioRequestLists[handle].available = available; 355 postAudioSamplingChangeEvents(handle); 356 } 357 358 scheduleNextAudioDataEvent(handle); 359 } else { 360 LOGE("Audio availability handle out of range: %" PRIu32, handle); 361 } 362 } 363 364 void AudioRequestManager::scheduleNextAudioDataEvent(uint32_t handle) { 365 auto &reqList = mAudioRequestLists[handle]; 366 AudioRequest *nextRequest = findNextAudioRequest(handle); 367 368 // Clear the next request and it will be reset below if needed. 369 reqList.nextAudioRequest = nullptr; 370 if (reqList.available && nextRequest != nullptr) { 371 Nanoseconds curTime = SystemTime::getMonotonicTime(); 372 Nanoseconds eventDelay = Nanoseconds(0); 373 if (nextRequest->nextEventTimestamp > curTime) { 374 eventDelay = nextRequest->nextEventTimestamp - curTime; 375 } 376 reqList.nextAudioRequest = nextRequest; 377 mPlatformAudio.requestAudioDataEvent(handle, nextRequest->numSamples, 378 eventDelay); 379 } else { 380 mPlatformAudio.cancelAudioDataEventRequest(handle); 381 } 382 } 383 384 void AudioRequestManager::postAudioSamplingChangeEvents(uint32_t handle) { 385 const auto &requestList = mAudioRequestLists[handle]; 386 for (const auto &request : requestList.requests) { 387 for (const auto &instanceId : request.instanceIds) { 388 postAudioSamplingChangeEvent(instanceId, handle, requestList.available); 389 } 390 } 391 } 392 393 void AudioRequestManager::postAudioSamplingChangeEvent(uint32_t instanceId, 394 uint32_t handle, 395 bool available) { 396 auto *event = memoryAlloc<struct chreAudioSourceStatusEvent>(); 397 event->handle = handle; 398 event->status.enabled = true; 399 event->status.suspended = !available; 400 401 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( 402 CHRE_EVENT_AUDIO_SAMPLING_CHANGE, event, freeEventDataCallback, 403 instanceId); 404 } 405 406 void AudioRequestManager::postAudioDataEventFatal( 407 struct chreAudioDataEvent *event, 408 const DynamicVector<uint32_t> &instanceIds) { 409 if (instanceIds.empty()) { 410 LOGW("Received audio data event for no clients"); 411 mPlatformAudio.releaseAudioDataEvent(event); 412 } else { 413 for (const auto &instanceId : instanceIds) { 414 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( 415 CHRE_EVENT_AUDIO_DATA, event, freeAudioDataEventCallback, instanceId); 416 } 417 418 mAudioDataEventRefCounts.emplace_back( 419 event, static_cast<uint32_t>(instanceIds.size())); 420 } 421 } 422 423 void AudioRequestManager::handleFreeAudioDataEvent( 424 struct chreAudioDataEvent *audioDataEvent) { 425 size_t audioDataEventRefCountIndex = 426 mAudioDataEventRefCounts.find(AudioDataEventRefCount(audioDataEvent)); 427 if (audioDataEventRefCountIndex == mAudioDataEventRefCounts.size()) { 428 LOGE("Freeing invalid audio data event"); 429 } else { 430 auto &audioDataEventRefCount = 431 mAudioDataEventRefCounts[audioDataEventRefCountIndex]; 432 if (audioDataEventRefCount.refCount == 0) { 433 LOGE("Attempting to free an event with zero published events"); 434 } else { 435 audioDataEventRefCount.refCount--; 436 if (audioDataEventRefCount.refCount == 0) { 437 mAudioDataEventRefCounts.erase(audioDataEventRefCountIndex); 438 mPlatformAudio.releaseAudioDataEvent(audioDataEvent); 439 } 440 } 441 } 442 } 443 444 void AudioRequestManager::freeAudioDataEventCallback(uint16_t eventType, 445 void *eventData) { 446 auto *event = static_cast<struct chreAudioDataEvent *>(eventData); 447 EventLoopManagerSingleton::get() 448 ->getAudioRequestManager() 449 .handleFreeAudioDataEvent(event); 450 } 451 452 } // namespace chre 453