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 <sys/types.h>
20 #include <unistd.h>
21
22 #include <android/log.h>
23 #include <gtest/gtest.h>
24
25 #include "test_aaudio.h"
26 #include "utils.h"
27
getNanoseconds(clockid_t clockId)28 int64_t getNanoseconds(clockid_t clockId) {
29 struct timespec time;
30 int result = clock_gettime(clockId, &time);
31 if (result < 0) {
32 return -errno;
33 }
34 return (time.tv_sec * NANOS_PER_SECOND) + time.tv_nsec;
35 }
36
performanceModeToString(aaudio_performance_mode_t mode)37 const char* performanceModeToString(aaudio_performance_mode_t mode) {
38 switch (mode) {
39 case AAUDIO_PERFORMANCE_MODE_NONE: return "DEFAULT";
40 case AAUDIO_PERFORMANCE_MODE_POWER_SAVING: return "POWER_SAVING";
41 case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY: return "LOW_LATENCY";
42 }
43 return "UNKNOWN";
44 }
45
sharingModeToString(aaudio_sharing_mode_t mode)46 const char* sharingModeToString(aaudio_sharing_mode_t mode) {
47 switch (mode) {
48 case AAUDIO_SHARING_MODE_SHARED: return "SHARED";
49 case AAUDIO_SHARING_MODE_EXCLUSIVE: return "EXCLUSIVE";
50 }
51 return "UNKNOWN";
52 }
53
54
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)55 StreamBuilderHelper::StreamBuilderHelper(
56 aaudio_direction_t direction, int32_t sampleRate,
57 int32_t channelCount, aaudio_format_t dataFormat,
58 aaudio_sharing_mode_t sharingMode, aaudio_performance_mode_t perfMode)
59 : mDirection{direction},
60 mRequested{sampleRate, channelCount, dataFormat, sharingMode, perfMode},
61 mActual{0, 0, AAUDIO_FORMAT_INVALID, -1, -1}, mFramesPerBurst{-1},
62 mBuilder{nullptr}, mStream{nullptr} {}
63
~StreamBuilderHelper()64 StreamBuilderHelper::~StreamBuilderHelper() {
65 close();
66 }
67
initBuilder()68 void StreamBuilderHelper::initBuilder() {
69 // Use an AAudioStreamBuilder to define the stream.
70 aaudio_result_t result = AAudio_createStreamBuilder(&mBuilder);
71 ASSERT_EQ(AAUDIO_OK, result);
72 ASSERT_TRUE(mBuilder != nullptr);
73
74 // Request stream properties.
75 AAudioStreamBuilder_setDeviceId(mBuilder, AAUDIO_UNSPECIFIED);
76 AAudioStreamBuilder_setDirection(mBuilder, mDirection);
77 AAudioStreamBuilder_setSampleRate(mBuilder, mRequested.sampleRate);
78 AAudioStreamBuilder_setChannelCount(mBuilder, mRequested.channelCount);
79 AAudioStreamBuilder_setFormat(mBuilder, mRequested.dataFormat);
80 AAudioStreamBuilder_setSharingMode(mBuilder, mRequested.sharingMode);
81 AAudioStreamBuilder_setPerformanceMode(mBuilder, mRequested.perfMode);
82 }
83
84 // Needs to be a 'void' function due to ASSERT requirements.
createAndVerifyStream(bool * success)85 void StreamBuilderHelper::createAndVerifyStream(bool *success) {
86 *success = false;
87
88 aaudio_result_t result = AAudioStreamBuilder_openStream(mBuilder, &mStream);
89 if (mRequested.sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE && result != AAUDIO_OK) {
90 __android_log_write(ANDROID_LOG_WARN, LOG_TAG, "Could not open a stream in EXCLUSIVE mode");
91 return;
92 }
93 ASSERT_EQ(AAUDIO_OK, result);
94 ASSERT_TRUE(mStream != nullptr);
95 ASSERT_EQ(AAUDIO_STREAM_STATE_OPEN, AAudioStream_getState(mStream));
96 ASSERT_EQ(mDirection, AAudioStream_getDirection(mStream));
97
98 mActual.sharingMode = AAudioStream_getSharingMode(mStream);
99 if (mActual.sharingMode != mRequested.sharingMode) {
100 // Since we are covering all possible values, the "actual" mode
101 // will also be tested, so no need to run the same test twice.
102 __android_log_print(ANDROID_LOG_WARN, LOG_TAG, "Sharing mode %s is not available",
103 sharingModeToString(mRequested.sharingMode));
104 return;
105 }
106
107 // Check to see what kind of stream we actually got.
108 mActual.sampleRate = AAudioStream_getSampleRate(mStream);
109 ASSERT_GE(mActual.sampleRate, 44100);
110 ASSERT_LE(mActual.sampleRate, 96000); // TODO what is min/max?
111
112 mActual.channelCount = AAudioStream_getChannelCount(mStream);
113 ASSERT_GE(mActual.channelCount, 1);
114 ASSERT_LE(mActual.channelCount, 16); // TODO what is min/max?
115
116 mActual.dataFormat = AAudioStream_getFormat(mStream);
117 ASSERT_EQ(AAUDIO_FORMAT_PCM_I16, mActual.dataFormat);
118
119 mActual.perfMode = AAudioStream_getPerformanceMode(mStream);
120 if (mRequested.perfMode != AAUDIO_PERFORMANCE_MODE_NONE
121 && mRequested.perfMode != mActual.perfMode) {
122 // Since we are covering all possible values, the "actual" mode
123 // will also be tested, so no need to run the same test twice.
124 __android_log_print(ANDROID_LOG_WARN, LOG_TAG, "Performance mode %s is not available",
125 performanceModeToString(mRequested.sharingMode));
126 return;
127 }
128
129 mFramesPerBurst = AAudioStream_getFramesPerBurst(mStream);
130 ASSERT_GE(mFramesPerBurst, 16);
131 ASSERT_LE(mFramesPerBurst, 3072); // on some devices, it can be 2052
132
133 int32_t actualBufferSize = AAudioStream_getBufferSizeInFrames(mStream);
134 ASSERT_GT(actualBufferSize, 0);
135 ASSERT_GT(AAudioStream_setBufferSizeInFrames(mStream, actualBufferSize), 0);
136
137 *success = true;
138 }
139
close()140 void StreamBuilderHelper::close() {
141 if (mBuilder != nullptr) {
142 ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(mBuilder));
143 }
144 if (mStream != nullptr) {
145 ASSERT_EQ(AAUDIO_OK, AAudioStream_close(mStream));
146 }
147 }
148
streamCommand(StreamCommand cmd,aaudio_stream_state_t fromState,aaudio_stream_state_t toState)149 void StreamBuilderHelper::streamCommand(
150 StreamCommand cmd, aaudio_stream_state_t fromState, aaudio_stream_state_t toState) {
151 ASSERT_EQ(AAUDIO_OK, cmd(mStream));
152 aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNINITIALIZED;
153 ASSERT_EQ(AAUDIO_OK,
154 AAudioStream_waitForStateChange(mStream, fromState, &state, DEFAULT_STATE_TIMEOUT));
155 ASSERT_EQ(toState, state);
156 }
157
158
InputStreamBuilderHelper(aaudio_sharing_mode_t requestedSharingMode,aaudio_performance_mode_t requestedPerfMode)159 InputStreamBuilderHelper::InputStreamBuilderHelper(
160 aaudio_sharing_mode_t requestedSharingMode, aaudio_performance_mode_t requestedPerfMode)
161 : StreamBuilderHelper{AAUDIO_DIRECTION_INPUT,
162 48000, 1, AAUDIO_FORMAT_PCM_I16, requestedSharingMode, requestedPerfMode} {}
163
164 // Native apps don't have permissions, thus recording can
165 // only be tested when running as root.
canTestRecording()166 static bool canTestRecording() {
167 static const bool runningAsRoot = getuid() == 0;
168 return runningAsRoot;
169 }
170
createAndVerifyStream(bool * success)171 void InputStreamBuilderHelper::createAndVerifyStream(bool *success) {
172 if (!canTestRecording()) {
173 __android_log_write(ANDROID_LOG_WARN, LOG_TAG, "No permissions to run recording tests");
174 *success = false;
175 } else {
176 StreamBuilderHelper::createAndVerifyStream(success);
177 }
178 }
179
180
OutputStreamBuilderHelper(aaudio_sharing_mode_t requestedSharingMode,aaudio_performance_mode_t requestedPerfMode)181 OutputStreamBuilderHelper::OutputStreamBuilderHelper(
182 aaudio_sharing_mode_t requestedSharingMode, aaudio_performance_mode_t requestedPerfMode)
183 : StreamBuilderHelper{AAUDIO_DIRECTION_OUTPUT,
184 48000, 2, AAUDIO_FORMAT_PCM_I16, requestedSharingMode, requestedPerfMode} {}
185
initBuilder()186 void OutputStreamBuilderHelper::initBuilder() {
187 StreamBuilderHelper::initBuilder();
188 AAudioStreamBuilder_setBufferCapacityInFrames(mBuilder, kBufferCapacityFrames);
189 }
190
createAndVerifyStream(bool * success)191 void OutputStreamBuilderHelper::createAndVerifyStream(bool *success) {
192 StreamBuilderHelper::createAndVerifyStream(success);
193 if (*success) {
194 ASSERT_GE(AAudioStream_getBufferCapacityInFrames(mStream), kBufferCapacityFrames);
195 }
196 }
197