• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &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.
findExclusiveEndpoint_l(const AAudioStreamConfiguration & configuration)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.
findSharedEndpoint_l(const AAudioStreamConfiguration & configuration)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 
openEndpoint(AAudioService & audioService,const aaudio::AAudioStreamRequest & request)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 
openExclusiveEndpoint(AAudioService & aaudioService,const aaudio::AAudioStreamRequest & request)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 
openSharedEndpoint(AAudioService & aaudioService,const aaudio::AAudioStreamRequest & request)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 
closeEndpoint(sp<AAudioServiceEndpoint> serviceEndpoint)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 
closeExclusiveEndpoint(sp<AAudioServiceEndpoint> serviceEndpoint)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 
closeSharedEndpoint(sp<AAudioServiceEndpoint> serviceEndpoint)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