/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "AAudioStreamTracker" //#define LOG_NDEBUG 0 #include #include #include #include #include #include #include "AAudioStreamTracker.h" using namespace android; using namespace aaudio; int32_t AAudioStreamTracker::removeStreamByHandle( aaudio_handle_t streamHandle) { std::lock_guard lock(mHandleLock); auto count = mStreamsByHandle.erase(streamHandle); return static_cast(count); } sp AAudioStreamTracker::getStreamByHandle( aaudio_handle_t streamHandle) { std::lock_guard lock(mHandleLock); sp serviceStream; auto it = mStreamsByHandle.find(streamHandle); if (it != mStreamsByHandle.end()) { serviceStream = it->second; } return serviceStream; } // The port handle is only available when the stream is started. // So we have to iterate over all the streams. // Luckily this rarely happens. sp AAudioStreamTracker::findStreamByPortHandle( audio_port_handle_t portHandle) { std::lock_guard lock(mHandleLock); sp serviceStream; auto it = mStreamsByHandle.begin(); while (it != mStreamsByHandle.end()) { auto candidate = it->second; if (candidate->getPortHandle() == portHandle) { serviceStream = candidate; break; } it++; } return serviceStream; } // advance to next legal handle value __attribute__((no_sanitize("integer"))) aaudio_handle_t AAudioStreamTracker::bumpHandle(aaudio_handle_t handle) { handle++; // Only use positive integers. if (handle <= 0) { handle = 1; } return handle; } aaudio_handle_t AAudioStreamTracker::addStreamForHandle(sp serviceStream) { std::lock_guard lock(mHandleLock); aaudio_handle_t handle = mPreviousHandle; // Assign a unique handle. while (true) { handle = bumpHandle(handle); sp oldServiceStream = mStreamsByHandle[handle]; // Is this an unused handle? It would be extremely unlikely to wrap // around and collide with a very old handle. But just in case. if (oldServiceStream.get() == nullptr) { mStreamsByHandle[handle] = serviceStream; break; } } mPreviousHandle = handle; return handle; } std::string AAudioStreamTracker::dump() const NO_THREAD_SAFETY_ANALYSIS { std::stringstream result; const bool isLocked = AAudio_tryUntilTrue( [this]()->bool { return mHandleLock.try_lock(); } /* f */, 50 /* times */, 20 /* sleepMs */); if (!isLocked) { result << "AAudioStreamTracker may be deadlocked\n"; } else { result << "Stream Handles:\n"; for (const auto& it : mStreamsByHandle) { aaudio_handle_t handle = it.second->getHandle(); result << " 0x" << std::setfill('0') << std::setw(8) << std::hex << handle << std::dec << std::setfill(' ') << "\n"; } mHandleLock.unlock(); } return result.str(); }