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 <stdint.h> 22 23 #include <sys/system_properties.h> 24 25 #include "common/OboeDebug.h" 26 #include "oboe/Oboe.h" 27 #include "AAudioLoader.h" 28 29 namespace oboe { 30 31 #define LIB_AAUDIO_NAME "libaaudio.so" 32 #define FUNCTION_IS_MMAP "AAudioStream_isMMapUsed" 33 #define FUNCTION_SET_MMAP_POLICY "AAudio_setMMapPolicy" 34 #define FUNCTION_GET_MMAP_POLICY "AAudio_getMMapPolicy" 35 36 #define AAUDIO_ERROR_UNAVAILABLE static_cast<aaudio_result_t>(Result::ErrorUnavailable) 37 38 typedef struct AAudioStreamStruct AAudioStream; 39 40 /** 41 * Call some AAudio test routines that are not part of the normal API. 42 */ 43 class AAudioExtensions { 44 private: // Because it is a singleton. Call getInstance() instead. AAudioExtensions()45 AAudioExtensions() { 46 int32_t policy = getIntegerProperty("aaudio.mmap_policy", 0); 47 mMMapSupported = isPolicyEnabled(policy); 48 49 policy = getIntegerProperty("aaudio.mmap_exclusive_policy", 0); 50 mMMapExclusiveSupported = isPolicyEnabled(policy); 51 } 52 53 public: isPolicyEnabled(int32_t policy)54 static bool isPolicyEnabled(int32_t policy) { 55 return (policy == AAUDIO_POLICY_AUTO || policy == AAUDIO_POLICY_ALWAYS); 56 } 57 getInstance()58 static AAudioExtensions &getInstance() { 59 static AAudioExtensions instance; 60 return instance; 61 } 62 isMMapUsed(oboe::AudioStream * oboeStream)63 bool isMMapUsed(oboe::AudioStream *oboeStream) { 64 AAudioStream *aaudioStream = (AAudioStream *) oboeStream->getUnderlyingStream(); 65 return isMMapUsed(aaudioStream); 66 } 67 isMMapUsed(AAudioStream * aaudioStream)68 bool isMMapUsed(AAudioStream *aaudioStream) { 69 if (loadSymbols()) return false; 70 if (mAAudioStream_isMMap == nullptr) return false; 71 return mAAudioStream_isMMap(aaudioStream); 72 } 73 74 /** 75 * Controls whether the MMAP data path can be selected when opening a stream. 76 * It has no effect after the stream has been opened. 77 * It only affects the application that calls it. Other apps are not affected. 78 * 79 * @param enabled 80 * @return 0 or a negative error code 81 */ setMMapEnabled(bool enabled)82 int32_t setMMapEnabled(bool enabled) { 83 if (loadSymbols()) return AAUDIO_ERROR_UNAVAILABLE; 84 if (mAAudio_setMMapPolicy == nullptr) return false; 85 return mAAudio_setMMapPolicy(enabled ? AAUDIO_POLICY_AUTO : AAUDIO_POLICY_NEVER); 86 } 87 isMMapEnabled()88 bool isMMapEnabled() { 89 if (loadSymbols()) return false; 90 if (mAAudio_getMMapPolicy == nullptr) return false; 91 int32_t policy = mAAudio_getMMapPolicy(); 92 return (policy == Unspecified) ? mMMapSupported : isPolicyEnabled(policy); 93 } 94 isMMapSupported()95 bool isMMapSupported() { 96 return mMMapSupported; 97 } 98 isMMapExclusiveSupported()99 bool isMMapExclusiveSupported() { 100 return mMMapExclusiveSupported; 101 } 102 103 private: 104 105 enum { 106 AAUDIO_POLICY_NEVER = 1, 107 AAUDIO_POLICY_AUTO, 108 AAUDIO_POLICY_ALWAYS 109 }; 110 typedef int32_t aaudio_policy_t; 111 getIntegerProperty(const char * name,int defaultValue)112 int getIntegerProperty(const char *name, int defaultValue) { 113 int result = defaultValue; 114 char valueText[PROP_VALUE_MAX] = {0}; 115 if (__system_property_get(name, valueText) != 0) { 116 result = atoi(valueText); 117 } 118 return result; 119 } 120 121 /** 122 * Load the function pointers. 123 * This can be called multiple times. 124 * It should only be called from one thread. 125 * 126 * @return 0 if successful or negative error. 127 */ loadSymbols()128 aaudio_result_t loadSymbols() { 129 if (mAAudio_getMMapPolicy != nullptr) { 130 return 0; 131 } 132 133 AAudioLoader *libLoader = AAudioLoader::getInstance(); 134 int openResult = libLoader->open(); 135 if (openResult != 0) { 136 LOGD("%s() could not open " LIB_AAUDIO_NAME, __func__); 137 return AAUDIO_ERROR_UNAVAILABLE; 138 } 139 140 void *libHandle = AAudioLoader::getInstance()->getLibHandle(); 141 if (libHandle == nullptr) { 142 LOGE("%s() could not find " LIB_AAUDIO_NAME, __func__); 143 return AAUDIO_ERROR_UNAVAILABLE; 144 } 145 146 mAAudioStream_isMMap = (bool (*)(AAudioStream *stream)) 147 dlsym(libHandle, FUNCTION_IS_MMAP); 148 if (mAAudioStream_isMMap == nullptr) { 149 LOGI("%s() could not find " FUNCTION_IS_MMAP, __func__); 150 return AAUDIO_ERROR_UNAVAILABLE; 151 } 152 153 mAAudio_setMMapPolicy = (int32_t (*)(aaudio_policy_t policy)) 154 dlsym(libHandle, FUNCTION_SET_MMAP_POLICY); 155 if (mAAudio_setMMapPolicy == nullptr) { 156 LOGI("%s() could not find " FUNCTION_SET_MMAP_POLICY, __func__); 157 return AAUDIO_ERROR_UNAVAILABLE; 158 } 159 160 mAAudio_getMMapPolicy = (aaudio_policy_t (*)()) 161 dlsym(libHandle, FUNCTION_GET_MMAP_POLICY); 162 if (mAAudio_getMMapPolicy == nullptr) { 163 LOGI("%s() could not find " FUNCTION_GET_MMAP_POLICY, __func__); 164 return AAUDIO_ERROR_UNAVAILABLE; 165 } 166 167 return 0; 168 } 169 170 bool mMMapSupported = false; 171 bool mMMapExclusiveSupported = false; 172 173 bool (*mAAudioStream_isMMap)(AAudioStream *stream) = nullptr; 174 int32_t (*mAAudio_setMMapPolicy)(aaudio_policy_t policy) = nullptr; 175 aaudio_policy_t (*mAAudio_getMMapPolicy)() = nullptr; 176 }; 177 178 } // namespace oboe 179 180 #endif //OBOE_AAUDIO_EXTENSIONS_H 181