/* * Copyright 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "pc/peer_connection_wrapper.h" #include #include #include #include #include #include "api/function_view.h" #include "api/set_remote_description_observer_interface.h" #include "pc/sdp_utils.h" #include "pc/test/fake_video_track_source.h" #include "rtc_base/checks.h" #include "rtc_base/gunit.h" #include "rtc_base/logging.h" #include "rtc_base/ref_counted_object.h" #include "test/gtest.h" namespace webrtc { using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions; namespace { const uint32_t kDefaultTimeout = 10000U; } PeerConnectionWrapper::PeerConnectionWrapper( rtc::scoped_refptr pc_factory, rtc::scoped_refptr pc, std::unique_ptr observer) : pc_factory_(std::move(pc_factory)), observer_(std::move(observer)), pc_(std::move(pc)) { RTC_DCHECK(pc_factory_); RTC_DCHECK(pc_); RTC_DCHECK(observer_); observer_->SetPeerConnectionInterface(pc_.get()); } PeerConnectionWrapper::~PeerConnectionWrapper() { if (pc_) pc_->Close(); } PeerConnectionFactoryInterface* PeerConnectionWrapper::pc_factory() { return pc_factory_.get(); } PeerConnectionInterface* PeerConnectionWrapper::pc() { return pc_.get(); } MockPeerConnectionObserver* PeerConnectionWrapper::observer() { return observer_.get(); } std::unique_ptr PeerConnectionWrapper::CreateOffer() { return CreateOffer(RTCOfferAnswerOptions()); } std::unique_ptr PeerConnectionWrapper::CreateOffer( const PeerConnectionInterface::RTCOfferAnswerOptions& options, std::string* error_out) { return CreateSdp( [this, options](CreateSessionDescriptionObserver* observer) { pc()->CreateOffer(observer, options); }, error_out); } std::unique_ptr PeerConnectionWrapper::CreateOfferAndSetAsLocal() { return CreateOfferAndSetAsLocal(RTCOfferAnswerOptions()); } std::unique_ptr PeerConnectionWrapper::CreateOfferAndSetAsLocal( const PeerConnectionInterface::RTCOfferAnswerOptions& options) { auto offer = CreateOffer(options); if (!offer) { return nullptr; } EXPECT_TRUE(SetLocalDescription(CloneSessionDescription(offer.get()))); return offer; } std::unique_ptr PeerConnectionWrapper::CreateAnswer() { return CreateAnswer(RTCOfferAnswerOptions()); } std::unique_ptr PeerConnectionWrapper::CreateAnswer( const PeerConnectionInterface::RTCOfferAnswerOptions& options, std::string* error_out) { return CreateSdp( [this, options](CreateSessionDescriptionObserver* observer) { pc()->CreateAnswer(observer, options); }, error_out); } std::unique_ptr PeerConnectionWrapper::CreateAnswerAndSetAsLocal() { return CreateAnswerAndSetAsLocal(RTCOfferAnswerOptions()); } std::unique_ptr PeerConnectionWrapper::CreateAnswerAndSetAsLocal( const PeerConnectionInterface::RTCOfferAnswerOptions& options) { auto answer = CreateAnswer(options); if (!answer) { return nullptr; } EXPECT_TRUE(SetLocalDescription(CloneSessionDescription(answer.get()))); return answer; } std::unique_ptr PeerConnectionWrapper::CreateRollback() { return CreateSessionDescription(SdpType::kRollback, ""); } std::unique_ptr PeerConnectionWrapper::CreateSdp( rtc::FunctionView fn, std::string* error_out) { auto observer = rtc::make_ref_counted(); fn(observer); EXPECT_EQ_WAIT(true, observer->called(), kDefaultTimeout); if (error_out && !observer->result()) { *error_out = observer->error(); } return observer->MoveDescription(); } bool PeerConnectionWrapper::SetLocalDescription( std::unique_ptr desc, std::string* error_out) { return SetSdp( [this, &desc](SetSessionDescriptionObserver* observer) { pc()->SetLocalDescription(observer, desc.release()); }, error_out); } bool PeerConnectionWrapper::SetRemoteDescription( std::unique_ptr desc, std::string* error_out) { return SetSdp( [this, &desc](SetSessionDescriptionObserver* observer) { pc()->SetRemoteDescription(observer, desc.release()); }, error_out); } bool PeerConnectionWrapper::SetRemoteDescription( std::unique_ptr desc, RTCError* error_out) { rtc::scoped_refptr observer = new FakeSetRemoteDescriptionObserver(); pc()->SetRemoteDescription(std::move(desc), observer); EXPECT_EQ_WAIT(true, observer->called(), kDefaultTimeout); bool ok = observer->error().ok(); if (error_out) *error_out = std::move(observer->error()); return ok; } bool PeerConnectionWrapper::SetSdp( rtc::FunctionView fn, std::string* error_out) { auto observer = rtc::make_ref_counted(); fn(observer); EXPECT_EQ_WAIT(true, observer->called(), kDefaultTimeout); if (error_out && !observer->result()) { *error_out = observer->error(); } return observer->result(); } bool PeerConnectionWrapper::ExchangeOfferAnswerWith( PeerConnectionWrapper* answerer) { return ExchangeOfferAnswerWith(answerer, RTCOfferAnswerOptions(), RTCOfferAnswerOptions()); } bool PeerConnectionWrapper::ExchangeOfferAnswerWith( PeerConnectionWrapper* answerer, const PeerConnectionInterface::RTCOfferAnswerOptions& offer_options, const PeerConnectionInterface::RTCOfferAnswerOptions& answer_options) { RTC_DCHECK(answerer); if (answerer == this) { RTC_LOG(LS_ERROR) << "Cannot exchange offer/answer with ourself!"; return false; } auto offer = CreateOffer(offer_options); EXPECT_TRUE(offer); if (!offer) { return false; } bool set_local_offer = SetLocalDescription(CloneSessionDescription(offer.get())); EXPECT_TRUE(set_local_offer); if (!set_local_offer) { return false; } bool set_remote_offer = answerer->SetRemoteDescription(std::move(offer)); EXPECT_TRUE(set_remote_offer); if (!set_remote_offer) { return false; } auto answer = answerer->CreateAnswer(answer_options); EXPECT_TRUE(answer); if (!answer) { return false; } bool set_local_answer = answerer->SetLocalDescription(CloneSessionDescription(answer.get())); EXPECT_TRUE(set_local_answer); if (!set_local_answer) { return false; } bool set_remote_answer = SetRemoteDescription(std::move(answer)); EXPECT_TRUE(set_remote_answer); return set_remote_answer; } rtc::scoped_refptr PeerConnectionWrapper::AddTransceiver(cricket::MediaType media_type) { RTCErrorOr> result = pc()->AddTransceiver(media_type); EXPECT_EQ(RTCErrorType::NONE, result.error().type()); return result.MoveValue(); } rtc::scoped_refptr PeerConnectionWrapper::AddTransceiver(cricket::MediaType media_type, const RtpTransceiverInit& init) { RTCErrorOr> result = pc()->AddTransceiver(media_type, init); EXPECT_EQ(RTCErrorType::NONE, result.error().type()); return result.MoveValue(); } rtc::scoped_refptr PeerConnectionWrapper::AddTransceiver( rtc::scoped_refptr track) { RTCErrorOr> result = pc()->AddTransceiver(track); EXPECT_EQ(RTCErrorType::NONE, result.error().type()); return result.MoveValue(); } rtc::scoped_refptr PeerConnectionWrapper::AddTransceiver( rtc::scoped_refptr track, const RtpTransceiverInit& init) { RTCErrorOr> result = pc()->AddTransceiver(track, init); EXPECT_EQ(RTCErrorType::NONE, result.error().type()); return result.MoveValue(); } rtc::scoped_refptr PeerConnectionWrapper::CreateAudioTrack( const std::string& label) { return pc_factory()->CreateAudioTrack(label, nullptr); } rtc::scoped_refptr PeerConnectionWrapper::CreateVideoTrack( const std::string& label) { return pc_factory()->CreateVideoTrack(label, FakeVideoTrackSource::Create()); } rtc::scoped_refptr PeerConnectionWrapper::AddTrack( rtc::scoped_refptr track, const std::vector& stream_ids) { RTCErrorOr> result = pc()->AddTrack(track, stream_ids); EXPECT_EQ(RTCErrorType::NONE, result.error().type()); return result.MoveValue(); } rtc::scoped_refptr PeerConnectionWrapper::AddAudioTrack( const std::string& track_label, const std::vector& stream_ids) { return AddTrack(CreateAudioTrack(track_label), stream_ids); } rtc::scoped_refptr PeerConnectionWrapper::AddVideoTrack( const std::string& track_label, const std::vector& stream_ids) { return AddTrack(CreateVideoTrack(track_label), stream_ids); } rtc::scoped_refptr PeerConnectionWrapper::CreateDataChannel(const std::string& label) { auto result = pc()->CreateDataChannelOrError(label, nullptr); if (!result.ok()) { RTC_LOG(LS_ERROR) << "CreateDataChannel failed: " << ToString(result.error().type()) << " " << result.error().message(); return nullptr; } return result.MoveValue(); } PeerConnectionInterface::SignalingState PeerConnectionWrapper::signaling_state() { return pc()->signaling_state(); } bool PeerConnectionWrapper::IsIceGatheringDone() { return observer()->ice_gathering_complete_; } bool PeerConnectionWrapper::IsIceConnected() { return observer()->ice_connected_; } rtc::scoped_refptr PeerConnectionWrapper::GetStats() { auto callback = rtc::make_ref_counted(); pc()->GetStats(callback); EXPECT_TRUE_WAIT(callback->called(), kDefaultTimeout); return callback->report(); } } // namespace webrtc