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 "AAudioEndpointManager" 18//#define LOG_NDEBUG 0 19#include <utils/Log.h> 20 21#include <assert.h> 22#include <functional> 23#include <map> 24#include <mutex> 25#include <sstream> 26#include <utility/AAudioUtilities.h> 27 28#include "AAudioEndpointManager.h" 29#include "AAudioServiceEndpointShared.h" 30#include "AAudioServiceEndpointMMAP.h" 31#include "AAudioServiceEndpointCapture.h" 32#include "AAudioServiceEndpointPlay.h" 33 34using namespace android; 35using namespace aaudio; 36 37ANDROID_SINGLETON_STATIC_INSTANCE(AAudioEndpointManager); 38 39AAudioEndpointManager::AAudioEndpointManager() 40 : Singleton<AAudioEndpointManager>() 41 , mSharedStreams() 42 , mExclusiveStreams() { 43} 44 45std::string AAudioEndpointManager::dump() const { 46 std::stringstream result; 47 int index = 0; 48 49 result << "AAudioEndpointManager:" << "\n"; 50 51 const bool isSharedLocked = AAudio_tryUntilTrue( 52 [this]()->bool { return mSharedLock.try_lock(); } /* f */, 53 50 /* times */, 54 20 /* sleepMs */); 55 if (!isSharedLocked) { 56 result << "AAudioEndpointManager Shared may be deadlocked\n"; 57 } 58 59 { 60 const bool isExclusiveLocked = AAudio_tryUntilTrue( 61 [this]() -> bool { return mExclusiveLock.try_lock(); } /* f */, 62 50 /* times */, 63 20 /* sleepMs */); 64 if (!isExclusiveLocked) { 65 result << "AAudioEndpointManager Exclusive may be deadlocked\n"; 66 } 67 68 result << "Exclusive MMAP Endpoints: " << mExclusiveStreams.size() << "\n"; 69 index = 0; 70 for (const auto &output : mExclusiveStreams) { 71 result << " #" << index++ << ":"; 72 result << output->dump() << "\n"; 73 } 74 75 if (isExclusiveLocked) { 76 mExclusiveLock.unlock(); 77 } 78 } 79 80 result << "Shared Endpoints: " << mSharedStreams.size() << "\n"; 81 index = 0; 82 for (const auto &input : mSharedStreams) { 83 result << " #" << index++ << ":"; 84 result << input->dump() << "\n"; 85 } 86 87 if (isSharedLocked) { 88 mSharedLock.unlock(); 89 } 90 return result.str(); 91} 92 93 94// Try to find an existing endpoint. 95sp<AAudioServiceEndpoint> AAudioEndpointManager::findExclusiveEndpoint_l( 96 const AAudioStreamConfiguration &configuration) { 97 sp<AAudioServiceEndpoint> endpoint; 98 for (const auto ep : mExclusiveStreams) { 99 if (ep->matches(configuration)) { 100 endpoint = ep; 101 break; 102 } 103 } 104 105 ALOGV("AAudioEndpointManager.findExclusiveEndpoint_l(), found %p for device = %d", 106 endpoint.get(), configuration.getDeviceId()); 107 return endpoint; 108} 109 110// Try to find an existing endpoint. 111sp<AAudioServiceEndpointShared> AAudioEndpointManager::findSharedEndpoint_l( 112 const AAudioStreamConfiguration &configuration) { 113 sp<AAudioServiceEndpointShared> endpoint; 114 for (const auto ep : mSharedStreams) { 115 if (ep->matches(configuration)) { 116 endpoint = ep; 117 break; 118 } 119 } 120 121 ALOGV("AAudioEndpointManager.findSharedEndpoint_l(), found %p for device = %d", 122 endpoint.get(), configuration.getDeviceId()); 123 return endpoint; 124} 125 126sp<AAudioServiceEndpoint> AAudioEndpointManager::openEndpoint(AAudioService &audioService, 127 const aaudio::AAudioStreamRequest &request, 128 aaudio_sharing_mode_t sharingMode) { 129 if (sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE) { 130 return openExclusiveEndpoint(audioService, request); 131 } else { 132 return openSharedEndpoint(audioService, request); 133 } 134} 135 136sp<AAudioServiceEndpoint> AAudioEndpointManager::openExclusiveEndpoint( 137 AAudioService &aaudioService __unused, 138 const aaudio::AAudioStreamRequest &request) { 139 140 std::lock_guard<std::mutex> lock(mExclusiveLock); 141 142 const AAudioStreamConfiguration &configuration = request.getConstantConfiguration(); 143 144 // Try to find an existing endpoint. 145 sp<AAudioServiceEndpoint> endpoint = findExclusiveEndpoint_l(configuration); 146 147 // If we find an existing one then this one cannot be exclusive. 148 if (endpoint.get() != nullptr) { 149 ALOGE("AAudioEndpointManager.openExclusiveEndpoint() already in use"); 150 // Already open so do not allow a second stream. 151 return nullptr; 152 } else { 153 sp<AAudioServiceEndpointMMAP> endpointMMap = new AAudioServiceEndpointMMAP(); 154 ALOGE("AAudioEndpointManager.openEndpoint(),created MMAP %p", endpointMMap.get()); 155 endpoint = endpointMMap; 156 157 aaudio_result_t result = endpoint->open(request); 158 if (result != AAUDIO_OK) { 159 ALOGE("AAudioEndpointManager.openEndpoint(), open failed"); 160 endpoint.clear(); 161 } else { 162 mExclusiveStreams.push_back(endpointMMap); 163 } 164 165 ALOGD("AAudioEndpointManager.openEndpoint(), created %p for device = %d", 166 endpoint.get(), configuration.getDeviceId()); 167 } 168 169 if (endpoint.get() != nullptr) { 170 // Increment the reference count under this lock. 171 endpoint->setOpenCount(endpoint->getOpenCount() + 1); 172 } 173 return endpoint; 174} 175 176sp<AAudioServiceEndpoint> AAudioEndpointManager::openSharedEndpoint( 177 AAudioService &aaudioService, 178 const aaudio::AAudioStreamRequest &request) { 179 180 std::lock_guard<std::mutex> lock(mSharedLock); 181 182 const AAudioStreamConfiguration &configuration = request.getConstantConfiguration(); 183 aaudio_direction_t direction = configuration.getDirection(); 184 185 // Try to find an existing endpoint. 186 sp<AAudioServiceEndpointShared> endpoint = findSharedEndpoint_l(configuration); 187 188 // If we can't find an existing one then open a new one. 189 if (endpoint.get() == nullptr) { 190 // we must call openStream with audioserver identity 191 int64_t token = IPCThreadState::self()->clearCallingIdentity(); 192 switch (direction) { 193 case AAUDIO_DIRECTION_INPUT: 194 endpoint = new AAudioServiceEndpointCapture(aaudioService); 195 break; 196 case AAUDIO_DIRECTION_OUTPUT: 197 endpoint = new AAudioServiceEndpointPlay(aaudioService); 198 break; 199 default: 200 break; 201 } 202 203 if (endpoint.get() != nullptr) { 204 aaudio_result_t result = endpoint->open(request); 205 if (result != AAUDIO_OK) { 206 ALOGE("AAudioEndpointManager.openEndpoint(), open failed"); 207 endpoint.clear(); 208 } else { 209 mSharedStreams.push_back(endpoint); 210 } 211 } 212 ALOGD("AAudioEndpointManager.openSharedEndpoint(), created %p for device = %d, dir = %d", 213 endpoint.get(), configuration.getDeviceId(), (int)direction); 214 IPCThreadState::self()->restoreCallingIdentity(token); 215 } 216 217 if (endpoint.get() != nullptr) { 218 // Increment the reference count under this lock. 219 endpoint->setOpenCount(endpoint->getOpenCount() + 1); 220 } 221 return endpoint; 222} 223 224void AAudioEndpointManager::closeEndpoint(sp<AAudioServiceEndpoint>serviceEndpoint) { 225 if (serviceEndpoint->getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) { 226 return closeExclusiveEndpoint(serviceEndpoint); 227 } else { 228 return closeSharedEndpoint(serviceEndpoint); 229 } 230} 231 232void AAudioEndpointManager::closeExclusiveEndpoint(sp<AAudioServiceEndpoint> serviceEndpoint) { 233 if (serviceEndpoint.get() == nullptr) { 234 return; 235 } 236 237 // Decrement the reference count under this lock. 238 std::lock_guard<std::mutex> lock(mExclusiveLock); 239 int32_t newRefCount = serviceEndpoint->getOpenCount() - 1; 240 serviceEndpoint->setOpenCount(newRefCount); 241 242 // If no longer in use then close and delete it. 243 if (newRefCount <= 0) { 244 mExclusiveStreams.erase( 245 std::remove(mExclusiveStreams.begin(), mExclusiveStreams.end(), serviceEndpoint), 246 mExclusiveStreams.end()); 247 248 serviceEndpoint->close(); 249 ALOGD("AAudioEndpointManager::closeExclusiveEndpoint() %p for device %d", 250 serviceEndpoint.get(), serviceEndpoint->getDeviceId()); 251 } 252} 253 254void AAudioEndpointManager::closeSharedEndpoint(sp<AAudioServiceEndpoint> serviceEndpoint) { 255 if (serviceEndpoint.get() == nullptr) { 256 return; 257 } 258 259 // Decrement the reference count under this lock. 260 std::lock_guard<std::mutex> lock(mSharedLock); 261 int32_t newRefCount = serviceEndpoint->getOpenCount() - 1; 262 serviceEndpoint->setOpenCount(newRefCount); 263 264 // If no longer in use then close and delete it. 265 if (newRefCount <= 0) { 266 mSharedStreams.erase( 267 std::remove(mSharedStreams.begin(), mSharedStreams.end(), serviceEndpoint), 268 mSharedStreams.end()); 269 270 serviceEndpoint->close(); 271 ALOGD("AAudioEndpointManager::closeSharedEndpoint() %p for device %d", 272 serviceEndpoint.get(), serviceEndpoint->getDeviceId()); 273 } 274} 275