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 public:
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 
isPolicyEnabled(int32_t policy)53     static bool isPolicyEnabled(int32_t policy) {
54         return (policy == AAUDIO_POLICY_AUTO || policy == AAUDIO_POLICY_ALWAYS);
55     }
56 
getInstance()57     static AAudioExtensions &getInstance() {
58         static AAudioExtensions instance;
59         return instance;
60     }
61 
isMMapUsed(oboe::AudioStream * oboeStream)62     bool isMMapUsed(oboe::AudioStream *oboeStream) {
63         AAudioStream *aaudioStream = (AAudioStream *) oboeStream->getUnderlyingStream();
64         return isMMapUsed(aaudioStream);
65     }
66 
isMMapUsed(AAudioStream * aaudioStream)67     bool isMMapUsed(AAudioStream *aaudioStream) {
68         if (loadSymbols()) return false;
69         if (mAAudioStream_isMMap == nullptr) return false;
70         return mAAudioStream_isMMap(aaudioStream);
71     }
72 
73     /**
74      * Controls whether the MMAP data path can be selected when opening a stream.
75      * It has no effect after the stream has been opened.
76      * It only affects the application that calls it. Other apps are not affected.
77      *
78      * @param enabled
79      * @return 0 or a negative error code
80      */
setMMapEnabled(bool enabled)81     int32_t setMMapEnabled(bool enabled) {
82         if (loadSymbols()) return AAUDIO_ERROR_UNAVAILABLE;
83         if (mAAudio_setMMapPolicy == nullptr) return false;
84         return mAAudio_setMMapPolicy(enabled ? AAUDIO_POLICY_AUTO : AAUDIO_POLICY_NEVER);
85     }
86 
isMMapEnabled()87     bool isMMapEnabled() {
88         if (loadSymbols()) return false;
89         if (mAAudio_getMMapPolicy == nullptr) return false;
90         int32_t policy = mAAudio_getMMapPolicy();
91         return isPolicyEnabled(policy);
92     }
93 
isMMapSupported()94     bool isMMapSupported() {
95         return mMMapSupported;
96     }
97 
isMMapExclusiveSupported()98     bool isMMapExclusiveSupported() {
99         return mMMapExclusiveSupported;
100     }
101 
102 private:
103 
104     enum {
105         AAUDIO_POLICY_NEVER = 1,
106         AAUDIO_POLICY_AUTO,
107         AAUDIO_POLICY_ALWAYS
108     };
109     typedef int32_t aaudio_policy_t;
110 
getIntegerProperty(const char * name,int defaultValue)111     int getIntegerProperty(const char *name, int defaultValue) {
112         int result = defaultValue;
113         char valueText[PROP_VALUE_MAX] = {0};
114         if (__system_property_get(name, valueText) != 0) {
115             result = atoi(valueText);
116         }
117         return result;
118     }
119 
120     /**
121      * Load the function pointers.
122      * This can be called multiple times.
123      * It should only be called from one thread.
124      *
125      * @return 0 if successful or negative error.
126      */
loadSymbols()127     aaudio_result_t loadSymbols() {
128         if (mAAudio_getMMapPolicy != nullptr) {
129             return 0;
130         }
131 
132         void *libHandle = AAudioLoader::getInstance()->getLibHandle();
133         if (libHandle == nullptr) {
134             LOGI("%s() could not find " LIB_AAUDIO_NAME, __func__);
135             return AAUDIO_ERROR_UNAVAILABLE;
136         }
137 
138         mAAudioStream_isMMap = (bool (*)(AAudioStream *stream))
139                 dlsym(libHandle, FUNCTION_IS_MMAP);
140         if (mAAudioStream_isMMap == nullptr) {
141             LOGI("%s() could not find " FUNCTION_IS_MMAP, __func__);
142             return AAUDIO_ERROR_UNAVAILABLE;
143         }
144 
145         mAAudio_setMMapPolicy = (int32_t (*)(aaudio_policy_t policy))
146                 dlsym(libHandle, FUNCTION_SET_MMAP_POLICY);
147         if (mAAudio_setMMapPolicy == nullptr) {
148             LOGI("%s() could not find " FUNCTION_SET_MMAP_POLICY, __func__);
149             return AAUDIO_ERROR_UNAVAILABLE;
150         }
151 
152         mAAudio_getMMapPolicy = (aaudio_policy_t (*)())
153                 dlsym(libHandle, FUNCTION_GET_MMAP_POLICY);
154         if (mAAudio_getMMapPolicy == nullptr) {
155             LOGI("%s() could not find " FUNCTION_GET_MMAP_POLICY, __func__);
156             return AAUDIO_ERROR_UNAVAILABLE;
157         }
158 
159         return 0;
160     }
161 
162     bool      mMMapSupported = false;
163     bool      mMMapExclusiveSupported = false;
164 
165     bool    (*mAAudioStream_isMMap)(AAudioStream *stream) = nullptr;
166     int32_t (*mAAudio_setMMapPolicy)(aaudio_policy_t policy) = nullptr;
167     aaudio_policy_t (*mAAudio_getMMapPolicy)() = nullptr;
168 };
169 
170 } // namespace oboe
171 
172 #endif //OBOE_AAUDIO_EXTENSIONS_H
173