1 /* 2 * Copyright (C) 2016 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 "AAudioStreamTracker" 18 //#define LOG_NDEBUG 0 19 #include <utils/Log.h> 20 21 #include <iomanip> 22 #include <iostream> 23 #include <sstream> 24 25 #include <aaudio/AAudio.h> 26 #include <utils/String16.h> 27 28 #include "AAudioStreamTracker.h" 29 30 using namespace android; 31 using namespace aaudio; 32 decrementAndRemoveStreamByHandle(aaudio_handle_t streamHandle)33sp<AAudioServiceStreamBase> AAudioStreamTracker::decrementAndRemoveStreamByHandle( 34 aaudio_handle_t streamHandle) { 35 std::lock_guard<std::mutex> lock(mHandleLock); 36 sp<AAudioServiceStreamBase> serviceStream; 37 auto it = mStreamsByHandle.find(streamHandle); 38 if (it != mStreamsByHandle.end()) { 39 sp<AAudioServiceStreamBase> tempStream = it->second; 40 // Does the caller need to close the stream? 41 // The reference count should never be negative. 42 // But it is safer to check for <= 0 than == 0. 43 if ((tempStream->decrementServiceReferenceCount_l() <= 0) && tempStream->isCloseNeeded()) { 44 serviceStream = tempStream; // Only return stream if ready to be closed. 45 mStreamsByHandle.erase(it); 46 } 47 } 48 return serviceStream; 49 } 50 getStreamByHandleAndIncrement(aaudio_handle_t streamHandle)51sp<AAudioServiceStreamBase> AAudioStreamTracker::getStreamByHandleAndIncrement( 52 aaudio_handle_t streamHandle) { 53 std::lock_guard<std::mutex> lock(mHandleLock); 54 sp<AAudioServiceStreamBase> serviceStream; 55 auto it = mStreamsByHandle.find(streamHandle); 56 if (it != mStreamsByHandle.end()) { 57 serviceStream = it->second; 58 serviceStream->incrementServiceReferenceCount_l(); 59 } 60 return serviceStream; 61 } 62 63 // The port handle is only available when the stream is started. 64 // So we have to iterate over all the streams. 65 // Luckily this rarely happens. findStreamByPortHandleAndIncrement(audio_port_handle_t portHandle)66sp<AAudioServiceStreamBase> AAudioStreamTracker::findStreamByPortHandleAndIncrement( 67 audio_port_handle_t portHandle) { 68 std::lock_guard<std::mutex> lock(mHandleLock); 69 sp<AAudioServiceStreamBase> serviceStream; 70 auto it = mStreamsByHandle.begin(); 71 while (it != mStreamsByHandle.end()) { 72 auto candidate = it->second; 73 if (candidate->getPortHandle() == portHandle) { 74 serviceStream = candidate; 75 serviceStream->incrementServiceReferenceCount_l(); 76 break; 77 } 78 it++; 79 } 80 return serviceStream; 81 } 82 83 // advance to next legal handle value 84 __attribute__((no_sanitize("integer"))) bumpHandle(aaudio_handle_t handle)85aaudio_handle_t AAudioStreamTracker::bumpHandle(aaudio_handle_t handle) { 86 handle++; 87 // Only use positive integers. 88 if (handle <= 0) { 89 handle = 1; 90 } 91 return handle; 92 } 93 addStreamForHandle(sp<AAudioServiceStreamBase> serviceStream)94aaudio_handle_t AAudioStreamTracker::addStreamForHandle(sp<AAudioServiceStreamBase> serviceStream) { 95 std::lock_guard<std::mutex> lock(mHandleLock); 96 aaudio_handle_t handle = mPreviousHandle; 97 // Assign a unique handle. 98 while (true) { 99 handle = bumpHandle(handle); 100 sp<AAudioServiceStreamBase> oldServiceStream = mStreamsByHandle[handle]; 101 // Is this an unused handle? It would be extremely unlikely to wrap 102 // around and collide with a very old handle. But just in case. 103 if (oldServiceStream.get() == nullptr) { 104 mStreamsByHandle[handle] = serviceStream; 105 break; 106 } 107 } 108 mPreviousHandle = handle; 109 return handle; 110 } 111 dump() const112std::string AAudioStreamTracker::dump() const { 113 std::stringstream result; 114 const bool isLocked = AAudio_tryUntilTrue( 115 [this]()->bool { return mHandleLock.try_lock(); } /* f */, 116 50 /* times */, 117 20 /* sleepMs */); 118 if (!isLocked) { 119 result << "AAudioStreamTracker may be deadlocked\n"; 120 } else { 121 result << "Stream Handles:\n"; 122 for (const auto& it : mStreamsByHandle) { 123 aaudio_handle_t handle = it.second->getHandle(); 124 result << " 0x" << std::setfill('0') << std::setw(8) << std::hex << handle 125 << std::dec << std::setfill(' ') << "\n"; 126 } 127 128 mHandleLock.unlock(); 129 } 130 return result.str(); 131 } 132