forked from eden-emu/eden
		
	
		
			
	
	
		
			207 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			207 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | /*
 | ||
|  |  * Copyright 2023 The Android Open Source Project | ||
|  |  * | ||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||
|  |  * you may not use this file except in compliance with the License. | ||
|  |  * You may obtain a copy of the License at | ||
|  |  * | ||
|  |  *      http://www.apache.org/licenses/LICENSE-2.0
 | ||
|  |  * | ||
|  |  * Unless required by applicable law or agreed to in writing, software | ||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
|  |  * See the License for the specific language governing permissions and | ||
|  |  * limitations under the License. | ||
|  |  */ | ||
|  | 
 | ||
|  | #include <thread>
 | ||
|  | 
 | ||
|  | #include <gtest/gtest.h>
 | ||
|  | 
 | ||
|  | #include <oboe/Oboe.h>
 | ||
|  | 
 | ||
|  | using namespace oboe; | ||
|  | 
 | ||
|  | static constexpr int kTimeToSleepMicros = 5 * 1000 * 1000; // 5 s
 | ||
|  | 
 | ||
|  | using TestFullDuplexStreamParams = std::tuple<AudioApi, PerformanceMode, AudioApi, PerformanceMode>; | ||
|  | 
 | ||
|  | class TestFullDuplexStream : public ::testing::Test, | ||
|  |                          public ::testing::WithParamInterface<TestFullDuplexStreamParams>, | ||
|  |                          public FullDuplexStream { | ||
|  | public: | ||
|  |     DataCallbackResult onBothStreamsReady( | ||
|  |             const void *inputData, | ||
|  |             int numInputFrames, | ||
|  |             void *outputData, | ||
|  |             int numOutputFrames) override { | ||
|  |         mCallbackCount++; | ||
|  |         if (numInputFrames == numOutputFrames) { | ||
|  |             mGoodCallbackCount++; | ||
|  |         } | ||
|  |         return DataCallbackResult::Continue; | ||
|  |     } | ||
|  | 
 | ||
|  | protected: | ||
|  | 
 | ||
|  |     void openStream(AudioApi inputAudioApi, PerformanceMode inputPerfMode, | ||
|  |             AudioApi outputAudioApi, PerformanceMode outputPerfMode) { | ||
|  |         mOutputBuilder.setDirection(Direction::Output); | ||
|  |         if (mOutputBuilder.isAAudioRecommended()) { | ||
|  |             mOutputBuilder.setAudioApi(outputAudioApi); | ||
|  |         } | ||
|  |         mOutputBuilder.setPerformanceMode(outputPerfMode); | ||
|  |         mOutputBuilder.setChannelCount(1); | ||
|  |         mOutputBuilder.setFormat(AudioFormat::Float); | ||
|  |         mOutputBuilder.setDataCallback(this); | ||
|  | 
 | ||
|  |         Result r = mOutputBuilder.openStream(mOutputStream); | ||
|  |         ASSERT_EQ(r, Result::OK) << "Failed to open output stream " << convertToText(r); | ||
|  | 
 | ||
|  |         mInputBuilder.setDirection(Direction::Input); | ||
|  |         if (mInputBuilder.isAAudioRecommended()) { | ||
|  |             mInputBuilder.setAudioApi(inputAudioApi); | ||
|  |         } | ||
|  |         mInputBuilder.setPerformanceMode(inputPerfMode); | ||
|  |         mInputBuilder.setChannelCount(1); | ||
|  |         mInputBuilder.setFormat(AudioFormat::Float); | ||
|  |         mInputBuilder.setBufferCapacityInFrames(mOutputStream->getBufferCapacityInFrames() * 2); | ||
|  |         mInputBuilder.setSampleRate(mOutputStream->getSampleRate()); | ||
|  | 
 | ||
|  |         r = mInputBuilder.openStream(mInputStream); | ||
|  |         ASSERT_EQ(r, Result::OK) << "Failed to open input stream " << convertToText(r); | ||
|  | 
 | ||
|  |         setSharedInputStream(mInputStream); | ||
|  |         setSharedOutputStream(mOutputStream); | ||
|  |     } | ||
|  | 
 | ||
|  |     void startStream() { | ||
|  |         Result r = start(); | ||
|  |         ASSERT_EQ(r, Result::OK) << "Failed to start streams " << convertToText(r); | ||
|  |     } | ||
|  | 
 | ||
|  |     void stopStream() { | ||
|  |         Result r = stop(); | ||
|  |         ASSERT_EQ(r, Result::OK) << "Failed to stop streams " << convertToText(r); | ||
|  |     } | ||
|  | 
 | ||
|  |     void closeStream() { | ||
|  |         Result r = mOutputStream->close(); | ||
|  |         ASSERT_EQ(r, Result::OK) << "Failed to close output stream " << convertToText(r); | ||
|  |         r = mInputStream->close(); | ||
|  |         ASSERT_EQ(r, Result::OK) << "Failed to close input stream " << convertToText(r); | ||
|  |     } | ||
|  | 
 | ||
|  |     void checkXRuns() { | ||
|  |         // Expect few xRuns with the use of full duplex stream
 | ||
|  |         EXPECT_LT(mInputStream->getXRunCount().value(), 10); | ||
|  |         EXPECT_LT(mOutputStream->getXRunCount().value(), 10); | ||
|  |     } | ||
|  | 
 | ||
|  |     void checkInputAndOutputBufferSizesMatch() { | ||
|  |         // Expect the large majority of callbacks to have the same sized input and output
 | ||
|  |         EXPECT_GE(mGoodCallbackCount, mCallbackCount * 4 / 5); | ||
|  |     } | ||
|  | 
 | ||
|  |     AudioStreamBuilder mInputBuilder; | ||
|  |     AudioStreamBuilder mOutputBuilder; | ||
|  |     std::shared_ptr<AudioStream> mInputStream; | ||
|  |     std::shared_ptr<AudioStream> mOutputStream; | ||
|  |     std::atomic<int32_t> mCallbackCount{0}; | ||
|  |     std::atomic<int32_t> mGoodCallbackCount{0}; | ||
|  | }; | ||
|  | 
 | ||
|  | TEST_P(TestFullDuplexStream, VerifyFullDuplexStream) { | ||
|  |     const AudioApi inputAudioApi = std::get<0>(GetParam()); | ||
|  |     const PerformanceMode inputPerformanceMode = std::get<1>(GetParam()); | ||
|  |     const AudioApi outputAudioApi = std::get<2>(GetParam()); | ||
|  |     const PerformanceMode outputPerformanceMode = std::get<3>(GetParam()); | ||
|  | 
 | ||
|  |     openStream(inputAudioApi, inputPerformanceMode, outputAudioApi, outputPerformanceMode); | ||
|  |     startStream(); | ||
|  |     usleep(kTimeToSleepMicros); | ||
|  |     checkXRuns(); | ||
|  |     checkInputAndOutputBufferSizesMatch(); | ||
|  |     stopStream(); | ||
|  |     closeStream(); | ||
|  | } | ||
|  | 
 | ||
|  | INSTANTIATE_TEST_SUITE_P( | ||
|  |         TestFullDuplexStreamTest, | ||
|  |         TestFullDuplexStream, | ||
|  |         ::testing::Values( | ||
|  |                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::LowLatency, | ||
|  |                         AudioApi::AAudio, PerformanceMode::LowLatency}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::LowLatency, | ||
|  |                         AudioApi::AAudio, PerformanceMode::None}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::LowLatency, | ||
|  |                         AudioApi::AAudio, PerformanceMode::PowerSaving}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::LowLatency, | ||
|  |                         AudioApi::OpenSLES, PerformanceMode::LowLatency}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::LowLatency, | ||
|  |                         AudioApi::OpenSLES, PerformanceMode::None}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::LowLatency, | ||
|  |                         AudioApi::OpenSLES, PerformanceMode::PowerSaving}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::None, | ||
|  |                         AudioApi::AAudio, PerformanceMode::LowLatency}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::None, | ||
|  |                         AudioApi::AAudio, PerformanceMode::None}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::None, | ||
|  |                         AudioApi::AAudio, PerformanceMode::PowerSaving}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::None, | ||
|  |                         AudioApi::OpenSLES, PerformanceMode::LowLatency}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::None, | ||
|  |                         AudioApi::OpenSLES, PerformanceMode::None}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::None, | ||
|  |                         AudioApi::OpenSLES, PerformanceMode::PowerSaving}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::PowerSaving, | ||
|  |                         AudioApi::AAudio, PerformanceMode::LowLatency}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::PowerSaving, | ||
|  |                         AudioApi::AAudio, PerformanceMode::None}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::PowerSaving, | ||
|  |                         AudioApi::AAudio, PerformanceMode::PowerSaving}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::PowerSaving, | ||
|  |                         AudioApi::OpenSLES, PerformanceMode::LowLatency}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::PowerSaving, | ||
|  |                         AudioApi::OpenSLES, PerformanceMode::None}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::AAudio, PerformanceMode::PowerSaving, | ||
|  |                         AudioApi::OpenSLES, PerformanceMode::PowerSaving}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::LowLatency, | ||
|  |                         AudioApi::AAudio, PerformanceMode::LowLatency}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::LowLatency, | ||
|  |                         AudioApi::AAudio, PerformanceMode::None}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::LowLatency, | ||
|  |                         AudioApi::AAudio, PerformanceMode::PowerSaving}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::LowLatency, | ||
|  |                         AudioApi::OpenSLES, PerformanceMode::LowLatency}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::LowLatency, | ||
|  |                         AudioApi::OpenSLES, PerformanceMode::None}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::LowLatency, | ||
|  |                         AudioApi::OpenSLES, PerformanceMode::PowerSaving}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::None, | ||
|  |                         AudioApi::AAudio, PerformanceMode::LowLatency}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::None, | ||
|  |                         AudioApi::AAudio, PerformanceMode::None}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::None, | ||
|  |                         AudioApi::AAudio, PerformanceMode::PowerSaving}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::None, | ||
|  |                         AudioApi::OpenSLES, PerformanceMode::LowLatency}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::None, | ||
|  |                         AudioApi::OpenSLES, PerformanceMode::None}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::None, | ||
|  |                         AudioApi::OpenSLES, PerformanceMode::PowerSaving}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::PowerSaving, | ||
|  |                         AudioApi::AAudio, PerformanceMode::LowLatency}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::PowerSaving, | ||
|  |                         AudioApi::AAudio, PerformanceMode::None}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::PowerSaving, | ||
|  |                         AudioApi::AAudio, PerformanceMode::PowerSaving}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::PowerSaving, | ||
|  |                         AudioApi::OpenSLES, PerformanceMode::LowLatency}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::PowerSaving, | ||
|  |                         AudioApi::OpenSLES, PerformanceMode::None}), | ||
|  |                 TestFullDuplexStreamParams({AudioApi::OpenSLES, PerformanceMode::PowerSaving, | ||
|  |                         AudioApi::OpenSLES, PerformanceMode::PowerSaving}) | ||
|  |         ) | ||
|  | ); |