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,默认是没勾选的哦)
为了实现屏幕共享,我们还需要改动示例代码


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 }
conductor.cc
改好之后就打开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
Windows编译运行webrtc全过程,并实现屏幕共享的更多相关文章
- Windows编译运行webrtc全过程
年纪大了,不想写什么开头.摘要,咱直接开始吧. 不过首先还是要感谢声网提供的webrtc国内源码镜像. 首先,编译webrtc你需要一台win10,而且必须得是一直在更新版本的.因为编译过程需要用到c ...
- 在Windows命令行中编译运行C/C++程序
此处运行环境是在Windos下,运行cmd命令进入DOS界面 现在有一段简单C++代码(文件名为 demo.cpp),用于计算a*b的值 #include<iostream> using ...
- Windows/Linux下引用jar包,并用javac/java编译运行
Windows/Linux下引用jar包,并用javac/java编译运行,有需要的朋友可以参考下. 1> Windows 假设要引用的jar放在D:/test目录下,名字为t1.jar, ja ...
- JAVA 基础开发环境 vscode 搭建 Windows下VSCode编译运行简单java
JAVA 基础开发环境 vscode 搭建 来源 https://www.cnblogs.com/freewsf/p/7744728.html 对于使用 Visual Studio Code 的 Ja ...
- vscode配置编译运行调试C/C++文件-windows环境
在windows环境下,编译运行小文件的C/C++环境 软件准备: vscode mingw64(官网下特别慢,可以在devc++安装软件里中找,放到全局变量中) 插件下载: Run Code C/C ...
- Linux程序在Windows下编译运行_MinGW和Cygwin
linux要在windows下编译运行,需要win下的gcc编译器,一般有两种:MinGW和Cygwin. 但某些函数在windows没有,即使使用两种工具也编译不过,需要查询windows函数并使用 ...
- Windows用cmd编译运行C程序
在Windows环境下用命令行编译运行程序 浙江大学-C语言程序设计进阶 配置gcc 准备一个Dev-cpp 找到gcc.exe所在目录 Dev-Cpp\MinGW64\bin 地址栏右键将地址复制为 ...
- webrtc windows编译记录
//cmd set path=D:\zzh\depot_tools;%path% set DEPOT_TOOLS_WIN_TOOLCHAIN 0 set vs2022_install=C:\Progr ...
- Windows下使用MinGW在命令行编译运行C++程序
之前学习C语言的时候都是用IDE类似CodeBlocks的工具写完直接编译运行的,今天突然心血来潮,自己下一个编译器,在命令行下,编译运行C++程序,了解一下编译过程. 一.安装编译器 首先你需要下载 ...
- 如何用javac 和java 编译运行整个Java工程 (转载)【转】在Linux下编译与执行Java程序
如何用javac 和java 编译运行整个Java工程 (转载) http://blog.csdn.net/huagong_adu/article/details/6929817 [转]在Linux ...
随机推荐
- 9组-Beta冲刺-2/5
一.基本情况(15分) 队名:不行就摆了吧 组长博客:9组-Beta冲刺-2/5 GitHub链接:https://github.com/miaohengming/studynote/tree/mai ...
- Java抽象类 小白版
什么是抽象 抽象就是从多个事物中将共性的,本质的内容抽象出来. 什么是抽象类 Java语言中,用abstract关键字修饰的类叫作抽象类.类本身是不存在的,所以抽象类无法创建对象无法实例化. 在面向对 ...
- 一种很变态但有效的DDD建模沟通方式
本文书接上回<这就是为什么你学不会DDD>,关注公众号(老肖想当外语大佬)获取信息: 最新文章更新: DDD框架源码(.NET.Java双平台): 加群畅聊,建模分析.技术实现交流: 视频 ...
- CC2530系列课程 | IAR新建一个工程
之前录制了无线传感网综合项目实战课程,这个课程非常适合应届毕业生和想转行Linux的朋友,用来增加项目经验. 其中一部分内容是关于CC2530+zigbee的知识,后面会更新几篇关于cc2530的文章 ...
- 千牛hook 旺旺hook,旺旺发消息call,千牛发消息call,千牛机器人,破解旺旺发消息代码,破解千牛发消息代码,反汇编旺旺发消息,反汇编千牛发消息,旺旺发消息组件,千牛发消息组件
由于工作需要,做了相关的编码,有demo,拿去后,直接按demo写代码即可实现千牛发消息,非常稳定.非反汇编找call,基本不怕千牛升级,原理是基于千牛架构做出来的,除非千牛改架构,已稳定使用2年,未 ...
- 如果nacos注册中心挂了怎么办
当服务异常宕机,Nacos还未反应过来时,可能会发生的状况以及现有的解决方案. Nacos的健康检查 故事还要从Nacos对服务实例的健康检查说起. Nacos目前支持临时实例使用心跳上报方式维持活性 ...
- C++ : 仅添加一个引用& 就直接导致程序崩溃
问题描述 在项目某次开发中,测试过程中出现了coredump问题.经过asan工具检测,报了heap-use-after-free内存错误,最终定位到竟是无意中添加了一个引用&导致的! 开发时 ...
- Element——前端样式美化
Element 简介 Element 快速入门 https://element.eleme.cn/#/zh-CN/component/button Element 布局 ht ...
- C语言实现面向对象方法学的GLib、GObject-初体验
0. 扫盲: GLib是用C写的一些utilities,即C的工具库,和libc/glibc(GNU C Library)没有关系. GLib是 Gtk+ 库和 Gnome 的基础.GLib可以在多个 ...
- 2024csps初赛记
对于此次初赛,教训有不少,有一些差点把自己整死. 第一点,铅笔只能用2B,不要尝试使用HB 2nd:一定要带涂卡笔和橡皮,不然就算借别人用了也会发现橡皮还不如手擦的干净(可能因为这个原因我都要丢几分) ...