xref: /aosp_15_r20/external/oboe/tests/testFullDuplexStream.cpp (revision 05767d913155b055644481607e6fa1e35e2fe72c)
1 /*
2  * Copyright 2023 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 #include <thread>
18 
19 #include <gtest/gtest.h>
20 
21 #include <oboe/Oboe.h>
22 
23 using namespace oboe;
24 
25 static constexpr int kTimeToSleepMicros = 5 * 1000 * 1000; // 5 s
26 
27 using TestFullDuplexStreamParams = std::tuple<AudioApi, PerformanceMode, AudioApi, PerformanceMode>;
28 
29 class TestFullDuplexStream : public ::testing::Test,
30                          public ::testing::WithParamInterface<TestFullDuplexStreamParams>,
31                          public FullDuplexStream {
32 public:
onBothStreamsReady(const void * inputData,int numInputFrames,void * outputData,int numOutputFrames)33     DataCallbackResult onBothStreamsReady(
34             const void *inputData,
35             int numInputFrames,
36             void *outputData,
37             int numOutputFrames) override {
38         mCallbackCount++;
39         if (numInputFrames == numOutputFrames) {
40             mGoodCallbackCount++;
41         }
42         return DataCallbackResult::Continue;
43     }
44 
45 protected:
46 
openStream(AudioApi inputAudioApi,PerformanceMode inputPerfMode,AudioApi outputAudioApi,PerformanceMode outputPerfMode)47     void openStream(AudioApi inputAudioApi, PerformanceMode inputPerfMode,
48             AudioApi outputAudioApi, PerformanceMode outputPerfMode) {
49         mOutputBuilder.setDirection(Direction::Output);
50         if (mOutputBuilder.isAAudioRecommended()) {
51             mOutputBuilder.setAudioApi(outputAudioApi);
52         }
53         mOutputBuilder.setPerformanceMode(outputPerfMode);
54         mOutputBuilder.setChannelCount(1);
55         mOutputBuilder.setFormat(AudioFormat::Float);
56         mOutputBuilder.setDataCallback(this);
57 
58         Result r = mOutputBuilder.openStream(&mOutputStream);
59         ASSERT_EQ(r, Result::OK) << "Failed to open output stream " << convertToText(r);
60 
61         mInputBuilder.setDirection(Direction::Input);
62         if (mInputBuilder.isAAudioRecommended()) {
63             mInputBuilder.setAudioApi(inputAudioApi);
64         }
65         mInputBuilder.setPerformanceMode(inputPerfMode);
66         mInputBuilder.setChannelCount(1);
67         mInputBuilder.setFormat(AudioFormat::Float);
68         mInputBuilder.setBufferCapacityInFrames(mOutputStream->getBufferCapacityInFrames() * 2);
69         mInputBuilder.setSampleRate(mOutputStream->getSampleRate());
70 
71         r = mInputBuilder.openStream(&mInputStream);
72         ASSERT_EQ(r, Result::OK) << "Failed to open input stream " << convertToText(r);
73 
74         setInputStream(mInputStream);
75         setOutputStream(mOutputStream);
76     }
77 
startStream()78     void startStream() {
79         Result r = start();
80         ASSERT_EQ(r, Result::OK) << "Failed to start streams " << convertToText(r);
81     }
82 
stopStream()83     void stopStream() {
84         Result r = stop();
85         ASSERT_EQ(r, Result::OK) << "Failed to stop streams " << convertToText(r);
86     }
87 
closeStream()88     void closeStream() {
89         Result r = mOutputStream->close();
90         ASSERT_EQ(r, Result::OK) << "Failed to close output stream " << convertToText(r);
91         setOutputStream(nullptr);
92         r = mInputStream->close();
93         ASSERT_EQ(r, Result::OK) << "Failed to close input stream " << convertToText(r);
94         setInputStream(nullptr);
95     }
96 
checkXRuns()97     void checkXRuns() {
98         // Expect few xRuns with the use of full duplex stream
99         EXPECT_LT(mInputStream->getXRunCount().value(), 10);
100         EXPECT_LT(mOutputStream->getXRunCount().value(), 10);
101     }
102 
checkInputAndOutputBufferSizesMatch()103     void checkInputAndOutputBufferSizesMatch() {
104         // Expect the large majority of callbacks to have the same sized input and output
105         EXPECT_GE(mGoodCallbackCount, mCallbackCount * 9 / 10);
106     }
107 
108     AudioStreamBuilder mInputBuilder;
109     AudioStreamBuilder mOutputBuilder;
110     AudioStream *mInputStream = nullptr;
111     AudioStream *mOutputStream = nullptr;
112     std::atomic<int32_t> mCallbackCount{0};
113     std::atomic<int32_t> mGoodCallbackCount{0};
114 };
115 
TEST_P(TestFullDuplexStream,VerifyFullDuplexStream)116 TEST_P(TestFullDuplexStream, VerifyFullDuplexStream) {
117     const AudioApi inputAudioApi = std::get<0>(GetParam());
118     const PerformanceMode inputPerformanceMode = std::get<1>(GetParam());
119     const AudioApi outputAudioApi = std::get<2>(GetParam());
120     const PerformanceMode outputPerformanceMode = std::get<3>(GetParam());
121 
122     openStream(inputAudioApi, inputPerformanceMode, outputAudioApi, outputPerformanceMode);
123     startStream();
124     usleep(kTimeToSleepMicros);
125     checkXRuns();
126     checkInputAndOutputBufferSizesMatch();
127     stopStream();
128     closeStream();
129 }
130 
131 INSTANTIATE_TEST_SUITE_P(
132         TestFullDuplexStreamTest,
133         TestFullDuplexStream,
134         ::testing::Values(
135                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::LowLatency,
136                         AudioApi::AAudio, PerformanceMode::LowLatency}),
137                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::LowLatency,
138                         AudioApi::AAudio, PerformanceMode::None}),
139                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::LowLatency,
140                         AudioApi::AAudio, PerformanceMode::PowerSaving}),
141                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::LowLatency,
142                         AudioApi::OpenSLES, PerformanceMode::LowLatency}),
143                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::LowLatency,
144                         AudioApi::OpenSLES, PerformanceMode::None}),
145                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::LowLatency,
146                         AudioApi::OpenSLES, PerformanceMode::PowerSaving}),
147                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::None,
148                         AudioApi::AAudio, PerformanceMode::LowLatency}),
149                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::None,
150                         AudioApi::AAudio, PerformanceMode::None}),
151                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::None,
152                         AudioApi::AAudio, PerformanceMode::PowerSaving}),
153                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::None,
154                         AudioApi::OpenSLES, PerformanceMode::LowLatency}),
155                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::None,
156                         AudioApi::OpenSLES, PerformanceMode::None}),
157                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::None,
158                         AudioApi::OpenSLES, PerformanceMode::PowerSaving}),
159                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::PowerSaving,
160                         AudioApi::AAudio, PerformanceMode::LowLatency}),
161                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::PowerSaving,
162                         AudioApi::AAudio, PerformanceMode::None}),
163                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::PowerSaving,
164                         AudioApi::AAudio, PerformanceMode::PowerSaving}),
165                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::PowerSaving,
166                         AudioApi::OpenSLES, PerformanceMode::LowLatency}),
167                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::PowerSaving,
168                         AudioApi::OpenSLES, PerformanceMode::None}),
169                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::PowerSaving,
170                         AudioApi::OpenSLES, PerformanceMode::PowerSaving}),
171                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::LowLatency,
172                         AudioApi::AAudio, PerformanceMode::LowLatency}),
173                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::LowLatency,
174                         AudioApi::AAudio, PerformanceMode::None}),
175                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::LowLatency,
176                         AudioApi::AAudio, PerformanceMode::PowerSaving}),
177                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::LowLatency,
178                         AudioApi::OpenSLES, PerformanceMode::LowLatency}),
179                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::LowLatency,
180                         AudioApi::OpenSLES, PerformanceMode::None}),
181                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::LowLatency,
182                         AudioApi::OpenSLES, PerformanceMode::PowerSaving}),
183                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::None,
184                         AudioApi::AAudio, PerformanceMode::LowLatency}),
185                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::None,
186                         AudioApi::AAudio, PerformanceMode::None}),
187                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::None,
188                         AudioApi::AAudio, PerformanceMode::PowerSaving}),
189                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::None,
190                         AudioApi::OpenSLES, PerformanceMode::LowLatency}),
191                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::None,
192                         AudioApi::OpenSLES, PerformanceMode::None}),
193                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::None,
194                         AudioApi::OpenSLES, PerformanceMode::PowerSaving}),
195                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::PowerSaving,
196                         AudioApi::AAudio, PerformanceMode::LowLatency}),
197                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::PowerSaving,
198                         AudioApi::AAudio, PerformanceMode::None}),
199                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::PowerSaving,
200                         AudioApi::AAudio, PerformanceMode::PowerSaving}),
201                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::PowerSaving,
202                         AudioApi::OpenSLES, PerformanceMode::LowLatency}),
203                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::PowerSaving,
204                         AudioApi::OpenSLES, PerformanceMode::None}),
205                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::PowerSaving,
206                         AudioApi::OpenSLES, PerformanceMode::PowerSaving})
207         )
208 );
209