123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445 |
- /*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include "chre/core/audio_request_manager.h"
- #include "chre/core/event_loop_manager.h"
- #include "chre/platform/fatal_error.h"
- #include "chre/platform/system_time.h"
- #include "chre/util/system/debug_dump.h"
- /*
- * TODO(P1-62e045): Evict pending audio events from the event queue as needed.
- *
- * Under the following conditions, an audio data event may be posted to the
- * CHRE event queue when it should not be.
- *
- * 1. Nanoapp changes request
- * 2. Nanoapp removes request
- *
- * A previously scheduled audio data event may be residing in the event queue
- * and will be dispatched to the nanoapp after it has cancelled the request.
- *
- * The solution is to evict any audio events for a given audio handle that are
- * directed to a nanoapp before scheduling the next request to the platform.
- */
- namespace chre {
- void AudioRequestManager::init() {
- mPlatformAudio.init();
- size_t sourceCount = mPlatformAudio.getSourceCount();
- if (!mAudioRequestLists.reserve(sourceCount)) {
- FATAL_ERROR_OOM();
- }
- for (size_t i = 0; i < sourceCount; i++) {
- mAudioRequestLists.emplace_back();
- }
- }
- bool AudioRequestManager::configureSource(const Nanoapp *nanoapp,
- uint32_t handle,
- bool enable,
- uint64_t bufferDuration,
- uint64_t deliveryInterval) {
- uint32_t numSamples;
- return validateConfigureSourceArguments(handle, enable, bufferDuration,
- deliveryInterval, &numSamples)
- && doConfigureSource(nanoapp->getInstanceId(), handle, enable, numSamples,
- Nanoseconds(deliveryInterval));
- }
- void AudioRequestManager::handleAudioDataEvent(
- const struct chreAudioDataEvent *audioDataEvent) {
- uint32_t handle = audioDataEvent->handle;
- if (handle >= mAudioRequestLists.size()) {
- LOGE("Received audio event for unknown handle %" PRIu32, handle);
- } else {
- mAudioRequestLists[handle].lastEventTimestamp
- = SystemTime::getMonotonicTime();
- }
- auto callback = [](uint16_t /* eventType */, void *eventData) {
- auto *event = static_cast<struct chreAudioDataEvent *>(eventData);
- EventLoopManagerSingleton::get()->getAudioRequestManager()
- .handleAudioDataEventSync(event);
- };
- // Cast off the event const so that it can be provided to the free callback as
- // non-const. The event is provided to nanoapps as const and the runtime
- // itself will not modify this memory so this is safe.
- EventLoopManagerSingleton::get()->deferCallback(
- SystemCallbackType::AudioHandleDataEvent,
- const_cast<struct chreAudioDataEvent *>(audioDataEvent), callback);
- }
- void AudioRequestManager::handleAudioAvailability(uint32_t handle, bool available) {
- struct CallbackState {
- uint32_t handle;
- bool available;
- };
- auto *cbState = memoryAlloc<CallbackState>();
- if (cbState == nullptr) {
- LOG_OOM();
- } else {
- cbState->handle = handle;
- cbState->available = available;
- auto callback = [](uint16_t /* eventType */, void *eventData) {
- auto *state = static_cast<CallbackState *>(eventData);
- EventLoopManagerSingleton::get()->getAudioRequestManager()
- .handleAudioAvailabilitySync(state->handle, state->available);
- memoryFree(state);
- };
- EventLoopManagerSingleton::get()->deferCallback(
- SystemCallbackType::AudioAvailabilityChange, cbState, callback);
- }
- }
- void AudioRequestManager::logStateToBuffer(char *buffer, size_t *bufferPos,
- size_t bufferSize) const {
- debugDumpPrint(buffer, bufferPos, bufferSize, "\nAudio:\n");
- for (size_t i = 0; i < mAudioRequestLists.size(); i++) {
- uint32_t handle = static_cast<uint32_t>(i);
- struct chreAudioSource source;
- mPlatformAudio.getAudioSource(handle, &source);
- Nanoseconds timeSinceLastAudioEvent = SystemTime::getMonotonicTime()
- - mAudioRequestLists[i].lastEventTimestamp;
- debugDumpPrint(buffer, bufferPos, bufferSize,
- " handle=%" PRIu32 ", name=\"%s\", available=%d, sampleRate=%" PRIu32
- ", buffer(ms)=[%" PRIu64 ",%" PRIu64 "], format=%" PRIu8
- ", timeSinceLastAudioEvent(ms)=%" PRIu64 "\n",
- handle, source.name, mAudioRequestLists[i].available, source.sampleRate,
- Milliseconds(Nanoseconds(source.minBufferDuration)).getMilliseconds(),
- Milliseconds(Nanoseconds(source.maxBufferDuration)).getMilliseconds(),
- source.format, Milliseconds(timeSinceLastAudioEvent).getMilliseconds());
- for (const auto& request : mAudioRequestLists[i].requests) {
- for (const auto& instanceId : request.instanceIds) {
- debugDumpPrint(buffer, bufferPos, bufferSize,
- " nanoappId=%" PRIu32 ", numSamples=%" PRIu32
- ", interval(ms)=%" PRIu64 "\n", instanceId, request.numSamples,
- Milliseconds(Nanoseconds(request.deliveryInterval))
- .getMilliseconds());
- }
- }
- }
- }
- bool AudioRequestManager::validateConfigureSourceArguments(
- uint32_t handle, bool enable, uint64_t bufferDuration,
- uint64_t deliveryInterval, uint32_t *numSamples) {
- bool success = false;
- if (handle >= mAudioRequestLists.size()) {
- LOGE("Provided audio handle out of range");
- } else if (enable) {
- chreAudioSource audioSource;
- if (!mPlatformAudio.getAudioSource(handle, &audioSource)) {
- LOGE("Failed to query for audio source");
- } else if (bufferDuration > deliveryInterval) {
- LOGE("Buffer duration must be less than or equal to delivery interval");
- } else if (bufferDuration < audioSource.minBufferDuration
- || bufferDuration > audioSource.maxBufferDuration) {
- LOGE("Invalid buffer duration %" PRIu64 " not in range [%" PRIu64
- ",%" PRIu64 "]", bufferDuration, audioSource.minBufferDuration,
- audioSource.maxBufferDuration);
- } else {
- *numSamples = getSampleCountFromRateAndDuration(
- audioSource.sampleRate, Nanoseconds(bufferDuration));
- success = true;
- }
- } else {
- // Disabling the request, no need to validate bufferDuration or
- // deliveryInterval.
- success = true;
- }
- return success;
- }
- bool AudioRequestManager::doConfigureSource(
- uint32_t instanceId, uint32_t handle, bool enable, uint32_t numSamples,
- Nanoseconds deliveryInterval) {
- size_t requestIndex;
- size_t requestInstanceIdIndex;
- auto *audioRequest = findAudioRequestByInstanceId(
- handle, instanceId, &requestIndex, &requestInstanceIdIndex);
- AudioRequestList& requestList = mAudioRequestLists[handle];
- size_t lastNumRequests = requestList.requests.size();
- bool success = false;
- if (audioRequest == nullptr) {
- if (enable) {
- success = createAudioRequest(handle, instanceId, numSamples,
- deliveryInterval);
- } else {
- LOGW("Nanoapp disabling nonexistent audio request");
- }
- } else {
- if (audioRequest->instanceIds.size() > 1) {
- // If there are other clients listening in this configuration, remove
- // just the instance ID.
- audioRequest->instanceIds.erase(requestInstanceIdIndex);
- } else {
- // If this is the last client listening in this configuration, remove
- // the entire request.
- requestList.requests.erase(requestIndex);
- }
- // If the client is disabling, there is nothing to do, otherwise a request
- // must be created successfully.
- success = (!enable || createAudioRequest(handle, instanceId, numSamples,
- deliveryInterval));
- }
- if (success) {
- scheduleNextAudioDataEvent(handle);
- updatePlatformHandleEnabled(handle, lastNumRequests);
- }
- return success;
- }
- void AudioRequestManager::updatePlatformHandleEnabled(
- uint32_t handle, size_t lastNumRequests) {
- size_t numRequests = mAudioRequestLists[handle].requests.size();
- if (lastNumRequests == 0 && numRequests > 0) {
- mPlatformAudio.setHandleEnabled(handle, true /* enabled */);
- } else if (lastNumRequests > 0 && numRequests == 0) {
- mPlatformAudio.setHandleEnabled(handle, false /* enabled */);
- }
- }
- bool AudioRequestManager::createAudioRequest(
- uint32_t handle, uint32_t instanceId, uint32_t numSamples,
- Nanoseconds deliveryInterval) {
- AudioRequestList& requestList = mAudioRequestLists[handle];
- size_t matchingRequestIndex;
- auto *matchingAudioRequest = findAudioRequestByConfiguration(
- handle, numSamples, deliveryInterval, &matchingRequestIndex);
- bool success = false;
- if (matchingAudioRequest != nullptr) {
- if (!matchingAudioRequest->instanceIds.push_back(instanceId)) {
- LOG_OOM();
- } else {
- success = true;
- }
- } else {
- Nanoseconds timeNow = SystemTime::getMonotonicTime();
- Nanoseconds nextEventTimestamp = timeNow + deliveryInterval;
- if (!requestList.requests.emplace_back(numSamples, deliveryInterval,
- nextEventTimestamp)) {
- LOG_OOM();
- } else if (!requestList.requests.back().instanceIds.push_back(instanceId)) {
- requestList.requests.pop_back();
- LOG_OOM();
- } else {
- success = true;
- }
- }
- if (success) {
- postAudioSamplingChangeEvent(instanceId, handle, requestList.available);
- }
- return success;
- }
- AudioRequestManager::AudioRequest *AudioRequestManager::
- findAudioRequestByInstanceId(
- uint32_t handle, uint32_t instanceId, size_t *index,
- size_t *instanceIdIndex) {
- AudioRequest *foundAudioRequest = nullptr;
- auto& requests = mAudioRequestLists[handle].requests;
- for (size_t i = 0; i < requests.size(); i++) {
- auto& audioRequest = requests[i];
- size_t foundInstanceIdIndex = audioRequest.instanceIds.find(instanceId);
- if (foundInstanceIdIndex != audioRequest.instanceIds.size()) {
- foundAudioRequest = &audioRequest;
- *index = i;
- *instanceIdIndex = foundInstanceIdIndex;
- break;
- }
- }
- return foundAudioRequest;
- }
- AudioRequestManager::AudioRequest *AudioRequestManager::
- findAudioRequestByConfiguration(
- uint32_t handle, uint32_t numSamples, Nanoseconds deliveryInterval,
- size_t *index) {
- AudioRequest *foundAudioRequest = nullptr;
- auto& requests = mAudioRequestLists[handle].requests;
- for (size_t i = 0; i < requests.size(); i++) {
- auto& audioRequest = requests[i];
- if (audioRequest.numSamples == numSamples
- && audioRequest.deliveryInterval == deliveryInterval) {
- foundAudioRequest = &audioRequest;
- *index = i;
- break;
- }
- }
- return foundAudioRequest;
- }
- AudioRequestManager::AudioRequest *AudioRequestManager::findNextAudioRequest(
- uint32_t handle) {
- Nanoseconds earliestNextEventTimestamp = Nanoseconds(UINT64_MAX);
- AudioRequest *nextRequest = nullptr;
- auto& reqList = mAudioRequestLists[handle];
- for (auto& req : reqList.requests) {
- if (req.nextEventTimestamp < earliestNextEventTimestamp) {
- earliestNextEventTimestamp = req.nextEventTimestamp;
- nextRequest = &req;
- }
- }
- return nextRequest;
- }
- void AudioRequestManager::handleAudioDataEventSync(
- struct chreAudioDataEvent *event) {
- uint32_t handle = event->handle;
- if (handle < mAudioRequestLists.size()) {
- auto& reqList = mAudioRequestLists[handle];
- AudioRequest *nextAudioRequest = reqList.nextAudioRequest;
- if (nextAudioRequest != nullptr) {
- postAudioDataEventFatal(event, nextAudioRequest->instanceIds);
- nextAudioRequest->nextEventTimestamp = SystemTime::getMonotonicTime()
- + nextAudioRequest->deliveryInterval;
- } else {
- LOGW("Received audio data event with no pending audio request");
- mPlatformAudio.releaseAudioDataEvent(event);
- }
- scheduleNextAudioDataEvent(handle);
- } else {
- LOGE("Audio data event handle out of range: %" PRIu32, handle);
- }
- }
- void AudioRequestManager::handleAudioAvailabilitySync(uint32_t handle,
- bool available) {
- if (handle < mAudioRequestLists.size()) {
- if (mAudioRequestLists[handle].available != available) {
- mAudioRequestLists[handle].available = available;
- postAudioSamplingChangeEvents(handle);
- }
- scheduleNextAudioDataEvent(handle);
- } else {
- LOGE("Audio availability handle out of range: %" PRIu32, handle);
- }
- }
- void AudioRequestManager::scheduleNextAudioDataEvent(uint32_t handle) {
- auto& reqList = mAudioRequestLists[handle];
- AudioRequest *nextRequest = findNextAudioRequest(handle);
- // Clear the next request and it will be reset below if needed.
- reqList.nextAudioRequest = nullptr;
- if (reqList.available && nextRequest != nullptr) {
- Nanoseconds curTime = SystemTime::getMonotonicTime();
- Nanoseconds eventDelay = Nanoseconds(0);
- if (nextRequest->nextEventTimestamp > curTime) {
- eventDelay = nextRequest->nextEventTimestamp - curTime;
- }
- reqList.nextAudioRequest = nextRequest;
- mPlatformAudio.requestAudioDataEvent(
- handle, nextRequest->numSamples, eventDelay);
- } else {
- mPlatformAudio.cancelAudioDataEventRequest(handle);
- }
- }
- void AudioRequestManager::postAudioSamplingChangeEvents(uint32_t handle) {
- const auto& requestList = mAudioRequestLists[handle];
- for (const auto& request : requestList.requests) {
- for (const auto& instanceId : request.instanceIds) {
- postAudioSamplingChangeEvent(instanceId, handle, requestList.available);
- }
- }
- }
- void AudioRequestManager::postAudioSamplingChangeEvent(uint32_t instanceId,
- uint32_t handle,
- bool available) {
- auto *event = memoryAlloc<struct chreAudioSourceStatusEvent>();
- event->handle = handle;
- event->status.enabled = true;
- event->status.suspended = !available;
- EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
- CHRE_EVENT_AUDIO_SAMPLING_CHANGE, event, freeEventDataCallback,
- instanceId);
- }
- void AudioRequestManager::postAudioDataEventFatal(
- struct chreAudioDataEvent *event,
- const DynamicVector<uint32_t>& instanceIds) {
- if (instanceIds.empty()) {
- LOGW("Received audio data event for no clients");
- mPlatformAudio.releaseAudioDataEvent(event);
- } else {
- for (const auto &instanceId : instanceIds) {
- EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
- CHRE_EVENT_AUDIO_DATA, event, freeAudioDataEventCallback, instanceId);
- }
- mAudioDataEventRefCounts.emplace_back(
- event, static_cast<uint32_t>(instanceIds.size()));
- }
- }
- void AudioRequestManager::handleFreeAudioDataEvent(
- struct chreAudioDataEvent *audioDataEvent) {
- size_t audioDataEventRefCountIndex =
- mAudioDataEventRefCounts.find(AudioDataEventRefCount(audioDataEvent));
- if (audioDataEventRefCountIndex == mAudioDataEventRefCounts.size()) {
- LOGE("Freeing invalid audio data event");
- } else {
- auto& audioDataEventRefCount =
- mAudioDataEventRefCounts[audioDataEventRefCountIndex];
- if (audioDataEventRefCount.refCount == 0) {
- LOGE("Attempting to free an event with zero published events");
- } else {
- audioDataEventRefCount.refCount--;
- if (audioDataEventRefCount.refCount == 0) {
- mAudioDataEventRefCounts.erase(audioDataEventRefCountIndex);
- mPlatformAudio.releaseAudioDataEvent(audioDataEvent);
- }
- }
- }
- }
- void AudioRequestManager::freeAudioDataEventCallback(uint16_t eventType,
- void *eventData) {
- auto *event = static_cast<struct chreAudioDataEvent *>(eventData);
- EventLoopManagerSingleton::get()->getAudioRequestManager()
- .handleFreeAudioDataEvent(event);
- }
- } // namespace chre
|