• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 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 #ifndef OBOE_AAUDIO_EXTENSIONS_H
18 #define OBOE_AAUDIO_EXTENSIONS_H
19 
20 #include <dlfcn.h>
21 #include <set>
22 #include <stdint.h>
23 
24 #include <sys/system_properties.h>
25 
26 #include "common/OboeDebug.h"
27 #include "oboe/Oboe.h"
28 #include "AAudioLoader.h"
29 
30 namespace oboe {
31 
32 #define LIB_AAUDIO_NAME          "libaaudio.so"
33 #define FUNCTION_IS_MMAP         "AAudioStream_isMMapUsed"
34 #define FUNCTION_SET_MMAP_POLICY "AAudio_setMMapPolicy"
35 #define FUNCTION_GET_MMAP_POLICY "AAudio_getMMapPolicy"
36 
37 #define AAUDIO_ERROR_UNAVAILABLE  static_cast<aaudio_result_t>(Result::ErrorUnavailable)
38 
39 typedef struct AAudioStreamStruct         AAudioStream;
40 
41 // The output device type collection must be updated if there is any new added output device type
42 const static std::set<DeviceType> ALL_OUTPUT_DEVICE_TYPES = {
43         DeviceType::BuiltinEarpiece,
44         DeviceType::BuiltinSpeaker,
45         DeviceType::WiredHeadset,
46         DeviceType::WiredHeadphones,
47         DeviceType::LineAnalog,
48         DeviceType::LineDigital,
49         DeviceType::BluetoothSco,
50         DeviceType::BluetoothA2dp,
51         DeviceType::Hdmi,
52         DeviceType::HdmiArc,
53         DeviceType::HdmiEarc,
54         DeviceType::UsbDevice,
55         DeviceType::UsbHeadset,
56         DeviceType::UsbAccessory,
57         DeviceType::Dock,
58         DeviceType::DockAnalog,
59         DeviceType::FM,
60         DeviceType::Telephony,
61         DeviceType::AuxLine,
62         DeviceType::IP,
63         DeviceType::Bus,
64         DeviceType::HearingAid,
65         DeviceType::BuiltinSpeakerSafe,
66         DeviceType::RemoteSubmix,
67         DeviceType::BleHeadset,
68         DeviceType::BleSpeaker,
69         DeviceType::BleBroadcast,
70 };
71 
72 // The input device type collection must be updated if there is any new added input device type
73 const static std::set<DeviceType> ALL_INPUT_DEVICE_TYPES = {
74         DeviceType::BuiltinMic,
75         DeviceType::BluetoothSco,
76         DeviceType::WiredHeadset,
77         DeviceType::Hdmi,
78         DeviceType::Telephony,
79         DeviceType::Dock,
80         DeviceType::DockAnalog,
81         DeviceType::UsbAccessory,
82         DeviceType::UsbDevice,
83         DeviceType::UsbHeadset,
84         DeviceType::FMTuner,
85         DeviceType::TVTuner,
86         DeviceType::LineAnalog,
87         DeviceType::LineDigital,
88         DeviceType::BluetoothA2dp,
89         DeviceType::IP,
90         DeviceType::Bus,
91         DeviceType::RemoteSubmix,
92         DeviceType::BleHeadset,
93         DeviceType::HdmiArc,
94         DeviceType::HdmiEarc,
95 };
96 
97 /**
98  * Call some AAudio test routines that are not part of the normal API.
99  */
100 class AAudioExtensions {
101 private: // Because it is a singleton. Call getInstance() instead.
AAudioExtensions()102     AAudioExtensions() {
103         mLibLoader = AAudioLoader::getInstance();
104         if (!initMMapPolicy()) {
105             int32_t policy = getIntegerProperty("aaudio.mmap_policy", 0);
106             mMMapSupported = isPolicyEnabled(policy);
107 
108             policy = getIntegerProperty("aaudio.mmap_exclusive_policy", 0);
109             mMMapExclusiveSupported = isPolicyEnabled(policy);
110         }
111     }
112 
113 public:
isPolicyEnabled(int32_t policy)114     static bool isPolicyEnabled(int32_t policy) {
115         const MMapPolicy mmapPolicy = static_cast<MMapPolicy>(policy);
116         return (mmapPolicy == MMapPolicy::Auto || mmapPolicy == MMapPolicy::Always);
117     }
118 
getInstance()119     static AAudioExtensions &getInstance() {
120         static AAudioExtensions instance;
121         return instance;
122     }
123 
isMMapUsed(oboe::AudioStream * oboeStream)124     bool isMMapUsed(oboe::AudioStream *oboeStream) {
125         AAudioStream *aaudioStream = (AAudioStream *) oboeStream->getUnderlyingStream();
126         return isMMapUsed(aaudioStream);
127     }
128 
isMMapUsed(AAudioStream * aaudioStream)129     bool isMMapUsed(AAudioStream *aaudioStream) {
130         if (mLibLoader != nullptr && mLibLoader->stream_isMMapUsed != nullptr) {
131             return mLibLoader->stream_isMMapUsed(aaudioStream);
132         }
133         if (loadSymbols()) return false;
134         if (mAAudioStream_isMMap == nullptr) return false;
135         return mAAudioStream_isMMap(aaudioStream);
136     }
137 
138     /**
139      * Controls whether the MMAP data path can be selected when opening a stream.
140      * It has no effect after the stream has been opened.
141      * It only affects the application that calls it. Other apps are not affected.
142      *
143      * @param enabled
144      * @return 0 or a negative error code
145      */
setMMapEnabled(bool enabled)146     int32_t setMMapEnabled(bool enabled) {
147         // The API for setting mmap policy is public after API level 36.
148         if (mLibLoader != nullptr && mLibLoader->aaudio_setMMapPolicy != nullptr) {
149             return mLibLoader->aaudio_setMMapPolicy(
150                     static_cast<aaudio_policy_t>(enabled ? MMapPolicy::Auto : MMapPolicy::Never));
151         }
152         // When there is no public API, fallback to loading the symbol from hidden API.
153         if (loadSymbols()) return AAUDIO_ERROR_UNAVAILABLE;
154         if (mAAudio_setMMapPolicy == nullptr) return false;
155         return mAAudio_setMMapPolicy(
156                 static_cast<int32_t>(enabled ? MMapPolicy::Auto : MMapPolicy::Never));
157     }
158 
isMMapEnabled()159     bool isMMapEnabled() {
160         // The API for getting mmap policy is public after API level 36.
161         // Use it when it is available.
162         if (mLibLoader != nullptr && mLibLoader->aaudio_getMMapPolicy != nullptr) {
163             MMapPolicy policy = static_cast<MMapPolicy>(mLibLoader->aaudio_getMMapPolicy());
164             return policy == MMapPolicy::Unspecified
165                     ? mMMapSupported : isPolicyEnabled(static_cast<int32_t>(policy));
166         }
167         // When there is no public API, fallback to loading the symbol from hidden API.
168         if (loadSymbols()) return false;
169         if (mAAudio_getMMapPolicy == nullptr) return false;
170         int32_t policy = mAAudio_getMMapPolicy();
171         return (policy == Unspecified) ? mMMapSupported : isPolicyEnabled(policy);
172     }
173 
isMMapSupported()174     bool isMMapSupported() {
175         return mMMapSupported;
176     }
177 
isMMapExclusiveSupported()178     bool isMMapExclusiveSupported() {
179         return mMMapExclusiveSupported;
180     }
181 
getMMapPolicy(DeviceType deviceType,Direction direction)182     MMapPolicy getMMapPolicy(DeviceType deviceType, Direction direction) {
183         if (mLibLoader == nullptr ||
184             mLibLoader->aaudio_getPlatformMMapPolicy == nullptr) {
185             return MMapPolicy::Unspecified;
186         }
187         return static_cast<MMapPolicy>(mLibLoader->aaudio_getPlatformMMapPolicy(
188                 static_cast<AAudio_DeviceType>(deviceType),
189                 static_cast<aaudio_direction_t>(direction)));
190     }
191 
getMMapExclusivePolicy(DeviceType deviceType,Direction direction)192     MMapPolicy getMMapExclusivePolicy(DeviceType deviceType, Direction direction) {
193         if (mLibLoader == nullptr ||
194             mLibLoader->aaudio_getPlatformMMapExclusivePolicy == nullptr) {
195             return MMapPolicy::Unspecified;
196         }
197         return static_cast<MMapPolicy>(mLibLoader->aaudio_getPlatformMMapExclusivePolicy(
198                 static_cast<AAudio_DeviceType>(deviceType),
199                 static_cast<aaudio_direction_t>(direction)));
200     }
201 
202 private:
initMMapPolicy()203     bool initMMapPolicy() {
204         if (mLibLoader == nullptr || mLibLoader->open() != 0) {
205             return false;
206         }
207         if (mLibLoader->aaudio_getPlatformMMapPolicy == nullptr ||
208             mLibLoader->aaudio_getPlatformMMapExclusivePolicy == nullptr) {
209             return false;
210         }
211         mMMapSupported =
212                 std::any_of(ALL_INPUT_DEVICE_TYPES.begin(), ALL_INPUT_DEVICE_TYPES.end(),
213                             [this](DeviceType deviceType) {
214                                 return  isPolicyEnabled(static_cast<int32_t>(
215                                         getMMapPolicy(deviceType, Direction::Input)));
216                             }) ||
217                 std::any_of(ALL_OUTPUT_DEVICE_TYPES.begin(), ALL_OUTPUT_DEVICE_TYPES.end(),
218                             [this](DeviceType deviceType) {
219                                 return  isPolicyEnabled(static_cast<int32_t>(
220                                         getMMapPolicy(deviceType, Direction::Output)));
221                             });
222         mMMapExclusiveSupported =
223                 std::any_of(ALL_INPUT_DEVICE_TYPES.begin(), ALL_INPUT_DEVICE_TYPES.end(),
224                             [this](DeviceType deviceType) {
225                                 return  isPolicyEnabled(static_cast<int32_t>(
226                                         getMMapExclusivePolicy(deviceType, Direction::Input)));
227                             }) ||
228                 std::any_of(ALL_OUTPUT_DEVICE_TYPES.begin(), ALL_OUTPUT_DEVICE_TYPES.end(),
229                             [this](DeviceType deviceType) {
230                                 return  isPolicyEnabled(static_cast<int32_t>(
231                                         getMMapExclusivePolicy(deviceType, Direction::Output)));
232                             });
233         return true;
234     }
235 
getIntegerProperty(const char * name,int defaultValue)236     int getIntegerProperty(const char *name, int defaultValue) {
237         int result = defaultValue;
238         char valueText[PROP_VALUE_MAX] = {0};
239         if (__system_property_get(name, valueText) != 0) {
240             result = atoi(valueText);
241         }
242         return result;
243     }
244 
245     /**
246      * Load the function pointers.
247      * This can be called multiple times.
248      * It should only be called from one thread.
249      *
250      * @return 0 if successful or negative error.
251      */
loadSymbols()252     aaudio_result_t loadSymbols() {
253         if (mAAudio_getMMapPolicy != nullptr) {
254             return 0;
255         }
256 
257         if (mLibLoader == nullptr || mLibLoader->open() != 0) {
258             LOGD("%s() could not open " LIB_AAUDIO_NAME, __func__);
259             return AAUDIO_ERROR_UNAVAILABLE;
260         }
261 
262         void *libHandle = mLibLoader->getLibHandle();
263         if (libHandle == nullptr) {
264             LOGE("%s() could not find " LIB_AAUDIO_NAME, __func__);
265             return AAUDIO_ERROR_UNAVAILABLE;
266         }
267 
268         mAAudioStream_isMMap = (bool (*)(AAudioStream *stream))
269                 dlsym(libHandle, FUNCTION_IS_MMAP);
270         if (mAAudioStream_isMMap == nullptr) {
271             LOGI("%s() could not find " FUNCTION_IS_MMAP, __func__);
272             return AAUDIO_ERROR_UNAVAILABLE;
273         }
274 
275         mAAudio_setMMapPolicy = (int32_t (*)(aaudio_policy_t policy))
276                 dlsym(libHandle, FUNCTION_SET_MMAP_POLICY);
277         if (mAAudio_setMMapPolicy == nullptr) {
278             LOGI("%s() could not find " FUNCTION_SET_MMAP_POLICY, __func__);
279             return AAUDIO_ERROR_UNAVAILABLE;
280         }
281 
282         mAAudio_getMMapPolicy = (aaudio_policy_t (*)())
283                 dlsym(libHandle, FUNCTION_GET_MMAP_POLICY);
284         if (mAAudio_getMMapPolicy == nullptr) {
285             LOGI("%s() could not find " FUNCTION_GET_MMAP_POLICY, __func__);
286             return AAUDIO_ERROR_UNAVAILABLE;
287         }
288 
289         return 0;
290     }
291 
292     bool      mMMapSupported = false;
293     bool      mMMapExclusiveSupported = false;
294 
295     bool    (*mAAudioStream_isMMap)(AAudioStream *stream) = nullptr;
296     int32_t (*mAAudio_setMMapPolicy)(aaudio_policy_t policy) = nullptr;
297     aaudio_policy_t (*mAAudio_getMMapPolicy)() = nullptr;
298 
299     AAudioLoader *mLibLoader;
300 };
301 
302 } // namespace oboe
303 
304 #endif //OBOE_AAUDIO_EXTENSIONS_H
305