diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2018-03-01 08:25:39 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2018-03-01 08:25:39 +0000 |
commit | eb32795813c7e4fa51928d15313959c1fc1f6e36 (patch) | |
tree | dd1e7506522a0979c67801a969ecdc2158d3e86f | |
parent | 0a84591a4fdf3d3d21f46494b23383421c02b26b (diff) | |
parent | 1df8a0039ffaa5161e1ecdfda3ae3f7e5c7068c2 (diff) | |
download | libhardware-eb32795813c7e4fa51928d15313959c1fc1f6e36.tar.gz |
Snap for 4628106 from 1df8a0039ffaa5161e1ecdfda3ae3f7e5c7068c2 to pi-release
Change-Id: I5b436863f3778a5ab7b070a458f9773afa45d18a
-rw-r--r-- | modules/audio_remote_submix/audio_hw.cpp | 32 | ||||
-rw-r--r-- | modules/audio_remote_submix/tests/remote_submix_tests.cpp | 224 |
2 files changed, 209 insertions, 47 deletions
diff --git a/modules/audio_remote_submix/audio_hw.cpp b/modules/audio_remote_submix/audio_hw.cpp index 8c0c0971..d78e723d 100644 --- a/modules/audio_remote_submix/audio_hw.cpp +++ b/modules/audio_remote_submix/audio_hw.cpp @@ -418,8 +418,8 @@ static void submix_audio_device_create_pipe_l(struct submix_audio_device * const config->format); const NBAIO_Format offers[1] = {format}; size_t numCounterOffers = 0; - // Create a MonoPipe with optional blocking set to true. - MonoPipe* sink = new MonoPipe(buffer_size_frames, format, true /*writeCanBlock*/); + // Create a MonoPipe with optional blocking set to false. + MonoPipe* sink = new MonoPipe(buffer_size_frames, format, false /*writeCanBlock*/); // Negotiation between the source and sink cannot fail as the device open operation // creates both ends of the pipe using the same audio format. ssize_t index = sink->negotiate(offers, 1, NULL, numCounterOffers); @@ -714,30 +714,8 @@ static int out_dump(const struct audio_stream *stream, int fd) static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) { - int exiting = -1; - AudioParameter parms = AudioParameter(String8(kvpairs)); + (void)stream; SUBMIX_ALOGV("out_set_parameters() kvpairs='%s'", kvpairs); - - // FIXME this is using hard-coded strings but in the future, this functionality will be - // converted to use audio HAL extensions required to support tunneling - if ((parms.getInt(String8("exiting"), exiting) == NO_ERROR) && (exiting > 0)) { - struct submix_audio_device * const rsxadev = - audio_stream_get_submix_stream_out(stream)->dev; - pthread_mutex_lock(&rsxadev->lock); - { // using the sink - sp<MonoPipe> sink = - rsxadev->routes[audio_stream_get_submix_stream_out(stream)->route_handle] - .rsxSink; - if (sink == NULL) { - pthread_mutex_unlock(&rsxadev->lock); - return 0; - } - - ALOGD("out_set_parameters(): shutting down MonoPipe sink"); - sink->shutdown(true); - } // done using the sink - pthread_mutex_unlock(&rsxadev->lock); - } return 0; } @@ -805,12 +783,12 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, return 0; } - // If the write to the sink would block when no input stream is present, flush enough frames + // If the write to the sink would block, flush enough frames // from the pipe to make space to write the most recent data. { const size_t availableToWrite = sink->availableToWrite(); sp<MonoPipeReader> source = rsxadev->routes[out->route_handle].rsxSource; - if (rsxadev->routes[out->route_handle].input == NULL && availableToWrite < frames) { + if (availableToWrite < frames) { static uint8_t flush_buffer[64]; const size_t flushBufferSizeFrames = sizeof(flush_buffer) / frame_size; size_t frames_to_flush_from_source = frames - availableToWrite; diff --git a/modules/audio_remote_submix/tests/remote_submix_tests.cpp b/modules/audio_remote_submix/tests/remote_submix_tests.cpp index e644fd48..36650e76 100644 --- a/modules/audio_remote_submix/tests/remote_submix_tests.cpp +++ b/modules/audio_remote_submix/tests/remote_submix_tests.cpp @@ -30,7 +30,7 @@ using namespace android; -static status_t load_audio_interface(const char *if_name, audio_hw_device_t **dev) +static status_t load_audio_interface(const char* if_name, audio_hw_device_t **dev) { const hw_module_t *mod; int rc; @@ -65,9 +65,19 @@ class RemoteSubmixTest : public testing::Test { void SetUp() override; void TearDown() override; - void OpenInputStream(const char *address, audio_stream_in_t** streamIn); - void OpenOutputStream(const char *address, audio_stream_out_t** streamOut); - void WriteIntoStream(audio_stream_out_t* streamOut, size_t bufferSize, size_t repeats); + void GenerateData(char* buffer, size_t bufferSize); + void OpenInputStream( + const char* address, bool mono, uint32_t sampleRate, audio_stream_in_t** streamIn); + void OpenOutputStream( + const char* address, bool mono, uint32_t sampleRate, audio_stream_out_t** streamOut); + void ReadFromStream(audio_stream_in_t* streamIn, char* buffer, size_t bufferSize); + void VerifyBufferAllZeroes(char* buffer, size_t bufferSize); + void VerifyBufferNotZeroes(char* buffer, size_t bufferSize); + void VerifyOutputInput( + audio_stream_out_t* streamOut, size_t outBufferSize, + audio_stream_in_t* streamIn, size_t inBufferSize, size_t repeats); + void WriteIntoStream(audio_stream_out_t* streamOut, const char* buffer, size_t bufferSize); + void WriteSomethingIntoStream(audio_stream_out_t* streamOut, size_t bufferSize, size_t repeats); audio_hw_device_t* mDev; }; @@ -87,11 +97,18 @@ void RemoteSubmixTest::TearDown() { } } -void RemoteSubmixTest::OpenInputStream(const char *address, audio_stream_in_t** streamIn) { +void RemoteSubmixTest::GenerateData(char* buffer, size_t bufferSize) { + for (size_t i = 0; i < bufferSize; ++i) { + buffer[i] = static_cast<char>(i & 0x7f); + } +} + +void RemoteSubmixTest::OpenInputStream( + const char* address, bool mono, uint32_t sampleRate, audio_stream_in_t** streamIn) { *streamIn = nullptr; struct audio_config configIn = {}; - configIn.channel_mask = AUDIO_CHANNEL_IN_MONO; - configIn.sample_rate = 48000; + configIn.channel_mask = mono ? AUDIO_CHANNEL_IN_MONO : AUDIO_CHANNEL_IN_STEREO; + configIn.sample_rate = sampleRate; status_t result = mDev->open_input_stream(mDev, AUDIO_IO_HANDLE_NONE, AUDIO_DEVICE_NONE, &configIn, streamIn, AUDIO_INPUT_FLAG_NONE, address, AUDIO_SOURCE_DEFAULT); @@ -99,11 +116,12 @@ void RemoteSubmixTest::OpenInputStream(const char *address, audio_stream_in_t** ASSERT_NE(nullptr, *streamIn); } -void RemoteSubmixTest::OpenOutputStream(const char *address, audio_stream_out_t** streamOut) { +void RemoteSubmixTest::OpenOutputStream( + const char* address, bool mono, uint32_t sampleRate, audio_stream_out_t** streamOut) { *streamOut = nullptr; struct audio_config configOut = {}; - configOut.channel_mask = AUDIO_CHANNEL_OUT_MONO; - configOut.sample_rate = 48000; + configOut.channel_mask = mono ? AUDIO_CHANNEL_OUT_MONO : AUDIO_CHANNEL_OUT_STEREO; + configOut.sample_rate = sampleRate; status_t result = mDev->open_output_stream(mDev, AUDIO_IO_HANDLE_NONE, AUDIO_DEVICE_NONE, AUDIO_OUTPUT_FLAG_NONE, &configOut, streamOut, address); @@ -111,12 +129,58 @@ void RemoteSubmixTest::OpenOutputStream(const char *address, audio_stream_out_t* ASSERT_NE(nullptr, *streamOut); } +void RemoteSubmixTest::ReadFromStream( + audio_stream_in_t* streamIn, char* buffer, size_t bufferSize) { + ssize_t result = streamIn->read(streamIn, buffer, bufferSize); + EXPECT_EQ(bufferSize, static_cast<size_t>(result)); +} + +void RemoteSubmixTest::VerifyBufferAllZeroes(char* buffer, size_t bufferSize) { + for (size_t i = 0; i < bufferSize; ++i) { + if (buffer[i]) { + ADD_FAILURE(); + return; + } + } +} + +void RemoteSubmixTest::VerifyBufferNotZeroes(char* buffer, size_t bufferSize) { + for (size_t i = 0; i < bufferSize; ++i) { + if (buffer[i]) return; + } + ADD_FAILURE(); +} + +void RemoteSubmixTest::VerifyOutputInput( + audio_stream_out_t* streamOut, size_t outBufferSize, + audio_stream_in_t* streamIn, size_t inBufferSize, + size_t repeats) { + std::unique_ptr<char[]> outBuffer(new char[outBufferSize]), inBuffer(new char[inBufferSize]); + GenerateData(outBuffer.get(), outBufferSize); + for (size_t i = 0; i < repeats; ++i) { + WriteIntoStream(streamOut, outBuffer.get(), outBufferSize); + memset(inBuffer.get(), 0, inBufferSize); + ReadFromStream(streamIn, inBuffer.get(), inBufferSize); + if (inBufferSize == outBufferSize) { + ASSERT_EQ(0, memcmp(outBuffer.get(), inBuffer.get(), inBufferSize)); + } else { + VerifyBufferNotZeroes(inBuffer.get(), inBufferSize); + } + } +} + void RemoteSubmixTest::WriteIntoStream( + audio_stream_out_t* streamOut, const char* buffer, size_t bufferSize) { + ssize_t result = streamOut->write(streamOut, buffer, bufferSize); + EXPECT_EQ(bufferSize, static_cast<size_t>(result)); +} + +void RemoteSubmixTest::WriteSomethingIntoStream( audio_stream_out_t* streamOut, size_t bufferSize, size_t repeats) { std::unique_ptr<char[]> buffer(new char[bufferSize]); + GenerateData(buffer.get(), bufferSize); for (size_t i = 0; i < repeats; ++i) { - ssize_t result = streamOut->write(streamOut, buffer.get(), bufferSize); - EXPECT_EQ(bufferSize, static_cast<size_t>(result)); + WriteIntoStream(streamOut, buffer.get(), bufferSize); } } @@ -126,22 +190,142 @@ TEST_F(RemoteSubmixTest, InitSuccess) { // Verifies that when no input was opened, writing into an output stream does not block. TEST_F(RemoteSubmixTest, OutputDoesNotBlockWhenNoInput) { - const char *address = "1"; + const char* address = "1"; audio_stream_out_t* streamOut; - OpenOutputStream(address, &streamOut); - WriteIntoStream(streamOut, 1024, 16); + OpenOutputStream(address, true /*mono*/, 48000, &streamOut); + WriteSomethingIntoStream(streamOut, 1024, 16); mDev->close_output_stream(mDev, streamOut); } // Verifies that when input is opened but not reading, writing into an output stream does not block. -// !!! Currently does not finish because requires setting a parameter from another thread !!! TEST_F(RemoteSubmixTest, OutputDoesNotBlockWhenInputStuck) { - const char *address = "1"; + const char* address = "1"; + audio_stream_out_t* streamOut; + OpenOutputStream(address, true /*mono*/, 48000, &streamOut); + audio_stream_in_t* streamIn; + OpenInputStream(address, true /*mono*/, 48000, &streamIn); + WriteSomethingIntoStream(streamOut, 1024, 16); + mDev->close_input_stream(mDev, streamIn); + mDev->close_output_stream(mDev, streamOut); +} + +TEST_F(RemoteSubmixTest, OutputAndInput) { + const char* address = "1"; + audio_stream_out_t* streamOut; + OpenOutputStream(address, true /*mono*/, 48000, &streamOut); + audio_stream_in_t* streamIn; + OpenInputStream(address, true /*mono*/, 48000, &streamIn); + const size_t bufferSize = 1024; + VerifyOutputInput(streamOut, bufferSize, streamIn, bufferSize, 16); + mDev->close_input_stream(mDev, streamIn); + mDev->close_output_stream(mDev, streamOut); +} + +// Verifies that reading and writing into a closed stream fails gracefully. +TEST_F(RemoteSubmixTest, OutputAndInputAfterClose) { + const char* address = "1"; + audio_stream_out_t* streamOut; + OpenOutputStream(address, true /*mono*/, 48000, &streamOut); + audio_stream_in_t* streamIn; + OpenInputStream(address, true /*mono*/, 48000, &streamIn); + mDev->close_input_stream(mDev, streamIn); + mDev->close_output_stream(mDev, streamOut); + const size_t bufferSize = 1024; + std::unique_ptr<char[]> buffer(new char[bufferSize]); + memset(buffer.get(), 0, bufferSize); + ASSERT_EQ(0, streamOut->write(streamOut, buffer.get(), bufferSize)); + ASSERT_EQ(static_cast<ssize_t>(bufferSize), streamIn->read(streamIn, buffer.get(), bufferSize)); + VerifyBufferAllZeroes(buffer.get(), bufferSize); +} + +TEST_F(RemoteSubmixTest, PresentationPosition) { + const char* address = "1"; + audio_stream_out_t* streamOut; + OpenOutputStream(address, true /*mono*/, 48000, &streamOut); + uint64_t frames; + struct timespec timestamp; + EXPECT_EQ(0, streamOut->get_presentation_position(streamOut, &frames, ×tamp)); + EXPECT_EQ(uint64_t{0}, frames); + uint64_t prevFrames = frames; + for (size_t i = 0; i < 16; ++i) { + WriteSomethingIntoStream(streamOut, 1024, 1); + EXPECT_EQ(0, streamOut->get_presentation_position(streamOut, &frames, ×tamp)); + EXPECT_LE(prevFrames, frames); + prevFrames = frames; + } + mDev->close_output_stream(mDev, streamOut); +} + +TEST_F(RemoteSubmixTest, RenderPosition) { + const char* address = "1"; + audio_stream_out_t* streamOut; + OpenOutputStream(address, true /*mono*/, 48000, &streamOut); + uint32_t frames; + EXPECT_EQ(0, streamOut->get_render_position(streamOut, &frames)); + EXPECT_EQ(0U, frames); + uint32_t prevFrames = frames; + for (size_t i = 0; i < 16; ++i) { + WriteSomethingIntoStream(streamOut, 1024, 1); + EXPECT_EQ(0, streamOut->get_render_position(streamOut, &frames)); + EXPECT_LE(prevFrames, frames); + prevFrames = frames; + } + mDev->close_output_stream(mDev, streamOut); +} + +// This requires ENABLE_CHANNEL_CONVERSION to be set in the HAL module +TEST_F(RemoteSubmixTest, MonoToStereoConversion) { + const char* address = "1"; + audio_stream_out_t* streamOut; + OpenOutputStream(address, true /*mono*/, 48000, &streamOut); + audio_stream_in_t* streamIn; + OpenInputStream(address, false /*mono*/, 48000, &streamIn); + const size_t bufferSize = 1024; + VerifyOutputInput(streamOut, bufferSize, streamIn, bufferSize * 2, 16); + mDev->close_input_stream(mDev, streamIn); + mDev->close_output_stream(mDev, streamOut); +} + +// This requires ENABLE_CHANNEL_CONVERSION to be set in the HAL module +TEST_F(RemoteSubmixTest, StereoToMonoConversion) { + const char* address = "1"; + audio_stream_out_t* streamOut; + OpenOutputStream(address, false /*mono*/, 48000, &streamOut); + audio_stream_in_t* streamIn; + OpenInputStream(address, true /*mono*/, 48000, &streamIn); + const size_t bufferSize = 1024; + VerifyOutputInput(streamOut, bufferSize * 2, streamIn, bufferSize, 16); + mDev->close_input_stream(mDev, streamIn); + mDev->close_output_stream(mDev, streamOut); +} + +// This requires ENABLE_RESAMPLING to be set in the HAL module +TEST_F(RemoteSubmixTest, OutputAndInputResampling) { + const char* address = "1"; audio_stream_out_t* streamOut; - OpenOutputStream(address, &streamOut); + OpenOutputStream(address, true /*mono*/, 48000, &streamOut); audio_stream_in_t* streamIn; - OpenInputStream(address, &streamIn); - WriteIntoStream(streamOut, 1024, 16); + OpenInputStream(address, true /*mono*/, 24000, &streamIn); + const size_t bufferSize = 1024; + VerifyOutputInput(streamOut, bufferSize * 2, streamIn, bufferSize, 16); mDev->close_input_stream(mDev, streamIn); mDev->close_output_stream(mDev, streamOut); } + +// This requires ENABLE_LEGACY_INPUT_OPEN to be set in the HAL module +TEST_F(RemoteSubmixTest, OpenInputMultipleTimes) { + const char* address = "1"; + audio_stream_out_t* streamOut; + OpenOutputStream(address, true /*mono*/, 48000, &streamOut); + const size_t streamInCount = 3; + audio_stream_in_t* streamIn[streamInCount]; + for (size_t i = 0; i < streamInCount; ++i) { + OpenInputStream(address, true /*mono*/, 48000, &streamIn[i]); + } + const size_t bufferSize = 1024; + for (size_t i = 0; i < streamInCount; ++i) { + VerifyOutputInput(streamOut, bufferSize, streamIn[i], bufferSize, 16); + mDev->close_input_stream(mDev, streamIn[i]); + } + mDev->close_output_stream(mDev, streamOut); +} |