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