blob: 0f471c881713d2d311880744e8df226a662b33e2 [file] [log] [blame]
// 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 <map>
#include <utility>
#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<SourceFrameRef>& candidates,
const MatchesCallback& results_callback));
MOCK_METHOD1(AddInput,
media::AudioOutputStream*(const media::AudioParameters& params));
void SimulateQuery(const std::set<SourceFrameRef>& candidates,
const MatchesCallback& results_callback) {
++query_count_;
std::set<SourceFrameRef> 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<AudioOutputStream*>(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<MockMirroringDestination>& 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<MockMirroringDestination>& dest) {
mirroring_manager_.StopMirroring(dest.get());
}
int CountStreamsDivertedTo(
const scoped_ptr<MockMirroringDestination>& 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<MockMirroringDestination> 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<MockMirroringDestination> destination(
new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
StartMirroringTo(destination, 0);
EXPECT_EQ(0, CountStreamsDivertedTo(destination));
StopMirroringTo(destination);
EXPECT_EQ(0, destination->query_count());
const scoped_ptr<MockMirroringDestination> 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<MockMirroringDestination> 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<MockMirroringDestination> 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<MockMirroringDestination> 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<MockMirroringDestination> 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<MockMirroringDestination> destination(
new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
StartMirroringTo(destination, 1);
EXPECT_EQ(1, destination->query_count());
EXPECT_EQ(1, CountStreamsDivertedTo(destination));
const scoped_ptr<MockMirroringDestination> 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<MockMirroringDestination> destination(
new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
StartMirroringTo(destination, 1);
EXPECT_EQ(1, destination->query_count());
EXPECT_EQ(1, CountStreamsDivertedTo(destination));
const scoped_ptr<MockMirroringDestination> 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<MockMirroringDestination> destination(
new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
StartMirroringTo(destination, 1);
EXPECT_EQ(1, destination->query_count());
EXPECT_EQ(1, CountStreamsDivertedTo(destination));
const scoped_ptr<MockMirroringDestination> 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<MockMirroringDestination> 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<MockMirroringDestination> destination(
new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
StartMirroringTo(destination, 1);
EXPECT_EQ(1, destination->query_count());
EXPECT_EQ(1, CountStreamsDivertedTo(destination));
const scoped_ptr<MockMirroringDestination> 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<MockMirroringDestination> 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