xref: /aosp_15_r20/external/oboe/src/aaudio/AAudioExtensions.h (revision 05767d913155b055644481607e6fa1e35e2fe72c)
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