Home | History | Annotate | Download | only in oboeservice
      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