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 removeStreamByHandle(aaudio_handle_t streamHandle)33int32_t AAudioStreamTracker::removeStreamByHandle( 34 aaudio_handle_t streamHandle) { 35 std::lock_guard<std::mutex> lock(mHandleLock); 36 auto count = mStreamsByHandle.erase(streamHandle); 37 return static_cast<int32_t>(count); 38 } 39 getStreamByHandle(aaudio_handle_t streamHandle)40sp<AAudioServiceStreamBase> AAudioStreamTracker::getStreamByHandle( 41 aaudio_handle_t streamHandle) { 42 std::lock_guard<std::mutex> lock(mHandleLock); 43 sp<AAudioServiceStreamBase> serviceStream; 44 auto it = mStreamsByHandle.find(streamHandle); 45 if (it != mStreamsByHandle.end()) { 46 serviceStream = it->second; 47 } 48 return serviceStream; 49 } 50 51 // The port handle is only available when the stream is started. 52 // So we have to iterate over all the streams. 53 // Luckily this rarely happens. findStreamByPortHandle(audio_port_handle_t portHandle)54sp<AAudioServiceStreamBase> AAudioStreamTracker::findStreamByPortHandle( 55 audio_port_handle_t portHandle) { 56 std::lock_guard<std::mutex> lock(mHandleLock); 57 sp<AAudioServiceStreamBase> serviceStream; 58 auto it = mStreamsByHandle.begin(); 59 while (it != mStreamsByHandle.end()) { 60 auto candidate = it->second; 61 if (candidate->getPortHandle() == portHandle) { 62 serviceStream = candidate; 63 break; 64 } 65 it++; 66 } 67 return serviceStream; 68 } 69 70 // advance to next legal handle value 71 __attribute__((no_sanitize("integer"))) bumpHandle(aaudio_handle_t handle)72aaudio_handle_t AAudioStreamTracker::bumpHandle(aaudio_handle_t handle) { 73 handle++; 74 // Only use positive integers. 75 if (handle <= 0) { 76 handle = 1; 77 } 78 return handle; 79 } 80 addStreamForHandle(const sp<AAudioServiceStreamBase> & serviceStream)81aaudio_handle_t AAudioStreamTracker::addStreamForHandle( 82 const sp<AAudioServiceStreamBase>& serviceStream) { 83 std::lock_guard<std::mutex> lock(mHandleLock); 84 aaudio_handle_t handle = mPreviousHandle; 85 // Assign a unique handle. 86 while (true) { 87 handle = bumpHandle(handle); 88 sp<AAudioServiceStreamBase> oldServiceStream = mStreamsByHandle[handle]; 89 // Is this an unused handle? It would be extremely unlikely to wrap 90 // around and collide with a very old handle. But just in case. 91 if (oldServiceStream.get() == nullptr) { 92 mStreamsByHandle[handle] = serviceStream; 93 break; 94 } 95 } 96 mPreviousHandle = handle; 97 return handle; 98 } 99 dump() const100std::string AAudioStreamTracker::dump() const NO_THREAD_SAFETY_ANALYSIS { 101 std::stringstream result; 102 const bool isLocked = AAudio_tryUntilTrue( 103 [this]()->bool { return mHandleLock.try_lock(); } /* f */, 104 50 /* times */, 105 20 /* sleepMs */); 106 if (!isLocked) { 107 result << "AAudioStreamTracker may be deadlocked\n"; 108 } else { 109 result << "Stream Handles:\n"; 110 for (const auto& it : mStreamsByHandle) { 111 aaudio_handle_t handle = it.second->getHandle(); 112 result << " 0x" << std::setfill('0') << std::setw(8) << std::hex << handle 113 << std::dec << std::setfill(' ') << "\n"; 114 } 115 116 mHandleLock.unlock(); 117 } 118 return result.str(); 119 } 120