123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- // Copyright 2015 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "services/audio/input_sync_writer.h"
- #include <stddef.h>
- #include <stdint.h>
- #include <memory>
- #include <string>
- #include <utility>
- #include "base/compiler_specific.h"
- #include "base/memory/ptr_util.h"
- #include "base/memory/raw_ptr.h"
- #include "base/memory/read_only_shared_memory_region.h"
- #include "base/sync_socket.h"
- #include "base/test/mock_callback.h"
- #include "base/test/task_environment.h"
- #include "base/time/time.h"
- #include "build/build_config.h"
- #include "media/base/audio_bus.h"
- #include "media/base/audio_parameters.h"
- #include "media/base/channel_layout.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- using ::testing::_;
- namespace audio {
- namespace {
- // Number of audio buffers in the faked ring buffer.
- const int kSegments = 10;
- } // namespace
- // Mocked out sockets used for Send/ReceiveWithTimeout. Counts the number of
- // outstanding reads, i.e. the diff between send and receive calls.
- class MockCancelableSyncSocket : public base::CancelableSyncSocket {
- public:
- explicit MockCancelableSyncSocket(int buffer_size)
- : in_failure_mode_(false),
- writes_(0),
- reads_(0),
- receives_(0),
- buffer_size_(buffer_size),
- read_buffer_index_(0) {}
- MockCancelableSyncSocket(const MockCancelableSyncSocket&) = delete;
- MockCancelableSyncSocket& operator=(const MockCancelableSyncSocket&) = delete;
- size_t Send(const void* buffer, size_t length) override {
- EXPECT_EQ(length, sizeof(uint32_t));
- ++writes_;
- EXPECT_LE(NumberOfBuffersFilled(), buffer_size_);
- return length;
- }
- size_t Receive(void* buffer, size_t length) override {
- EXPECT_EQ(0u, length % sizeof(uint32_t));
- if (in_failure_mode_)
- return 0;
- if (receives_ == reads_)
- return 0;
- uint32_t* ptr = static_cast<uint32_t*>(buffer);
- size_t received = 0;
- for (; received < length / sizeof(uint32_t) && receives_ < reads_;
- ++received, ++ptr) {
- ++receives_;
- EXPECT_LE(receives_, reads_);
- *ptr = ++read_buffer_index_;
- }
- return received * sizeof(uint32_t);
- }
- size_t Peek() override { return (reads_ - receives_) * sizeof(uint32_t); }
- // Simluates reading |buffers| number of buffers from the ring buffer.
- void Read(int buffers) {
- reads_ += buffers;
- EXPECT_LE(reads_, writes_);
- }
- // When |in_failure_mode_| == true, the socket fails to receive.
- void SetFailureMode(bool in_failure_mode) {
- in_failure_mode_ = in_failure_mode;
- }
- int NumberOfBuffersFilled() { return writes_ - reads_; }
- private:
- bool in_failure_mode_;
- int writes_;
- int reads_;
- int receives_;
- int buffer_size_;
- uint32_t read_buffer_index_;
- };
- class InputSyncWriterTest : public testing::Test {
- public:
- InputSyncWriterTest() {
- const int sampling_frequency_hz = 16000;
- const int frames = sampling_frequency_hz / 100; // 10 ms
- const media::AudioParameters audio_params(
- media::AudioParameters::AUDIO_FAKE, media::CHANNEL_LAYOUT_MONO,
- sampling_frequency_hz, frames);
- const uint32_t data_size =
- ComputeAudioInputBufferSize(audio_params, kSegments);
- auto shared_memory = base::ReadOnlySharedMemoryRegion::Create(data_size);
- EXPECT_TRUE(shared_memory.IsValid());
- auto socket = std::make_unique<MockCancelableSyncSocket>(kSegments);
- socket_ = socket.get();
- writer_ = std::make_unique<InputSyncWriter>(
- mock_logger_.Get(), std::move(shared_memory), std::move(socket),
- kSegments, audio_params);
- audio_bus_ = media::AudioBus::Create(audio_params);
- }
- InputSyncWriterTest(const InputSyncWriterTest&) = delete;
- InputSyncWriterTest& operator=(const InputSyncWriterTest&) = delete;
- ~InputSyncWriterTest() override {}
- // Get total number of expected log calls. On non-Android we expect one log
- // call at first Write() call, zero on Android. We also expect all call in the
- // with a glitch summary from the destructor. Besides that only for errors
- // and fifo info.
- int GetTotalNumberOfExpectedLogCalls(int expected_calls_due_to_error) {
- #if BUILDFLAG(IS_ANDROID)
- return expected_calls_due_to_error + 1;
- #else
- return expected_calls_due_to_error + 2;
- #endif
- }
- // Tests expected numbers which are given as arguments.
- bool TestSocketAndFifoExpectations(int number_of_buffers_in_socket,
- size_t number_of_verifications_in_socket,
- size_t number_of_buffers_in_fifo) {
- EXPECT_EQ(number_of_buffers_in_socket, socket_->NumberOfBuffersFilled());
- EXPECT_EQ(number_of_verifications_in_socket, socket_->Peek());
- EXPECT_EQ(number_of_buffers_in_fifo, writer_->overflow_data_.size());
- return number_of_buffers_in_socket == socket_->NumberOfBuffersFilled() &&
- number_of_verifications_in_socket == socket_->Peek() &&
- number_of_buffers_in_fifo == writer_->overflow_data_.size();
- }
- protected:
- using MockLogger =
- base::MockCallback<base::RepeatingCallback<void(const std::string&)>>;
- base::test::TaskEnvironment env_;
- MockLogger mock_logger_;
- std::unique_ptr<InputSyncWriter> writer_;
- raw_ptr<MockCancelableSyncSocket> socket_;
- std::unique_ptr<media::AudioBus> audio_bus_;
- };
- TEST_F(InputSyncWriterTest, SingleWriteAndRead) {
- EXPECT_CALL(mock_logger_, Run(_)).Times(GetTotalNumberOfExpectedLogCalls(0));
- writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
- EXPECT_TRUE(TestSocketAndFifoExpectations(1, 0, 0));
- socket_->Read(1);
- EXPECT_TRUE(TestSocketAndFifoExpectations(0, 1 * sizeof(uint32_t), 0));
- }
- TEST_F(InputSyncWriterTest, MultipleWritesAndReads) {
- EXPECT_CALL(mock_logger_, Run(_)).Times(GetTotalNumberOfExpectedLogCalls(0));
- for (int i = 1; i <= 2 * kSegments; ++i) {
- writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
- EXPECT_TRUE(TestSocketAndFifoExpectations(1, 0, 0));
- socket_->Read(1);
- EXPECT_TRUE(TestSocketAndFifoExpectations(0, 1 * sizeof(uint32_t), 0));
- }
- }
- TEST_F(InputSyncWriterTest, MultipleWritesNoReads) {
- EXPECT_CALL(mock_logger_, Run(_)).Times(GetTotalNumberOfExpectedLogCalls(1));
- // Fill the ring buffer.
- for (int i = 1; i <= kSegments; ++i) {
- writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
- EXPECT_TRUE(TestSocketAndFifoExpectations(i, 0, 0));
- }
- // Now the ring buffer is full, do more writes. We should start filling the
- // fifo and should get one extra log call for that.
- for (size_t i = 1; i <= kSegments; ++i) {
- writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
- EXPECT_TRUE(TestSocketAndFifoExpectations(kSegments, 0, i));
- }
- }
- TEST_F(InputSyncWriterTest, FillAndEmptyRingBuffer) {
- EXPECT_CALL(mock_logger_, Run(_)).Times(GetTotalNumberOfExpectedLogCalls(2));
- // Fill the ring buffer.
- for (int i = 1; i <= kSegments; ++i) {
- writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
- }
- EXPECT_TRUE(TestSocketAndFifoExpectations(kSegments, 0, 0));
- // Empty half of the ring buffer.
- const int buffers_to_read = kSegments / 2;
- socket_->Read(buffers_to_read);
- EXPECT_TRUE(TestSocketAndFifoExpectations(
- kSegments - buffers_to_read, buffers_to_read * sizeof(uint32_t), 0));
- // Fill up again. The first write should do receive until that queue is
- // empty.
- for (int i = kSegments - buffers_to_read + 1; i <= kSegments; ++i) {
- writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
- EXPECT_TRUE(TestSocketAndFifoExpectations(i, 0, 0));
- }
- // Another write, should put the data in the fifo, and render an extra log
- // call.
- writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
- EXPECT_TRUE(TestSocketAndFifoExpectations(kSegments, 0, 1));
- // Empty the ring buffer.
- socket_->Read(kSegments);
- EXPECT_TRUE(
- TestSocketAndFifoExpectations(0, kSegments * sizeof(uint32_t), 1));
- // Another write, should do receive until that queue is empty and write both
- // the data in the fifo and the new data, and render a log call.
- writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
- EXPECT_TRUE(TestSocketAndFifoExpectations(2, 0, 0));
- // Read the two data blocks.
- socket_->Read(2);
- EXPECT_TRUE(TestSocketAndFifoExpectations(0, 2 * sizeof(uint32_t), 0));
- }
- TEST_F(InputSyncWriterTest, FillRingBufferAndFifo) {
- EXPECT_CALL(mock_logger_, Run(_)).Times(GetTotalNumberOfExpectedLogCalls(2));
- // Fill the ring buffer.
- for (int i = 1; i <= kSegments; ++i) {
- writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
- }
- EXPECT_TRUE(TestSocketAndFifoExpectations(kSegments, 0, 0));
- // Fill the fifo. Should render one log call for starting filling it.
- const size_t max_fifo_size = InputSyncWriter::kMaxOverflowBusesSize;
- for (size_t i = 1; i <= max_fifo_size; ++i) {
- writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
- }
- EXPECT_TRUE(TestSocketAndFifoExpectations(kSegments, 0, max_fifo_size));
- // Another write, data should be dropped and render one log call.
- writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
- EXPECT_TRUE(TestSocketAndFifoExpectations(kSegments, 0, max_fifo_size));
- }
- TEST_F(InputSyncWriterTest, MultipleFillAndEmptyRingBufferAndPartOfFifo) {
- EXPECT_CALL(mock_logger_, Run(_)).Times(GetTotalNumberOfExpectedLogCalls(4));
- // Fill the ring buffer.
- for (int i = 1; i <= kSegments; ++i) {
- writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
- }
- EXPECT_TRUE(TestSocketAndFifoExpectations(kSegments, 0, 0));
- // Write more data, should be put in the fifo and render one log call for
- // starting filling it.
- for (size_t i = 1; i <= 2 * kSegments; ++i) {
- writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
- }
- EXPECT_TRUE(TestSocketAndFifoExpectations(kSegments, 0, 2 * kSegments));
- // Empty the ring buffer.
- socket_->Read(kSegments);
- EXPECT_TRUE(TestSocketAndFifoExpectations(0, kSegments * sizeof(uint32_t),
- 2 * kSegments));
- // Another write should fill up the ring buffer with data from the fifo and
- // put this data into the fifo.
- writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
- EXPECT_TRUE(TestSocketAndFifoExpectations(kSegments, 0, kSegments + 1));
- // Empty the ring buffer again.
- socket_->Read(kSegments);
- EXPECT_TRUE(TestSocketAndFifoExpectations(0, kSegments * sizeof(uint32_t),
- kSegments + 1));
- // Another write should fill up the ring buffer with data from the fifo and
- // put this data into the fifo.
- writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
- EXPECT_TRUE(TestSocketAndFifoExpectations(kSegments, 0, 2));
- // Empty the ring buffer again.
- socket_->Read(kSegments);
- EXPECT_TRUE(
- TestSocketAndFifoExpectations(0, kSegments * sizeof(uint32_t), 2));
- // Another write should put the remaining data in the fifo in the ring buffer
- // together with this data. Should render a log call for emptying the fifo.
- writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
- EXPECT_TRUE(TestSocketAndFifoExpectations(3, 0, 0));
- // Read the remaining data.
- socket_->Read(3);
- EXPECT_TRUE(TestSocketAndFifoExpectations(0, 3 * sizeof(uint32_t), 0));
- // Fill the ring buffer and part of the fifo. Should render one log call for
- // starting filling it.
- for (int i = 1; i <= kSegments + 2; ++i) {
- writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
- }
- EXPECT_TRUE(TestSocketAndFifoExpectations(kSegments, 0, 2));
- // Empty both. Should render a log call for emptying the fifo.
- socket_->Read(kSegments);
- writer_->Write(audio_bus_.get(), 0, false, base::TimeTicks::Now());
- socket_->Read(3);
- EXPECT_TRUE(TestSocketAndFifoExpectations(0, 3 * sizeof(uint32_t), 0));
- }
- } // namespace audio
|