Windows编译运行webrtc全过程,并实现屏幕共享
文章分为三部分,代码获取/编译/运行。
第一步获取代码,打开cmd执行以下指令即可
set WORKSPACE=E:\webrtc mkdir %WORKSPACE% cd /d %WORKSPACE% git clone --depth 1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
set PATH=%WORKSPACE%\depot_tools;%PATH% mkdir webrtc-checkout && cd webrtc-checkout set DEPOT_TOOLS_WIN_TOOLCHAIN=0 fetch --nohooks webrtc gclient sync
(下载代码需要用到外网的服务器,我是直接购买机房在外国的云服务器,安装Windows Server系统来编译。使用vpn等是不可行的,因为一般vpn服务器还在国内,受到监管,而购买外网服务器则没有这个问题,不会被拦截;你只是最后回传一个编译好的库文件而已,也就没什么大的问题,可以购买一个很低端的配置,就不贵。)
代码下载完毕之后如下图所示
第二部编译代码。需要visual studio并安装vc++,还要把windows sdk的debug开启。如下两图的步骤
(如果使用vs2022编译,则需要安装20348版本的sdk,默认是没勾选的哦)
为了实现屏幕共享,我们还需要改动示例代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* 2 * Copyright 2012 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "examples/peerconnection/client/conductor.h" 12 13 #include <stddef.h> 14 #include <stdint.h> 15 16 #include <memory> 17 #include <utility> 18 #include <vector> 19 #include <thread> 20 21 #include "absl/memory/memory.h" 22 #include "absl/types/optional.h" 23 #include "api/audio/audio_mixer.h" 24 #include "api/audio_codecs/audio_decoder_factory.h" 25 #include "api/audio_codecs/audio_encoder_factory.h" 26 #include "api/audio_codecs/builtin_audio_decoder_factory.h" 27 #include "api/audio_codecs/builtin_audio_encoder_factory.h" 28 #include "api/audio_options.h" 29 #include "api/create_peerconnection_factory.h" 30 #include "api/rtp_sender_interface.h" 31 #include "api/video_codecs/builtin_video_decoder_factory.h" 32 #include "api/video_codecs/builtin_video_encoder_factory.h" 33 #include "api/video_codecs/video_decoder_factory.h" 34 #include "api/video_codecs/video_encoder_factory.h" 35 #include "examples/peerconnection/client/defaults.h" 36 #include "modules/audio_device/include/audio_device.h" 37 #include "modules/audio_processing/include/audio_processing.h" 38 #include "modules/video_capture/video_capture.h" 39 #include "modules/video_capture/video_capture_factory.h" 40 #include "p2p/base/port_allocator.h" 41 #include "pc/video_track_source.h" 42 #include "rtc_base/checks.h" 43 #include "rtc_base/logging.h" 44 #include "rtc_base/ref_counted_object.h" 45 #include "rtc_base/rtc_certificate_generator.h" 46 #include "rtc_base/strings/json.h" 47 #include "test/vcm_capturer.h" 48 #include "modules/desktop_capture/desktop_capturer.h" 49 #include "modules/desktop_capture/desktop_frame.h" 50 #include "modules/desktop_capture/desktop_capture_options.h" 51 #include "media/base/adapted_video_track_source.h" 52 #include "api/video/i420_buffer.h" 53 #include "third_party/libyuv/include/libyuv.h" 54 55 namespace { 56 // Names used for a IceCandidate JSON object. 57 const char kCandidateSdpMidName[] = "sdpMid"; 58 const char kCandidateSdpMlineIndexName[] = "sdpMLineIndex"; 59 const char kCandidateSdpName[] = "candidate"; 60 61 // Names used for a SessionDescription JSON object. 62 const char kSessionDescriptionTypeName[] = "type"; 63 const char kSessionDescriptionSdpName[] = "sdp"; 64 65 class DummySetSessionDescriptionObserver 66 : public webrtc::SetSessionDescriptionObserver { 67 public: 68 static DummySetSessionDescriptionObserver* Create() { 69 return new rtc::RefCountedObject<DummySetSessionDescriptionObserver>(); 70 } 71 virtual void OnSuccess() { RTC_LOG(INFO) << __FUNCTION__; } 72 virtual void OnFailure(webrtc::RTCError error) { 73 RTC_LOG(INFO) << __FUNCTION__ << " " << ToString(error.type()) << ": " 74 << error.message(); 75 } 76 }; 77 78 class CapturerTrackSource : public webrtc::VideoTrackSource { 79 public: 80 static rtc::scoped_refptr<CapturerTrackSource> Create() { 81 const size_t kWidth = 640; 82 const size_t kHeight = 480; 83 const size_t kFps = 30; 84 std::unique_ptr<webrtc::test::VcmCapturer> capturer; 85 std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> info( 86 webrtc::VideoCaptureFactory::CreateDeviceInfo()); 87 if (!info) { 88 return nullptr; 89 } 90 int num_devices = info->NumberOfDevices(); 91 for (int i = 0; i < num_devices; ++i) { 92 capturer = absl::WrapUnique( 93 webrtc::test::VcmCapturer::Create(kWidth, kHeight, kFps, i)); 94 if (capturer) { 95 return new rtc::RefCountedObject<CapturerTrackSource>( 96 std::move(capturer)); 97 } 98 } 99 100 return nullptr; 101 } 102 103 protected: 104 explicit CapturerTrackSource( 105 std::unique_ptr<webrtc::test::VcmCapturer> capturer) 106 : VideoTrackSource(/*remote=*/false), capturer_(std::move(capturer)) {} 107 108 private: 109 rtc::VideoSourceInterface<webrtc::VideoFrame>* source() override { 110 return capturer_.get(); 111 } 112 std::unique_ptr<webrtc::test::VcmCapturer> capturer_; 113 }; 114 115 class MyDesktopCapture : public rtc::AdaptedVideoTrackSource, 116 public webrtc::DesktopCapturer::Callback { 117 public: 118 ~MyDesktopCapture() override { 119 StopCapture(); 120 if (!dc_) 121 return; 122 123 dc_.reset(nullptr); 124 } 125 //--RefCountedObject 126 void SetState(SourceState new_state); 127 128 SourceState state() const override { return state_; } 129 bool remote() const override { return remote_; } 130 131 bool is_screencast() const override { return false; } 132 absl::optional<bool> needs_denoising() const override { 133 return absl::nullopt; 134 } 135 136 bool GetStats(Stats* stats) override { return false; } 137 //--RefCountedObject 138 139 std::string GetWindowTitle() const { return window_title_; } 140 141 void StartCapture() { 142 if (start_flag_) { 143 RTC_LOG(WARNING) << "Capture already been running..."; 144 return; 145 } 146 147 start_flag_ = true; 148 149 // Start new thread to capture 150 capture_thread_.reset(new std::thread([this]() { 151 dc_->Start(this); 152 153 while (start_flag_) { 154 dc_->CaptureFrame(); 155 std::this_thread::sleep_for(std::chrono::milliseconds(1000 / fps_)); 156 } 157 })); 158 } 159 160 void StopCapture() { 161 start_flag_ = false; 162 163 if (capture_thread_ && capture_thread_->joinable()) { 164 capture_thread_->join(); 165 } 166 } 167 168 static rtc::scoped_refptr<MyDesktopCapture> Create( 169 size_t target_fps, 170 size_t capture_screen_index) { 171 auto dc = webrtc::DesktopCapturer::CreateScreenCapturer( 172 webrtc::DesktopCaptureOptions::CreateDefault()); 173 174 if (!dc) 175 return nullptr; 176 177 webrtc::DesktopCapturer::SourceList sources; 178 dc->GetSourceList(&sources); 179 if (capture_screen_index > sources.size()) { 180 RTC_LOG(LS_WARNING) << "The total sources of screen is " << sources.size() 181 << ", but require source of index at " 182 << capture_screen_index; 183 return nullptr; 184 } 185 186 RTC_CHECK(dc->SelectSource(sources[capture_screen_index].id)); 187 auto window_title = sources[capture_screen_index].title; 188 auto fps = target_fps; 189 190 RTC_LOG(LS_INFO) << "Init DesktopCapture finish"; 191 // Start new thread to capture 192 return new rtc::RefCountedObject<MyDesktopCapture>(std::move(dc), fps, 193 std::move(window_title)); 194 } 195 196 void OnCaptureResult( 197 webrtc::DesktopCapturer::Result result, 198 std::unique_ptr<webrtc::DesktopFrame> desktopframe) override { 199 if (result != webrtc::DesktopCapturer::Result::SUCCESS) 200 return; 201 int width = desktopframe->size().width(); 202 int height = desktopframe->size().height(); 203 // int half_width = (width + 1) / 2; 204 205 if (!i420_buffer_.get() || 206 i420_buffer_->width() * i420_buffer_->height() < width * height) { 207 i420_buffer_ = webrtc::I420Buffer::Create(width, height); 208 } 209 210 int stride = width; 211 uint8_t* yplane = i420_buffer_->MutableDataY(); 212 uint8_t* uplane = i420_buffer_->MutableDataU(); 213 uint8_t* vplane = i420_buffer_->MutableDataV(); 214 libyuv::ConvertToI420(desktopframe->data(), 0, yplane, stride, uplane, 215 (stride + 1) / 2, vplane, (stride + 1) / 2, 0, 0, 216 width, height, width, height, libyuv::kRotate0, 217 libyuv::FOURCC_ARGB); 218 webrtc::VideoFrame frame = 219 webrtc::VideoFrame(i420_buffer_, 0, 0, webrtc::kVideoRotation_0); 220 this->OnFrame(frame); 221 } 222 223 protected: 224 explicit MyDesktopCapture(std::unique_ptr<webrtc::DesktopCapturer> dc, 225 size_t fps, 226 std::string window_title) 227 : dc_(std::move(dc)), 228 fps_(fps), 229 window_title_(std::move(window_title)), 230 start_flag_(false), 231 remote_(false) {} 232 233 private: 234 std::unique_ptr<webrtc::DesktopCapturer> dc_; 235 size_t fps_; 236 std::string window_title_; 237 rtc::scoped_refptr<webrtc::I420Buffer> i420_buffer_; 238 std::unique_ptr<std::thread> capture_thread_; 239 std::atomic_bool start_flag_; 240 // RefCountedObject 241 SourceState state_; 242 const bool remote_; 243 }; 244 245 } // namespace 246 247 Conductor::Conductor(PeerConnectionClient* client, MainWindow* main_wnd) 248 : peer_id_(-1), loopback_(false), client_(client), main_wnd_(main_wnd) { 249 client_->RegisterObserver(this); 250 main_wnd->RegisterObserver(this); 251 } 252 253 Conductor::~Conductor() { 254 RTC_DCHECK(!peer_connection_); 255 } 256 257 bool Conductor::connection_active() const { 258 return peer_connection_ != nullptr; 259 } 260 261 void Conductor::Close() { 262 client_->SignOut(); 263 DeletePeerConnection(); 264 } 265 266 static std::unique_ptr<rtc::Thread> g_worker_thread; 267 static std::unique_ptr<rtc::Thread> g_signaling_thread; 268 bool Conductor::InitializePeerConnection() { 269 RTC_DCHECK(!peer_connection_factory_); 270 RTC_DCHECK(!peer_connection_); 271 g_worker_thread = rtc::Thread::Create(); 272 g_worker_thread->Start(); 273 g_signaling_thread = rtc::Thread::Create(); 274 g_signaling_thread->Start(); 275 276 peer_connection_factory_ = webrtc::CreatePeerConnectionFactory( 277 nullptr /* network_thread */, g_worker_thread.get() /* worker_thread */, 278 g_signaling_thread.get() /* signaling_thread */, nullptr /* default_adm */, 279 webrtc::CreateBuiltinAudioEncoderFactory(), 280 webrtc::CreateBuiltinAudioDecoderFactory(), 281 webrtc::CreateBuiltinVideoEncoderFactory(), 282 webrtc::CreateBuiltinVideoDecoderFactory(), nullptr /* audio_mixer */, 283 nullptr /* audio_processing */); 284 285 if (!peer_connection_factory_) { 286 main_wnd_->MessageBox("Error", "Failed to initialize PeerConnectionFactory", 287 true); 288 DeletePeerConnection(); 289 return false; 290 } 291 292 if (!CreatePeerConnection(/*dtls=*/true)) { 293 main_wnd_->MessageBox("Error", "CreatePeerConnection failed", true); 294 DeletePeerConnection(); 295 } 296 297 AddTracks(); 298 299 return peer_connection_ != nullptr; 300 } 301 302 bool Conductor::ReinitializePeerConnectionForLoopback() { 303 loopback_ = true; 304 std::vector<rtc::scoped_refptr<webrtc::RtpSenderInterface>> senders = 305 peer_connection_->GetSenders(); 306 peer_connection_ = nullptr; 307 if (CreatePeerConnection(/*dtls=*/false)) { 308 for (const auto& sender : senders) { 309 peer_connection_->AddTrack(sender->track(), sender->stream_ids()); 310 } 311 peer_connection_->CreateOffer( 312 this, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions()); 313 } 314 return peer_connection_ != nullptr; 315 } 316 317 bool Conductor::CreatePeerConnection(bool dtls) { 318 RTC_DCHECK(peer_connection_factory_); 319 RTC_DCHECK(!peer_connection_); 320 321 webrtc::PeerConnectionInterface::RTCConfiguration config; 322 config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan; 323 config.enable_dtls_srtp = dtls; 324 webrtc::PeerConnectionInterface::IceServer server; 325 server.uri = GetPeerConnectionString(); 326 config.servers.push_back(server); 327 328 peer_connection_ = peer_connection_factory_->CreatePeerConnection( 329 config, nullptr, nullptr, this); 330 return peer_connection_ != nullptr; 331 } 332 333 void Conductor::DeletePeerConnection() { 334 main_wnd_->StopLocalRenderer(); 335 main_wnd_->StopRemoteRenderer(); 336 peer_connection_ = nullptr; 337 peer_connection_factory_ = nullptr; 338 peer_id_ = -1; 339 loopback_ = false; 340 } 341 342 void Conductor::EnsureStreamingUI() { 343 RTC_DCHECK(peer_connection_); 344 if (main_wnd_->IsWindow()) { 345 if (main_wnd_->current_ui() != MainWindow::STREAMING) 346 main_wnd_->SwitchToStreamingUI(); 347 } 348 } 349 350 // 351 // PeerConnectionObserver implementation. 352 // 353 354 void Conductor::OnAddTrack( 355 rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver, 356 const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>& 357 streams) { 358 RTC_LOG(INFO) << __FUNCTION__ << " " << receiver->id(); 359 main_wnd_->QueueUIThreadCallback(NEW_TRACK_ADDED, 360 receiver->track().release()); 361 } 362 363 void Conductor::OnRemoveTrack( 364 rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver) { 365 RTC_LOG(INFO) << __FUNCTION__ << " " << receiver->id(); 366 main_wnd_->QueueUIThreadCallback(TRACK_REMOVED, receiver->track().release()); 367 } 368 369 void Conductor::OnIceCandidate(const webrtc::IceCandidateInterface* candidate) { 370 RTC_LOG(INFO) << __FUNCTION__ << " " << candidate->sdp_mline_index(); 371 // For loopback test. To save some connecting delay. 372 if (loopback_) { 373 if (!peer_connection_->AddIceCandidate(candidate)) { 374 RTC_LOG(WARNING) << "Failed to apply the received candidate"; 375 } 376 return; 377 } 378 379 Json::StyledWriter writer; 380 Json::Value jmessage; 381 382 jmessage[kCandidateSdpMidName] = candidate->sdp_mid(); 383 jmessage[kCandidateSdpMlineIndexName] = candidate->sdp_mline_index(); 384 std::string sdp; 385 if (!candidate->ToString(&sdp)) { 386 RTC_LOG(LS_ERROR) << "Failed to serialize candidate"; 387 return; 388 } 389 jmessage[kCandidateSdpName] = sdp; 390 SendMessage(writer.write(jmessage)); 391 } 392 393 // 394 // PeerConnectionClientObserver implementation. 395 // 396 397 void Conductor::OnSignedIn() { 398 RTC_LOG(INFO) << __FUNCTION__; 399 main_wnd_->SwitchToPeerList(client_->peers()); 400 } 401 402 void Conductor::OnDisconnected() { 403 RTC_LOG(INFO) << __FUNCTION__; 404 405 DeletePeerConnection(); 406 407 if (main_wnd_->IsWindow()) 408 main_wnd_->SwitchToConnectUI(); 409 } 410 411 void Conductor::OnPeerConnected(int id, const std::string& name) { 412 RTC_LOG(INFO) << __FUNCTION__; 413 // Refresh the list if we're showing it. 414 if (main_wnd_->current_ui() == MainWindow::LIST_PEERS) 415 main_wnd_->SwitchToPeerList(client_->peers()); 416 } 417 418 void Conductor::OnPeerDisconnected(int id) { 419 RTC_LOG(INFO) << __FUNCTION__; 420 if (id == peer_id_) { 421 RTC_LOG(INFO) << "Our peer disconnected"; 422 main_wnd_->QueueUIThreadCallback(PEER_CONNECTION_CLOSED, NULL); 423 } else { 424 // Refresh the list if we're showing it. 425 if (main_wnd_->current_ui() == MainWindow::LIST_PEERS) 426 main_wnd_->SwitchToPeerList(client_->peers()); 427 } 428 } 429 430 void Conductor::OnMessageFromPeer(int peer_id, const std::string& message) { 431 RTC_DCHECK(peer_id_ == peer_id || peer_id_ == -1); 432 RTC_DCHECK(!message.empty()); 433 434 if (!peer_connection_.get()) { 435 RTC_DCHECK(peer_id_ == -1); 436 peer_id_ = peer_id; 437 438 if (!InitializePeerConnection()) { 439 RTC_LOG(LS_ERROR) << "Failed to initialize our PeerConnection instance"; 440 client_->SignOut(); 441 return; 442 } 443 } else if (peer_id != peer_id_) { 444 RTC_DCHECK(peer_id_ != -1); 445 RTC_LOG(WARNING) 446 << "Received a message from unknown peer while already in a " 447 "conversation with a different peer."; 448 return; 449 } 450 451 Json::Reader reader; 452 Json::Value jmessage; 453 if (!reader.parse(message, jmessage)) { 454 RTC_LOG(WARNING) << "Received unknown message. " << message; 455 return; 456 } 457 std::string type_str; 458 std::string json_object; 459 460 rtc::GetStringFromJsonObject(jmessage, kSessionDescriptionTypeName, 461 &type_str); 462 if (!type_str.empty()) { 463 if (type_str == "offer-loopback") { 464 // This is a loopback call. 465 // Recreate the peerconnection with DTLS disabled. 466 if (!ReinitializePeerConnectionForLoopback()) { 467 RTC_LOG(LS_ERROR) << "Failed to initialize our PeerConnection instance"; 468 DeletePeerConnection(); 469 client_->SignOut(); 470 } 471 return; 472 } 473 absl::optional<webrtc::SdpType> type_maybe = 474 webrtc::SdpTypeFromString(type_str); 475 if (!type_maybe) { 476 RTC_LOG(LS_ERROR) << "Unknown SDP type: " << type_str; 477 return; 478 } 479 webrtc::SdpType type = *type_maybe; 480 std::string sdp; 481 if (!rtc::GetStringFromJsonObject(jmessage, kSessionDescriptionSdpName, 482 &sdp)) { 483 RTC_LOG(WARNING) << "Can't parse received session description message."; 484 return; 485 } 486 webrtc::SdpParseError error; 487 std::unique_ptr<webrtc::SessionDescriptionInterface> session_description = 488 webrtc::CreateSessionDescription(type, sdp, &error); 489 if (!session_description) { 490 RTC_LOG(WARNING) << "Can't parse received session description message. " 491 "SdpParseError was: " 492 << error.description; 493 return; 494 } 495 RTC_LOG(INFO) << " Received session description :" << message; 496 peer_connection_->SetRemoteDescription( 497 DummySetSessionDescriptionObserver::Create(), 498 session_description.release()); 499 if (type == webrtc::SdpType::kOffer) { 500 peer_connection_->CreateAnswer( 501 this, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions()); 502 } 503 } else { 504 std::string sdp_mid; 505 int sdp_mlineindex = 0; 506 std::string sdp; 507 if (!rtc::GetStringFromJsonObject(jmessage, kCandidateSdpMidName, 508 &sdp_mid) || 509 !rtc::GetIntFromJsonObject(jmessage, kCandidateSdpMlineIndexName, 510 &sdp_mlineindex) || 511 !rtc::GetStringFromJsonObject(jmessage, kCandidateSdpName, &sdp)) { 512 RTC_LOG(WARNING) << "Can't parse received message."; 513 return; 514 } 515 webrtc::SdpParseError error; 516 std::unique_ptr<webrtc::IceCandidateInterface> candidate( 517 webrtc::CreateIceCandidate(sdp_mid, sdp_mlineindex, sdp, &error)); 518 if (!candidate.get()) { 519 RTC_LOG(WARNING) << "Can't parse received candidate message. " 520 "SdpParseError was: " 521 << error.description; 522 return; 523 } 524 if (!peer_connection_->AddIceCandidate(candidate.get())) { 525 RTC_LOG(WARNING) << "Failed to apply the received candidate"; 526 return; 527 } 528 RTC_LOG(INFO) << " Received candidate :" << message; 529 } 530 } 531 532 void Conductor::OnMessageSent(int err) { 533 // Process the next pending message if any. 534 main_wnd_->QueueUIThreadCallback(SEND_MESSAGE_TO_PEER, NULL); 535 } 536 537 void Conductor::OnServerConnectionFailure() { 538 main_wnd_->MessageBox("Error", ("Failed to connect to " + server_).c_str(), 539 true); 540 } 541 542 // 543 // MainWndCallback implementation. 544 // 545 546 void Conductor::StartLogin(const std::string& server, int port) { 547 if (client_->is_connected()) 548 return; 549 server_ = server; 550 client_->Connect(server, port, GetPeerName()); 551 } 552 553 void Conductor::DisconnectFromServer() { 554 if (client_->is_connected()) 555 client_->SignOut(); 556 } 557 558 void Conductor::ConnectToPeer(int peer_id) { 559 RTC_DCHECK(peer_id_ == -1); 560 RTC_DCHECK(peer_id != -1); 561 562 if (peer_connection_.get()) { 563 main_wnd_->MessageBox( 564 "Error", "We only support connecting to one peer at a time", true); 565 return; 566 } 567 568 if (InitializePeerConnection()) { 569 peer_id_ = peer_id; 570 peer_connection_->CreateOffer( 571 this, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions()); 572 } else { 573 main_wnd_->MessageBox("Error", "Failed to initialize PeerConnection", true); 574 } 575 } 576 577 void Conductor::AddTracks() { 578 if (!peer_connection_->GetSenders().empty()) { 579 return; // Already added tracks. 580 } 581 582 rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track( 583 peer_connection_factory_->CreateAudioTrack( 584 kAudioLabel, peer_connection_factory_->CreateAudioSource( 585 cricket::AudioOptions()))); 586 auto result_or_error = peer_connection_->AddTrack(audio_track, {kStreamId}); 587 if (!result_or_error.ok()) { 588 RTC_LOG(LS_ERROR) << "Failed to add audio track to PeerConnection: " 589 << result_or_error.error().message(); 590 } 591 592 rtc::scoped_refptr<MyDesktopCapture> video_device = MyDesktopCapture::Create(15,0); 593 //rtc::scoped_refptr<CapturerTrackSource> video_device = CapturerTrackSource::Create(); 594 595 if (video_device) { 596 rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track_( 597 peer_connection_factory_->CreateVideoTrack(kVideoLabel, video_device)); 598 video_device->StartCapture(); 599 main_wnd_->StartLocalRenderer(video_track_); 600 601 result_or_error = peer_connection_->AddTrack(video_track_, {kStreamId}); 602 if (!result_or_error.ok()) { 603 RTC_LOG(LS_ERROR) << "Failed to add video track to PeerConnection: " 604 << result_or_error.error().message(); 605 } 606 } else { 607 RTC_LOG(LS_ERROR) << "OpenVideoCaptureDevice failed"; 608 } 609 610 main_wnd_->SwitchToStreamingUI(); 611 } 612 613 void Conductor::DisconnectFromCurrentPeer() { 614 RTC_LOG(INFO) << __FUNCTION__; 615 if (peer_connection_.get()) { 616 client_->SendHangUp(peer_id_); 617 DeletePeerConnection(); 618 } 619 620 if (main_wnd_->IsWindow()) 621 main_wnd_->SwitchToPeerList(client_->peers()); 622 } 623 624 void Conductor::UIThreadCallback(int msg_id, void* data) { 625 switch (msg_id) { 626 case PEER_CONNECTION_CLOSED: 627 RTC_LOG(INFO) << "PEER_CONNECTION_CLOSED"; 628 DeletePeerConnection(); 629 630 if (main_wnd_->IsWindow()) { 631 if (client_->is_connected()) { 632 main_wnd_->SwitchToPeerList(client_->peers()); 633 } else { 634 main_wnd_->SwitchToConnectUI(); 635 } 636 } else { 637 DisconnectFromServer(); 638 } 639 break; 640 641 case SEND_MESSAGE_TO_PEER: { 642 RTC_LOG(INFO) << "SEND_MESSAGE_TO_PEER"; 643 std::string* msg = reinterpret_cast<std::string*>(data); 644 if (msg) { 645 // For convenience, we always run the message through the queue. 646 // This way we can be sure that messages are sent to the server 647 // in the same order they were signaled without much hassle. 648 pending_messages_.push_back(msg); 649 } 650 651 if (!pending_messages_.empty() && !client_->IsSendingMessage()) { 652 msg = pending_messages_.front(); 653 pending_messages_.pop_front(); 654 655 if (!client_->SendToPeer(peer_id_, *msg) && peer_id_ != -1) { 656 RTC_LOG(LS_ERROR) << "SendToPeer failed"; 657 DisconnectFromServer(); 658 } 659 delete msg; 660 } 661 662 if (!peer_connection_.get()) 663 peer_id_ = -1; 664 665 break; 666 } 667 668 case NEW_TRACK_ADDED: { 669 auto* track = reinterpret_cast<webrtc::MediaStreamTrackInterface*>(data); 670 if (track->kind() == webrtc::MediaStreamTrackInterface::kVideoKind) { 671 auto* video_track = static_cast<webrtc::VideoTrackInterface*>(track); 672 main_wnd_->StartRemoteRenderer(video_track); 673 } 674 track->Release(); 675 break; 676 } 677 678 case TRACK_REMOVED: { 679 // Remote peer stopped sending a track. 680 auto* track = reinterpret_cast<webrtc::MediaStreamTrackInterface*>(data); 681 track->Release(); 682 break; 683 } 684 685 default: 686 RTC_NOTREACHED(); 687 break; 688 } 689 } 690 691 void Conductor::OnSuccess(webrtc::SessionDescriptionInterface* desc) { 692 RTC_LOG(INFO) << __FUNCTION__; 693 peer_connection_->SetLocalDescription( 694 DummySetSessionDescriptionObserver::Create(), desc); 695 696 std::string sdp; 697 desc->ToString(&sdp); 698 699 // For loopback test. To save some connecting delay. 700 if (loopback_) { 701 // Replace message type from "offer" to "answer" 702 std::unique_ptr<webrtc::SessionDescriptionInterface> session_description = 703 webrtc::CreateSessionDescription(webrtc::SdpType::kAnswer, sdp); 704 peer_connection_->SetRemoteDescription( 705 DummySetSessionDescriptionObserver::Create(), 706 session_description.release()); 707 return; 708 } 709 710 Json::StyledWriter writer; 711 Json::Value jmessage; 712 jmessage[kSessionDescriptionTypeName] = 713 webrtc::SdpTypeToString(desc->GetType()); 714 jmessage[kSessionDescriptionSdpName] = sdp; 715 SendMessage(writer.write(jmessage)); 716 } 717 718 void Conductor::OnFailure(webrtc::RTCError error) { 719 RTC_LOG(LERROR) << ToString(error.type()) << ": " << error.message(); 720 } 721 722 void Conductor::SendMessage(const std::string& json_object) { 723 std::string* msg = new std::string(json_object); 724 main_wnd_->QueueUIThreadCallback(SEND_MESSAGE_TO_PEER, msg); 725 }
改好之后就打开vc++的命令行窗口
并执行以下代码进行编译
set WORKSPACE=E:\webrtc set PATH=%WORKSPACE%\depot_tools;%PATH% cd /d %WORKSPACE%\webrtc-checkout\src
set DEPOT_TOOLS_WIN_TOOLCHAIN=0 set GYP_MSVS_VERSION=2019 gn gen out\Default --args="is_debug=false" ninja -C out\Default
(如果是编译32位版本,则需要加入target_cpu=\"x86\")
编译完成的截图如下
如果你编译过程中报错,可能是由于你的操作系统登录名为中文,则需要手动改一下配置文件(检查如下图所示部位是否为空,为空则自行手动加入)
最后是测试,我们找一台服务器来运行peerconnection_server端
然后找两台电脑运行peerconnection_client端
(上文中我使用了n台电脑来演示步骤,力争简洁和完整。所以有时候读者会发现图片的风格从win10/win11/win server切换了,那是因为我需要去外网下代码,编译/运行等)
有高手希望指点的话可以通过微信与我联系,我的id是wxid_8r2mjkbcu2an22
最后修改时间 2021-10-24 10:50:16
如果要寻找特定版本,可以从这个网址。
然后切换到特定版本
cd /d %WORKSPACE%\webrtc-checkout\src git checkout branch-heads/5060 gclient sync -D -r branch-heads/5060 # cd .. # gn gen...
最后修改时间 2022-09-11 19:53:14