blob: 07d65e54c5d88c7a9f970b4296246a56162d2006 [file] [log] [blame]
// Copyright (c) 2012 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/webrtc/rtc_peer_connection_handler.h"
#include <stddef.h>
#include <string.h>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/location.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "content/child/child_process.h"
#include "content/renderer/media/audio/mock_audio_device_factory.h"
#include "content/renderer/media/stream/media_stream_video_track.h"
#include "content/renderer/media/stream/mock_constraint_factory.h"
#include "content/renderer/media/stream/mock_media_stream_video_source.h"
#include "content/renderer/media/stream/processed_local_audio_source.h"
#include "content/renderer/media/webrtc/mock_data_channel_impl.h"
#include "content/renderer/media/webrtc/mock_peer_connection_dependency_factory.h"
#include "content/renderer/media/webrtc/mock_peer_connection_impl.h"
#include "content/renderer/media/webrtc/mock_web_rtc_peer_connection_handler_client.h"
#include "content/renderer/media/webrtc/peer_connection_tracker.h"
#include "content/renderer/media/webrtc/rtc_stats.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/modules/mediastream/media_stream_audio_source.h"
#include "third_party/blink/public/platform/modules/mediastream/media_stream_audio_track.h"
#include "third_party/blink/public/platform/modules/mediastream/web_platform_media_stream_source.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/public/platform/web_media_constraints.h"
#include "third_party/blink/public/platform/web_media_stream.h"
#include "third_party/blink/public/platform/web_media_stream_source.h"
#include "third_party/blink/public/platform/web_media_stream_track.h"
#include "third_party/blink/public/platform/web_rtc_data_channel_init.h"
#include "third_party/blink/public/platform/web_rtc_dtmf_sender_handler.h"
#include "third_party/blink/public/platform/web_rtc_ice_candidate.h"
#include "third_party/blink/public/platform/web_rtc_peer_connection_handler_client.h"
#include "third_party/blink/public/platform/web_rtc_rtp_receiver.h"
#include "third_party/blink/public/platform/web_rtc_session_description.h"
#include "third_party/blink/public/platform/web_rtc_session_description_request.h"
#include "third_party/blink/public/platform/web_rtc_stats.h"
#include "third_party/blink/public/platform/web_rtc_stats_request.h"
#include "third_party/blink/public/platform/web_rtc_void_request.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/web/web_heap.h"
#include "third_party/webrtc/api/peer_connection_interface.h"
#include "third_party/webrtc/api/rtp_receiver_interface.h"
#include "third_party/webrtc/stats/test/rtc_test_stats.h"
static const char kDummySdp[] = "dummy sdp";
static const char kDummySdpType[] = "dummy type";
using blink::WebRTCPeerConnectionHandlerClient;
using testing::_;
using testing::Invoke;
using testing::NiceMock;
using testing::Ref;
using testing::SaveArg;
using testing::WithArg;
namespace content {
// Action SaveArgPointeeMove<k>(pointer) saves the value pointed to by the k-th
// (0-based) argument of the mock function by moving it to *pointer.
ACTION_TEMPLATE(SaveArgPointeeMove,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_1_VALUE_PARAMS(pointer)) {
*pointer = std::move(*testing::get<k>(args));
}
class MockRTCStatsResponse : public LocalRTCStatsResponse {
public:
MockRTCStatsResponse()
: report_count_(0),
statistic_count_(0) {
}
void addStats(const blink::WebRTCLegacyStats& stats) override {
++report_count_;
for (std::unique_ptr<blink::WebRTCLegacyStatsMemberIterator> member(
stats.Iterator());
!member->IsEnd(); member->Next()) {
++statistic_count_;
}
}
int report_count() const { return report_count_; }
private:
int report_count_;
int statistic_count_;
};
// Mocked wrapper for blink::WebRTCStatsRequest
class MockRTCStatsRequest : public LocalRTCStatsRequest {
public:
MockRTCStatsRequest()
: has_selector_(false),
request_succeeded_called_(false) {}
bool hasSelector() const override { return has_selector_; }
blink::WebMediaStreamTrack component() const override { return component_; }
scoped_refptr<LocalRTCStatsResponse> createResponse() override {
DCHECK(!response_.get());
response_ = new rtc::RefCountedObject<MockRTCStatsResponse>();
return response_;
}
void requestSucceeded(const LocalRTCStatsResponse* response) override {
EXPECT_EQ(response, response_.get());
request_succeeded_called_ = true;
}
// Function for setting whether or not a selector is available.
void setSelector(const blink::WebMediaStreamTrack& component) {
has_selector_ = true;
component_ = component;
}
// Function for inspecting the result of a stats request.
MockRTCStatsResponse* result() {
if (request_succeeded_called_) {
return response_.get();
} else {
return nullptr;
}
}
private:
bool has_selector_;
blink::WebMediaStreamTrack component_;
scoped_refptr<MockRTCStatsResponse> response_;
bool request_succeeded_called_;
};
class MockPeerConnectionTracker : public PeerConnectionTracker {
public:
MockPeerConnectionTracker()
: PeerConnectionTracker(
blink::scheduler::GetSingleThreadTaskRunnerForTesting()) {}
MOCK_METHOD1(UnregisterPeerConnection,
void(RTCPeerConnectionHandler* pc_handler));
// TODO(jiayl): add coverage for the following methods
MOCK_METHOD2(TrackCreateOffer,
void(RTCPeerConnectionHandler* pc_handler,
const blink::WebMediaConstraints& constraints));
MOCK_METHOD2(TrackCreateAnswer,
void(RTCPeerConnectionHandler* pc_handler,
const blink::WebMediaConstraints& constraints));
MOCK_METHOD4(TrackSetSessionDescription,
void(RTCPeerConnectionHandler* pc_handler,
const std::string& sdp, const std::string& type,
Source source));
MOCK_METHOD2(
TrackSetConfiguration,
void(RTCPeerConnectionHandler* pc_handler,
const webrtc::PeerConnectionInterface::RTCConfiguration& config));
MOCK_METHOD4(TrackAddIceCandidate,
void(RTCPeerConnectionHandler* pc_handler,
scoped_refptr<blink::WebRTCICECandidate> candidate,
Source source,
bool succeeded));
MOCK_METHOD4(TrackAddTransceiver,
void(RTCPeerConnectionHandler* pc_handler,
TransceiverUpdatedReason reason,
const blink::WebRTCRtpTransceiver& transceiver,
size_t transceiver_index));
MOCK_METHOD4(TrackModifyTransceiver,
void(RTCPeerConnectionHandler* pc_handler,
TransceiverUpdatedReason reason,
const blink::WebRTCRtpTransceiver& transceiver,
size_t transceiver_index));
MOCK_METHOD4(TrackRemoveTransceiver,
void(RTCPeerConnectionHandler* pc_handler,
TransceiverUpdatedReason reason,
const blink::WebRTCRtpTransceiver& transceiver,
size_t transceiver_index));
MOCK_METHOD1(TrackOnIceComplete,
void(RTCPeerConnectionHandler* pc_handler));
MOCK_METHOD3(TrackCreateDataChannel,
void(RTCPeerConnectionHandler* pc_handler,
const webrtc::DataChannelInterface* data_channel,
Source source));
MOCK_METHOD1(TrackStop, void(RTCPeerConnectionHandler* pc_handler));
MOCK_METHOD2(TrackSignalingStateChange,
void(RTCPeerConnectionHandler* pc_handler,
webrtc::PeerConnectionInterface::SignalingState state));
MOCK_METHOD2(TrackIceConnectionStateChange,
void(RTCPeerConnectionHandler* pc_handler,
webrtc::PeerConnectionInterface::IceConnectionState state));
MOCK_METHOD2(TrackIceGatheringStateChange,
void(RTCPeerConnectionHandler* pc_handler,
webrtc::PeerConnectionInterface::IceGatheringState state));
MOCK_METHOD4(TrackSessionDescriptionCallback,
void(RTCPeerConnectionHandler* pc_handler,
Action action,
const std::string& type,
const std::string& value));
MOCK_METHOD1(TrackOnRenegotiationNeeded,
void(RTCPeerConnectionHandler* pc_handler));
MOCK_METHOD2(TrackCreateDTMFSender,
void(RTCPeerConnectionHandler* pc_handler,
const blink::WebMediaStreamTrack& track));
};
class MockRTCStatsReportCallback : public blink::WebRTCStatsReportCallback {
public:
explicit MockRTCStatsReportCallback(
std::unique_ptr<blink::WebRTCStatsReport>* result)
: main_thread_(blink::scheduler::GetSingleThreadTaskRunnerForTesting()),
result_(result) {
DCHECK(result_);
}
void OnStatsDelivered(
std::unique_ptr<blink::WebRTCStatsReport> report) override {
EXPECT_TRUE(main_thread_->BelongsToCurrentThread());
EXPECT_TRUE(report);
result_->reset(report.release());
}
private:
scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
std::unique_ptr<blink::WebRTCStatsReport>* result_;
};
template<typename T>
std::vector<T> ToSequence(T value) {
std::vector<T> vec;
vec.push_back(value);
return vec;
}
template<typename T>
void ExpectSequenceEquals(const blink::WebVector<T>& sequence, T value) {
EXPECT_EQ(sequence.size(), static_cast<size_t>(1));
EXPECT_EQ(sequence[0], value);
}
class RTCPeerConnectionHandlerUnderTest : public RTCPeerConnectionHandler {
public:
RTCPeerConnectionHandlerUnderTest(
WebRTCPeerConnectionHandlerClient* client,
PeerConnectionDependencyFactory* dependency_factory)
: RTCPeerConnectionHandler(
client,
dependency_factory,
blink::scheduler::GetSingleThreadTaskRunnerForTesting()) {}
MockPeerConnectionImpl* native_peer_connection() {
return static_cast<MockPeerConnectionImpl*>(
RTCPeerConnectionHandler::native_peer_connection());
}
webrtc::PeerConnectionObserver* observer() {
return native_peer_connection()->observer();
}
};
class RTCPeerConnectionHandlerTest : public ::testing::Test {
public:
RTCPeerConnectionHandlerTest() : mock_peer_connection_(nullptr) {}
void SetUp() override {
mock_client_.reset(new NiceMock<MockWebRTCPeerConnectionHandlerClient>());
mock_dependency_factory_.reset(new MockPeerConnectionDependencyFactory());
pc_handler_ = CreateRTCPeerConnectionHandlerUnderTest();
mock_tracker_.reset(new NiceMock<MockPeerConnectionTracker>());
webrtc::PeerConnectionInterface::RTCConfiguration config;
config.sdp_semantics = webrtc::SdpSemantics::kPlanB;
blink::WebMediaConstraints constraints;
EXPECT_TRUE(pc_handler_->InitializeForTest(
config, constraints, mock_tracker_.get()->AsWeakPtr()));
mock_peer_connection_ = pc_handler_->native_peer_connection();
ASSERT_TRUE(mock_peer_connection_);
EXPECT_CALL(*mock_peer_connection_, Close());
}
void TearDown() override {
pc_handler_.reset();
mock_tracker_.reset();
mock_dependency_factory_.reset();
mock_client_.reset();
blink::WebHeap::CollectAllGarbageForTesting();
}
std::unique_ptr<RTCPeerConnectionHandlerUnderTest>
CreateRTCPeerConnectionHandlerUnderTest() {
return std::make_unique<RTCPeerConnectionHandlerUnderTest>(
mock_client_.get(), mock_dependency_factory_.get());
}
// Creates a WebKit local MediaStream.
blink::WebMediaStream CreateLocalMediaStream(
const std::string& stream_label) {
std::string video_track_label("video-label");
std::string audio_track_label("audio-label");
blink::WebMediaStreamSource blink_audio_source;
blink_audio_source.Initialize(blink::WebString::FromUTF8(audio_track_label),
blink::WebMediaStreamSource::kTypeAudio,
blink::WebString::FromUTF8("audio_track"),
false /* remote */);
ProcessedLocalAudioSource* const audio_source =
new ProcessedLocalAudioSource(
-1 /* consumer_render_frame_id is N/A for non-browser tests */,
blink::MediaStreamDevice(
blink::MEDIA_DEVICE_AUDIO_CAPTURE, "mock_device_id",
"Mock device", media::AudioParameters::kAudioCDSampleRate,
media::CHANNEL_LAYOUT_STEREO,
media::AudioParameters::kAudioCDSampleRate / 100),
false /* disable_local_echo */, AudioProcessingProperties(),
base::Bind(&RTCPeerConnectionHandlerTest::OnAudioSourceStarted),
mock_dependency_factory_.get());
audio_source->SetAllowInvalidRenderFrameIdForTesting(true);
blink_audio_source.SetPlatformSource(
base::WrapUnique(audio_source)); // Takes ownership.
blink::WebMediaStreamSource video_source;
video_source.Initialize(blink::WebString::FromUTF8(video_track_label),
blink::WebMediaStreamSource::kTypeVideo,
blink::WebString::FromUTF8("video_track"),
false /* remote */);
MockMediaStreamVideoSource* native_video_source =
new MockMediaStreamVideoSource();
video_source.SetPlatformSource(base::WrapUnique(native_video_source));
blink::WebVector<blink::WebMediaStreamTrack> audio_tracks(
static_cast<size_t>(1));
audio_tracks[0].Initialize(blink_audio_source.Id(), blink_audio_source);
EXPECT_CALL(*mock_audio_device_factory_.mock_capturer_source(),
Initialize(_, _));
EXPECT_CALL(*mock_audio_device_factory_.mock_capturer_source(),
SetAutomaticGainControl(true));
EXPECT_CALL(*mock_audio_device_factory_.mock_capturer_source(), Start());
EXPECT_CALL(*mock_audio_device_factory_.mock_capturer_source(), Stop());
CHECK(audio_source->ConnectToTrack(audio_tracks[0]));
blink::WebVector<blink::WebMediaStreamTrack> video_tracks(
static_cast<size_t>(1));
video_tracks[0] = MediaStreamVideoTrack::CreateVideoTrack(
native_video_source, MediaStreamVideoSource::ConstraintsCallback(),
true);
blink::WebMediaStream local_stream;
local_stream.Initialize(blink::WebString::FromUTF8(stream_label),
audio_tracks, video_tracks);
return local_stream;
}
// Creates a remote MediaStream and adds it to the mocked native
// peer connection.
rtc::scoped_refptr<webrtc::MediaStreamInterface> AddRemoteMockMediaStream(
const std::string& stream_label,
const std::string& video_track_label,
const std::string& audio_track_label) {
rtc::scoped_refptr<webrtc::MediaStreamInterface> stream(
mock_dependency_factory_->CreateLocalMediaStream(stream_label).get());
if (!video_track_label.empty()) {
InvokeAddTrack(stream,
MockWebRtcVideoTrack::Create(video_track_label).get());
}
if (!audio_track_label.empty()) {
InvokeAddTrack(stream,
MockWebRtcAudioTrack::Create(audio_track_label).get());
}
mock_peer_connection_->AddRemoteStream(stream);
return stream;
}
void StopAllTracks(const blink::WebMediaStream& stream) {
for (const auto& track : stream.AudioTracks())
blink::MediaStreamAudioTrack::From(track)->Stop();
for (const auto& track : stream.VideoTracks())
MediaStreamVideoTrack::GetVideoTrack(track)->Stop();
}
static void OnAudioSourceStarted(blink::WebPlatformMediaStreamSource* source,
blink::MediaStreamRequestResult result,
const blink::WebString& result_name) {}
bool AddStream(const blink::WebMediaStream& web_stream) {
size_t senders_size_before_add = senders_.size();
for (const auto& web_audio_track : web_stream.AudioTracks()) {
auto error_or_transceiver = pc_handler_->AddTrack(
web_audio_track, std::vector<blink::WebMediaStream>({web_stream}));
if (error_or_transceiver.ok()) {
DCHECK_EQ(
error_or_transceiver.value()->ImplementationType(),
blink::WebRTCRtpTransceiverImplementationType::kPlanBSenderOnly);
auto sender = error_or_transceiver.value()->Sender();
senders_.push_back(std::unique_ptr<RTCRtpSender>(
static_cast<RTCRtpSender*>(sender.release())));
}
}
for (const auto& web_video_track : web_stream.VideoTracks()) {
auto error_or_transceiver = pc_handler_->AddTrack(
web_video_track, std::vector<blink::WebMediaStream>({web_stream}));
if (error_or_transceiver.ok()) {
DCHECK_EQ(
error_or_transceiver.value()->ImplementationType(),
blink::WebRTCRtpTransceiverImplementationType::kPlanBSenderOnly);
auto sender = error_or_transceiver.value()->Sender();
senders_.push_back(std::unique_ptr<RTCRtpSender>(
static_cast<RTCRtpSender*>(sender.release())));
}
}
return senders_size_before_add < senders_.size();
}
std::vector<std::unique_ptr<RTCRtpSender>>::iterator FindSenderForTrack(
const blink::WebMediaStreamTrack& web_track) {
for (auto it = senders_.begin(); it != senders_.end(); ++it) {
if ((*it)->Track().UniqueId() == web_track.UniqueId())
return it;
}
return senders_.end();
}
bool RemoveStream(const blink::WebMediaStream& web_stream) {
size_t senders_size_before_remove = senders_.size();
// TODO(hbos): With Unified Plan senders are not removed.
// https://crbug.com/799030
for (const auto& web_audio_track : web_stream.AudioTracks()) {
auto it = FindSenderForTrack(web_audio_track);
if (it != senders_.end() && pc_handler_->RemoveTrack((*it).get()).ok())
senders_.erase(it);
}
for (const auto& web_video_track : web_stream.VideoTracks()) {
auto it = FindSenderForTrack(web_video_track);
if (it != senders_.end() && pc_handler_->RemoveTrack((*it).get()).ok())
senders_.erase(it);
}
return senders_size_before_remove > senders_.size();
}
void InvokeOnAddStream(
const rtc::scoped_refptr<webrtc::MediaStreamInterface>& remote_stream) {
for (const auto& audio_track : remote_stream->GetAudioTracks()) {
InvokeOnAddTrack(audio_track, remote_stream);
}
for (const auto& video_track : remote_stream->GetVideoTracks()) {
InvokeOnAddTrack(video_track, remote_stream);
}
}
void InvokeOnAddTrack(
const rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>& remote_track,
const rtc::scoped_refptr<webrtc::MediaStreamInterface>& remote_stream) {
rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver(
new rtc::RefCountedObject<FakeRtpReceiver>(remote_track));
receivers_by_track_.insert(std::make_pair(remote_track.get(), receiver));
std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>
receiver_streams;
receiver_streams.push_back(remote_stream);
InvokeOnSignalingThread(base::Bind(
&webrtc::PeerConnectionObserver::OnAddTrack,
base::Unretained(pc_handler_->observer()), receiver, receiver_streams));
}
void InvokeOnRemoveStream(
const rtc::scoped_refptr<webrtc::MediaStreamInterface>& remote_stream) {
for (const auto& audio_track : remote_stream->GetAudioTracks()) {
InvokeOnRemoveTrack(audio_track);
}
for (const auto& video_track : remote_stream->GetVideoTracks()) {
InvokeOnRemoveTrack(video_track);
}
}
void InvokeOnRemoveTrack(
const rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>&
remote_track) {
rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver =
receivers_by_track_.find(remote_track.get())->second;
InvokeOnSignalingThread(
base::Bind(&webrtc::PeerConnectionObserver::OnRemoveTrack,
base::Unretained(pc_handler_->observer()), receiver));
}
template <typename T>
void InvokeAddTrack(
const rtc::scoped_refptr<webrtc::MediaStreamInterface>& remote_stream,
T* webrtc_track) {
InvokeOnSignalingThread(base::Bind(
[](webrtc::MediaStreamInterface* remote_stream, T* webrtc_track) {
EXPECT_TRUE(remote_stream->AddTrack(webrtc_track));
},
base::Unretained(remote_stream.get()), base::Unretained(webrtc_track)));
}
template <typename T>
void InvokeRemoveTrack(
const rtc::scoped_refptr<webrtc::MediaStreamInterface>& remote_stream,
T* webrtc_track) {
InvokeOnSignalingThread(base::Bind(
[](webrtc::MediaStreamInterface* remote_stream, T* webrtc_track) {
EXPECT_TRUE(remote_stream->RemoveTrack(webrtc_track));
},
base::Unretained(remote_stream.get()), base::Unretained(webrtc_track)));
}
bool HasReceiverForEveryTrack(
const rtc::scoped_refptr<webrtc::MediaStreamInterface>& remote_stream,
const std::vector<std::unique_ptr<blink::WebRTCRtpReceiver>>& receivers) {
for (const auto& audio_track : remote_stream->GetAudioTracks()) {
if (!HasReceiverForTrack(*audio_track.get(), receivers))
return false;
}
for (const auto& video_track : remote_stream->GetAudioTracks()) {
if (!HasReceiverForTrack(*video_track.get(), receivers))
return false;
}
return true;
}
bool HasReceiverForTrack(
const webrtc::MediaStreamTrackInterface& track,
const std::vector<std::unique_ptr<blink::WebRTCRtpReceiver>>& receivers) {
for (const auto& receiver : receivers) {
if (receiver->Track().Id().Utf8() == track.id())
return true;
}
return false;
}
template <typename T>
void InvokeOnSignalingThread(T callback) {
mock_dependency_factory_->GetWebRtcSignalingThread()->PostTask(
FROM_HERE, std::move(callback));
RunMessageLoopsUntilIdle();
}
// Wait for all current posts to the webrtc signaling thread to run and then
// run the message loop until idle on the main thread.
void RunMessageLoopsUntilIdle() {
base::WaitableEvent waitable_event(
base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED);
mock_dependency_factory_->GetWebRtcSignalingThread()->PostTask(
FROM_HERE, base::BindOnce(&base::WaitableEvent::Signal,
base::Unretained(&waitable_event)));
waitable_event.Wait();
base::RunLoop().RunUntilIdle();
}
private:
void SignalWaitableEvent(base::WaitableEvent* waitable_event) {
waitable_event->Signal();
}
public:
// The ScopedTaskEnvironment prevents the ChildProcess from leaking a
// TaskScheduler.
base::test::ScopedTaskEnvironment scoped_task_environment_;
ChildProcess child_process_;
std::unique_ptr<MockWebRTCPeerConnectionHandlerClient> mock_client_;
std::unique_ptr<MockPeerConnectionDependencyFactory> mock_dependency_factory_;
std::unique_ptr<NiceMock<MockPeerConnectionTracker>> mock_tracker_;
std::unique_ptr<RTCPeerConnectionHandlerUnderTest> pc_handler_;
MockAudioDeviceFactory mock_audio_device_factory_;
// Weak reference to the mocked native peer connection implementation.
MockPeerConnectionImpl* mock_peer_connection_;
std::vector<std::unique_ptr<RTCRtpSender>> senders_;
std::map<webrtc::MediaStreamTrackInterface*,
rtc::scoped_refptr<webrtc::RtpReceiverInterface>>
receivers_by_track_;
};
TEST_F(RTCPeerConnectionHandlerTest, Destruct) {
EXPECT_CALL(*mock_tracker_.get(), UnregisterPeerConnection(pc_handler_.get()))
.Times(1);
pc_handler_.reset(nullptr);
}
TEST_F(RTCPeerConnectionHandlerTest, NoCallbacksToClientAfterStop) {
pc_handler_->Stop();
EXPECT_CALL(*mock_client_.get(), NegotiationNeeded()).Times(0);
pc_handler_->observer()->OnRenegotiationNeeded();
EXPECT_CALL(*mock_client_.get(), DidGenerateICECandidate(_)).Times(0);
std::unique_ptr<webrtc::IceCandidateInterface> native_candidate(
mock_dependency_factory_->CreateIceCandidate("sdpMid", 1, kDummySdp));
pc_handler_->observer()->OnIceCandidate(native_candidate.get());
EXPECT_CALL(*mock_client_.get(), DidChangeSignalingState(_)).Times(0);
pc_handler_->observer()->OnSignalingChange(
webrtc::PeerConnectionInterface::kHaveRemoteOffer);
EXPECT_CALL(*mock_client_.get(), DidChangeIceGatheringState(_)).Times(0);
pc_handler_->observer()->OnIceGatheringChange(
webrtc::PeerConnectionInterface::kIceGatheringNew);
EXPECT_CALL(*mock_client_.get(), DidChangeIceConnectionState(_)).Times(0);
pc_handler_->observer()->OnIceConnectionChange(
webrtc::PeerConnectionInterface::kIceConnectionDisconnected);
EXPECT_CALL(*mock_client_.get(), DidAddReceiverPlanBForMock(_)).Times(0);
rtc::scoped_refptr<webrtc::MediaStreamInterface> remote_stream(
AddRemoteMockMediaStream("remote_stream", "video", "audio"));
InvokeOnAddStream(remote_stream);
EXPECT_CALL(*mock_client_.get(), DidRemoveReceiverPlanBForMock(_)).Times(0);
InvokeOnRemoveStream(remote_stream);
EXPECT_CALL(*mock_client_.get(), DidAddRemoteDataChannel(_)).Times(0);
webrtc::DataChannelInit config;
rtc::scoped_refptr<webrtc::DataChannelInterface> remote_data_channel(
new rtc::RefCountedObject<MockDataChannel>("dummy", &config));
pc_handler_->observer()->OnDataChannel(remote_data_channel);
RunMessageLoopsUntilIdle();
}
TEST_F(RTCPeerConnectionHandlerTest, CreateOffer) {
blink::WebRTCSessionDescriptionRequest request;
blink::WebMediaConstraints options;
EXPECT_CALL(*mock_tracker_.get(), TrackCreateOffer(pc_handler_.get(), _));
// TODO(perkj): Can blink::WebRTCSessionDescriptionRequest be changed so
// the |reqest| requestSucceeded can be tested? Currently the |request| object
// can not be initialized from a unit test.
EXPECT_FALSE(mock_peer_connection_->created_session_description() != nullptr);
pc_handler_->CreateOffer(request, options);
EXPECT_TRUE(mock_peer_connection_->created_session_description() != nullptr);
}
TEST_F(RTCPeerConnectionHandlerTest, CreateAnswer) {
blink::WebRTCSessionDescriptionRequest request;
blink::WebMediaConstraints options;
EXPECT_CALL(*mock_tracker_.get(), TrackCreateAnswer(pc_handler_.get(), _));
// TODO(perkj): Can blink::WebRTCSessionDescriptionRequest be changed so
// the |reqest| requestSucceeded can be tested? Currently the |request| object
// can not be initialized from a unit test.
EXPECT_FALSE(mock_peer_connection_->created_session_description() != nullptr);
pc_handler_->CreateAnswer(request, options);
EXPECT_TRUE(mock_peer_connection_->created_session_description() != nullptr);
}
TEST_F(RTCPeerConnectionHandlerTest, setLocalDescription) {
blink::WebRTCVoidRequest request;
blink::WebRTCSessionDescription description;
description.Initialize(kDummySdpType, kDummySdp);
// PeerConnectionTracker::TrackSetSessionDescription is expected to be called
// before |mock_peer_connection| is called.
testing::InSequence sequence;
EXPECT_CALL(*mock_tracker_.get(),
TrackSetSessionDescription(pc_handler_.get(), kDummySdp,
kDummySdpType,
PeerConnectionTracker::SOURCE_LOCAL));
EXPECT_CALL(*mock_peer_connection_, SetLocalDescription(_, _));
pc_handler_->SetLocalDescription(request, description);
RunMessageLoopsUntilIdle();
EXPECT_EQ(description.GetType(), pc_handler_->LocalDescription().GetType());
EXPECT_EQ(description.Sdp(), pc_handler_->LocalDescription().Sdp());
std::string sdp_string;
ASSERT_TRUE(mock_peer_connection_->local_description() != nullptr);
EXPECT_EQ(kDummySdpType, mock_peer_connection_->local_description()->type());
mock_peer_connection_->local_description()->ToString(&sdp_string);
EXPECT_EQ(kDummySdp, sdp_string);
// TODO(deadbeef): Also mock the "success" callback from the PeerConnection
// and ensure that the sucessful result is tracked by PeerConnectionTracker.
}
// Test that setLocalDescription with invalid SDP will result in a failure, and
// is tracked as a failure with PeerConnectionTracker.
TEST_F(RTCPeerConnectionHandlerTest, setLocalDescriptionParseError) {
blink::WebRTCVoidRequest request;
blink::WebRTCSessionDescription description;
description.Initialize(kDummySdpType, kDummySdp);
testing::InSequence sequence;
// Expect two "Track" calls, one for the start of the attempt and one for the
// failure.
EXPECT_CALL(
*mock_tracker_.get(),
TrackSetSessionDescription(pc_handler_.get(), kDummySdp, kDummySdpType,
PeerConnectionTracker::SOURCE_LOCAL));
EXPECT_CALL(
*mock_tracker_.get(),
TrackSessionDescriptionCallback(
pc_handler_.get(),
PeerConnectionTracker::ACTION_SET_LOCAL_DESCRIPTION, "OnFailure", _));
// Used to simulate a parse failure.
mock_dependency_factory_->SetFailToCreateSessionDescription(true);
pc_handler_->SetLocalDescription(request, description);
RunMessageLoopsUntilIdle();
// A description that failed to be applied shouldn't be stored.
EXPECT_TRUE(pc_handler_->LocalDescription().IsNull());
}
TEST_F(RTCPeerConnectionHandlerTest, setRemoteDescription) {
blink::WebRTCVoidRequest request;
blink::WebRTCSessionDescription description;
description.Initialize(kDummySdpType, kDummySdp);
// PeerConnectionTracker::TrackSetSessionDescription is expected to be called
// before |mock_peer_connection| is called.
testing::InSequence sequence;
EXPECT_CALL(*mock_tracker_.get(),
TrackSetSessionDescription(pc_handler_.get(), kDummySdp,
kDummySdpType,
PeerConnectionTracker::SOURCE_REMOTE));
EXPECT_CALL(*mock_peer_connection_, SetRemoteDescriptionForMock(_, _));
pc_handler_->SetRemoteDescription(request, description);
RunMessageLoopsUntilIdle();
EXPECT_EQ(description.GetType(), pc_handler_->RemoteDescription().GetType());
EXPECT_EQ(description.Sdp(), pc_handler_->RemoteDescription().Sdp());
std::string sdp_string;
ASSERT_TRUE(mock_peer_connection_->remote_description() != nullptr);
EXPECT_EQ(kDummySdpType, mock_peer_connection_->remote_description()->type());
mock_peer_connection_->remote_description()->ToString(&sdp_string);
EXPECT_EQ(kDummySdp, sdp_string);
// TODO(deadbeef): Also mock the "success" callback from the PeerConnection
// and ensure that the sucessful result is tracked by PeerConnectionTracker.
}
// Test that setRemoteDescription with invalid SDP will result in a failure, and
// is tracked as a failure with PeerConnectionTracker.
TEST_F(RTCPeerConnectionHandlerTest, setRemoteDescriptionParseError) {
blink::WebRTCVoidRequest request;
blink::WebRTCSessionDescription description;
description.Initialize(kDummySdpType, kDummySdp);
testing::InSequence sequence;
// Expect two "Track" calls, one for the start of the attempt and one for the
// failure.
EXPECT_CALL(
*mock_tracker_.get(),
TrackSetSessionDescription(pc_handler_.get(), kDummySdp, kDummySdpType,
PeerConnectionTracker::SOURCE_REMOTE));
EXPECT_CALL(*mock_tracker_.get(),
TrackSessionDescriptionCallback(
pc_handler_.get(),
PeerConnectionTracker::ACTION_SET_REMOTE_DESCRIPTION,
"OnFailure", _));
// Used to simulate a parse failure.
mock_dependency_factory_->SetFailToCreateSessionDescription(true);
pc_handler_->SetRemoteDescription(request, description);
RunMessageLoopsUntilIdle();
// A description that failed to be applied shouldn't be stored.
EXPECT_TRUE(pc_handler_->RemoteDescription().IsNull());
}
TEST_F(RTCPeerConnectionHandlerTest, setConfiguration) {
webrtc::PeerConnectionInterface::RTCConfiguration config;
config.sdp_semantics = webrtc::SdpSemantics::kPlanB;
EXPECT_CALL(*mock_tracker_.get(),
TrackSetConfiguration(pc_handler_.get(), _));
EXPECT_EQ(webrtc::RTCErrorType::NONE, pc_handler_->SetConfiguration(config));
}
// Test that when an error occurs in SetConfiguration, it's converted to a
// blink error and false is returned.
TEST_F(RTCPeerConnectionHandlerTest, setConfigurationError) {
webrtc::PeerConnectionInterface::RTCConfiguration config;
config.sdp_semantics = webrtc::SdpSemantics::kPlanB;
mock_peer_connection_->set_setconfiguration_error_type(
webrtc::RTCErrorType::INVALID_MODIFICATION);
EXPECT_CALL(*mock_tracker_.get(),
TrackSetConfiguration(pc_handler_.get(), _));
EXPECT_EQ(webrtc::RTCErrorType::INVALID_MODIFICATION,
pc_handler_->SetConfiguration(config));
}
TEST_F(RTCPeerConnectionHandlerTest, addICECandidate) {
scoped_refptr<blink::WebRTCICECandidate> candidate =
blink::WebRTCICECandidate::Create(kDummySdp, "sdpMid", 1);
EXPECT_CALL(*mock_tracker_.get(),
TrackAddIceCandidate(pc_handler_.get(), candidate,
PeerConnectionTracker::SOURCE_REMOTE, true));
EXPECT_TRUE(pc_handler_->AddICECandidate(candidate));
EXPECT_EQ(kDummySdp, mock_peer_connection_->ice_sdp());
EXPECT_EQ(1, mock_peer_connection_->sdp_mline_index());
EXPECT_EQ("sdpMid", mock_peer_connection_->sdp_mid());
}
TEST_F(RTCPeerConnectionHandlerTest, addAndRemoveStream) {
std::string stream_label = "local_stream";
blink::WebMediaStream local_stream(
CreateLocalMediaStream(stream_label));
EXPECT_CALL(
*mock_tracker_.get(),
TrackAddTransceiver(
pc_handler_.get(),
PeerConnectionTracker::TransceiverUpdatedReason::kAddTrack, _, _))
.Times(2);
EXPECT_CALL(
*mock_tracker_.get(),
TrackRemoveTransceiver(
pc_handler_.get(),
PeerConnectionTracker::TransceiverUpdatedReason::kRemoveTrack, _, _))
.Times(2);
EXPECT_TRUE(AddStream(local_stream));
EXPECT_EQ(stream_label, mock_peer_connection_->stream_label());
EXPECT_EQ(2u, mock_peer_connection_->GetSenders().size());
EXPECT_FALSE(AddStream(local_stream));
EXPECT_TRUE(RemoveStream(local_stream));
EXPECT_EQ(0u, mock_peer_connection_->GetSenders().size());
StopAllTracks(local_stream);
}
TEST_F(RTCPeerConnectionHandlerTest, addStreamWithStoppedAudioAndVideoTrack) {
std::string stream_label = "local_stream";
blink::WebMediaStream local_stream(
CreateLocalMediaStream(stream_label));
blink::WebVector<blink::WebMediaStreamTrack> audio_tracks =
local_stream.AudioTracks();
blink::MediaStreamAudioSource* native_audio_source =
blink::MediaStreamAudioSource::From(audio_tracks[0].Source());
native_audio_source->StopSource();
blink::WebVector<blink::WebMediaStreamTrack> video_tracks =
local_stream.VideoTracks();
MediaStreamVideoSource* native_video_source =
static_cast<MediaStreamVideoSource*>(
video_tracks[0].Source().GetPlatformSource());
native_video_source->StopSource();
EXPECT_TRUE(AddStream(local_stream));
EXPECT_EQ(stream_label, mock_peer_connection_->stream_label());
EXPECT_EQ(2u, mock_peer_connection_->GetSenders().size());
StopAllTracks(local_stream);
}
TEST_F(RTCPeerConnectionHandlerTest, GetStatsNoSelector) {
scoped_refptr<MockRTCStatsRequest> request(
new rtc::RefCountedObject<MockRTCStatsRequest>());
pc_handler_->getStats(request.get());
RunMessageLoopsUntilIdle();
ASSERT_TRUE(request->result());
EXPECT_LT(1, request->result()->report_count());
}
TEST_F(RTCPeerConnectionHandlerTest, GetStatsAfterClose) {
scoped_refptr<MockRTCStatsRequest> request(
new rtc::RefCountedObject<MockRTCStatsRequest>());
pc_handler_->Stop();
RunMessageLoopsUntilIdle();
pc_handler_->getStats(request.get());
RunMessageLoopsUntilIdle();
ASSERT_TRUE(request->result());
EXPECT_LT(1, request->result()->report_count());
}
TEST_F(RTCPeerConnectionHandlerTest, GetStatsWithLocalSelector) {
blink::WebMediaStream local_stream(
CreateLocalMediaStream("local_stream"));
EXPECT_TRUE(AddStream(local_stream));
blink::WebVector<blink::WebMediaStreamTrack> tracks =
local_stream.AudioTracks();
ASSERT_LE(1ul, tracks.size());
scoped_refptr<MockRTCStatsRequest> request(
new rtc::RefCountedObject<MockRTCStatsRequest>());
request->setSelector(tracks[0]);
pc_handler_->getStats(request.get());
RunMessageLoopsUntilIdle();
EXPECT_EQ(1, request->result()->report_count());
StopAllTracks(local_stream);
}
TEST_F(RTCPeerConnectionHandlerTest, GetStatsWithBadSelector) {
// The setup is the same as GetStatsWithLocalSelector, but the stream is not
// added to the PeerConnection.
blink::WebMediaStream local_stream(
CreateLocalMediaStream("local_stream_2"));
blink::WebVector<blink::WebMediaStreamTrack> tracks =
local_stream.AudioTracks();
blink::WebMediaStreamTrack component = tracks[0];
mock_peer_connection_->SetGetStatsResult(false);
scoped_refptr<MockRTCStatsRequest> request(
new rtc::RefCountedObject<MockRTCStatsRequest>());
request->setSelector(component);
pc_handler_->getStats(request.get());
RunMessageLoopsUntilIdle();
EXPECT_EQ(0, request->result()->report_count());
StopAllTracks(local_stream);
}
TEST_F(RTCPeerConnectionHandlerTest, GetRTCStats) {
WhitelistStatsForTesting(webrtc::RTCTestStats::kType);
rtc::scoped_refptr<webrtc::RTCStatsReport> report =
webrtc::RTCStatsReport::Create();
report->AddStats(std::unique_ptr<const webrtc::RTCStats>(
new webrtc::RTCTestStats("RTCUndefinedStats", 1000)));
std::unique_ptr<webrtc::RTCTestStats> stats_defined_members(
new webrtc::RTCTestStats("RTCDefinedStats", 2000));
stats_defined_members->m_bool = true;
stats_defined_members->m_int32 = 42;
stats_defined_members->m_uint32 = 42;
stats_defined_members->m_int64 = 42;
stats_defined_members->m_uint64 = 42;
stats_defined_members->m_double = 42.0;
stats_defined_members->m_string = "42";
stats_defined_members->m_sequence_bool = ToSequence<bool>(true);
stats_defined_members->m_sequence_int32 = ToSequence<int32_t>(42);
stats_defined_members->m_sequence_uint32 = ToSequence<uint32_t>(42);
stats_defined_members->m_sequence_int64 = ToSequence<int64_t>(42);
stats_defined_members->m_sequence_uint64 = ToSequence<uint64_t>(42);
stats_defined_members->m_sequence_double = ToSequence<double>(42);
stats_defined_members->m_sequence_string = ToSequence<std::string>("42");
report->AddStats(std::unique_ptr<const webrtc::RTCStats>(
stats_defined_members.release()));
pc_handler_->native_peer_connection()->SetGetStatsReport(report);
std::unique_ptr<blink::WebRTCStatsReport> result;
pc_handler_->GetStats(std::unique_ptr<blink::WebRTCStatsReportCallback>(
new MockRTCStatsReportCallback(&result)),
blink::RTCStatsFilter::kIncludeNonStandardMembers);
RunMessageLoopsUntilIdle();
EXPECT_TRUE(result);
int undefined_stats_count = 0;
int defined_stats_count = 0;
for (std::unique_ptr<blink::WebRTCStats> stats = result->Next(); stats;
stats.reset(result->Next().release())) {
EXPECT_EQ(stats->GetType().Utf8(), webrtc::RTCTestStats::kType);
if (stats->Id().Utf8() == "RTCUndefinedStats") {
++undefined_stats_count;
EXPECT_EQ(stats->Timestamp(), 1.0);
for (size_t i = 0; i < stats->MembersCount(); ++i) {
EXPECT_FALSE(stats->GetMember(i)->IsDefined());
}
} else if (stats->Id().Utf8() == "RTCDefinedStats") {
++defined_stats_count;
EXPECT_EQ(stats->Timestamp(), 2.0);
std::set<blink::WebRTCStatsMemberType> members;
for (size_t i = 0; i < stats->MembersCount(); ++i) {
std::unique_ptr<blink::WebRTCStatsMember> member = stats->GetMember(i);
// TODO(hbos): A WebRTC-change is adding new members, this would cause
// not all members to be defined. This if-statement saves Chromium from
// crashing. As soon as the change has been rolled in, I will update
// this test. crbug.com/627816
if (!member->IsDefined())
continue;
EXPECT_TRUE(member->IsDefined());
members.insert(member->GetType());
switch (member->GetType()) {
case blink::kWebRTCStatsMemberTypeBool:
EXPECT_EQ(member->ValueBool(), true);
break;
case blink::kWebRTCStatsMemberTypeInt32:
EXPECT_EQ(member->ValueInt32(), static_cast<int32_t>(42));
break;
case blink::kWebRTCStatsMemberTypeUint32:
EXPECT_EQ(member->ValueUint32(), static_cast<uint32_t>(42));
break;
case blink::kWebRTCStatsMemberTypeInt64:
EXPECT_EQ(member->ValueInt64(), static_cast<int64_t>(42));
break;
case blink::kWebRTCStatsMemberTypeUint64:
EXPECT_EQ(member->ValueUint64(), static_cast<uint64_t>(42));
break;
case blink::kWebRTCStatsMemberTypeDouble:
EXPECT_EQ(member->ValueDouble(), 42.0);
break;
case blink::kWebRTCStatsMemberTypeString:
EXPECT_EQ(member->ValueString(), blink::WebString::FromUTF8("42"));
break;
case blink::kWebRTCStatsMemberTypeSequenceBool:
ExpectSequenceEquals(member->ValueSequenceBool(), 1);
break;
case blink::kWebRTCStatsMemberTypeSequenceInt32:
ExpectSequenceEquals(member->ValueSequenceInt32(),
static_cast<int32_t>(42));
break;
case blink::kWebRTCStatsMemberTypeSequenceUint32:
ExpectSequenceEquals(member->ValueSequenceUint32(),
static_cast<uint32_t>(42));
break;
case blink::kWebRTCStatsMemberTypeSequenceInt64:
ExpectSequenceEquals(member->ValueSequenceInt64(),
static_cast<int64_t>(42));
break;
case blink::kWebRTCStatsMemberTypeSequenceUint64:
ExpectSequenceEquals(member->ValueSequenceUint64(),
static_cast<uint64_t>(42));
break;
case blink::kWebRTCStatsMemberTypeSequenceDouble:
ExpectSequenceEquals(member->ValueSequenceDouble(), 42.0);
break;
case blink::kWebRTCStatsMemberTypeSequenceString:
ExpectSequenceEquals(member->ValueSequenceString(),
blink::WebString::FromUTF8("42"));
break;
default:
NOTREACHED();
}
}
EXPECT_EQ(members.size(), static_cast<size_t>(14));
} else {
NOTREACHED();
}
}
EXPECT_EQ(undefined_stats_count, 1);
EXPECT_EQ(defined_stats_count, 1);
}
TEST_F(RTCPeerConnectionHandlerTest, OnIceConnectionChange) {
testing::InSequence sequence;
webrtc::PeerConnectionInterface::IceConnectionState new_state =
webrtc::PeerConnectionInterface::kIceConnectionNew;
EXPECT_CALL(*mock_tracker_.get(),
TrackIceConnectionStateChange(
pc_handler_.get(),
webrtc::PeerConnectionInterface::kIceConnectionNew));
EXPECT_CALL(*mock_client_.get(),
DidChangeIceConnectionState(
webrtc::PeerConnectionInterface::kIceConnectionNew));
pc_handler_->observer()->OnStandardizedIceConnectionChange(new_state);
new_state = webrtc::PeerConnectionInterface::kIceConnectionChecking;
EXPECT_CALL(*mock_tracker_.get(),
TrackIceConnectionStateChange(
pc_handler_.get(),
webrtc::PeerConnectionInterface::kIceConnectionChecking));
EXPECT_CALL(*mock_client_.get(),
DidChangeIceConnectionState(
webrtc::PeerConnectionInterface::kIceConnectionChecking));
pc_handler_->observer()->OnStandardizedIceConnectionChange(new_state);
new_state = webrtc::PeerConnectionInterface::kIceConnectionConnected;
EXPECT_CALL(*mock_tracker_.get(),
TrackIceConnectionStateChange(
pc_handler_.get(),
webrtc::PeerConnectionInterface::kIceConnectionConnected));
EXPECT_CALL(*mock_client_.get(),
DidChangeIceConnectionState(
webrtc::PeerConnectionInterface::kIceConnectionConnected));
pc_handler_->observer()->OnStandardizedIceConnectionChange(new_state);
new_state = webrtc::PeerConnectionInterface::kIceConnectionCompleted;
EXPECT_CALL(*mock_tracker_.get(),
TrackIceConnectionStateChange(
pc_handler_.get(),
webrtc::PeerConnectionInterface::kIceConnectionCompleted));
EXPECT_CALL(*mock_client_.get(),
DidChangeIceConnectionState(
webrtc::PeerConnectionInterface::kIceConnectionCompleted));
pc_handler_->observer()->OnStandardizedIceConnectionChange(new_state);
new_state = webrtc::PeerConnectionInterface::kIceConnectionFailed;
EXPECT_CALL(*mock_tracker_.get(),
TrackIceConnectionStateChange(
pc_handler_.get(),
webrtc::PeerConnectionInterface::kIceConnectionFailed));
EXPECT_CALL(*mock_client_.get(),
DidChangeIceConnectionState(
webrtc::PeerConnectionInterface::kIceConnectionFailed));
pc_handler_->observer()->OnStandardizedIceConnectionChange(new_state);
new_state = webrtc::PeerConnectionInterface::kIceConnectionDisconnected;
EXPECT_CALL(*mock_tracker_.get(),
TrackIceConnectionStateChange(
pc_handler_.get(),
webrtc::PeerConnectionInterface::kIceConnectionDisconnected));
EXPECT_CALL(*mock_client_.get(),
DidChangeIceConnectionState(
webrtc::PeerConnectionInterface::kIceConnectionDisconnected));
pc_handler_->observer()->OnStandardizedIceConnectionChange(new_state);
new_state = webrtc::PeerConnectionInterface::kIceConnectionClosed;
EXPECT_CALL(*mock_tracker_.get(),
TrackIceConnectionStateChange(
pc_handler_.get(),
webrtc::PeerConnectionInterface::kIceConnectionClosed));
EXPECT_CALL(*mock_client_.get(),
DidChangeIceConnectionState(
webrtc::PeerConnectionInterface::kIceConnectionClosed));
pc_handler_->observer()->OnStandardizedIceConnectionChange(new_state);
}
TEST_F(RTCPeerConnectionHandlerTest, OnIceGatheringChange) {
testing::InSequence sequence;
EXPECT_CALL(*mock_tracker_.get(),
TrackIceGatheringStateChange(
pc_handler_.get(),
webrtc::PeerConnectionInterface::kIceGatheringNew));
EXPECT_CALL(*mock_client_.get(),
DidChangeIceGatheringState(
webrtc::PeerConnectionInterface::kIceGatheringNew));
EXPECT_CALL(*mock_tracker_.get(),
TrackIceGatheringStateChange(
pc_handler_.get(),
webrtc::PeerConnectionInterface::kIceGatheringGathering));
EXPECT_CALL(*mock_client_.get(),
DidChangeIceGatheringState(
webrtc::PeerConnectionInterface::kIceGatheringGathering));
EXPECT_CALL(*mock_tracker_.get(),
TrackIceGatheringStateChange(
pc_handler_.get(),
webrtc::PeerConnectionInterface::kIceGatheringComplete));
EXPECT_CALL(*mock_client_.get(),
DidChangeIceGatheringState(
webrtc::PeerConnectionInterface::kIceGatheringComplete));
webrtc::PeerConnectionInterface::IceGatheringState new_state =
webrtc::PeerConnectionInterface::kIceGatheringNew;
pc_handler_->observer()->OnIceGatheringChange(new_state);
new_state = webrtc::PeerConnectionInterface::kIceGatheringGathering;
pc_handler_->observer()->OnIceGatheringChange(new_state);
new_state = webrtc::PeerConnectionInterface::kIceGatheringComplete;
pc_handler_->observer()->OnIceGatheringChange(new_state);
// Check NULL candidate after ice gathering is completed.
EXPECT_EQ("", mock_client_->candidate_mid());
EXPECT_EQ(-1, mock_client_->candidate_mlineindex());
EXPECT_EQ("", mock_client_->candidate_sdp());
}
// TODO(hbos): Enable when not mocking or remove test. https://crbug.com/788659
TEST_F(RTCPeerConnectionHandlerTest, DISABLED_OnAddAndOnRemoveStream) {
rtc::scoped_refptr<webrtc::MediaStreamInterface> remote_stream(
AddRemoteMockMediaStream("remote_stream", "video", "audio"));
// Grab the added receivers when it's been successfully added to the PC.
std::vector<std::unique_ptr<blink::WebRTCRtpReceiver>> receivers_added;
EXPECT_CALL(*mock_client_.get(), DidAddReceiverPlanBForMock(_))
.WillRepeatedly(
Invoke([&receivers_added](
std::unique_ptr<blink::WebRTCRtpReceiver>* receiver) {
receivers_added.push_back(std::move(*receiver));
}));
EXPECT_CALL(
*mock_tracker_.get(),
TrackAddTransceiver(
pc_handler_.get(),
PeerConnectionTracker::TransceiverUpdatedReason::kAddTrack, _, _))
.Times(2);
// Grab the removed receivers when it's been successfully added to the PC.
std::vector<std::unique_ptr<blink::WebRTCRtpReceiver>> receivers_removed;
EXPECT_CALL(
*mock_tracker_.get(),
TrackRemoveTransceiver(
pc_handler_.get(),
PeerConnectionTracker::TransceiverUpdatedReason::kRemoveTrack, _, _))
.Times(2);
EXPECT_CALL(*mock_client_.get(), DidRemoveReceiverPlanBForMock(_))
.WillRepeatedly(
Invoke([&receivers_removed](
std::unique_ptr<blink::WebRTCRtpReceiver>* receiver) {
receivers_removed.push_back(std::move(*receiver));
}));
InvokeOnAddStream(remote_stream);
RunMessageLoopsUntilIdle();
EXPECT_TRUE(HasReceiverForEveryTrack(remote_stream, receivers_added));
InvokeOnRemoveStream(remote_stream);
RunMessageLoopsUntilIdle();
EXPECT_EQ(receivers_added.size(), 2u);
EXPECT_EQ(receivers_added.size(), receivers_removed.size());
EXPECT_EQ(receivers_added[0]->Id(), receivers_removed[0]->Id());
EXPECT_EQ(receivers_added[1]->Id(), receivers_removed[1]->Id());
}
TEST_F(RTCPeerConnectionHandlerTest, OnIceCandidate) {
testing::InSequence sequence;
EXPECT_CALL(*mock_tracker_.get(),
TrackAddIceCandidate(pc_handler_.get(), _,
PeerConnectionTracker::SOURCE_LOCAL, true));
EXPECT_CALL(*mock_client_.get(), DidGenerateICECandidate(_));
std::unique_ptr<webrtc::IceCandidateInterface> native_candidate(
mock_dependency_factory_->CreateIceCandidate("sdpMid", 1, kDummySdp));
pc_handler_->observer()->OnIceCandidate(native_candidate.get());
RunMessageLoopsUntilIdle();
EXPECT_EQ("sdpMid", mock_client_->candidate_mid());
EXPECT_EQ(1, mock_client_->candidate_mlineindex());
EXPECT_EQ(kDummySdp, mock_client_->candidate_sdp());
}
TEST_F(RTCPeerConnectionHandlerTest, OnRenegotiationNeeded) {
testing::InSequence sequence;
EXPECT_CALL(*mock_tracker_.get(),
TrackOnRenegotiationNeeded(pc_handler_.get()));
EXPECT_CALL(*mock_client_.get(), NegotiationNeeded());
pc_handler_->observer()->OnRenegotiationNeeded();
}
TEST_F(RTCPeerConnectionHandlerTest, CreateDataChannel) {
blink::WebString label = "d1";
EXPECT_CALL(*mock_tracker_.get(),
TrackCreateDataChannel(pc_handler_.get(),
testing::NotNull(),
PeerConnectionTracker::SOURCE_LOCAL));
scoped_refptr<webrtc::DataChannelInterface> channel =
pc_handler_->CreateDataChannel("d1", blink::WebRTCDataChannelInit());
EXPECT_TRUE(channel.get() != nullptr);
EXPECT_EQ(label.Utf8(), channel->label());
}
} // namespace content