Index: content/browser/renderer_host/media/audio_input_sync_writer_unittest.cc |
diff --git a/content/browser/renderer_host/media/audio_input_sync_writer_unittest.cc b/content/browser/renderer_host/media/audio_input_sync_writer_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..cce27ca90baacb5a2884e3b3377451716a6487c6 |
--- /dev/null |
+++ b/content/browser/renderer_host/media/audio_input_sync_writer_unittest.cc |
@@ -0,0 +1,265 @@ |
+// 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 "base/compiler_specific.h" |
+#include "base/memory/scoped_ptr.h" |
+#include "base/sync_socket.h" |
+#include "base/time/time.h" |
+#include "content/browser/renderer_host/media/audio_input_sync_writer.h" |
+#include "content/public/test/test_browser_thread_bundle.h" |
+#include "media/audio/audio_parameters.h" |
+#include "media/base/audio_bus.h" |
+#include "media/base/channel_layout.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+using ::testing::_; |
+using base::TimeDelta; |
+using media::AudioBus; |
+using media::AudioParameters; |
+ |
+namespace content { |
+ |
+namespace { |
+ |
+// Number of audio buffers in the faked ring buffer. |
+const int kSegments = 10; |
+ |
+// Audio buffer parameters. |
+const int channels = 1; |
+const int sampling_frequency_hz = 16000; |
+const int frames = sampling_frequency_hz / 100; // 10 ms |
+const int bits_per_sample = 16; |
+ |
+// Faked ring buffer. Must be aligned. |
+#define DATA_ALIGNMENT 16 |
+COMPILE_ASSERT(AudioBus::kChannelAlignment == DATA_ALIGNMENT, |
+ Data_alignment_not_same_as_AudioBus); |
+ALIGNAS(DATA_ALIGNMENT) uint8 data[kSegments * |
+ (sizeof(media::AudioInputBufferParameters) + frames * channels * |
+ sizeof(float))]; |
+ |
+} // 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: |
+ MockCancelableSyncSocket(int buffer_size) |
+ : in_failure_mode_(false), |
+ writes_(0), |
+ reads_(0), |
+ receives_(0), |
+ buffer_size_(buffer_size), |
+ read_buffer_index_(0) {} |
+ |
+ 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_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(MockCancelableSyncSocket); |
+}; |
+ |
+class AudioInputSyncWriterUnderTest : public AudioInputSyncWriter { |
+ public: |
+ AudioInputSyncWriterUnderTest(void* shared_memory, |
+ size_t shared_memory_size, |
+ int shared_memory_segment_count, |
+ const media::AudioParameters& params, |
+ base::CancelableSyncSocket* socket) |
+ : AudioInputSyncWriter(shared_memory, shared_memory_size, |
+ shared_memory_segment_count, params) { |
+ socket_.reset(socket); |
+ } |
+ |
+ ~AudioInputSyncWriterUnderTest() override {} |
+ |
+ MOCK_METHOD1(AddToNativeLog, void(const std::string& message)); |
+}; |
+ |
+class AudioInputSyncWriterTest : public testing::Test { |
+ public: |
+ AudioInputSyncWriterTest() |
+ : socket_(nullptr) { |
+ const media::ChannelLayout layout = |
+ media::GuessChannelLayout(channels); |
+ EXPECT_NE(media::ChannelLayout::CHANNEL_LAYOUT_UNSUPPORTED, layout); |
+ AudioParameters audio_params( |
+ AudioParameters::AUDIO_FAKE, layout, sampling_frequency_hz, |
+ bits_per_sample, frames); |
+ |
+ const uint32 segment_size = |
+ sizeof(media::AudioInputBufferParameters) + |
+ AudioBus::CalculateMemorySize(audio_params); |
+ size_t data_size = kSegments * segment_size; |
+ EXPECT_LE(data_size, sizeof(data)); |
+ |
+ socket_ = new MockCancelableSyncSocket(kSegments); |
+ writer_.reset(new AudioInputSyncWriterUnderTest( |
+ &data[0], data_size, kSegments, audio_params, socket_)); |
+ audio_bus_ = AudioBus::Create(audio_params); |
+ } |
+ |
+ ~AudioInputSyncWriterTest() override { |
+ } |
+ |
+ // Get total number of expected log calls. On non-Android we expect one log |
+ // call at first Write() call, zero on Android. Besides that only for errors. |
+ int GetTotalNumberOfExpectedLogCalls(int expected_calls_due_to_error) { |
+#if defined(OS_ANDROID) |
+ return expected_calls_due_to_error; |
+#else |
+ return expected_calls_due_to_error + 1; |
+#endif |
+ } |
+ |
+ protected: |
+ scoped_ptr<AudioInputSyncWriterUnderTest> writer_; |
+ MockCancelableSyncSocket* socket_; |
+ scoped_ptr<AudioBus> audio_bus_; |
+ |
+ private: |
+ TestBrowserThreadBundle thread_bundle_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(AudioInputSyncWriterTest); |
+}; |
+ |
+TEST_F(AudioInputSyncWriterTest, SingleWriteAndRead) { |
+ // We always expect one log call at first write. |
+ EXPECT_CALL(*writer_.get(), AddToNativeLog(_)) |
+ .Times(GetTotalNumberOfExpectedLogCalls(0)); |
+ |
+ writer_->Write(audio_bus_.get(), 0, false, 0); |
+ EXPECT_EQ(1, socket_->NumberOfBuffersFilled()); |
+ EXPECT_EQ(0u, socket_->Peek()); |
+ |
+ socket_->Read(1); |
+ EXPECT_EQ(0, socket_->NumberOfBuffersFilled()); |
+ EXPECT_EQ(sizeof(uint32_t), socket_->Peek()); |
+} |
+ |
+TEST_F(AudioInputSyncWriterTest, MultipleWritesAndReads) { |
+ EXPECT_CALL(*writer_.get(), AddToNativeLog(_)) |
+ .Times(GetTotalNumberOfExpectedLogCalls(0)); |
+ |
+ for (int i = 1; i <= 2 * kSegments; ++i) { |
+ writer_->Write(audio_bus_.get(), 0, false, 0); |
+ EXPECT_EQ(1, socket_->NumberOfBuffersFilled()); |
+ EXPECT_EQ(0u, socket_->Peek()); |
+ |
+ socket_->Read(1); |
+ EXPECT_EQ(0, socket_->NumberOfBuffersFilled()); |
+ EXPECT_EQ(sizeof(uint32_t), socket_->Peek()); |
+ } |
+} |
+ |
+TEST_F(AudioInputSyncWriterTest, MultipleWritesNoReads) { |
+ EXPECT_CALL(*writer_.get(), AddToNativeLog(_)) |
+ .Times(GetTotalNumberOfExpectedLogCalls(kSegments)); |
+ |
+ for (int i = 1; i <= kSegments; ++i) { |
+ writer_->Write(audio_bus_.get(), 0, false, 0); |
+ EXPECT_EQ(i, socket_->NumberOfBuffersFilled()); |
+ EXPECT_EQ(0u, socket_->Peek()); |
+ } |
+ |
+ // Now the ring buffer is full, do more writes. We should get an extra error |
+ // log call for each write. See top EXPECT_CALL. |
+ for (int i = 1; i <= kSegments; ++i) { |
+ writer_->Write(audio_bus_.get(), 0, false, 0); |
+ EXPECT_EQ(kSegments, socket_->NumberOfBuffersFilled()); |
+ EXPECT_EQ(0u, socket_->Peek()); |
+ } |
+} |
+ |
+TEST_F(AudioInputSyncWriterTest, FillAndEmptyRingBuffer) { |
+ EXPECT_CALL(*writer_.get(), AddToNativeLog(_)) |
+ .Times(GetTotalNumberOfExpectedLogCalls(1)); |
+ |
+ // Fill ring buffer. |
+ for (int i = 1; i <= kSegments; ++i) { |
+ writer_->Write(audio_bus_.get(), 0, false, 0); |
+ } |
+ EXPECT_EQ(kSegments, socket_->NumberOfBuffersFilled()); |
+ EXPECT_EQ(0u, socket_->Peek()); |
+ |
+ // Empty half of the ring buffer. |
+ int buffers_to_read = kSegments / 2; |
+ socket_->Read(buffers_to_read); |
+ EXPECT_EQ(kSegments - buffers_to_read, socket_->NumberOfBuffersFilled()); |
+ EXPECT_EQ(buffers_to_read * sizeof(uint32_t), socket_->Peek()); |
+ |
+ // 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, 0); |
+ EXPECT_EQ(i, socket_->NumberOfBuffersFilled()); |
+ EXPECT_EQ(0u, socket_->Peek()); |
+ } |
+ |
+ // Another write, should render and extra error log call. |
+ writer_->Write(audio_bus_.get(), 0, false, 0); |
+ EXPECT_EQ(kSegments, socket_->NumberOfBuffersFilled()); |
+ EXPECT_EQ(0u, socket_->Peek()); |
+ |
+ // Empty the ring buffer. |
+ socket_->Read(kSegments); |
+ EXPECT_EQ(0, socket_->NumberOfBuffersFilled()); |
+ EXPECT_EQ(kSegments * sizeof(uint32_t), socket_->Peek()); |
+ |
+ // Another write, should do receive until that queue is empty. |
+ writer_->Write(audio_bus_.get(), 0, false, 0); |
+ EXPECT_EQ(1, socket_->NumberOfBuffersFilled()); |
+ EXPECT_EQ(0u, socket_->Peek()); |
+} |
+ |
+} // namespace content |