r_submix: Add more tests

From analyzing the coverage data, these tests seem to cover
all the critical functionality of the remote submix module.

Bug: 73175392
Test: r_submix_tests
Change-Id: I7f6be95245c6ab59611fc5e269e3f9f2079b8ee4
diff --git a/modules/audio_remote_submix/tests/remote_submix_tests.cpp b/modules/audio_remote_submix/tests/remote_submix_tests.cpp
index e644fd4..2c01c92 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 @@
     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::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 @@
     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 @@
     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,143 @@
 
 // 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";
+// TEST_F(RemoteSubmixTest, OutputDoesNotBlockWhenInputStuck) {
+//     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, &streamOut);
+    OpenOutputStream(address, true /*mono*/, 48000, &streamOut);
     audio_stream_in_t* streamIn;
-    OpenInputStream(address, &streamIn);
-    WriteIntoStream(streamOut, 1024, 16);
+    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, &timestamp));
+    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, &timestamp));
+        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, true /*mono*/, 48000, &streamOut);
+    audio_stream_in_t* streamIn;
+    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);
+}