| // 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/rtc_peer_connection_handler.h" |
| |
| #include <stddef.h> |
| |
| #include <memory> |
| #include <set> |
| #include <string> |
| #include <vector> |
| |
| #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/threading/thread_task_runner_handle.h" |
| #include "base/values.h" |
| #include "content/child/child_process.h" |
| #include "content/renderer/media/media_stream.h" |
| #include "content/renderer/media/media_stream_audio_source.h" |
| #include "content/renderer/media/media_stream_audio_track.h" |
| #include "content/renderer/media/media_stream_source.h" |
| #include "content/renderer/media/media_stream_video_track.h" |
| #include "content/renderer/media/mock_audio_device_factory.h" |
| #include "content/renderer/media/mock_constraint_factory.h" |
| #include "content/renderer/media/mock_data_channel_impl.h" |
| #include "content/renderer/media/mock_media_stream_video_source.h" |
| #include "content/renderer/media/mock_peer_connection_impl.h" |
| #include "content/renderer/media/mock_web_rtc_peer_connection_handler_client.h" |
| #include "content/renderer/media/peer_connection_tracker.h" |
| #include "content/renderer/media/webrtc/mock_peer_connection_dependency_factory.h" |
| #include "content/renderer/media/webrtc/processed_local_audio_source.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/WebKit/public/platform/WebMediaConstraints.h" |
| #include "third_party/WebKit/public/platform/WebMediaStream.h" |
| #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" |
| #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" |
| #include "third_party/WebKit/public/platform/WebRTCConfiguration.h" |
| #include "third_party/WebKit/public/platform/WebRTCDTMFSenderHandler.h" |
| #include "third_party/WebKit/public/platform/WebRTCDataChannelHandler.h" |
| #include "third_party/WebKit/public/platform/WebRTCDataChannelInit.h" |
| #include "third_party/WebKit/public/platform/WebRTCError.h" |
| #include "third_party/WebKit/public/platform/WebRTCICECandidate.h" |
| #include "third_party/WebKit/public/platform/WebRTCPeerConnectionHandlerClient.h" |
| #include "third_party/WebKit/public/platform/WebRTCSessionDescription.h" |
| #include "third_party/WebKit/public/platform/WebRTCSessionDescriptionRequest.h" |
| #include "third_party/WebKit/public/platform/WebRTCStatsRequest.h" |
| #include "third_party/WebKit/public/platform/WebRTCVoidRequest.h" |
| #include "third_party/WebKit/public/platform/WebURL.h" |
| #include "third_party/WebKit/public/web/WebHeap.h" |
| #include "third_party/webrtc/api/peerconnectioninterface.h" |
| #include "third_party/webrtc/stats/test/rtcteststats.h" |
| |
| static const char kDummySdp[] = "dummy sdp"; |
| static const char kDummySdpType[] = "dummy type"; |
| |
| using blink::WebRTCPeerConnectionHandlerClient; |
| using testing::NiceMock; |
| using testing::_; |
| using testing::Ref; |
| using testing::SaveArg; |
| |
| namespace content { |
| |
| ACTION_P2(ExitMessageLoop, message_loop, quit_closure) { |
| message_loop->task_runner()->PostTask(FROM_HERE, quit_closure); |
| } |
| |
| 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 NULL; |
| } |
| } |
| |
| private: |
| bool has_selector_; |
| blink::WebMediaStreamTrack component_; |
| scoped_refptr<MockRTCStatsResponse> response_; |
| bool request_succeeded_called_; |
| }; |
| |
| class MockPeerConnectionTracker : public PeerConnectionTracker { |
| public: |
| 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, |
| const blink::WebRTCICECandidate& candidate, |
| Source source, |
| bool succeeded)); |
| MOCK_METHOD3(TrackAddStream, |
| void(RTCPeerConnectionHandler* pc_handler, |
| const blink::WebMediaStream& stream, |
| Source source)); |
| MOCK_METHOD3(TrackRemoveStream, |
| void(RTCPeerConnectionHandler* pc_handler, |
| const blink::WebMediaStream& stream, |
| Source source)); |
| 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, |
| WebRTCPeerConnectionHandlerClient::SignalingState state)); |
| MOCK_METHOD2( |
| TrackIceConnectionStateChange, |
| void(RTCPeerConnectionHandler* pc_handler, |
| WebRTCPeerConnectionHandlerClient::ICEConnectionState state)); |
| MOCK_METHOD2( |
| TrackIceGatheringStateChange, |
| void(RTCPeerConnectionHandler* pc_handler, |
| WebRTCPeerConnectionHandlerClient::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_(base::ThreadTaskRunnerHandle::Get()), 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) { |
| } |
| |
| MockPeerConnectionImpl* native_peer_connection() { |
| return static_cast<MockPeerConnectionImpl*>( |
| RTCPeerConnectionHandler::native_peer_connection()); |
| } |
| |
| webrtc::PeerConnectionObserver* observer() { |
| return native_peer_connection()->observer(); |
| } |
| |
| scoped_refptr<base::SingleThreadTaskRunner> |
| signaling_thread() const override { |
| return base::ThreadTaskRunnerHandle::Get(); |
| } |
| }; |
| |
| class RTCPeerConnectionHandlerTest : public ::testing::Test { |
| public: |
| RTCPeerConnectionHandlerTest() : mock_peer_connection_(NULL) { |
| child_process_.reset(new ChildProcess()); |
| } |
| |
| void SetUp() override { |
| mock_client_.reset(new NiceMock<MockWebRTCPeerConnectionHandlerClient>()); |
| mock_dependency_factory_.reset(new MockPeerConnectionDependencyFactory()); |
| pc_handler_.reset( |
| new RTCPeerConnectionHandlerUnderTest( |
| mock_client_.get(), mock_dependency_factory_.get())); |
| mock_tracker_.reset(new NiceMock<MockPeerConnectionTracker>()); |
| blink::WebRTCConfiguration config; |
| 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(); |
| } |
| |
| // 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::TypeAudio, |
| blink::WebString::fromUTF8("audio_track")); |
| ProcessedLocalAudioSource* const audio_source = |
| new ProcessedLocalAudioSource( |
| -1 /* consumer_render_frame_id is N/A for non-browser tests */, |
| StreamDeviceInfo(MEDIA_DEVICE_AUDIO_CAPTURE, "Mock device", |
| "mock_device_id", |
| media::AudioParameters::kAudioCDSampleRate, |
| media::CHANNEL_LAYOUT_STEREO, |
| media::AudioParameters::kAudioCDSampleRate / 100), |
| MockConstraintFactory().CreateWebMediaConstraints(), |
| base::Bind(&RTCPeerConnectionHandlerTest::OnAudioSourceStarted), |
| mock_dependency_factory_.get()); |
| audio_source->SetAllowInvalidRenderFrameIdForTesting(true); |
| blink_audio_source.setExtraData(audio_source); // Takes ownership. |
| |
| blink::WebMediaStreamSource video_source; |
| video_source.initialize(blink::WebString::fromUTF8(video_track_label), |
| blink::WebMediaStreamSource::TypeVideo, |
| blink::WebString::fromUTF8("video_track")); |
| MockMediaStreamVideoSource* native_video_source = |
| new MockMediaStreamVideoSource(false); |
| video_source.setExtraData(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(_, _, -1)); |
| 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)); |
| blink::WebMediaConstraints video_constraints; |
| video_constraints.initialize(); |
| video_tracks[0] = MediaStreamVideoTrack::CreateVideoTrack( |
| native_video_source, video_constraints, |
| MediaStreamVideoSource::ConstraintsCallback(), true); |
| |
| blink::WebMediaStream local_stream; |
| local_stream.initialize(blink::WebString::fromUTF8(stream_label), |
| audio_tracks, video_tracks); |
| local_stream.setExtraData(new MediaStream()); |
| 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()) { |
| stream->AddTrack(MockWebRtcVideoTrack::Create(video_track_label).get()); |
| } |
| if (!audio_track_label.empty()) { |
| stream->AddTrack(MockWebRtcAudioTrack::Create(audio_track_label).get()); |
| } |
| mock_peer_connection_->AddRemoteStream(stream); |
| return stream; |
| } |
| |
| void StopAllTracks(const blink::WebMediaStream& stream) { |
| blink::WebVector<blink::WebMediaStreamTrack> audio_tracks; |
| stream.audioTracks(audio_tracks); |
| for (const auto& track : audio_tracks) |
| MediaStreamAudioTrack::From(track)->Stop(); |
| |
| blink::WebVector<blink::WebMediaStreamTrack> video_tracks; |
| stream.videoTracks(video_tracks); |
| for (const auto& track : video_tracks) |
| MediaStreamVideoTrack::GetVideoTrack(track)->Stop(); |
| } |
| |
| static void OnAudioSourceStarted(MediaStreamSource* source, |
| MediaStreamRequestResult result, |
| const blink::WebString& result_name) {} |
| |
| base::MessageLoop message_loop_; |
| std::unique_ptr<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_; |
| }; |
| |
| TEST_F(RTCPeerConnectionHandlerTest, Destruct) { |
| EXPECT_CALL(*mock_tracker_.get(), UnregisterPeerConnection(pc_handler_.get())) |
| .Times(1); |
| pc_handler_.reset(NULL); |
| } |
| |
| 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(), didAddRemoteStream(_)).Times(0); |
| std::string remote_stream_label("remote_stream"); |
| rtc::scoped_refptr<webrtc::MediaStreamInterface> remote_stream( |
| AddRemoteMockMediaStream(remote_stream_label, "video", "audio")); |
| pc_handler_->observer()->OnAddStream(remote_stream); |
| |
| EXPECT_CALL(*mock_client_.get(), didRemoveRemoteStream(_)).Times(0); |
| pc_handler_->observer()->OnRemoveStream(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); |
| |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| TEST_F(RTCPeerConnectionHandlerTest, DestructAllHandlers) { |
| EXPECT_CALL(*mock_client_.get(), releasePeerConnectionHandler()) |
| .Times(1); |
| RTCPeerConnectionHandler::DestructAllHandlers(); |
| } |
| |
| 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() != NULL); |
| pc_handler_->createOffer(request, options); |
| EXPECT_TRUE(mock_peer_connection_->created_session_description() != NULL); |
| } |
| |
| 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() != NULL); |
| pc_handler_->createAnswer(request, options); |
| EXPECT_TRUE(mock_peer_connection_->created_session_description() != NULL); |
| } |
| |
| 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); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(description.type(), pc_handler_->localDescription().type()); |
| EXPECT_EQ(description.sdp(), pc_handler_->localDescription().sdp()); |
| |
| std::string sdp_string; |
| ASSERT_TRUE(mock_peer_connection_->local_description() != NULL); |
| 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); |
| base::RunLoop().RunUntilIdle(); |
| // A description that failed to be applied shouldn't be stored. |
| EXPECT_TRUE(pc_handler_->localDescription().sdp().isEmpty()); |
| } |
| |
| 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_, SetRemoteDescription(_, _)); |
| |
| pc_handler_->setRemoteDescription(request, description); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(description.type(), pc_handler_->remoteDescription().type()); |
| EXPECT_EQ(description.sdp(), pc_handler_->remoteDescription().sdp()); |
| |
| std::string sdp_string; |
| ASSERT_TRUE(mock_peer_connection_->remote_description() != NULL); |
| 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); |
| base::RunLoop().RunUntilIdle(); |
| // A description that failed to be applied shouldn't be stored. |
| EXPECT_TRUE(pc_handler_->remoteDescription().sdp().isEmpty()); |
| } |
| |
| TEST_F(RTCPeerConnectionHandlerTest, setConfiguration) { |
| blink::WebRTCConfiguration config; |
| |
| EXPECT_CALL(*mock_tracker_.get(), |
| TrackSetConfiguration(pc_handler_.get(), _)); |
| // TODO(perkj): Test that the parameters in |config| can be translated when a |
| // WebRTCConfiguration can be constructed. It's WebKit class and can't be |
| // initialized from a test. |
| EXPECT_EQ(blink::WebRTCErrorType::kNone, |
| 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) { |
| blink::WebRTCConfiguration config; |
| |
| mock_peer_connection_->set_setconfiguration_error_type( |
| webrtc::RTCErrorType::INVALID_MODIFICATION); |
| EXPECT_CALL(*mock_tracker_.get(), |
| TrackSetConfiguration(pc_handler_.get(), _)); |
| EXPECT_EQ(blink::WebRTCErrorType::kInvalidModification, |
| pc_handler_->setConfiguration(config)); |
| } |
| |
| TEST_F(RTCPeerConnectionHandlerTest, addICECandidate) { |
| blink::WebRTCICECandidate candidate; |
| candidate.initialize(kDummySdp, "sdpMid", 1); |
| |
| EXPECT_CALL(*mock_tracker_.get(), |
| TrackAddIceCandidate(pc_handler_.get(), |
| testing::Ref(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)); |
| blink::WebMediaConstraints constraints; |
| |
| EXPECT_CALL(*mock_tracker_.get(), |
| TrackAddStream(pc_handler_.get(), |
| testing::Ref(local_stream), |
| PeerConnectionTracker::SOURCE_LOCAL)); |
| EXPECT_CALL(*mock_tracker_.get(), |
| TrackRemoveStream(pc_handler_.get(), |
| testing::Ref(local_stream), |
| PeerConnectionTracker::SOURCE_LOCAL)); |
| EXPECT_TRUE(pc_handler_->addStream(local_stream, constraints)); |
| EXPECT_EQ(stream_label, mock_peer_connection_->stream_label()); |
| EXPECT_EQ(1u, |
| mock_peer_connection_->local_streams()->at(0)->GetAudioTracks().size()); |
| EXPECT_EQ(1u, |
| mock_peer_connection_->local_streams()->at(0)->GetVideoTracks().size()); |
| |
| EXPECT_FALSE(pc_handler_->addStream(local_stream, constraints)); |
| |
| pc_handler_->removeStream(local_stream); |
| EXPECT_EQ(0u, mock_peer_connection_->local_streams()->count()); |
| |
| StopAllTracks(local_stream); |
| } |
| |
| TEST_F(RTCPeerConnectionHandlerTest, addStreamWithStoppedAudioAndVideoTrack) { |
| std::string stream_label = "local_stream"; |
| blink::WebMediaStream local_stream( |
| CreateLocalMediaStream(stream_label)); |
| blink::WebMediaConstraints constraints; |
| |
| blink::WebVector<blink::WebMediaStreamTrack> audio_tracks; |
| local_stream.audioTracks(audio_tracks); |
| MediaStreamAudioSource* native_audio_source = |
| MediaStreamAudioSource::From(audio_tracks[0].source()); |
| native_audio_source->StopSource(); |
| |
| blink::WebVector<blink::WebMediaStreamTrack> video_tracks; |
| local_stream.videoTracks(video_tracks); |
| MediaStreamVideoSource* native_video_source = |
| static_cast<MediaStreamVideoSource*>( |
| video_tracks[0].source().getExtraData()); |
| native_video_source->StopSource(); |
| |
| EXPECT_TRUE(pc_handler_->addStream(local_stream, constraints)); |
| EXPECT_EQ(stream_label, mock_peer_connection_->stream_label()); |
| EXPECT_EQ( |
| 1u, |
| mock_peer_connection_->local_streams()->at(0)->GetAudioTracks().size()); |
| EXPECT_EQ( |
| 1u, |
| mock_peer_connection_->local_streams()->at(0)->GetVideoTracks().size()); |
| |
| StopAllTracks(local_stream); |
| } |
| |
| TEST_F(RTCPeerConnectionHandlerTest, GetStatsNoSelector) { |
| scoped_refptr<MockRTCStatsRequest> request( |
| new rtc::RefCountedObject<MockRTCStatsRequest>()); |
| pc_handler_->getStats(request.get()); |
| base::RunLoop().RunUntilIdle(); |
| 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(); |
| base::RunLoop().RunUntilIdle(); |
| pc_handler_->getStats(request.get()); |
| base::RunLoop().RunUntilIdle(); |
| ASSERT_TRUE(request->result()); |
| EXPECT_LT(1, request->result()->report_count()); |
| } |
| |
| TEST_F(RTCPeerConnectionHandlerTest, GetStatsWithLocalSelector) { |
| blink::WebMediaStream local_stream( |
| CreateLocalMediaStream("local_stream")); |
| blink::WebMediaConstraints constraints; |
| pc_handler_->addStream(local_stream, constraints); |
| blink::WebVector<blink::WebMediaStreamTrack> tracks; |
| local_stream.audioTracks(tracks); |
| ASSERT_LE(1ul, tracks.size()); |
| |
| scoped_refptr<MockRTCStatsRequest> request( |
| new rtc::RefCountedObject<MockRTCStatsRequest>()); |
| request->setSelector(tracks[0]); |
| pc_handler_->getStats(request.get()); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(1, request->result()->report_count()); |
| |
| StopAllTracks(local_stream); |
| } |
| |
| TEST_F(RTCPeerConnectionHandlerTest, GetStatsWithRemoteSelector) { |
| rtc::scoped_refptr<webrtc::MediaStreamInterface> stream( |
| AddRemoteMockMediaStream("remote_stream", "video", "audio")); |
| pc_handler_->observer()->OnAddStream(stream); |
| base::RunLoop().RunUntilIdle(); |
| const blink::WebMediaStream& remote_stream = mock_client_->remote_stream(); |
| |
| blink::WebVector<blink::WebMediaStreamTrack> tracks; |
| remote_stream.audioTracks(tracks); |
| ASSERT_LE(1ul, tracks.size()); |
| |
| scoped_refptr<MockRTCStatsRequest> request( |
| new rtc::RefCountedObject<MockRTCStatsRequest>()); |
| request->setSelector(tracks[0]); |
| pc_handler_->getStats(request.get()); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(1, request->result()->report_count()); |
| } |
| |
| 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::WebMediaConstraints constraints; |
| blink::WebVector<blink::WebMediaStreamTrack> tracks; |
| |
| local_stream.audioTracks(tracks); |
| 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()); |
| base::RunLoop().RunUntilIdle(); |
| 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))); |
| base::RunLoop().RunUntilIdle(); |
| 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->type().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->type()); |
| switch (member->type()) { |
| case blink::WebRTCStatsMemberTypeBool: |
| EXPECT_EQ(member->valueBool(), true); |
| break; |
| case blink::WebRTCStatsMemberTypeInt32: |
| EXPECT_EQ(member->valueInt32(), static_cast<int32_t>(42)); |
| break; |
| case blink::WebRTCStatsMemberTypeUint32: |
| EXPECT_EQ(member->valueUint32(), static_cast<uint32_t>(42)); |
| break; |
| case blink::WebRTCStatsMemberTypeInt64: |
| EXPECT_EQ(member->valueInt64(), static_cast<int64_t>(42)); |
| break; |
| case blink::WebRTCStatsMemberTypeUint64: |
| EXPECT_EQ(member->valueUint64(), static_cast<uint64_t>(42)); |
| break; |
| case blink::WebRTCStatsMemberTypeDouble: |
| EXPECT_EQ(member->valueDouble(), 42.0); |
| break; |
| case blink::WebRTCStatsMemberTypeString: |
| EXPECT_EQ(member->valueString(), blink::WebString::fromUTF8("42")); |
| break; |
| case blink::WebRTCStatsMemberTypeSequenceBool: |
| ExpectSequenceEquals(member->valueSequenceBool(), 1); |
| break; |
| case blink::WebRTCStatsMemberTypeSequenceInt32: |
| ExpectSequenceEquals(member->valueSequenceInt32(), |
| static_cast<int32_t>(42)); |
| break; |
| case blink::WebRTCStatsMemberTypeSequenceUint32: |
| ExpectSequenceEquals(member->valueSequenceUint32(), |
| static_cast<uint32_t>(42)); |
| break; |
| case blink::WebRTCStatsMemberTypeSequenceInt64: |
| ExpectSequenceEquals(member->valueSequenceInt64(), |
| static_cast<int64_t>(42)); |
| break; |
| case blink::WebRTCStatsMemberTypeSequenceUint64: |
| ExpectSequenceEquals(member->valueSequenceUint64(), |
| static_cast<uint64_t>(42)); |
| break; |
| case blink::WebRTCStatsMemberTypeSequenceDouble: |
| ExpectSequenceEquals(member->valueSequenceDouble(), 42.0); |
| break; |
| case blink::WebRTCStatsMemberTypeSequenceString: |
| 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, OnSignalingChange) { |
| testing::InSequence sequence; |
| |
| webrtc::PeerConnectionInterface::SignalingState new_state = |
| webrtc::PeerConnectionInterface::kHaveRemoteOffer; |
| EXPECT_CALL(*mock_tracker_.get(), TrackSignalingStateChange( |
| pc_handler_.get(), |
| WebRTCPeerConnectionHandlerClient::SignalingStateHaveRemoteOffer)); |
| EXPECT_CALL(*mock_client_.get(), didChangeSignalingState( |
| WebRTCPeerConnectionHandlerClient::SignalingStateHaveRemoteOffer)); |
| pc_handler_->observer()->OnSignalingChange(new_state); |
| |
| new_state = webrtc::PeerConnectionInterface::kHaveLocalPrAnswer; |
| EXPECT_CALL(*mock_tracker_.get(), TrackSignalingStateChange( |
| pc_handler_.get(), |
| WebRTCPeerConnectionHandlerClient::SignalingStateHaveLocalPrAnswer)); |
| EXPECT_CALL(*mock_client_.get(), didChangeSignalingState( |
| WebRTCPeerConnectionHandlerClient::SignalingStateHaveLocalPrAnswer)); |
| pc_handler_->observer()->OnSignalingChange(new_state); |
| |
| new_state = webrtc::PeerConnectionInterface::kHaveLocalOffer; |
| EXPECT_CALL(*mock_tracker_.get(), TrackSignalingStateChange( |
| pc_handler_.get(), |
| WebRTCPeerConnectionHandlerClient::SignalingStateHaveLocalOffer)); |
| EXPECT_CALL(*mock_client_.get(), didChangeSignalingState( |
| WebRTCPeerConnectionHandlerClient::SignalingStateHaveLocalOffer)); |
| pc_handler_->observer()->OnSignalingChange(new_state); |
| |
| new_state = webrtc::PeerConnectionInterface::kHaveRemotePrAnswer; |
| EXPECT_CALL(*mock_tracker_.get(), TrackSignalingStateChange( |
| pc_handler_.get(), |
| WebRTCPeerConnectionHandlerClient::SignalingStateHaveRemotePrAnswer)); |
| EXPECT_CALL(*mock_client_.get(), didChangeSignalingState( |
| WebRTCPeerConnectionHandlerClient::SignalingStateHaveRemotePrAnswer)); |
| pc_handler_->observer()->OnSignalingChange(new_state); |
| |
| new_state = webrtc::PeerConnectionInterface::kClosed; |
| EXPECT_CALL(*mock_tracker_.get(), TrackSignalingStateChange( |
| pc_handler_.get(), |
| WebRTCPeerConnectionHandlerClient::SignalingStateClosed)); |
| EXPECT_CALL(*mock_client_.get(), didChangeSignalingState( |
| WebRTCPeerConnectionHandlerClient::SignalingStateClosed)); |
| pc_handler_->observer()->OnSignalingChange(new_state); |
| } |
| |
| TEST_F(RTCPeerConnectionHandlerTest, OnIceConnectionChange) { |
| testing::InSequence sequence; |
| |
| webrtc::PeerConnectionInterface::IceConnectionState new_state = |
| webrtc::PeerConnectionInterface::kIceConnectionNew; |
| EXPECT_CALL(*mock_tracker_.get(), TrackIceConnectionStateChange( |
| pc_handler_.get(), |
| WebRTCPeerConnectionHandlerClient::ICEConnectionStateStarting)); |
| EXPECT_CALL(*mock_client_.get(), didChangeICEConnectionState( |
| WebRTCPeerConnectionHandlerClient::ICEConnectionStateStarting)); |
| pc_handler_->observer()->OnIceConnectionChange(new_state); |
| |
| new_state = webrtc::PeerConnectionInterface::kIceConnectionChecking; |
| EXPECT_CALL(*mock_tracker_.get(), TrackIceConnectionStateChange( |
| pc_handler_.get(), |
| WebRTCPeerConnectionHandlerClient::ICEConnectionStateChecking)); |
| EXPECT_CALL(*mock_client_.get(), didChangeICEConnectionState( |
| WebRTCPeerConnectionHandlerClient::ICEConnectionStateChecking)); |
| pc_handler_->observer()->OnIceConnectionChange(new_state); |
| |
| new_state = webrtc::PeerConnectionInterface::kIceConnectionConnected; |
| EXPECT_CALL(*mock_tracker_.get(), TrackIceConnectionStateChange( |
| pc_handler_.get(), |
| WebRTCPeerConnectionHandlerClient::ICEConnectionStateConnected)); |
| EXPECT_CALL(*mock_client_.get(), didChangeICEConnectionState( |
| WebRTCPeerConnectionHandlerClient::ICEConnectionStateConnected)); |
| pc_handler_->observer()->OnIceConnectionChange(new_state); |
| |
| new_state = webrtc::PeerConnectionInterface::kIceConnectionCompleted; |
| EXPECT_CALL(*mock_tracker_.get(), TrackIceConnectionStateChange( |
| pc_handler_.get(), |
| WebRTCPeerConnectionHandlerClient::ICEConnectionStateCompleted)); |
| EXPECT_CALL(*mock_client_.get(), didChangeICEConnectionState( |
| WebRTCPeerConnectionHandlerClient::ICEConnectionStateCompleted)); |
| pc_handler_->observer()->OnIceConnectionChange(new_state); |
| |
| new_state = webrtc::PeerConnectionInterface::kIceConnectionFailed; |
| EXPECT_CALL(*mock_tracker_.get(), TrackIceConnectionStateChange( |
| pc_handler_.get(), |
| WebRTCPeerConnectionHandlerClient::ICEConnectionStateFailed)); |
| EXPECT_CALL(*mock_client_.get(), didChangeICEConnectionState( |
| WebRTCPeerConnectionHandlerClient::ICEConnectionStateFailed)); |
| pc_handler_->observer()->OnIceConnectionChange(new_state); |
| |
| new_state = webrtc::PeerConnectionInterface::kIceConnectionDisconnected; |
| EXPECT_CALL(*mock_tracker_.get(), TrackIceConnectionStateChange( |
| pc_handler_.get(), |
| WebRTCPeerConnectionHandlerClient::ICEConnectionStateDisconnected)); |
| EXPECT_CALL(*mock_client_.get(), didChangeICEConnectionState( |
| WebRTCPeerConnectionHandlerClient::ICEConnectionStateDisconnected)); |
| pc_handler_->observer()->OnIceConnectionChange(new_state); |
| |
| new_state = webrtc::PeerConnectionInterface::kIceConnectionClosed; |
| EXPECT_CALL(*mock_tracker_.get(), TrackIceConnectionStateChange( |
| pc_handler_.get(), |
| WebRTCPeerConnectionHandlerClient::ICEConnectionStateClosed)); |
| EXPECT_CALL(*mock_client_.get(), didChangeICEConnectionState( |
| WebRTCPeerConnectionHandlerClient::ICEConnectionStateClosed)); |
| pc_handler_->observer()->OnIceConnectionChange(new_state); |
| } |
| |
| TEST_F(RTCPeerConnectionHandlerTest, OnIceGatheringChange) { |
| testing::InSequence sequence; |
| EXPECT_CALL(*mock_tracker_.get(), TrackIceGatheringStateChange( |
| pc_handler_.get(), |
| WebRTCPeerConnectionHandlerClient::ICEGatheringStateNew)); |
| EXPECT_CALL(*mock_client_.get(), didChangeICEGatheringState( |
| WebRTCPeerConnectionHandlerClient::ICEGatheringStateNew)); |
| EXPECT_CALL(*mock_tracker_.get(), TrackIceGatheringStateChange( |
| pc_handler_.get(), |
| WebRTCPeerConnectionHandlerClient::ICEGatheringStateGathering)); |
| EXPECT_CALL(*mock_client_.get(), didChangeICEGatheringState( |
| WebRTCPeerConnectionHandlerClient::ICEGatheringStateGathering)); |
| EXPECT_CALL(*mock_tracker_.get(), TrackIceGatheringStateChange( |
| pc_handler_.get(), |
| WebRTCPeerConnectionHandlerClient::ICEGatheringStateComplete)); |
| EXPECT_CALL(*mock_client_.get(), didChangeICEGatheringState( |
| WebRTCPeerConnectionHandlerClient::ICEGatheringStateComplete)); |
| |
| 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()); |
| } |
| |
| TEST_F(RTCPeerConnectionHandlerTest, OnAddAndOnRemoveStream) { |
| std::string remote_stream_label("remote_stream"); |
| rtc::scoped_refptr<webrtc::MediaStreamInterface> remote_stream( |
| AddRemoteMockMediaStream(remote_stream_label, "video", "audio")); |
| |
| testing::InSequence sequence; |
| EXPECT_CALL( |
| *mock_tracker_.get(), |
| TrackAddStream( |
| pc_handler_.get(), |
| testing::Property(&blink::WebMediaStream::id, |
| blink::WebString::fromASCII(remote_stream_label)), |
| PeerConnectionTracker::SOURCE_REMOTE)); |
| EXPECT_CALL(*mock_client_.get(), |
| didAddRemoteStream(testing::Property( |
| &blink::WebMediaStream::id, |
| blink::WebString::fromASCII(remote_stream_label)))); |
| |
| EXPECT_CALL( |
| *mock_tracker_.get(), |
| TrackRemoveStream( |
| pc_handler_.get(), |
| testing::Property(&blink::WebMediaStream::id, |
| blink::WebString::fromASCII(remote_stream_label)), |
| PeerConnectionTracker::SOURCE_REMOTE)); |
| EXPECT_CALL(*mock_client_.get(), |
| didRemoveRemoteStream(testing::Property( |
| &blink::WebMediaStream::id, |
| blink::WebString::fromASCII(remote_stream_label)))); |
| |
| pc_handler_->observer()->OnAddStream(remote_stream); |
| base::RunLoop().RunUntilIdle(); |
| pc_handler_->observer()->OnRemoveStream(remote_stream); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| // This test that WebKit is notified about remote track state changes. |
| TEST_F(RTCPeerConnectionHandlerTest, RemoteTrackState) { |
| std::string remote_stream_label("remote_stream"); |
| rtc::scoped_refptr<webrtc::MediaStreamInterface> remote_stream( |
| AddRemoteMockMediaStream(remote_stream_label, "video", "audio")); |
| |
| testing::InSequence sequence; |
| EXPECT_CALL(*mock_client_.get(), |
| didAddRemoteStream(testing::Property( |
| &blink::WebMediaStream::id, |
| blink::WebString::fromASCII(remote_stream_label)))); |
| pc_handler_->observer()->OnAddStream(remote_stream); |
| base::RunLoop().RunUntilIdle(); |
| const blink::WebMediaStream& webkit_stream = mock_client_->remote_stream(); |
| |
| blink::WebVector<blink::WebMediaStreamTrack> audio_tracks; |
| webkit_stream.audioTracks(audio_tracks); |
| EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive, |
| audio_tracks[0].source().getReadyState()); |
| |
| blink::WebVector<blink::WebMediaStreamTrack> video_tracks; |
| webkit_stream.videoTracks(video_tracks); |
| EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive, |
| video_tracks[0].source().getReadyState()); |
| |
| static_cast<MockWebRtcAudioTrack*>(remote_stream->GetAudioTracks()[0].get()) |
| ->SetEnded(); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded, |
| audio_tracks[0].source().getReadyState()); |
| |
| static_cast<MockWebRtcVideoTrack*>(remote_stream->GetVideoTracks()[0].get()) |
| ->SetEnded(); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded, |
| video_tracks[0].source().getReadyState()); |
| } |
| |
| TEST_F(RTCPeerConnectionHandlerTest, RemoveAndAddAudioTrackFromRemoteStream) { |
| std::string remote_stream_label("remote_stream"); |
| base::RunLoop run_loop; |
| |
| // Grab the added media stream when it's been successfully added to the PC. |
| blink::WebMediaStream webkit_stream; |
| EXPECT_CALL(*mock_client_.get(), |
| didAddRemoteStream(testing::Property( |
| &blink::WebMediaStream::id, |
| blink::WebString::fromASCII(remote_stream_label)))) |
| .WillOnce(DoAll(SaveArg<0>(&webkit_stream), |
| ExitMessageLoop(&message_loop_, run_loop.QuitClosure()))); |
| |
| rtc::scoped_refptr<webrtc::MediaStreamInterface> remote_stream( |
| AddRemoteMockMediaStream(remote_stream_label, "video", "audio")); |
| pc_handler_->observer()->OnAddStream(remote_stream); |
| run_loop.Run(); |
| |
| { |
| // Test in a small scope so that |audio_tracks| don't hold on to destroyed |
| // source later. |
| blink::WebVector<blink::WebMediaStreamTrack> audio_tracks; |
| webkit_stream.audioTracks(audio_tracks); |
| EXPECT_EQ(1u, audio_tracks.size()); |
| } |
| |
| // Remove the Webrtc audio track from the Webrtc MediaStream. |
| scoped_refptr<webrtc::AudioTrackInterface> webrtc_track = |
| remote_stream->GetAudioTracks()[0].get(); |
| remote_stream->RemoveTrack(webrtc_track.get()); |
| base::RunLoop().RunUntilIdle(); |
| |
| { |
| blink::WebVector<blink::WebMediaStreamTrack> modified_audio_tracks1; |
| webkit_stream.audioTracks(modified_audio_tracks1); |
| EXPECT_EQ(0u, modified_audio_tracks1.size()); |
| } |
| |
| blink::WebHeap::collectGarbageForTesting(); |
| |
| // Add the WebRtc audio track again. |
| remote_stream->AddTrack(webrtc_track.get()); |
| base::RunLoop().RunUntilIdle(); |
| blink::WebVector<blink::WebMediaStreamTrack> modified_audio_tracks2; |
| webkit_stream.audioTracks(modified_audio_tracks2); |
| EXPECT_EQ(1u, modified_audio_tracks2.size()); |
| } |
| |
| TEST_F(RTCPeerConnectionHandlerTest, RemoveAndAddVideoTrackFromRemoteStream) { |
| std::string remote_stream_label("remote_stream"); |
| base::RunLoop run_loop; |
| |
| // Grab the added media stream when it's been successfully added to the PC. |
| blink::WebMediaStream webkit_stream; |
| EXPECT_CALL(*mock_client_.get(), |
| didAddRemoteStream(testing::Property( |
| &blink::WebMediaStream::id, |
| blink::WebString::fromASCII(remote_stream_label)))) |
| .WillOnce(DoAll(SaveArg<0>(&webkit_stream), |
| ExitMessageLoop(&message_loop_, run_loop.QuitClosure()))); |
| |
| rtc::scoped_refptr<webrtc::MediaStreamInterface> remote_stream( |
| AddRemoteMockMediaStream(remote_stream_label, "video", "audio")); |
| pc_handler_->observer()->OnAddStream(remote_stream); |
| run_loop.Run(); |
| |
| { |
| // Test in a small scope so that |video_tracks| don't hold on to destroyed |
| // source later. |
| blink::WebVector<blink::WebMediaStreamTrack> video_tracks; |
| webkit_stream.videoTracks(video_tracks); |
| EXPECT_EQ(1u, video_tracks.size()); |
| } |
| |
| // Remove the Webrtc video track from the Webrtc MediaStream. |
| scoped_refptr<webrtc::VideoTrackInterface> webrtc_track = |
| remote_stream->GetVideoTracks()[0].get(); |
| remote_stream->RemoveTrack(webrtc_track.get()); |
| base::RunLoop().RunUntilIdle(); |
| { |
| blink::WebVector<blink::WebMediaStreamTrack> modified_video_tracks1; |
| webkit_stream.videoTracks(modified_video_tracks1); |
| EXPECT_EQ(0u, modified_video_tracks1.size()); |
| } |
| |
| blink::WebHeap::collectGarbageForTesting(); |
| |
| // Add the WebRtc video track again. |
| remote_stream->AddTrack(webrtc_track.get()); |
| base::RunLoop().RunUntilIdle(); |
| blink::WebVector<blink::WebMediaStreamTrack> modified_video_tracks2; |
| webkit_stream.videoTracks(modified_video_tracks2); |
| EXPECT_EQ(1u, modified_video_tracks2.size()); |
| } |
| |
| TEST_F(RTCPeerConnectionHandlerTest, RemoveAndAddTracksFromRemoteStream) { |
| std::string remote_stream_label("remote_stream"); |
| base::RunLoop run_loop; |
| |
| // Grab the added media stream when it's been successfully added to the PC. |
| blink::WebMediaStream webkit_stream; |
| EXPECT_CALL(*mock_client_.get(), |
| didAddRemoteStream(testing::Property( |
| &blink::WebMediaStream::id, |
| blink::WebString::fromASCII(remote_stream_label)))) |
| .WillOnce(DoAll(SaveArg<0>(&webkit_stream), |
| ExitMessageLoop(&message_loop_, run_loop.QuitClosure()))); |
| |
| rtc::scoped_refptr<webrtc::MediaStreamInterface> remote_stream( |
| AddRemoteMockMediaStream(remote_stream_label, "video", "audio")); |
| pc_handler_->observer()->OnAddStream(remote_stream); |
| run_loop.Run(); |
| |
| { |
| // Test in a small scope so that |audio_tracks| don't hold on to destroyed |
| // source later. |
| blink::WebVector<blink::WebMediaStreamTrack> audio_tracks; |
| webkit_stream.audioTracks(audio_tracks); |
| EXPECT_EQ(1u, audio_tracks.size()); |
| blink::WebVector<blink::WebMediaStreamTrack> video_tracks; |
| webkit_stream.videoTracks(video_tracks); |
| EXPECT_EQ(1u, video_tracks.size()); |
| } |
| |
| // Remove the Webrtc tracks from the MediaStream. |
| auto audio_track = remote_stream->GetAudioTracks()[0]; |
| EXPECT_TRUE(remote_stream->RemoveTrack(audio_track.get())); |
| auto video_track = remote_stream->GetVideoTracks()[0]; |
| EXPECT_TRUE(remote_stream->RemoveTrack(video_track.get())); |
| base::RunLoop().RunUntilIdle(); |
| |
| { |
| blink::WebVector<blink::WebMediaStreamTrack> modified_audio_tracks; |
| webkit_stream.audioTracks(modified_audio_tracks); |
| EXPECT_EQ(0u, modified_audio_tracks.size()); |
| blink::WebVector<blink::WebMediaStreamTrack> modified_video_tracks; |
| webkit_stream.videoTracks(modified_video_tracks); |
| EXPECT_EQ(0u, modified_video_tracks.size()); |
| } |
| |
| blink::WebHeap::collectGarbageForTesting(); |
| |
| // Add the tracks again. |
| remote_stream->AddTrack(audio_track.get()); |
| base::RunLoop().RunUntilIdle(); |
| remote_stream->AddTrack(video_track.get()); |
| base::RunLoop().RunUntilIdle(); |
| |
| blink::WebHeap::collectGarbageForTesting(); |
| |
| blink::WebVector<blink::WebMediaStreamTrack> audio_tracks; |
| webkit_stream.audioTracks(audio_tracks); |
| EXPECT_EQ(1u, audio_tracks.size()); |
| blink::WebVector<blink::WebMediaStreamTrack> video_tracks; |
| webkit_stream.videoTracks(video_tracks); |
| EXPECT_EQ(1u, video_tracks.size()); |
| } |
| |
| 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()); |
| base::RunLoop().RunUntilIdle(); |
| 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)); |
| std::unique_ptr<blink::WebRTCDataChannelHandler> channel( |
| pc_handler_->createDataChannel("d1", blink::WebRTCDataChannelInit())); |
| EXPECT_TRUE(channel.get() != NULL); |
| EXPECT_EQ(label, channel->label()); |
| channel->setClient(nullptr); |
| } |
| |
| TEST_F(RTCPeerConnectionHandlerTest, CreateDtmfSender) { |
| std::string stream_label = "local_stream"; |
| blink::WebMediaStream local_stream(CreateLocalMediaStream(stream_label)); |
| blink::WebMediaConstraints constraints; |
| pc_handler_->addStream(local_stream, constraints); |
| |
| blink::WebVector<blink::WebMediaStreamTrack> tracks; |
| local_stream.videoTracks(tracks); |
| |
| ASSERT_LE(1ul, tracks.size()); |
| EXPECT_FALSE(pc_handler_->createDTMFSender(tracks[0])); |
| |
| local_stream.audioTracks(tracks); |
| ASSERT_LE(1ul, tracks.size()); |
| |
| EXPECT_CALL(*mock_tracker_.get(), |
| TrackCreateDTMFSender(pc_handler_.get(), |
| testing::Ref(tracks[0]))); |
| |
| std::unique_ptr<blink::WebRTCDTMFSenderHandler> sender( |
| pc_handler_->createDTMFSender(tracks[0])); |
| EXPECT_TRUE(sender.get()); |
| |
| StopAllTracks(local_stream); |
| } |
| |
| } // namespace content |