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