// Copyright (c) 2013 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 "content/browser/media/capture/audio_mirroring_manager.h" #include #include #include "base/bind.h" #include "base/bind_helpers.h" #include "base/macros.h" #include "base/message_loop/message_loop.h" #include "base/synchronization/waitable_event.h" #include "content/browser/browser_thread_impl.h" #include "media/audio/audio_parameters.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using media::AudioOutputStream; using media::AudioParameters; using testing::_; using testing::Invoke; using testing::NotNull; using testing::Ref; using testing::Return; using testing::ReturnRef; namespace content { namespace { class MockDiverter : public AudioMirroringManager::Diverter { public: MOCK_METHOD0(GetAudioParameters, const AudioParameters&()); MOCK_METHOD1(StartDiverting, void(AudioOutputStream*)); MOCK_METHOD0(StopDiverting, void()); }; class MockMirroringDestination : public AudioMirroringManager::MirroringDestination { public: typedef AudioMirroringManager::SourceFrameRef SourceFrameRef; MockMirroringDestination(int render_process_id, int render_frame_id) : render_process_id_(render_process_id), render_frame_id_(render_frame_id), query_count_(0) {} MOCK_METHOD2(QueryForMatches, void(const std::set& candidates, const MatchesCallback& results_callback)); MOCK_METHOD1(AddInput, media::AudioOutputStream*(const media::AudioParameters& params)); void SimulateQuery(const std::set& candidates, const MatchesCallback& results_callback) { ++query_count_; std::set result; if (candidates.find(SourceFrameRef(render_process_id_, render_frame_id_)) != candidates.end()) { result.insert(SourceFrameRef(render_process_id_, render_frame_id_)); } results_callback.Run(result); } media::AudioOutputStream* SimulateAddInput( const media::AudioParameters& params) { static AudioOutputStream* const kNonNullPointer = reinterpret_cast(0x11111110); return kNonNullPointer; } int query_count() const { return query_count_; } private: const int render_process_id_; const int render_frame_id_; int query_count_; }; } // namespace class AudioMirroringManagerTest : public testing::Test { public: typedef AudioMirroringManager::Diverter Diverter; typedef AudioMirroringManager::MirroringDestination MirroringDestination; typedef AudioMirroringManager::StreamRoutes StreamRoutes; AudioMirroringManagerTest() : io_thread_(BrowserThread::IO, &message_loop_), params_(AudioParameters::AUDIO_FAKE, media::CHANNEL_LAYOUT_STEREO, AudioParameters::kAudioCDSampleRate, 16, AudioParameters::kAudioCDSampleRate / 10) {} MockDiverter* CreateStream( int render_process_id, int render_frame_id, int expected_times_diverted) { MockDiverter* const diverter = new MockDiverter(); if (expected_times_diverted > 0) { EXPECT_CALL(*diverter, GetAudioParameters()) .Times(expected_times_diverted) .WillRepeatedly(ReturnRef(params_)); EXPECT_CALL(*diverter, StartDiverting(NotNull())) .Times(expected_times_diverted); EXPECT_CALL(*diverter, StopDiverting()) .Times(expected_times_diverted); } mirroring_manager_.AddDiverter( render_process_id, render_frame_id, diverter); return diverter; } void KillStream(MockDiverter* diverter) { mirroring_manager_.RemoveDiverter(diverter); delete diverter; } void StartMirroringTo(const scoped_ptr& dest, int expected_inputs_added) { EXPECT_CALL(*dest, QueryForMatches(_, _)) .WillRepeatedly(Invoke(dest.get(), &MockMirroringDestination::SimulateQuery)); if (expected_inputs_added > 0) { EXPECT_CALL(*dest, AddInput(Ref(params_))) .Times(expected_inputs_added) .WillRepeatedly(Invoke(dest.get(), &MockMirroringDestination::SimulateAddInput)) .RetiresOnSaturation(); } mirroring_manager_.StartMirroring(dest.get()); } void StopMirroringTo(const scoped_ptr& dest) { mirroring_manager_.StopMirroring(dest.get()); } int CountStreamsDivertedTo( const scoped_ptr& dest) const { int count = 0; for (StreamRoutes::const_iterator it = mirroring_manager_.routes_.begin(); it != mirroring_manager_.routes_.end(); ++it) { if (it->destination == dest.get()) ++count; } return count; } void ExpectNoLongerManagingAnything() const { EXPECT_TRUE(mirroring_manager_.routes_.empty()); EXPECT_TRUE(mirroring_manager_.sessions_.empty()); } private: base::MessageLoopForIO message_loop_; BrowserThreadImpl io_thread_; AudioParameters params_; AudioMirroringManager mirroring_manager_; DISALLOW_COPY_AND_ASSIGN(AudioMirroringManagerTest); }; namespace { const int kRenderProcessId = 123; const int kRenderFrameId = 456; const int kAnotherRenderProcessId = 789; const int kAnotherRenderFrameId = 1234; const int kYetAnotherRenderProcessId = 4560; const int kYetAnotherRenderFrameId = 7890; } TEST_F(AudioMirroringManagerTest, MirroringSessionOfNothing) { const scoped_ptr destination( new MockMirroringDestination(kRenderProcessId, kRenderFrameId)); StartMirroringTo(destination, 0); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); StopMirroringTo(destination); EXPECT_EQ(0, destination->query_count()); ExpectNoLongerManagingAnything(); } TEST_F(AudioMirroringManagerTest, TwoMirroringSessionsOfNothing) { const scoped_ptr destination( new MockMirroringDestination(kRenderProcessId, kRenderFrameId)); StartMirroringTo(destination, 0); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); StopMirroringTo(destination); EXPECT_EQ(0, destination->query_count()); const scoped_ptr another_destination( new MockMirroringDestination(kAnotherRenderProcessId, kAnotherRenderFrameId)); StartMirroringTo(another_destination, 0); EXPECT_EQ(0, CountStreamsDivertedTo(another_destination)); StopMirroringTo(another_destination); EXPECT_EQ(0, another_destination->query_count()); ExpectNoLongerManagingAnything(); } // Tests that a mirroring session starts after, and ends before, a stream that // will be diverted to it. TEST_F(AudioMirroringManagerTest, StreamLifetimeAroundMirroringSession) { MockDiverter* const stream = CreateStream(kRenderProcessId, kRenderFrameId, 1); const scoped_ptr destination( new MockMirroringDestination(kRenderProcessId, kRenderFrameId)); StartMirroringTo(destination, 1); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(1, CountStreamsDivertedTo(destination)); StopMirroringTo(destination); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); KillStream(stream); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); ExpectNoLongerManagingAnything(); } // Tests that a mirroring session starts before, and ends after, a stream that // will be diverted to it. TEST_F(AudioMirroringManagerTest, StreamLifetimeWithinMirroringSession) { const scoped_ptr destination( new MockMirroringDestination(kRenderProcessId, kRenderFrameId)); StartMirroringTo(destination, 1); EXPECT_EQ(0, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); MockDiverter* const stream = CreateStream(kRenderProcessId, kRenderFrameId, 1); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(1, CountStreamsDivertedTo(destination)); KillStream(stream); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); StopMirroringTo(destination); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); ExpectNoLongerManagingAnything(); } // Tests that a stream is diverted correctly as two mirroring sessions come and // go. TEST_F(AudioMirroringManagerTest, StreamLifetimeAcrossTwoMirroringSessions) { MockDiverter* const stream = CreateStream(kRenderProcessId, kRenderFrameId, 2); const scoped_ptr destination( new MockMirroringDestination(kRenderProcessId, kRenderFrameId)); StartMirroringTo(destination, 1); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(1, CountStreamsDivertedTo(destination)); StopMirroringTo(destination); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); const scoped_ptr second_destination( new MockMirroringDestination(kRenderProcessId, kRenderFrameId)); StartMirroringTo(second_destination, 1); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); EXPECT_EQ(1, second_destination->query_count()); EXPECT_EQ(1, CountStreamsDivertedTo(second_destination)); StopMirroringTo(second_destination); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); EXPECT_EQ(1, second_destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(second_destination)); KillStream(stream); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); EXPECT_EQ(1, second_destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(second_destination)); ExpectNoLongerManagingAnything(); } // Tests that a stream does not flip-flop between two destinations that are a // match for it. TEST_F(AudioMirroringManagerTest, StreamDivertingStickyToOneDestination_1) { MockDiverter* const stream = CreateStream(kRenderProcessId, kRenderFrameId, 2); const scoped_ptr destination( new MockMirroringDestination(kRenderProcessId, kRenderFrameId)); StartMirroringTo(destination, 1); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(1, CountStreamsDivertedTo(destination)); const scoped_ptr replacement_destination( new MockMirroringDestination(kRenderProcessId, kRenderFrameId)); StartMirroringTo(replacement_destination, 1); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(1, CountStreamsDivertedTo(destination)); EXPECT_EQ(0, replacement_destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(replacement_destination)); StopMirroringTo(destination); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); EXPECT_EQ(1, replacement_destination->query_count()); EXPECT_EQ(1, CountStreamsDivertedTo(replacement_destination)); StopMirroringTo(replacement_destination); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); EXPECT_EQ(1, replacement_destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(replacement_destination)); KillStream(stream); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); EXPECT_EQ(1, replacement_destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(replacement_destination)); ExpectNoLongerManagingAnything(); } // Same as StreamDivertingStickyToOneDestination_1, with a different order of // operations that should have the same effects. TEST_F(AudioMirroringManagerTest, StreamDivertingStickyToOneDestination_2) { MockDiverter* const stream = CreateStream(kRenderProcessId, kRenderFrameId, 2); const scoped_ptr destination( new MockMirroringDestination(kRenderProcessId, kRenderFrameId)); StartMirroringTo(destination, 1); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(1, CountStreamsDivertedTo(destination)); const scoped_ptr replacement_destination( new MockMirroringDestination(kRenderProcessId, kRenderFrameId)); StartMirroringTo(replacement_destination, 1); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(1, CountStreamsDivertedTo(destination)); EXPECT_EQ(0, replacement_destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(replacement_destination)); StopMirroringTo(destination); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); EXPECT_EQ(1, replacement_destination->query_count()); EXPECT_EQ(1, CountStreamsDivertedTo(replacement_destination)); KillStream(stream); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); EXPECT_EQ(1, replacement_destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(replacement_destination)); StopMirroringTo(replacement_destination); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); EXPECT_EQ(1, replacement_destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(replacement_destination)); ExpectNoLongerManagingAnything(); } // Same as StreamDivertingStickyToOneDestination_1, except that the stream is // killed before the first destination is stopped. Therefore, the second // destination should never see the stream. TEST_F(AudioMirroringManagerTest, StreamDivertingStickyToOneDestination_3) { MockDiverter* const stream = CreateStream(kRenderProcessId, kRenderFrameId, 1); const scoped_ptr destination( new MockMirroringDestination(kRenderProcessId, kRenderFrameId)); StartMirroringTo(destination, 1); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(1, CountStreamsDivertedTo(destination)); const scoped_ptr replacement_destination( new MockMirroringDestination(kRenderProcessId, kRenderFrameId)); StartMirroringTo(replacement_destination, 0); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(1, CountStreamsDivertedTo(destination)); EXPECT_EQ(0, replacement_destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(replacement_destination)); KillStream(stream); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); EXPECT_EQ(0, replacement_destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(replacement_destination)); StopMirroringTo(destination); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); EXPECT_EQ(0, replacement_destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(replacement_destination)); StopMirroringTo(replacement_destination); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); EXPECT_EQ(0, replacement_destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(replacement_destination)); ExpectNoLongerManagingAnything(); } // Tests that multiple streams are diverted/mixed to one destination. TEST_F(AudioMirroringManagerTest, MultipleStreamsInOneMirroringSession) { MockDiverter* const stream1 = CreateStream(kRenderProcessId, kRenderFrameId, 1); const scoped_ptr destination( new MockMirroringDestination(kRenderProcessId, kRenderFrameId)); StartMirroringTo(destination, 3); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(1, CountStreamsDivertedTo(destination)); MockDiverter* const stream2 = CreateStream(kRenderProcessId, kRenderFrameId, 1); EXPECT_EQ(2, destination->query_count()); EXPECT_EQ(2, CountStreamsDivertedTo(destination)); MockDiverter* const stream3 = CreateStream(kRenderProcessId, kRenderFrameId, 1); EXPECT_EQ(3, destination->query_count()); EXPECT_EQ(3, CountStreamsDivertedTo(destination)); KillStream(stream2); EXPECT_EQ(3, destination->query_count()); EXPECT_EQ(2, CountStreamsDivertedTo(destination)); StopMirroringTo(destination); EXPECT_EQ(3, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); KillStream(stream3); EXPECT_EQ(3, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); KillStream(stream1); EXPECT_EQ(3, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); ExpectNoLongerManagingAnything(); } // A random interleaving of operations for three separate targets, each of which // has one stream mirrored to one destination. TEST_F(AudioMirroringManagerTest, ThreeSeparateMirroringSessions) { MockDiverter* const stream = CreateStream(kRenderProcessId, kRenderFrameId, 1); const scoped_ptr destination( new MockMirroringDestination(kRenderProcessId, kRenderFrameId)); StartMirroringTo(destination, 1); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(1, CountStreamsDivertedTo(destination)); const scoped_ptr another_destination( new MockMirroringDestination(kAnotherRenderProcessId, kAnotherRenderFrameId)); StartMirroringTo(another_destination, 1); EXPECT_EQ(1, destination->query_count()); EXPECT_EQ(1, CountStreamsDivertedTo(destination)); EXPECT_EQ(0, another_destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(another_destination)); MockDiverter* const another_stream = CreateStream(kAnotherRenderProcessId, kAnotherRenderFrameId, 1); EXPECT_EQ(2, destination->query_count()); EXPECT_EQ(1, CountStreamsDivertedTo(destination)); EXPECT_EQ(1, another_destination->query_count()); EXPECT_EQ(1, CountStreamsDivertedTo(another_destination)); KillStream(stream); EXPECT_EQ(2, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); EXPECT_EQ(1, another_destination->query_count()); EXPECT_EQ(1, CountStreamsDivertedTo(another_destination)); MockDiverter* const yet_another_stream = CreateStream(kYetAnotherRenderProcessId, kYetAnotherRenderFrameId, 1); EXPECT_EQ(3, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); EXPECT_EQ(2, another_destination->query_count()); EXPECT_EQ(1, CountStreamsDivertedTo(another_destination)); const scoped_ptr yet_another_destination( new MockMirroringDestination(kYetAnotherRenderProcessId, kYetAnotherRenderFrameId)); StartMirroringTo(yet_another_destination, 1); EXPECT_EQ(3, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); EXPECT_EQ(2, another_destination->query_count()); EXPECT_EQ(1, CountStreamsDivertedTo(another_destination)); EXPECT_EQ(1, yet_another_destination->query_count()); EXPECT_EQ(1, CountStreamsDivertedTo(yet_another_destination)); StopMirroringTo(another_destination); EXPECT_EQ(4, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); EXPECT_EQ(2, another_destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(another_destination)); EXPECT_EQ(2, yet_another_destination->query_count()); EXPECT_EQ(1, CountStreamsDivertedTo(yet_another_destination)); StopMirroringTo(yet_another_destination); EXPECT_EQ(5, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); EXPECT_EQ(2, another_destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(another_destination)); EXPECT_EQ(2, yet_another_destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(yet_another_destination)); StopMirroringTo(destination); EXPECT_EQ(5, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); EXPECT_EQ(2, another_destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(another_destination)); EXPECT_EQ(2, yet_another_destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(yet_another_destination)); KillStream(another_stream); EXPECT_EQ(5, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); EXPECT_EQ(2, another_destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(another_destination)); EXPECT_EQ(2, yet_another_destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(yet_another_destination)); KillStream(yet_another_stream); EXPECT_EQ(5, destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(destination)); EXPECT_EQ(2, another_destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(another_destination)); EXPECT_EQ(2, yet_another_destination->query_count()); EXPECT_EQ(0, CountStreamsDivertedTo(yet_another_destination)); ExpectNoLongerManagingAnything(); } } // namespace content