Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(19)

Unified Diff: content/browser/renderer_host/media/audio_input_sync_writer_unittest.cc

Issue 1302423006: Ensure that data is not overwritten in the audio input shared memory ring buffer that sits on the b… (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed log call expectations for Android in unit test. Rebase. Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/browser/renderer_host/media/audio_input_sync_writer.cc ('k') | content/content_tests.gypi » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « content/browser/renderer_host/media/audio_input_sync_writer.cc ('k') | content/content_tests.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698