blob: b1ee1c3324430ba9ab8cfa160cce1d969195b33d [file] [log] [blame]
// Copyright 2016 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/renderer/media/media_devices_event_dispatcher.h"
#include <stddef.h>
#include <memory>
#include <string>
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"
using testing::_;
namespace content {
namespace {
class MockMediaDevicesEventSubscriber {
public:
MOCK_METHOD2(EventDispatched,
void(MediaDeviceType, const MediaDeviceInfoArray&));
};
class MockMediaDevicesDispatcherHost
: public ::mojom::MediaDevicesDispatcherHost {
public:
MockMediaDevicesDispatcherHost() : binding_(this) {}
MOCK_METHOD3(SubscribeDeviceChangeNotifications,
void(MediaDeviceType type,
uint32_t subscription_id,
const url::Origin& security_origin));
MOCK_METHOD2(UnsubscribeDeviceChangeNotifications,
void(MediaDeviceType type, uint32_t subscription_id));
void EnumerateDevices(bool request_audio_input,
bool request_video_input,
bool request_audio_output,
const url::Origin& security_origin,
EnumerateDevicesCallback) override {
NOTREACHED();
}
void GetVideoInputCapabilities(
const url::Origin& security_origin,
GetVideoInputCapabilitiesCallback client_callback) override {
NOTREACHED();
}
::mojom::MediaDevicesDispatcherHostPtr CreateInterfacePtrAndBind() {
return binding_.CreateInterfacePtrAndBind();
}
private:
mojo::Binding<::mojom::MediaDevicesDispatcherHost> binding_;
};
class MediaDevicesEventDispatcherTest : public ::testing::Test {
public:
MediaDevicesEventDispatcherTest() {}
void SetUp() override {
event_dispatcher_ = MediaDevicesEventDispatcher::GetForRenderFrame(nullptr);
::mojom::MediaDevicesDispatcherHostPtr ptr =
media_devices_dispatcher_.CreateInterfacePtrAndBind();
event_dispatcher_->SetMediaDevicesDispatcherForTesting(std::move(ptr));
}
void TearDown() override { event_dispatcher_->OnDestruct(); }
protected:
base::MessageLoop message_loop_;
base::WeakPtr<MediaDevicesEventDispatcher> event_dispatcher_;
MockMediaDevicesDispatcherHost media_devices_dispatcher_;
};
} // namespace
TEST_F(MediaDevicesEventDispatcherTest, SubscribeUnsubscribeSingleType) {
for (size_t i = 0; i < NUM_MEDIA_DEVICE_TYPES; ++i) {
MediaDeviceType type = static_cast<MediaDeviceType>(i);
MediaDeviceInfoArray device_infos;
MockMediaDevicesEventSubscriber subscriber1, subscriber2;
url::Origin security_origin(GURL("http://localhost"));
EXPECT_CALL(media_devices_dispatcher_,
SubscribeDeviceChangeNotifications(type, _, security_origin))
.Times(2);
auto subscription_id1 =
event_dispatcher_->SubscribeDeviceChangeNotifications(
type, security_origin,
base::Bind(&MockMediaDevicesEventSubscriber::EventDispatched,
base::Unretained(&subscriber1)));
auto subscription_id2 =
event_dispatcher_->SubscribeDeviceChangeNotifications(
type, security_origin,
base::Bind(&MockMediaDevicesEventSubscriber::EventDispatched,
base::Unretained(&subscriber2)));
// Simulate a device change.
EXPECT_CALL(subscriber1, EventDispatched(type, _));
EXPECT_CALL(subscriber2, EventDispatched(type, _));
event_dispatcher_->DispatchDevicesChangedEvent(type, device_infos);
base::RunLoop().RunUntilIdle();
// Unsubscribe one of the subscribers.
EXPECT_CALL(media_devices_dispatcher_,
UnsubscribeDeviceChangeNotifications(type, subscription_id1));
event_dispatcher_->UnsubscribeDeviceChangeNotifications(type,
subscription_id1);
// Simulate another device change.
EXPECT_CALL(subscriber1, EventDispatched(_, _)).Times(0);
EXPECT_CALL(subscriber2, EventDispatched(type, _));
event_dispatcher_->DispatchDevicesChangedEvent(type, device_infos);
base::RunLoop().RunUntilIdle();
// Unsubscribe the other subscriber.
EXPECT_CALL(media_devices_dispatcher_,
UnsubscribeDeviceChangeNotifications(type, subscription_id2));
event_dispatcher_->UnsubscribeDeviceChangeNotifications(type,
subscription_id2);
base::RunLoop().RunUntilIdle();
}
}
TEST_F(MediaDevicesEventDispatcherTest, SubscribeUnsubscribeAllTypes) {
MediaDeviceInfoArray device_infos;
MockMediaDevicesEventSubscriber subscriber1, subscriber2;
url::Origin security_origin(GURL("http://localhost"));
EXPECT_CALL(media_devices_dispatcher_,
SubscribeDeviceChangeNotifications(MEDIA_DEVICE_TYPE_AUDIO_INPUT,
_, security_origin))
.Times(2);
EXPECT_CALL(media_devices_dispatcher_,
SubscribeDeviceChangeNotifications(MEDIA_DEVICE_TYPE_VIDEO_INPUT,
_, security_origin))
.Times(2);
EXPECT_CALL(media_devices_dispatcher_,
SubscribeDeviceChangeNotifications(MEDIA_DEVICE_TYPE_AUDIO_OUTPUT,
_, security_origin))
.Times(2);
auto subscription_list_1 =
event_dispatcher_->SubscribeDeviceChangeNotifications(
security_origin,
base::Bind(&MockMediaDevicesEventSubscriber::EventDispatched,
base::Unretained(&subscriber1)));
auto subscription_list_2 =
event_dispatcher_->SubscribeDeviceChangeNotifications(
security_origin,
base::Bind(&MockMediaDevicesEventSubscriber::EventDispatched,
base::Unretained(&subscriber2)));
// Simulate a device changes for all types.
for (size_t i = 0; i < NUM_MEDIA_DEVICE_TYPES; ++i) {
MediaDeviceType type = static_cast<MediaDeviceType>(i);
EXPECT_CALL(subscriber1, EventDispatched(type, _));
EXPECT_CALL(subscriber2, EventDispatched(type, _));
event_dispatcher_->DispatchDevicesChangedEvent(type, device_infos);
base::RunLoop().RunUntilIdle();
}
// Unsubscribe one of the subscribers.
for (size_t i = 0; i < NUM_MEDIA_DEVICE_TYPES; ++i) {
MediaDeviceType type = static_cast<MediaDeviceType>(i);
EXPECT_CALL(
media_devices_dispatcher_,
UnsubscribeDeviceChangeNotifications(type, subscription_list_1[type]));
}
event_dispatcher_->UnsubscribeDeviceChangeNotifications(subscription_list_1);
base::RunLoop().RunUntilIdle();
// Simulate more device changes.
EXPECT_CALL(subscriber1, EventDispatched(_, _)).Times(0);
EXPECT_CALL(subscriber2, EventDispatched(_, _)).Times(NUM_MEDIA_DEVICE_TYPES);
for (size_t i = 0; i < NUM_MEDIA_DEVICE_TYPES; ++i) {
MediaDeviceType type = static_cast<MediaDeviceType>(i);
event_dispatcher_->DispatchDevicesChangedEvent(type, device_infos);
base::RunLoop().RunUntilIdle();
}
// Unsubscribe the other subscriber.
for (size_t i = 0; i < NUM_MEDIA_DEVICE_TYPES; ++i) {
MediaDeviceType type = static_cast<MediaDeviceType>(i);
EXPECT_CALL(
media_devices_dispatcher_,
UnsubscribeDeviceChangeNotifications(type, subscription_list_2[type]));
}
event_dispatcher_->UnsubscribeDeviceChangeNotifications(subscription_list_2);
base::RunLoop().RunUntilIdle();
}
} // namespace content