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 if (request.getConstantConfiguration().getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) { 145 return openExclusiveEndpoint(audioService, request); 146 } else { 147 return openSharedEndpoint(audioService, request); 148 } 149 } 150 151 sp<AAudioServiceEndpoint> AAudioEndpointManager::openExclusiveEndpoint( 152 AAudioService &aaudioService, 153 const aaudio::AAudioStreamRequest &request) { 154 155 std::lock_guard<std::mutex> lock(mExclusiveLock); 156 157 const AAudioStreamConfiguration &configuration = request.getConstantConfiguration(); 158 159 // Try to find an existing endpoint. 160 sp<AAudioServiceEndpoint> endpoint = findExclusiveEndpoint_l(configuration); 161 162 // If we find an existing one then this one cannot be exclusive. 163 if (endpoint.get() != nullptr) { 164 ALOGW("openExclusiveEndpoint() already in use"); 165 // Already open so do not allow a second stream. 166 return nullptr; 167 } else { 168 sp<AAudioServiceEndpointMMAP> endpointMMap = new AAudioServiceEndpointMMAP(aaudioService); 169 ALOGV("openExclusiveEndpoint(), no match so try to open MMAP %p for dev %d", 170 endpointMMap.get(), configuration.getDeviceId()); 171 endpoint = endpointMMap; 172 173 aaudio_result_t result = endpoint->open(request); 174 if (result != AAUDIO_OK) { 175 ALOGV("openExclusiveEndpoint(), open failed"); 176 endpoint.clear(); 177 } else { 178 mExclusiveStreams.push_back(endpointMMap); 179 mExclusiveOpenCount++; 180 } 181 } 182 183 if (endpoint.get() != nullptr) { 184 // Increment the reference count under this lock. 185 endpoint->setOpenCount(endpoint->getOpenCount() + 1); 186 } 187 return endpoint; 188 } 189 190 sp<AAudioServiceEndpoint> AAudioEndpointManager::openSharedEndpoint( 191 AAudioService &aaudioService, 192 const aaudio::AAudioStreamRequest &request) { 193 194 std::lock_guard<std::mutex> lock(mSharedLock); 195 196 const AAudioStreamConfiguration &configuration = request.getConstantConfiguration(); 197 aaudio_direction_t direction = configuration.getDirection(); 198 199 // Try to find an existing endpoint. 200 sp<AAudioServiceEndpointShared> endpoint = findSharedEndpoint_l(configuration); 201 202 // If we can't find an existing one then open a new one. 203 if (endpoint.get() == nullptr) { 204 // we must call openStream with audioserver identity 205 int64_t token = IPCThreadState::self()->clearCallingIdentity(); 206 switch (direction) { 207 case AAUDIO_DIRECTION_INPUT: 208 endpoint = new AAudioServiceEndpointCapture(aaudioService); 209 break; 210 case AAUDIO_DIRECTION_OUTPUT: 211 endpoint = new AAudioServiceEndpointPlay(aaudioService); 212 break; 213 default: 214 break; 215 } 216 217 if (endpoint.get() != nullptr) { 218 aaudio_result_t result = endpoint->open(request); 219 if (result != AAUDIO_OK) { 220 endpoint.clear(); 221 } else { 222 mSharedStreams.push_back(endpoint); 223 mSharedOpenCount++; 224 } 225 } 226 ALOGV("%s(), created endpoint %p, requested device = %d, dir = %d", 227 __func__, endpoint.get(), configuration.getDeviceId(), (int)direction); 228 IPCThreadState::self()->restoreCallingIdentity(token); 229 } 230 231 if (endpoint.get() != nullptr) { 232 // Increment the reference count under this lock. 233 endpoint->setOpenCount(endpoint->getOpenCount() + 1); 234 } 235 return endpoint; 236 } 237 238 void AAudioEndpointManager::closeEndpoint(sp<AAudioServiceEndpoint>serviceEndpoint) { 239 if (serviceEndpoint->getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) { 240 return closeExclusiveEndpoint(serviceEndpoint); 241 } else { 242 return closeSharedEndpoint(serviceEndpoint); 243 } 244 } 245 246 void AAudioEndpointManager::closeExclusiveEndpoint(sp<AAudioServiceEndpoint> serviceEndpoint) { 247 if (serviceEndpoint.get() == nullptr) { 248 return; 249 } 250 251 // Decrement the reference count under this lock. 252 std::lock_guard<std::mutex> lock(mExclusiveLock); 253 int32_t newRefCount = serviceEndpoint->getOpenCount() - 1; 254 serviceEndpoint->setOpenCount(newRefCount); 255 256 // If no longer in use then actually close it. 257 if (newRefCount <= 0) { 258 mExclusiveStreams.erase( 259 std::remove(mExclusiveStreams.begin(), mExclusiveStreams.end(), serviceEndpoint), 260 mExclusiveStreams.end()); 261 262 serviceEndpoint->close(); 263 mExclusiveCloseCount++; 264 ALOGV("%s() %p for device %d", 265 __func__, serviceEndpoint.get(), serviceEndpoint->getDeviceId()); 266 } 267 } 268 269 void AAudioEndpointManager::closeSharedEndpoint(sp<AAudioServiceEndpoint> serviceEndpoint) { 270 if (serviceEndpoint.get() == nullptr) { 271 return; 272 } 273 274 // Decrement the reference count under this lock. 275 std::lock_guard<std::mutex> lock(mSharedLock); 276 int32_t newRefCount = serviceEndpoint->getOpenCount() - 1; 277 serviceEndpoint->setOpenCount(newRefCount); 278 279 // If no longer in use then actually close it. 280 if (newRefCount <= 0) { 281 mSharedStreams.erase( 282 std::remove(mSharedStreams.begin(), mSharedStreams.end(), serviceEndpoint), 283 mSharedStreams.end()); 284 285 serviceEndpoint->close(); 286 mSharedCloseCount++; 287 ALOGV("%s() %p for device %d", 288 __func__, serviceEndpoint.get(), serviceEndpoint->getDeviceId()); 289 } 290 } 291