1 /*
2 * Copyright (C) 2018 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 // To run this test (as root):
18 // 1) Build it
19 // 2) adb push to /vendor/bin
20 // 3) adb shell /vendor/bin/r_submix_tests
21
22 #define LOG_TAG "RemoteSubmixTest"
23
24 #include <memory>
25
26 #include <gtest/gtest.h>
27 #include <hardware/audio.h>
28 #include <utils/Errors.h>
29 #include <utils/Log.h>
30
31 using namespace android;
32
load_audio_interface(const char * if_name,audio_hw_device_t ** dev)33 static status_t load_audio_interface(const char* if_name, audio_hw_device_t **dev)
34 {
35 const hw_module_t *mod;
36 int rc;
37
38 rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);
39 if (rc) {
40 ALOGE("%s couldn't load audio hw module %s.%s (%s)", __func__,
41 AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
42 goto out;
43 }
44 rc = audio_hw_device_open(mod, dev);
45 if (rc) {
46 ALOGE("%s couldn't open audio hw device in %s.%s (%s)", __func__,
47 AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
48 goto out;
49 }
50 if ((*dev)->common.version < AUDIO_DEVICE_API_VERSION_MIN) {
51 ALOGE("%s wrong audio hw device version %04x", __func__, (*dev)->common.version);
52 rc = BAD_VALUE;
53 audio_hw_device_close(*dev);
54 goto out;
55 }
56 return OK;
57
58 out:
59 *dev = NULL;
60 return rc;
61 }
62
63 class RemoteSubmixTest : public testing::Test {
64 protected:
65 void SetUp() override;
66 void TearDown() override;
67
68 void GenerateData(char* buffer, size_t bufferSize);
69 void OpenInputStream(
70 const char* address, bool mono, uint32_t sampleRate, audio_stream_in_t** streamIn);
71 void OpenOutputStream(
72 const char* address, bool mono, uint32_t sampleRate, audio_stream_out_t** streamOut);
73 void ReadFromStream(audio_stream_in_t* streamIn, char* buffer, size_t bufferSize);
74 void VerifyBufferAllZeroes(char* buffer, size_t bufferSize);
75 void VerifyBufferNotZeroes(char* buffer, size_t bufferSize);
76 void VerifyOutputInput(
77 audio_stream_out_t* streamOut, size_t outBufferSize,
78 audio_stream_in_t* streamIn, size_t inBufferSize, size_t repeats);
79 void WriteIntoStream(audio_stream_out_t* streamOut, const char* buffer, size_t bufferSize);
80 void WriteSomethingIntoStream(audio_stream_out_t* streamOut, size_t bufferSize, size_t repeats);
81
82 audio_hw_device_t* mDev;
83 };
84
SetUp()85 void RemoteSubmixTest::SetUp() {
86 mDev = nullptr;
87 ASSERT_EQ(OK, load_audio_interface(AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX, &mDev));
88 ASSERT_NE(nullptr, mDev);
89 }
90
TearDown()91 void RemoteSubmixTest::TearDown() {
92 if (mDev != nullptr) {
93 int status = audio_hw_device_close(mDev);
94 mDev = nullptr;
95 ALOGE_IF(status, "Error closing audio hw device %p: %s", mDev, strerror(-status));
96 ASSERT_EQ(0, status);
97 }
98 }
99
GenerateData(char * buffer,size_t bufferSize)100 void RemoteSubmixTest::GenerateData(char* buffer, size_t bufferSize) {
101 for (size_t i = 0; i < bufferSize; ++i) {
102 buffer[i] = static_cast<char>(i & 0x7f);
103 }
104 }
105
OpenInputStream(const char * address,bool mono,uint32_t sampleRate,audio_stream_in_t ** streamIn)106 void RemoteSubmixTest::OpenInputStream(
107 const char* address, bool mono, uint32_t sampleRate, audio_stream_in_t** streamIn) {
108 *streamIn = nullptr;
109 struct audio_config configIn = {};
110 configIn.channel_mask = mono ? AUDIO_CHANNEL_IN_MONO : AUDIO_CHANNEL_IN_STEREO;
111 configIn.sample_rate = sampleRate;
112 status_t result = mDev->open_input_stream(mDev,
113 AUDIO_IO_HANDLE_NONE, AUDIO_DEVICE_NONE, &configIn,
114 streamIn, AUDIO_INPUT_FLAG_NONE, address, AUDIO_SOURCE_DEFAULT);
115 ASSERT_EQ(OK, result);
116 ASSERT_NE(nullptr, *streamIn);
117 }
118
OpenOutputStream(const char * address,bool mono,uint32_t sampleRate,audio_stream_out_t ** streamOut)119 void RemoteSubmixTest::OpenOutputStream(
120 const char* address, bool mono, uint32_t sampleRate, audio_stream_out_t** streamOut) {
121 *streamOut = nullptr;
122 struct audio_config configOut = {};
123 configOut.channel_mask = mono ? AUDIO_CHANNEL_OUT_MONO : AUDIO_CHANNEL_OUT_STEREO;
124 configOut.sample_rate = sampleRate;
125 status_t result = mDev->open_output_stream(mDev,
126 AUDIO_IO_HANDLE_NONE, AUDIO_DEVICE_NONE, AUDIO_OUTPUT_FLAG_NONE,
127 &configOut, streamOut, address);
128 ASSERT_EQ(OK, result);
129 ASSERT_NE(nullptr, *streamOut);
130 }
131
ReadFromStream(audio_stream_in_t * streamIn,char * buffer,size_t bufferSize)132 void RemoteSubmixTest::ReadFromStream(
133 audio_stream_in_t* streamIn, char* buffer, size_t bufferSize) {
134 ssize_t result = streamIn->read(streamIn, buffer, bufferSize);
135 EXPECT_EQ(bufferSize, static_cast<size_t>(result));
136 }
137
VerifyBufferAllZeroes(char * buffer,size_t bufferSize)138 void RemoteSubmixTest::VerifyBufferAllZeroes(char* buffer, size_t bufferSize) {
139 for (size_t i = 0; i < bufferSize; ++i) {
140 if (buffer[i]) {
141 ADD_FAILURE();
142 return;
143 }
144 }
145 }
146
VerifyBufferNotZeroes(char * buffer,size_t bufferSize)147 void RemoteSubmixTest::VerifyBufferNotZeroes(char* buffer, size_t bufferSize) {
148 for (size_t i = 0; i < bufferSize; ++i) {
149 if (buffer[i]) return;
150 }
151 ADD_FAILURE();
152 }
153
VerifyOutputInput(audio_stream_out_t * streamOut,size_t outBufferSize,audio_stream_in_t * streamIn,size_t inBufferSize,size_t repeats)154 void RemoteSubmixTest::VerifyOutputInput(
155 audio_stream_out_t* streamOut, size_t outBufferSize,
156 audio_stream_in_t* streamIn, size_t inBufferSize,
157 size_t repeats) {
158 std::unique_ptr<char[]> outBuffer(new char[outBufferSize]), inBuffer(new char[inBufferSize]);
159 GenerateData(outBuffer.get(), outBufferSize);
160 for (size_t i = 0; i < repeats; ++i) {
161 WriteIntoStream(streamOut, outBuffer.get(), outBufferSize);
162 memset(inBuffer.get(), 0, inBufferSize);
163 ReadFromStream(streamIn, inBuffer.get(), inBufferSize);
164 if (inBufferSize == outBufferSize) {
165 ASSERT_EQ(0, memcmp(outBuffer.get(), inBuffer.get(), inBufferSize));
166 } else {
167 VerifyBufferNotZeroes(inBuffer.get(), inBufferSize);
168 }
169 }
170 }
171
WriteIntoStream(audio_stream_out_t * streamOut,const char * buffer,size_t bufferSize)172 void RemoteSubmixTest::WriteIntoStream(
173 audio_stream_out_t* streamOut, const char* buffer, size_t bufferSize) {
174 ssize_t result = streamOut->write(streamOut, buffer, bufferSize);
175 EXPECT_EQ(bufferSize, static_cast<size_t>(result));
176 }
177
WriteSomethingIntoStream(audio_stream_out_t * streamOut,size_t bufferSize,size_t repeats)178 void RemoteSubmixTest::WriteSomethingIntoStream(
179 audio_stream_out_t* streamOut, size_t bufferSize, size_t repeats) {
180 std::unique_ptr<char[]> buffer(new char[bufferSize]);
181 GenerateData(buffer.get(), bufferSize);
182 for (size_t i = 0; i < repeats; ++i) {
183 WriteIntoStream(streamOut, buffer.get(), bufferSize);
184 }
185 }
186
TEST_F(RemoteSubmixTest,InitSuccess)187 TEST_F(RemoteSubmixTest, InitSuccess) {
188 // SetUp must finish with no assertions.
189 }
190
191 // Verifies that when no input was opened, writing into an output stream does not block.
TEST_F(RemoteSubmixTest,OutputDoesNotBlockWhenNoInput)192 TEST_F(RemoteSubmixTest, OutputDoesNotBlockWhenNoInput) {
193 const char* address = "1";
194 audio_stream_out_t* streamOut;
195 OpenOutputStream(address, true /*mono*/, 48000, &streamOut);
196 WriteSomethingIntoStream(streamOut, 1024, 16);
197 mDev->close_output_stream(mDev, streamOut);
198 }
199
200 // Verifies that when input is opened but not reading, writing into an output stream does not block.
201 // !!! Currently does not finish because requires setting a parameter from another thread !!!
202 // TEST_F(RemoteSubmixTest, OutputDoesNotBlockWhenInputStuck) {
203 // const char* address = "1";
204 // audio_stream_out_t* streamOut;
205 // OpenOutputStream(address, true /*mono*/, 48000, &streamOut);
206 // audio_stream_in_t* streamIn;
207 // OpenInputStream(address, true /*mono*/, 48000, &streamIn);
208 // WriteSomethingIntoStream(streamOut, 1024, 16);
209 // mDev->close_input_stream(mDev, streamIn);
210 // mDev->close_output_stream(mDev, streamOut);
211 // }
212
TEST_F(RemoteSubmixTest,OutputAndInput)213 TEST_F(RemoteSubmixTest, OutputAndInput) {
214 const char* address = "1";
215 audio_stream_out_t* streamOut;
216 OpenOutputStream(address, true /*mono*/, 48000, &streamOut);
217 audio_stream_in_t* streamIn;
218 OpenInputStream(address, true /*mono*/, 48000, &streamIn);
219 const size_t bufferSize = 1024;
220 VerifyOutputInput(streamOut, bufferSize, streamIn, bufferSize, 16);
221 mDev->close_input_stream(mDev, streamIn);
222 mDev->close_output_stream(mDev, streamOut);
223 }
224
225 // Verifies that reading and writing into a closed stream fails gracefully.
TEST_F(RemoteSubmixTest,OutputAndInputAfterClose)226 TEST_F(RemoteSubmixTest, OutputAndInputAfterClose) {
227 const char* address = "1";
228 audio_stream_out_t* streamOut;
229 OpenOutputStream(address, true /*mono*/, 48000, &streamOut);
230 audio_stream_in_t* streamIn;
231 OpenInputStream(address, true /*mono*/, 48000, &streamIn);
232 mDev->close_input_stream(mDev, streamIn);
233 mDev->close_output_stream(mDev, streamOut);
234 const size_t bufferSize = 1024;
235 std::unique_ptr<char[]> buffer(new char[bufferSize]);
236 memset(buffer.get(), 0, bufferSize);
237 ASSERT_EQ(0, streamOut->write(streamOut, buffer.get(), bufferSize));
238 ASSERT_EQ(static_cast<ssize_t>(bufferSize), streamIn->read(streamIn, buffer.get(), bufferSize));
239 VerifyBufferAllZeroes(buffer.get(), bufferSize);
240 }
241
TEST_F(RemoteSubmixTest,PresentationPosition)242 TEST_F(RemoteSubmixTest, PresentationPosition) {
243 const char* address = "1";
244 audio_stream_out_t* streamOut;
245 OpenOutputStream(address, true /*mono*/, 48000, &streamOut);
246 uint64_t frames;
247 struct timespec timestamp;
248 EXPECT_EQ(0, streamOut->get_presentation_position(streamOut, &frames, ×tamp));
249 EXPECT_EQ(uint64_t{0}, frames);
250 uint64_t prevFrames = frames;
251 for (size_t i = 0; i < 16; ++i) {
252 WriteSomethingIntoStream(streamOut, 1024, 1);
253 EXPECT_EQ(0, streamOut->get_presentation_position(streamOut, &frames, ×tamp));
254 EXPECT_LE(prevFrames, frames);
255 prevFrames = frames;
256 }
257 mDev->close_output_stream(mDev, streamOut);
258 }
259
TEST_F(RemoteSubmixTest,RenderPosition)260 TEST_F(RemoteSubmixTest, RenderPosition) {
261 const char* address = "1";
262 audio_stream_out_t* streamOut;
263 OpenOutputStream(address, true /*mono*/, 48000, &streamOut);
264 uint32_t frames;
265 EXPECT_EQ(0, streamOut->get_render_position(streamOut, &frames));
266 EXPECT_EQ(0U, frames);
267 uint32_t prevFrames = frames;
268 for (size_t i = 0; i < 16; ++i) {
269 WriteSomethingIntoStream(streamOut, 1024, 1);
270 EXPECT_EQ(0, streamOut->get_render_position(streamOut, &frames));
271 EXPECT_LE(prevFrames, frames);
272 prevFrames = frames;
273 }
274 mDev->close_output_stream(mDev, streamOut);
275 }
276
277 // This requires ENABLE_CHANNEL_CONVERSION to be set in the HAL module
TEST_F(RemoteSubmixTest,MonoToStereoConversion)278 TEST_F(RemoteSubmixTest, MonoToStereoConversion) {
279 const char* address = "1";
280 audio_stream_out_t* streamOut;
281 OpenOutputStream(address, true /*mono*/, 48000, &streamOut);
282 audio_stream_in_t* streamIn;
283 OpenInputStream(address, false /*mono*/, 48000, &streamIn);
284 const size_t bufferSize = 1024;
285 VerifyOutputInput(streamOut, bufferSize, streamIn, bufferSize * 2, 16);
286 mDev->close_input_stream(mDev, streamIn);
287 mDev->close_output_stream(mDev, streamOut);
288 }
289
290 // This requires ENABLE_CHANNEL_CONVERSION to be set in the HAL module
TEST_F(RemoteSubmixTest,StereoToMonoConversion)291 TEST_F(RemoteSubmixTest, StereoToMonoConversion) {
292 const char* address = "1";
293 audio_stream_out_t* streamOut;
294 OpenOutputStream(address, false /*mono*/, 48000, &streamOut);
295 audio_stream_in_t* streamIn;
296 OpenInputStream(address, true /*mono*/, 48000, &streamIn);
297 const size_t bufferSize = 1024;
298 VerifyOutputInput(streamOut, bufferSize * 2, streamIn, bufferSize, 16);
299 mDev->close_input_stream(mDev, streamIn);
300 mDev->close_output_stream(mDev, streamOut);
301 }
302
303 // This requires ENABLE_RESAMPLING to be set in the HAL module
TEST_F(RemoteSubmixTest,OutputAndInputResampling)304 TEST_F(RemoteSubmixTest, OutputAndInputResampling) {
305 const char* address = "1";
306 audio_stream_out_t* streamOut;
307 OpenOutputStream(address, true /*mono*/, 48000, &streamOut);
308 audio_stream_in_t* streamIn;
309 OpenInputStream(address, true /*mono*/, 24000, &streamIn);
310 const size_t bufferSize = 1024;
311 VerifyOutputInput(streamOut, bufferSize * 2, streamIn, bufferSize, 16);
312 mDev->close_input_stream(mDev, streamIn);
313 mDev->close_output_stream(mDev, streamOut);
314 }
315
316 // This requires ENABLE_LEGACY_INPUT_OPEN to be set in the HAL module
TEST_F(RemoteSubmixTest,OpenInputMultipleTimes)317 TEST_F(RemoteSubmixTest, OpenInputMultipleTimes) {
318 const char* address = "1";
319 audio_stream_out_t* streamOut;
320 OpenOutputStream(address, true /*mono*/, 48000, &streamOut);
321 const size_t streamInCount = 3;
322 audio_stream_in_t* streamIn[streamInCount];
323 for (size_t i = 0; i < streamInCount; ++i) {
324 OpenInputStream(address, true /*mono*/, 48000, &streamIn[i]);
325 }
326 const size_t bufferSize = 1024;
327 for (size_t i = 0; i < streamInCount; ++i) {
328 VerifyOutputInput(streamOut, bufferSize, streamIn[i], bufferSize, 16);
329 mDev->close_input_stream(mDev, streamIn[i]);
330 }
331 mDev->close_output_stream(mDev, streamOut);
332 }
333