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