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, &timestamp));
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, &timestamp));
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