Index: content/browser/renderer_host/media/audio_renderer_host_unittest.cc |
diff --git a/content/browser/renderer_host/media/audio_renderer_host_unittest.cc b/content/browser/renderer_host/media/audio_renderer_host_unittest.cc |
index e8bd79c9d28e3aa48135e9bf43b3bbae6c56e962..371de4bdd7106c48c1c3d6405a13e65ad5b5c29d 100644 |
--- a/content/browser/renderer_host/media/audio_renderer_host_unittest.cc |
+++ b/content/browser/renderer_host/media/audio_renderer_host_unittest.cc |
@@ -24,12 +24,15 @@ using ::testing::AtLeast; |
using ::testing::DoAll; |
using ::testing::InSequence; |
using ::testing::InvokeWithoutArgs; |
+using ::testing::NotNull; |
using ::testing::Return; |
using ::testing::SaveArg; |
using ::testing::SetArgumentPointee; |
namespace content { |
+static const int kRenderProcessId = 1; |
+static const int kRenderViewId = 4; |
static const int kStreamId = 50; |
static bool IsRunningHeadless() { |
@@ -44,7 +47,7 @@ class MockAudioRendererHost : public AudioRendererHost { |
explicit MockAudioRendererHost( |
media::AudioManager* audio_manager, |
MediaObserver* media_observer) |
- : AudioRendererHost(audio_manager, media_observer), |
+ : AudioRendererHost(kRenderProcessId, audio_manager, media_observer), |
shared_memory_length_(0) { |
} |
@@ -60,6 +63,8 @@ class MockAudioRendererHost : public AudioRendererHost { |
virtual ~MockAudioRendererHost() { |
// Make sure all audio streams have been deleted. |
EXPECT_TRUE(audio_entries_.empty()); |
+ // Make sure no mirroring sessions are active. |
+ EXPECT_TRUE(mirror_sessions_.empty()); |
} |
// This method is used to dispatch IPC messages to the renderer. We intercept |
@@ -136,6 +141,23 @@ class MockAudioRendererHost : public AudioRendererHost { |
DISALLOW_COPY_AND_ASSIGN(MockAudioRendererHost); |
}; |
+class MockMirroringDestination |
+ : public AudioRendererHost::MirroringDestination { |
+ public: |
+ MockMirroringDestination() {} |
+ |
+ MOCK_METHOD2(AddInput, |
+ void(media::AudioOutputStream::AudioSourceCallback* callback, |
+ const media::AudioParameters& params)); |
+ MOCK_METHOD1(RemoveInput, |
+ void(media::AudioOutputStream::AudioSourceCallback* callback)); |
+ |
+ private: |
+ virtual ~MockMirroringDestination() {} |
+ |
+ DISALLOW_COPY_AND_ASSIGN(MockMirroringDestination); |
+}; |
+ |
ACTION_P(QuitMessageLoop, message_loop) { |
message_loop->PostTask(FROM_HERE, MessageLoop::QuitClosure()); |
} |
@@ -159,20 +181,24 @@ class AudioRendererHostTest : public testing::Test { |
audio_manager_.reset(media::AudioManager::Create()); |
observer_.reset(new MockMediaObserver()); |
host_ = new MockAudioRendererHost(audio_manager_.get(), observer_.get()); |
- |
- // Expect the audio stream will be deleted. |
- EXPECT_CALL(*observer_, OnDeleteAudioStream(_, kStreamId)); |
+ destination_ = new MockMirroringDestination(); |
+ another_destination_ = new MockMirroringDestination(); |
// Simulate IPC channel connected. |
host_->OnChannelConnected(base::GetCurrentProcId()); |
+ |
+ if (!IsRunningHeadless()) |
+ EnableRealDevice(); |
} |
virtual void TearDown() { |
// Simulate closing the IPC channel. |
host_->OnChannelClosing(); |
- // Release the reference to the mock object. The object will be destructed |
- // on message_loop_. |
+ // Release the reference to the mock objects. The MockAudioRendererHost |
+ // will be destroyed on message_loop_. |
+ another_destination_ = NULL; |
+ destination_ = NULL; |
host_ = NULL; |
// We need to continue running message_loop_ to complete all destructions. |
@@ -208,6 +234,13 @@ class AudioRendererHostTest : public testing::Test { |
// we receive the created message. |
host_->OnCreateStream(kStreamId, params, 0); |
message_loop_->Run(); |
+ |
+ // Simulate the renderer process associating a stream with a render view. |
+ host_->OnAssociateStreamWithProducer(kStreamId, kRenderViewId); |
+ message_loop_->RunUntilIdle(); |
+ |
+ // Expect the audio stream will be deleted at some later point. |
+ EXPECT_CALL(*observer_, OnDeleteAudioStream(_, kStreamId)); |
} |
void Close() { |
@@ -248,6 +281,20 @@ class AudioRendererHostTest : public testing::Test { |
message_loop_->RunUntilIdle(); |
} |
+ void StartMirroringTo(MockMirroringDestination* dest, |
+ int expected_inputs_seen) { |
+ EXPECT_CALL(*dest, AddInput(NotNull(), _)).Times(expected_inputs_seen); |
+ EXPECT_CALL(*dest, RemoveInput(NotNull())).Times(expected_inputs_seen); |
+ |
+ AudioRendererHost::StartMirroring(kRenderProcessId, kRenderViewId, dest); |
+ message_loop_->RunUntilIdle(); |
+ } |
+ |
+ void StopMirroringTo(MockMirroringDestination* dest) { |
+ AudioRendererHost::StopMirroring(kRenderProcessId, kRenderViewId, dest); |
+ message_loop_->RunUntilIdle(); |
+ } |
+ |
void SimulateError() { |
EXPECT_CALL(*observer_, |
OnSetAudioStreamStatus(_, kStreamId, "error")); |
@@ -297,10 +344,21 @@ class AudioRendererHostTest : public testing::Test { |
void EnableRealDevice() { mock_stream_ = false; } |
+ protected: |
+ // Accessors for testing mirroring to one or two destinations. |
+ MockMirroringDestination* destination() const { |
+ return destination_; |
+ } |
+ MockMirroringDestination* another_destination() const { |
+ return another_destination_; |
+ } |
+ |
private: |
bool mock_stream_; |
scoped_ptr<MockMediaObserver> observer_; |
scoped_refptr<MockAudioRendererHost> host_; |
+ scoped_refptr<MockMirroringDestination> destination_; |
+ scoped_refptr<MockMirroringDestination> another_destination_; |
scoped_ptr<MessageLoop> message_loop_; |
scoped_ptr<BrowserThreadImpl> io_thread_; |
scoped_ptr<BrowserThreadImpl> ui_thread_; |
@@ -310,34 +368,22 @@ class AudioRendererHostTest : public testing::Test { |
}; |
TEST_F(AudioRendererHostTest, CreateAndClose) { |
- if (!IsRunningHeadless()) |
- EnableRealDevice(); |
- |
Create(); |
Close(); |
} |
// Simulate the case where a stream is not properly closed. |
TEST_F(AudioRendererHostTest, CreateAndShutdown) { |
- if (!IsRunningHeadless()) |
- EnableRealDevice(); |
- |
Create(); |
} |
TEST_F(AudioRendererHostTest, CreatePlayAndClose) { |
- if (!IsRunningHeadless()) |
- EnableRealDevice(); |
- |
Create(); |
Play(); |
Close(); |
} |
TEST_F(AudioRendererHostTest, CreatePlayPauseAndClose) { |
- if (!IsRunningHeadless()) |
- EnableRealDevice(); |
- |
Create(); |
Play(); |
Pause(); |
@@ -345,9 +391,6 @@ TEST_F(AudioRendererHostTest, CreatePlayPauseAndClose) { |
} |
TEST_F(AudioRendererHostTest, SetVolume) { |
- if (!IsRunningHeadless()) |
- EnableRealDevice(); |
- |
Create(); |
SetVolume(0.5); |
Play(); |
@@ -357,27 +400,97 @@ TEST_F(AudioRendererHostTest, SetVolume) { |
// Simulate the case where a stream is not properly closed. |
TEST_F(AudioRendererHostTest, CreatePlayAndShutdown) { |
- if (!IsRunningHeadless()) |
- EnableRealDevice(); |
- |
Create(); |
Play(); |
} |
// Simulate the case where a stream is not properly closed. |
TEST_F(AudioRendererHostTest, CreatePlayPauseAndShutdown) { |
- if (!IsRunningHeadless()) |
- EnableRealDevice(); |
+ Create(); |
+ Play(); |
+ Pause(); |
+} |
+ |
+TEST_F(AudioRendererHostTest, MirroringOfNothing) { |
+ StartMirroringTo(destination(), 0); |
+ StopMirroringTo(destination()); |
+} |
+TEST_F(AudioRendererHostTest, StreamLifetimeAroundMirroringSession) { |
Create(); |
Play(); |
+ StartMirroringTo(destination(), 1); |
+ StopMirroringTo(destination()); |
+ Close(); |
+} |
+ |
+TEST_F(AudioRendererHostTest, PauseStreamDuringMirroringSession) { |
+ Create(); |
+ Play(); |
+ StartMirroringTo(destination(), 1); |
Pause(); |
+ StopMirroringTo(destination()); |
+ Close(); |
} |
-TEST_F(AudioRendererHostTest, SimulateError) { |
- if (!IsRunningHeadless()) |
- EnableRealDevice(); |
+TEST_F(AudioRendererHostTest, StreamLifetimeWithinMirroringSession) { |
+ StartMirroringTo(destination(), 1); |
+ Create(); |
+ Play(); |
+ Close(); |
+ StopMirroringTo(destination()); |
+} |
+ |
+TEST_F(AudioRendererHostTest, StreamLifetimeAroundTwoMirroringSessions) { |
+ Create(); |
+ Play(); |
+ StartMirroringTo(destination(), 1); |
+ StopMirroringTo(destination()); |
+ StartMirroringTo(another_destination(), 1); |
+ StopMirroringTo(another_destination()); |
+ Close(); |
+} |
+ |
+TEST_F(AudioRendererHostTest, StreamLifetimeWithinTwoMirroringSessions) { |
+ StartMirroringTo(destination(), 1); |
+ Create(); |
+ Play(); |
+ StopMirroringTo(destination()); |
+ StartMirroringTo(another_destination(), 1); |
+ Close(); |
+ StopMirroringTo(another_destination()); |
+} |
+ |
+TEST_F(AudioRendererHostTest, StreamSwitchesMirroringSessions) { |
+ StartMirroringTo(destination(), 1); |
+ Create(); |
+ Play(); |
+ StartMirroringTo(another_destination(), 1); |
+ Close(); |
+ StopMirroringTo(another_destination()); |
+ StopMirroringTo(destination()); // This should be a no-op. |
+} |
+ |
+TEST_F(AudioRendererHostTest, SwitchMirroringDestinationNoStreams) { |
+ StartMirroringTo(destination(), 0); |
+ StartMirroringTo(another_destination(), 0); |
+ StopMirroringTo(another_destination()); |
+} |
+ |
+// Simulate the case where mirroring was not stopped before shutdown. |
+TEST_F(AudioRendererHostTest, StartMirroringNothingAndShutdown) { |
+ StartMirroringTo(destination(), 0); |
+} |
+// Simulate the case where mirroring was not stopped before shutdown, and a |
+// stream was being mirrored. |
+TEST_F(AudioRendererHostTest, StartMirroringSomethingAndShutdown) { |
+ StartMirroringTo(destination(), 1); |
+ Create(); |
+ Play(); |
+} |
+ |
+TEST_F(AudioRendererHostTest, SimulateError) { |
Create(); |
Play(); |
SimulateError(); |
@@ -387,9 +500,6 @@ TEST_F(AudioRendererHostTest, SimulateError) { |
// the audio device is closed but the render process try to close the |
// audio stream again. |
TEST_F(AudioRendererHostTest, SimulateErrorAndClose) { |
- if (!IsRunningHeadless()) |
- EnableRealDevice(); |
- |
Create(); |
Play(); |
SimulateError(); |