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(sp<AAudioServiceStreamBase> serviceStream)81aaudio_handle_t AAudioStreamTracker::addStreamForHandle(sp<AAudioServiceStreamBase> serviceStream) { 82 std::lock_guard<std::mutex> lock(mHandleLock); 83 aaudio_handle_t handle = mPreviousHandle; 84 // Assign a unique handle. 85 while (true) { 86 handle = bumpHandle(handle); 87 sp<AAudioServiceStreamBase> oldServiceStream = mStreamsByHandle[handle]; 88 // Is this an unused handle? It would be extremely unlikely to wrap 89 // around and collide with a very old handle. But just in case. 90 if (oldServiceStream.get() == nullptr) { 91 mStreamsByHandle[handle] = serviceStream; 92 break; 93 } 94 } 95 mPreviousHandle = handle; 96 return handle; 97 } 98 dump() const99std::string AAudioStreamTracker::dump() const NO_THREAD_SAFETY_ANALYSIS { 100 std::stringstream result; 101 const bool isLocked = AAudio_tryUntilTrue( 102 [this]()->bool { return mHandleLock.try_lock(); } /* f */, 103 50 /* times */, 104 20 /* sleepMs */); 105 if (!isLocked) { 106 result << "AAudioStreamTracker may be deadlocked\n"; 107 } else { 108 result << "Stream Handles:\n"; 109 for (const auto& it : mStreamsByHandle) { 110 aaudio_handle_t handle = it.second->getHandle(); 111 result << " 0x" << std::setfill('0') << std::setw(8) << std::hex << handle 112 << std::dec << std::setfill(' ') << "\n"; 113 } 114 115 mHandleLock.unlock(); 116 } 117 return result.str(); 118 } 119