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 &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.
     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.
    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 
    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 
    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 
    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 
    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 
    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 
    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