WebRTCexamplepeerconnection介绍
⼀. 前⾔
WebRTC 提供了许多 example,本⽂介绍 peerconnection example 的使⽤与代码流程分析,通过该⽰例可以帮助理解 WebRTC 信令交互,媒体协商,⾳视频数据交互等流程。
该⽰例涉及两个⾓⾊:peerconnection_rver,peerconnection_client。peerconnection_rver 是⼀个信令服务器,它负责连接成员的管理以及信令交互与转发。peerconnection_client 是⼀个⽤于通话的客户端程序,它负责与信令服务器交互以及⾳视频的采集,编码,打包发送,接收,渲染。
⼆. peerconnection example 使⽤说明
1. 运⾏ ,启动后界⾯如下。
2. 在机器 1 运⾏ ,输⼊服务器 IP 和端⼝后点击 Connect,完成后页⾯如下,
List Of currently connected peers 会显⽰其他已加⼊的 peer(此时还没有其他 peer 加⼊)。
3. 在机器 2 同样运⾏ ,输⼊服务器 IP 和端⼝后点击 Connect,此时机器 1 和机器 2 上可以看到对端peer。
4. 双击 peer,即可开启⾳视频通话。
三. peerconnection_rver
peerconnection_rver 是⼀个 lect 模型的⾼并发服务器,它负责连接管理和信令消息中转,信令是使⽤ HTTP 短连接的⽅式,主要有 sign_in,message,wait,sign_out 信令,信令时序和作⽤如下所⽰。
信令⽅法含义⽰例
sign_in GET登⼊GET /sign_in?%s HTTP/1.0\r\n\r\n
message POST peerid发送消息给to POST /message?peer_id=%i&to=%i HTTP/1.0\r\n
Content-Length: %zu\r\n
Content-Type: text/plain\r\n\r\n
wait GET等待消息GET /wait?peer_id=%i HTTP/1.0\r\n\r\n
sign_out GET退出登录GET /sign_out?peer_id=%i HTTP/1.0\r\n\r\n
四. peerconnection_client
1. 类图关系介绍
peerconnection_client 是⼀个⽤于通话的客户端,核⼼类为 Conductor,它主要包含了 MainWindow 和 PeerConnectionClient 两个核⼼类对象(实际上它是⼀个中转调⽤的对象),前者是处理 Windows 窗⼝和消息的类,后者是与信令服务器交互的类,类关系图如
下。
2. 程序时序图
a. 创建MainWnd,PeerConnectionClient,Conductor类对象
peerconnection_client 程序时序图如上所⽰,⾸先创建 MainWnd 对象,调⽤ MainWnd::Create 函数注册窗⼝类,然后创建窗
⼝,显⽰窗⼝,接下来创建 PeerConnectionClient 对象,并使⽤ MainWnd 和 PeerConnectionClient 对象初始化 Conductor。
1int PASCAL wWinMain(HINSTANCE instance,
2 HINSTANCE prev_instance,糖腌柠檬
3 wchar_t* cmd_line,
4 int cmd_show) {
5 // 省略...
6
7 const std::string rver = absl::GetFlag(FLAGS_rver);
8 MainWnd wnd(rver.c_str(), absl::GetFlag(FLAGS_port),
9 absl::GetFlag(FLAGS_autoconnect), absl::GetFlag(FLAGS_autocall));
tbt通报10 if (!wnd.Create()) {
11 RTC_NOTREACHED();
12 return -1;
13 }
14
15 rtc::InitializeSSL();
16 PeerConnectionClient client;
17 rtc::scoped_refptr<Conductor> conductor(
18 new rtc::RefCountedObject<Conductor>(&client, &wnd));
19
20 // Main loop.
21 MSG msg;
部队班长22 BOOL gm;
23 while ((gm = ::GetMessage(&msg, NULL, 0, 0)) != 0 && gm != -1) {
24 if (!wnd.PreTranslateMessage(&msg)) {
25 ::TranslateMessage(&msg);
26 ::DispatchMessage(&msg);
27 }
28 }
29
30 // 省略...
31
32 return 0;
33}
MainWnd 窗⼝创建的主要逻辑:RegisterWindowClass 注册窗⼝类和消息处理函数,CreateWindowExW 创建窗⼝,CreateChildWindows 创建⼦窗⼝,SwitchToConnectUI 切换到进⾏连接服务器的窗⼝页⾯。
1bool MainWnd::Create() {
2 RTC_DCHECK(wnd_ == NULL);
3 if (!RegisterWindowClass())
4 return fal;
5
6 ui_thread_id_ = ::GetCurrentThreadId();
7 wnd_ =
8 ::CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, kClassName, L"WebRTC",
9 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
10 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
11 CW_USEDEFAULT, NULL, NULL, GetModuleHandle(NULL), this);
12
13 ::SendMessage(wnd_, WM_SETFONT, reinterpret_cast<WPARAM>(GetDefaultFont()),
14 TRUE);
15
16 CreateChildWindows();
17 SwitchToConnectUI();
18
19 return wnd_ != NULL;
20}
1bool MainWnd::RegisterWindowClass() {
2 if (wnd_class_)
3 return true;
心梗有什么症状4
5 WNDCLASSEXW wcex = {sizeof(WNDCLASSEX)};
6 wcex.style = CS_DBLCLKS;
7 wcex.hInstance = GetModuleHandle(NULL);
8 wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
9 wcex.hCursor = ::LoadCursor(NULL, IDC_ARROW);
10 wcex.lpfnWndProc = &WndProc;
11 wcex.lpszClassName = kClassName;
12 wnd_class_ = ::RegisterClassExW(&wcex);
13 RTC_DCHECK(wnd_class_ != 0);
14 return wnd_class_ != 0;
15}
姚雪芬
GetMessage,wnd.PreTranslateMessage,TranslateMessage,DispatchMessage 是窗⼝消息获取,消息转换,消息分发的框架代码,有了它我们可以获取窗⼝的消息事件,并进⾏相应的回调操作。
动漫正太图片1// Main loop.
2MSG msg;
3BOOL gm;
4while ((gm = ::GetMessage(&msg, NULL, 0, 0)) != 0 && gm != -1) {
5 if (!wnd.PreTranslateMessage(&msg)) {
6 ::TranslateMessage(&msg);
7 ::DispatchMessage(&msg);
8 }
9}
1bool MainWnd::PreTranslateMessage(MSG* msg) {
2 bool ret = fal;
3 if (msg->message == WM_CHAR) {
4 if (msg->wParam == VK_TAB) {龙陵战役
5 HandleTabbing();
6 ret = true;
7 } el if (msg->wParam == VK_RETURN) {
8 OnDefaultAction();
9 ret = true;
10 } el if (msg->wParam == VK_ESCAPE) {
11 if (callback_) {
12 if (ui_ == STREAMING) {
13 callback_->DisconnectFromCurrentPeer();
14 } el {
15 callback_->DisconnectFromServer();
16 }
17 }
18 }
19 } el if (msg->hwnd == NULL && msg->message == UI_THREAD_CALLBACK) {
20 callback_->UIThreadCallback(static_cast<int>(msg->wParam),
21 reinterpret_cast<void*>(msg->lParam));婚礼开场音乐
22 ret = true;
23 }
24 return ret;
25}
b. 点击Connect连接信令服务器
当窗⼝捕捉到⽤户点击 Connect 按键的事件后调⽤ Conductor->StartLogin 函数,然后调⽤ PeerConnectionClient->Connect 函数连接信令服务器,Connect 函数是通过 DoConnect 创建 Socket 连接到信令服务器,并注册了 Socket 的回调处理函数。