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 34 using namespace android; 35 using namespace aaudio; 36 37 ANDROID_SINGLETON_STATIC_INSTANCE(AAudioEndpointManager); 38 39 AAudioEndpointManager::AAudioEndpointManager() 40 : Singleton<AAudioEndpointManager>() 41 , mSharedStreams() 42 , mExclusiveStreams() { 43 } 44 45 std::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 &stream : mExclusiveStreams) { 71 result << " #" << index++ << ":"; 72 result << stream->dump() << "\n"; 73 } 74 75 result << " ExclusiveSearchCount: " << mExclusiveSearchCount << "\n"; 76 result << " ExclusiveFoundCount: " << mExclusiveFoundCount << "\n"; 77 result << " ExclusiveOpenCount: " << mExclusiveOpenCount << "\n"; 78 result << " ExclusiveCloseCount: " << mExclusiveCloseCount << "\n"; 79 result << "\n"; 80 81 if (isExclusiveLocked) { 82 mExclusiveLock.unlock(); 83 } 84 } 85 86 result << "Shared Endpoints: " << mSharedStreams.size() << "\n"; 87 index = 0; 88 for (const auto &stream : mSharedStreams) { 89 result << " #" << index++ << ":"; 90 result << stream->dump() << "\n"; 91 } 92 93 result << " SharedSearchCount: " << mSharedSearchCount << "\n"; 94 result << " SharedFoundCount: " << mSharedFoundCount << "\n"; 95 result << " SharedOpenCount: " << mSharedOpenCount << "\n"; 96 result << " SharedCloseCount: " << mSharedCloseCount << "\n"; 97 result << "\n"; 98 99 if (isSharedLocked) { 100 mSharedLock.unlock(); 101 } 102 return result.str(); 103 } 104 105 106 // Try to find an existing endpoint. 107 sp<AAudioServiceEndpoint> AAudioEndpointManager::findExclusiveEndpoint_l( 108 const AAudioStreamConfiguration &configuration) { 109 sp<AAudioServiceEndpoint> endpoint; 110 mExclusiveSearchCount++; 111 for (const auto ep : mExclusiveStreams) { 112 if (ep->matches(configuration)) { 113 mExclusiveFoundCount++; 114 endpoint = ep; 115 break; 116 } 117 } 118 119 ALOGV("findExclusiveEndpoint_l(), found %p for device = %d, sessionId = %d", 120 endpoint.get(), configuration.getDeviceId(), configuration.getSessionId()); 121 return endpoint; 122 } 123 124 // Try to find an existing endpoint. 125 sp<AAudioServiceEndpointShared> AAudioEndpointManager::findSharedEndpoint_l( 126 const AAudioStreamConfiguration &configuration) { 127 sp<AAudioServiceEndpointShared> endpoint; 128 mSharedSearchCount++; 129 for (const auto ep : mSharedStreams) { 130 if (ep->matches(configuration)) { 131 mSharedFoundCount++; 132 endpoint = ep; 133 break; 134 } 135 } 136 137 ALOGV("findSharedEndpoint_l(), found %p for device = %d, sessionId = %d", 138 endpoint.get(), configuration.getDeviceId(), configuration.getSessionId()); 139 return endpoint; 140 } 141 142 sp<AAudioServiceEndpoint> AAudioEndpointManager::openEndpoint(AAudioService &audioService, 143 const aaudio::AAudioStreamRequest &request, 144 aaudio_sharing_mode_t sharingMode) { 145 if (sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE) { 146 return openExclusiveEndpoint(audioService, request); 147 } else { 148 return openSharedEndpoint(audioService, request); 149 } 150 } 151 152 sp<AAudioServiceEndpoint> AAudioEndpointManager::openExclusiveEndpoint( 153 AAudioService &aaudioService, 154 const aaudio::AAudioStreamRequest &request) { 155 156 std::lock_guard<std::mutex> lock(mExclusiveLock); 157 158 const AAudioStreamConfiguration &configuration = request.getConstantConfiguration(); 159 160 // Try to find an existing endpoint. 161 sp<AAudioServiceEndpoint> endpoint = findExclusiveEndpoint_l(configuration); 162 163 // If we find an existing one then this one cannot be exclusive. 164 if (endpoint.get() != nullptr) { 165 ALOGW("openExclusiveEndpoint() already in use"); 166 // Already open so do not allow a second stream. 167 return nullptr; 168 } else { 169 sp<AAudioServiceEndpointMMAP> endpointMMap = new AAudioServiceEndpointMMAP(aaudioService); 170 ALOGV("openExclusiveEndpoint(), no match so try to open MMAP %p for dev %d", 171 endpointMMap.get(), configuration.getDeviceId()); 172 endpoint = endpointMMap; 173 174 aaudio_result_t result = endpoint->open(request); 175 if (result != AAUDIO_OK) { 176 ALOGE("openExclusiveEndpoint(), open failed"); 177 endpoint.clear(); 178 } else { 179 mExclusiveStreams.push_back(endpointMMap); 180 mExclusiveOpenCount++; 181 } 182 } 183 184 if (endpoint.get() != nullptr) { 185 // Increment the reference count under this lock. 186 endpoint->setOpenCount(endpoint->getOpenCount() + 1); 187 } 188 return endpoint; 189 } 190 191 sp<AAudioServiceEndpoint> AAudioEndpointManager::openSharedEndpoint( 192 AAudioService &aaudioService, 193 const aaudio::AAudioStreamRequest &request) { 194 195 std::lock_guard<std::mutex> lock(mSharedLock); 196 197 const AAudioStreamConfiguration &configuration = request.getConstantConfiguration(); 198 aaudio_direction_t direction = configuration.getDirection(); 199 200 // Try to find an existing endpoint. 201 sp<AAudioServiceEndpointShared> endpoint = findSharedEndpoint_l(configuration); 202 203 // If we can't find an existing one then open a new one. 204 if (endpoint.get() == nullptr) { 205 // we must call openStream with audioserver identity 206 int64_t token = IPCThreadState::self()->clearCallingIdentity(); 207 switch (direction) { 208 case AAUDIO_DIRECTION_INPUT: 209 endpoint = new AAudioServiceEndpointCapture(aaudioService); 210 break; 211 case AAUDIO_DIRECTION_OUTPUT: 212 endpoint = new AAudioServiceEndpointPlay(aaudioService); 213 break; 214 default: 215 break; 216 } 217 218 if (endpoint.get() != nullptr) { 219 aaudio_result_t result = endpoint->open(request); 220 if (result != AAUDIO_OK) { 221 endpoint.clear(); 222 } else { 223 mSharedStreams.push_back(endpoint); 224 mSharedOpenCount++; 225 } 226 } 227 ALOGV("%s(), created endpoint %p, requested device = %d, dir = %d", 228 __func__, endpoint.get(), configuration.getDeviceId(), (int)direction); 229 IPCThreadState::self()->restoreCallingIdentity(token); 230 } 231 232 if (endpoint.get() != nullptr) { 233 // Increment the reference count under this lock. 234 endpoint->setOpenCount(endpoint->getOpenCount() + 1); 235 } 236 return endpoint; 237 } 238 239 void AAudioEndpointManager::closeEndpoint(sp<AAudioServiceEndpoint>serviceEndpoint) { 240 if (serviceEndpoint->getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) { 241 return closeExclusiveEndpoint(serviceEndpoint); 242 } else { 243 return closeSharedEndpoint(serviceEndpoint); 244 } 245 } 246 247 void AAudioEndpointManager::closeExclusiveEndpoint(sp<AAudioServiceEndpoint> serviceEndpoint) { 248 if (serviceEndpoint.get() == nullptr) { 249 return; 250 } 251 252 // Decrement the reference count under this lock. 253 std::lock_guard<std::mutex> lock(mExclusiveLock); 254 int32_t newRefCount = serviceEndpoint->getOpenCount() - 1; 255 serviceEndpoint->setOpenCount(newRefCount); 256 257 // If no longer in use then actually close it. 258 if (newRefCount <= 0) { 259 mExclusiveStreams.erase( 260 std::remove(mExclusiveStreams.begin(), mExclusiveStreams.end(), serviceEndpoint), 261 mExclusiveStreams.end()); 262 263 serviceEndpoint->close(); 264 mExclusiveCloseCount++; 265 ALOGV("%s() %p for device %d", 266 __func__, serviceEndpoint.get(), serviceEndpoint->getDeviceId()); 267 } 268 } 269 270 void AAudioEndpointManager::closeSharedEndpoint(sp<AAudioServiceEndpoint> serviceEndpoint) { 271 if (serviceEndpoint.get() == nullptr) { 272 return; 273 } 274 275 // Decrement the reference count under this lock. 276 std::lock_guard<std::mutex> lock(mSharedLock); 277 int32_t newRefCount = serviceEndpoint->getOpenCount() - 1; 278 serviceEndpoint->setOpenCount(newRefCount); 279 280 // If no longer in use then actually close it. 281 if (newRefCount <= 0) { 282 mSharedStreams.erase( 283 std::remove(mSharedStreams.begin(), mSharedStreams.end(), serviceEndpoint), 284 mSharedStreams.end()); 285 286 serviceEndpoint->close(); 287 mSharedCloseCount++; 288 ALOGV("%s() %p for device %d", 289 __func__, serviceEndpoint.get(), serviceEndpoint->getDeviceId()); 290 } 291 } 292