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#define LOG_TAG "AAudioService" 18//#define LOG_NDEBUG 0 19#include <utils/Log.h> 20 21#include <assert.h> 22#include <map> 23#include <mutex> 24#include <utils/Singleton.h> 25 26#include "AAudioEndpointManager.h" 27#include "AAudioServiceEndpoint.h" 28#include <algorithm> 29#include <mutex> 30#include <vector> 31 32#include "core/AudioStreamBuilder.h" 33#include "AAudioServiceEndpoint.h" 34#include "AAudioServiceStreamShared.h" 35 36using namespace android; // TODO just import names needed 37using namespace aaudio; // TODO just import names needed 38 39#define MIN_TIMEOUT_NANOS (1000 * AAUDIO_NANOS_PER_MILLISECOND) 40 41// Wait at least this many times longer than the operation should take. 42#define MIN_TIMEOUT_OPERATIONS 4 43 44// This is the maximum size in frames. The effective size can be tuned smaller at runtime. 45#define DEFAULT_BUFFER_CAPACITY (48 * 8) 46 47// Set up an EXCLUSIVE MMAP stream that will be shared. 48aaudio_result_t AAudioServiceEndpoint::open(int32_t deviceId) { 49 mStreamInternal = getStreamInternal(); 50 51 AudioStreamBuilder builder; 52 builder.setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE); 53 // Don't fall back to SHARED because that would cause recursion. 54 builder.setSharingModeMatchRequired(true); 55 builder.setDeviceId(deviceId); 56 builder.setDirection(getDirection()); 57 builder.setBufferCapacity(DEFAULT_BUFFER_CAPACITY); 58 59 return getStreamInternal()->open(builder); 60} 61 62aaudio_result_t AAudioServiceEndpoint::close() { 63 return getStreamInternal()->close(); 64} 65 66// TODO, maybe use an interface to reduce exposure 67aaudio_result_t AAudioServiceEndpoint::registerStream(AAudioServiceStreamShared *sharedStream) { 68 std::lock_guard<std::mutex> lock(mLockStreams); 69 mRegisteredStreams.push_back(sharedStream); 70 return AAUDIO_OK; 71} 72 73aaudio_result_t AAudioServiceEndpoint::unregisterStream(AAudioServiceStreamShared *sharedStream) { 74 std::lock_guard<std::mutex> lock(mLockStreams); 75 mRegisteredStreams.erase(std::remove(mRegisteredStreams.begin(), mRegisteredStreams.end(), sharedStream), 76 mRegisteredStreams.end()); 77 return AAUDIO_OK; 78} 79 80aaudio_result_t AAudioServiceEndpoint::startStream(AAudioServiceStreamShared *sharedStream) { 81 // TODO use real-time technique to avoid mutex, eg. atomic command FIFO 82 std::lock_guard<std::mutex> lock(mLockStreams); 83 mRunningStreams.push_back(sharedStream); 84 if (mRunningStreams.size() == 1) { 85 startSharingThread_l(); 86 } 87 return AAUDIO_OK; 88} 89 90aaudio_result_t AAudioServiceEndpoint::stopStream(AAudioServiceStreamShared *sharedStream) { 91 int numRunningStreams = 0; 92 { 93 std::lock_guard<std::mutex> lock(mLockStreams); 94 mRunningStreams.erase( 95 std::remove(mRunningStreams.begin(), mRunningStreams.end(), sharedStream), 96 mRunningStreams.end()); 97 numRunningStreams = mRunningStreams.size(); 98 } 99 if (numRunningStreams == 0) { 100 // Don't call this under a lock because the callbackLoop also uses the lock. 101 stopSharingThread(); 102 } 103 return AAUDIO_OK; 104} 105 106static void *aaudio_endpoint_thread_proc(void *context) { 107 AAudioServiceEndpoint *endpoint = (AAudioServiceEndpoint *) context; 108 if (endpoint != NULL) { 109 return endpoint->callbackLoop(); 110 } else { 111 return NULL; 112 } 113} 114 115aaudio_result_t AAudioServiceEndpoint::startSharingThread_l() { 116 // Launch the callback loop thread. 117 int64_t periodNanos = getStreamInternal()->getFramesPerBurst() 118 * AAUDIO_NANOS_PER_SECOND 119 / getSampleRate(); 120 mCallbackEnabled.store(true); 121 return getStreamInternal()->createThread(periodNanos, aaudio_endpoint_thread_proc, this); 122} 123 124aaudio_result_t AAudioServiceEndpoint::stopSharingThread() { 125 mCallbackEnabled.store(false); 126 aaudio_result_t result = getStreamInternal()->joinThread(NULL); 127 return result; 128} 129 130void AAudioServiceEndpoint::disconnectRegisteredStreams() { 131 std::lock_guard<std::mutex> lock(mLockStreams); 132 for(AAudioServiceStreamShared *sharedStream : mRunningStreams) { 133 sharedStream->onStop(); 134 } 135 mRunningStreams.clear(); 136 for(AAudioServiceStreamShared *sharedStream : mRegisteredStreams) { 137 sharedStream->onDisconnect(); 138 } 139 mRegisteredStreams.clear(); 140} 141