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)33 int32_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)40 sp<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)54 sp<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)72 aaudio_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)81 aaudio_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() const99 std::string AAudioStreamTracker::dump() const {
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