• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 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 #define LOG_TAG "AAudioTest"
18 
19 #include <stdio.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22 
23 #include <string>
24 
25 #include <android/log.h>
26 #include <gtest/gtest.h>
27 
28 #include "test_aaudio.h"
29 #include "utils.h"
30 
getNanoseconds(clockid_t clockId)31 int64_t getNanoseconds(clockid_t clockId) {
32     struct timespec time;
33     int result = clock_gettime(clockId, &time);
34     if (result < 0) {
35         return -errno;
36     }
37     return (time.tv_sec * NANOS_PER_SECOND) + time.tv_nsec;
38 }
39 
performanceModeToString(aaudio_performance_mode_t mode)40 const char* performanceModeToString(aaudio_performance_mode_t mode) {
41     switch (mode) {
42         case AAUDIO_PERFORMANCE_MODE_NONE: return "DEFAULT";
43         case AAUDIO_PERFORMANCE_MODE_POWER_SAVING: return "POWER_SAVING";
44         case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY: return "LOW_LATENCY";
45     }
46     return "UNKNOWN";
47 }
48 
sharingModeToString(aaudio_sharing_mode_t mode)49 const char* sharingModeToString(aaudio_sharing_mode_t mode) {
50     switch (mode) {
51         case AAUDIO_SHARING_MODE_SHARED: return "SHARED";
52         case AAUDIO_SHARING_MODE_EXCLUSIVE: return "EXCLUSIVE";
53     }
54     return "UNKNOWN";
55 }
56 
57 // Runs "pm list features" and attempts to find the specified feature in its output.
deviceSupportsFeature(const char * feature)58 bool deviceSupportsFeature(const char* feature) {
59     bool hasFeature = false;
60     FILE *p = popen("/system/bin/pm list features", "re");
61     if (p) {
62       char* line = NULL;
63       size_t len = 0;
64       while (getline(&line, &len, p) > 0) {
65           if (strstr(line, feature)) {
66               hasFeature = true;
67               break;
68           }
69       }
70       pclose(p);
71     } else {
72         __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, "popen failed: %d", errno);
73         _exit(EXIT_FAILURE);
74     }
75     __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Feature %s: %ssupported",
76             feature, hasFeature ? "" : "not ");
77     return hasFeature;
78 }
79 
80 // These periods are quite generous. They are not designed to put
81 // any restrictions on the implementation, but only to ensure sanity.
82 // Use int64_t because 96000 * 30000 is close to int32_t limits.
83 const std::map<aaudio_performance_mode_t, int64_t> StreamBuilderHelper::sMaxFramesPerBurstMs =
84 { { AAUDIO_PERFORMANCE_MODE_NONE, 128 },
85   { AAUDIO_PERFORMANCE_MODE_POWER_SAVING, 30 * 1000 },
86   { AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, 40 } };
87 
StreamBuilderHelper(aaudio_direction_t direction,int32_t sampleRate,int32_t channelCount,aaudio_format_t dataFormat,aaudio_sharing_mode_t sharingMode,aaudio_performance_mode_t perfMode)88 StreamBuilderHelper::StreamBuilderHelper(
89         aaudio_direction_t direction, int32_t sampleRate,
90         int32_t channelCount, aaudio_format_t dataFormat,
91         aaudio_sharing_mode_t sharingMode, aaudio_performance_mode_t perfMode)
92         : mDirection{direction},
93           mRequested{sampleRate, channelCount, dataFormat, sharingMode, perfMode},
94           mActual{0, 0, AAUDIO_FORMAT_INVALID, -1, -1}, mFramesPerBurst{-1},
95           mBuilder{nullptr}, mStream{nullptr} {}
96 
~StreamBuilderHelper()97 StreamBuilderHelper::~StreamBuilderHelper() {
98     close();
99 }
100 
initBuilder()101 void StreamBuilderHelper::initBuilder() {
102     ASSERT_EQ(1U, sMaxFramesPerBurstMs.count(mRequested.perfMode));
103 
104     // Use an AAudioStreamBuilder to define the stream.
105     aaudio_result_t result = AAudio_createStreamBuilder(&mBuilder);
106     ASSERT_EQ(AAUDIO_OK, result);
107     ASSERT_TRUE(mBuilder != nullptr);
108 
109     // Request stream properties.
110     AAudioStreamBuilder_setDeviceId(mBuilder, AAUDIO_UNSPECIFIED);
111     AAudioStreamBuilder_setDirection(mBuilder, mDirection);
112     AAudioStreamBuilder_setSampleRate(mBuilder, mRequested.sampleRate);
113     AAudioStreamBuilder_setChannelCount(mBuilder, mRequested.channelCount);
114     AAudioStreamBuilder_setFormat(mBuilder, mRequested.dataFormat);
115     AAudioStreamBuilder_setSharingMode(mBuilder, mRequested.sharingMode);
116     AAudioStreamBuilder_setPerformanceMode(mBuilder, mRequested.perfMode);
117 }
118 
119 // Needs to be a 'void' function due to ASSERT requirements.
createAndVerifyStream(bool * success)120 void StreamBuilderHelper::createAndVerifyStream(bool *success) {
121     *success = false;
122 
123     aaudio_result_t result = AAudioStreamBuilder_openStream(mBuilder, &mStream);
124     if (mRequested.sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE && result != AAUDIO_OK) {
125         __android_log_write(ANDROID_LOG_WARN, LOG_TAG, "Could not open a stream in EXCLUSIVE mode");
126         return;
127     }
128     ASSERT_EQ(AAUDIO_OK, result);
129     ASSERT_TRUE(mStream != nullptr);
130     ASSERT_EQ(AAUDIO_STREAM_STATE_OPEN, AAudioStream_getState(mStream));
131     ASSERT_EQ(mDirection, AAudioStream_getDirection(mStream));
132 
133     mActual.sharingMode = AAudioStream_getSharingMode(mStream);
134     if (mActual.sharingMode != mRequested.sharingMode) {
135         // Since we are covering all possible values, the "actual" mode
136         // will also be tested, so no need to run the same test twice.
137         __android_log_print(ANDROID_LOG_WARN, LOG_TAG, "Sharing mode %s is not available",
138                 sharingModeToString(mRequested.sharingMode));
139         return;
140     }
141 
142     // Check to see what kind of stream we actually got.
143     mActual.sampleRate = AAudioStream_getSampleRate(mStream);
144     ASSERT_GE(mActual.sampleRate, 44100);
145     ASSERT_LE(mActual.sampleRate, 96000); // TODO what is min/max?
146 
147     mActual.channelCount = AAudioStream_getChannelCount(mStream);
148     ASSERT_GE(mActual.channelCount, 1);
149     ASSERT_LE(mActual.channelCount, 16); // TODO what is min/max?
150 
151     mActual.dataFormat = AAudioStream_getFormat(mStream);
152     if (mRequested.dataFormat != AAUDIO_FORMAT_UNSPECIFIED) {
153         ASSERT_EQ(mRequested.dataFormat, mActual.dataFormat);
154     }
155 
156     mActual.perfMode = AAudioStream_getPerformanceMode(mStream);
157     if (mRequested.perfMode != AAUDIO_PERFORMANCE_MODE_NONE
158             && mRequested.perfMode != mActual.perfMode) {
159         // Since we are covering all possible values, the "actual" mode
160         // will also be tested, so no need to run the same test twice.
161         __android_log_print(ANDROID_LOG_WARN, LOG_TAG, "Performance mode %s is not available",
162                 performanceModeToString(mRequested.sharingMode));
163         return;
164     }
165 
166     mFramesPerBurst = AAudioStream_getFramesPerBurst(mStream);
167     ASSERT_GE(mFramesPerBurst, 16);
168     const int32_t maxFramesPerBurst =
169             mActual.sampleRate * sMaxFramesPerBurstMs.at(mActual.perfMode) / MILLIS_PER_SECOND;
170     ASSERT_LE(mFramesPerBurst, maxFramesPerBurst);
171 
172     int32_t actualBufferSize = AAudioStream_getBufferSizeInFrames(mStream);
173     ASSERT_GT(actualBufferSize, 0);
174     ASSERT_GT(AAudioStream_setBufferSizeInFrames(mStream, actualBufferSize), 0);
175 
176     *success = true;
177 }
178 
close()179 void StreamBuilderHelper::close() {
180     if (mBuilder != nullptr) {
181         ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(mBuilder));
182     }
183     if (mStream != nullptr) {
184         ASSERT_EQ(AAUDIO_OK, AAudioStream_close(mStream));
185     }
186 }
187 
streamCommand(StreamCommand cmd,aaudio_stream_state_t fromState,aaudio_stream_state_t toState)188 void StreamBuilderHelper::streamCommand(
189         StreamCommand cmd, aaudio_stream_state_t fromState, aaudio_stream_state_t toState) {
190     ASSERT_EQ(AAUDIO_OK, cmd(mStream));
191     aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNINITIALIZED;
192     ASSERT_EQ(AAUDIO_OK,
193             AAudioStream_waitForStateChange(mStream, fromState, &state, DEFAULT_STATE_TIMEOUT));
194     ASSERT_EQ(toState, state);
195 }
196 
InputStreamBuilderHelper(aaudio_sharing_mode_t requestedSharingMode,aaudio_performance_mode_t requestedPerfMode,aaudio_format_t requestedFormat)197 InputStreamBuilderHelper::InputStreamBuilderHelper(
198         aaudio_sharing_mode_t requestedSharingMode,
199         aaudio_performance_mode_t requestedPerfMode,
200         aaudio_format_t requestedFormat)
201         : StreamBuilderHelper{AAUDIO_DIRECTION_INPUT,
202             48000, 1, requestedFormat, requestedSharingMode, requestedPerfMode} {}
203 
204 
OutputStreamBuilderHelper(aaudio_sharing_mode_t requestedSharingMode,aaudio_performance_mode_t requestedPerfMode,aaudio_format_t requestedFormat)205 OutputStreamBuilderHelper::OutputStreamBuilderHelper(
206         aaudio_sharing_mode_t requestedSharingMode,
207         aaudio_performance_mode_t requestedPerfMode,
208         aaudio_format_t requestedFormat)
209         : StreamBuilderHelper{AAUDIO_DIRECTION_OUTPUT,
210             48000, 2, requestedFormat, requestedSharingMode, requestedPerfMode} {}
211 
initBuilder()212 void OutputStreamBuilderHelper::initBuilder() {
213     StreamBuilderHelper::initBuilder();
214     AAudioStreamBuilder_setBufferCapacityInFrames(mBuilder, kBufferCapacityFrames);
215 }
216 
createAndVerifyStream(bool * success)217 void OutputStreamBuilderHelper::createAndVerifyStream(bool *success) {
218     StreamBuilderHelper::createAndVerifyStream(success);
219     if (*success) {
220         ASSERT_GE(AAudioStream_getBufferCapacityInFrames(mStream), kBufferCapacityFrames);
221     }
222 }
223 
AAudioExtensions()224 AAudioExtensions::AAudioExtensions()
225     : mMMapSupported(isPolicyEnabled(getMMapPolicyProperty()))
226     , mMMapExclusiveSupported(isPolicyEnabled(getIntegerProperty(
227             "aaudio.mmap_exclusive_policy", AAUDIO_POLICY_UNSPECIFIED))) {
228     loadLibrary();
229 }
230 
getIntegerProperty(const char * name,int defaultValue)231 int AAudioExtensions::getIntegerProperty(const char *name, int defaultValue) {
232     int result = defaultValue;
233     char valueText[PROP_VALUE_MAX] = {0};
234     if (__system_property_get(name, valueText) != 0) {
235         result = atoi(valueText);
236     }
237     return result;
238 }
239 
240 // This should only be called once from the constructor.
loadLibrary()241 bool AAudioExtensions::loadLibrary() {
242     mLibHandle = dlopen(LIB_AAUDIO_NAME, 0);
243     if (mLibHandle == nullptr) {
244         //LOGI("%s() could not find " LIB_AAUDIO_NAME, __func__);
245         return false;
246     }
247 
248     mAAudioStream_isMMap = (bool (*)(AAudioStream *stream))
249             dlsym(mLibHandle, FUNCTION_IS_MMAP);
250     if (mAAudioStream_isMMap == nullptr) {
251         //LOGI("%s() could not find " FUNCTION_IS_MMAP, __func__);
252         return false;
253     }
254 
255     mAAudio_setMMapPolicy = (int32_t (*)(aaudio_policy_t policy))
256             dlsym(mLibHandle, FUNCTION_SET_MMAP_POLICY);
257     if (mAAudio_setMMapPolicy == nullptr) {
258         //LOGI("%s() could not find " FUNCTION_SET_MMAP_POLICY, __func__);
259         return false;
260     }
261 
262     mAAudio_getMMapPolicy = (aaudio_policy_t (*)())
263             dlsym(mLibHandle, FUNCTION_GET_MMAP_POLICY);
264     if (mAAudio_getMMapPolicy == nullptr) {
265         //LOGI("%s() could not find " FUNCTION_GET_MMAP_POLICY, __func__);
266         return false;
267     }
268     mFunctionsLoaded = true;
269     return mFunctionsLoaded;
270 }