summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2018-03-01 08:25:39 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2018-03-01 08:25:39 +0000
commiteb32795813c7e4fa51928d15313959c1fc1f6e36 (patch)
treedd1e7506522a0979c67801a969ecdc2158d3e86f
parent0a84591a4fdf3d3d21f46494b23383421c02b26b (diff)
parent1df8a0039ffaa5161e1ecdfda3ae3f7e5c7068c2 (diff)
downloadlibhardware-eb32795813c7e4fa51928d15313959c1fc1f6e36.tar.gz
Snap for 4628106 from 1df8a0039ffaa5161e1ecdfda3ae3f7e5c7068c2 to pi-release
Change-Id: I5b436863f3778a5ab7b070a458f9773afa45d18a
-rw-r--r--modules/audio_remote_submix/audio_hw.cpp32
-rw-r--r--modules/audio_remote_submix/tests/remote_submix_tests.cpp224
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, &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, &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);
+}