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
AAudioEndpointManager()39 AAudioEndpointManager::AAudioEndpointManager()
40 : Singleton<AAudioEndpointManager>()
41 , mSharedStreams()
42 , mExclusiveStreams() {
43 }
44
dump() const45 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 &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.
findExclusiveEndpoint_l(const AAudioStreamConfiguration & configuration)95 sp<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.
findSharedEndpoint_l(const AAudioStreamConfiguration & configuration)111 sp<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
openEndpoint(AAudioService & audioService,const aaudio::AAudioStreamRequest & request,aaudio_sharing_mode_t sharingMode)126 sp<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
openExclusiveEndpoint(AAudioService & aaudioService __unused,const aaudio::AAudioStreamRequest & request)136 sp<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
openSharedEndpoint(AAudioService & aaudioService,const aaudio::AAudioStreamRequest & request)176 sp<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
closeEndpoint(sp<AAudioServiceEndpoint> serviceEndpoint)224 void 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
closeExclusiveEndpoint(sp<AAudioServiceEndpoint> serviceEndpoint)232 void 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
closeSharedEndpoint(sp<AAudioServiceEndpoint> serviceEndpoint)254 void 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