我是靠谱客的博主 优秀睫毛膏,这篇文章主要介绍webrtc源码分析,现在分享给大家,希望可以做个参考。

编译运行

在成功编译WebRTC源码之后,没有编译成功的可以直接下载我编译好的。https://github.com/hujianhua888/webrtc_vs2015 
成功编译后,可以运行WebRTC自带的例子体验一对一音视频通信效果。使用src/out/Debug 目录下的peerconnection_client.exe 和 peerconnection_server.exe两个文件,最终运行的架构图如下图所示: 
 
效果如下: 

局域网运行PeerConnection 例子需要用到两台电脑,并要求两台电脑都配置有摄像头和麦克风(没有的话,使用虚拟摄像头,看我之前的帧子)。测试步骤如下: 
1. 电脑A运行peerconnection_server.exe。 
2. 电脑A运行peerconnection_client.exe, Server一栏输入 localhost,点击Connect。 
3. 电脑B运行peerconnection_client.exe,Server一栏输入电脑A的局域网ip地址,点击Connect。 
4. 电脑A或电脑B双击列表框出现的第一个选项, 建立音视频通信。

代码解析

peerconnection_client 客户端代码框图如下: 

界面消息分发处理: 
下面函数,主要是私有消息,当我们通过程序处理得到sdp等信息时,通过调用 
void Conductor::OnSuccess(webrtc::SessionDescriptionInterface* desc) 调用sdp信息写 
jmessage[kSessionDescriptionSdpName] = sdp; 
SendMessage(writer.write(jmessage)); 
通过main_wnd_->QueueUIThreadCallback(SEND_MESSAGE_TO_PEER, msg)放入队列中,然后 
UIThreadCallback回调,进行消息的发送。

另外还有void Conductor::OnAddStream以及void Conductor::OnIceCandidate(const webrtc::IceCandidateInterface* candidate) 使用同样的方法进行消息发送。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
bool MainWnd::PreTranslateMessage(MSG* msg) { bool ret = false; if (msg->message == WM_CHAR) { if (msg->wParam == VK_TAB) { HandleTabbing(); ret = true; } else if (msg->wParam == VK_RETURN) { OnDefaultAction(); ret = true; } else if (msg->wParam == VK_ESCAPE) { if (callback_) { if (ui_ == STREAMING) { callback_->DisconnectFromCurrentPeer(); } else { callback_->DisconnectFromServer(); } } } } else if (msg->hwnd == NULL && msg->message == UI_THREAD_CALLBACK) { //通过此函数把SDP,ICE等信息发送到服务器 callback_->UIThreadCallback(static_cast<int>(msg->wParam), reinterpret_cast<void*>(msg->lParam)); ret = true; } return ret; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

Ui界面点击通过回调函数如下。 
以及socket收到消息时,通过下面回调进行处理。

复制代码
1
2
3
4
5
6
7
8
9
10
LRESULT CALLBACK MainWnd::WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { OnMessage//点击UI界面分发的消息主要通过此函数处理。 //bool MainWnd::OnMessage(UINT msg, WPARAM wp, LPARAM lp, LRESULT* result),实现包括连接peer功能。 } LRESULT Win32Window::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { OnMessage//收到服务器的消息通过此函数处理,并调用OnSocketNotify处理消息。 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

OnMessage创建时用来处理界面的消息程序,OnPaint()里面包括对视频图像的显示功能。

复制代码
1
2
3
4
5
if (ui_ == STREAMING && remote_renderer && local_renderer) { AutoLock<VideoRenderer> local_lock(local_renderer); AutoLock<VideoRenderer> remote_lock(remote_renderer); ...... }
  • 1
  • 2
  • 3
  • 4
  • 5

ui_值为CONNECT_TO_SERVER,LIST_PEERS,首先是为CONNECT_TO_SERVER显示连接到服务器的界面,当连接完成后,并且读到其他peer名字后,会置为LIST_PEERS,显示列表的界面。当点击连接与其他peer连接后,会进入到显示视频的界面。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
bool MainWnd::OnMessage(UINT msg, WPARAM wp, LPARAM lp, LRESULT* result) { switch (msg) { case WM_ERASEBKGND: *result = TRUE; return true; case WM_PAINT: OnPaint(); return true; case WM_SETFOCUS: if (ui_ == CONNECT_TO_SERVER) { SetFocus(edit1_); } else if (ui_ == LIST_PEERS) { SetFocus(listbox_); } return true; case WM_SIZE: if (ui_ == CONNECT_TO_SERVER) { LayoutConnectUI(true); } else if (ui_ == LIST_PEERS) { LayoutPeerListUI(true); } break; case WM_CTLCOLORSTATIC: *result = reinterpret_cast<LRESULT>(GetSysColorBrush(COLOR_WINDOW)); return true; case WM_COMMAND: if (button_ == reinterpret_cast<HWND>(lp)) { if (BN_CLICKED == HIWORD(wp)) OnDefaultAction(); } else if (listbox_ == reinterpret_cast<HWND>(lp)) { if (LBN_DBLCLK == HIWORD(wp)) { OnDefaultAction(); } } return true; case WM_CLOSE: if (callback_) callback_->Close(); break; } return false; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

Ui界面点击处理

OnDefaultAction 表示连接到服务器按下处理。 
(1)如果点击connect,那么执行StartLogin表示连接到服务器。那么将准备建立连接到服务器。那么会执行Connect等函数。其中DoConnect表示建立连接,OnConnect 表示发送消息,并读取peer列表,并且显示。详见下面的描述

(2)当得到peer列表时,点击相对应的peer,那么执行ConnectToPeer,表示创建p2p连接。那么会调用CreatePeerConnection等函数,创建本地信息。详见下面的描述

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if (ui_ == CONNECT_TO_SERVER) { std::string server(GetWindowText(edit1_)); std::string port_str(GetWindowText(edit2_)); int port = port_str.length() ? atoi(port_str.c_str()) : 0; callback_->StartLogin(server, port); } else if (ui_ == LIST_PEERS) { LRESULT sel = ::SendMessage(listbox_, LB_GETCURSEL, 0, 0); if (sel != LB_ERR) { LRESULT peer_id = ::SendMessage(listbox_, LB_GETITEMDATA, sel, 0); if (peer_id != -1 && callback_) { callback_->ConnectToPeer(peer_id); } } } else { MessageBoxA(wnd_, "OK!", "Yeah", MB_OK); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

连接到服务器 
执行StartLogin连接到服务器,当建立连接后,然后会收到服务器发过来的信息,包括peer name以及id,下面过程是读取其他客户端peer的名字。并进行显示。主要是socket接口回调PeerConnectionClient::OnRead来得到消息。 
void PeerConnectionClient::OnRead(rtc::AsyncSocket* socket) -> 
callback_->OnSignedIn()->SwitchToPeerList->LayoutPeerListUI

复制代码
1
2
3
4
5
if (ParseEntry(control_data_.substr(pos, eol - pos), &name, &id, &connected) && id != my_id_) { peers_[id] = name; callback_->OnPeerConnected(id, name); }
  • 1
  • 2
  • 3
  • 4
  • 5

当得到其他peer的名字,会把界面转为peer 列表。会调用PeerConnectionClient里面的callback_->OnSignedIn(); 
即void Conductor::OnSignedIn() ->SwitchToPeerList进行转化。 
连接到其他peer 
当点击其他peer名字,执行: 
MainWnd::WndProc->OnDefaultAction->ConnectToPeer->CreatePeerConnection->CreatePeerConnection 
MainWnd::WndProc->OnDefaultAction->ConnectToPeer->CreatePeerConnection-> AddStream 
ConnectToPeer当第二次调用OnDefaultAction,当前客户端连接到另一个客户端,即建立p2p连接。那么其中会调用AddStreams(), creatoffer等函数。 
其中在AddStreams()中调用: 
StartLocalRenderer 显示本地流。 
AddTrack 把流加载,用于进行传输。

本地消息发送函数

通过creatoffer得到本地的SDP信息后,然后需要把SDP信息发送到服务器。主要是通信把消息放在队列中,然后通过函数void Conductor::UIThreadCallback(int msg_id, void* data)实现发送。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void Conductor::UIThreadCallback(int msg_id, void* data) { case SEND_MESSAGE_TO_PEER: {//SEND_MESSAGE_TO_PEER 表示把当前的信息发送给服务器 LOG(INFO) << "SEND_MESSAGE_TO_PEER"; std::string* msg = reinterpret_cast<std::string*>(data);//SDP信息 if (!client_->SendToPeer(peer_id_, *msg) && peer_id_ != -1) { LOG(LS_ERROR) << "SendToPeer failed"; DisconnectFromServer(); } } case NEW_STREAM_ADDED: {//当建立p2p连接时,收到远程流,并且用于显示 webrtc::MediaStreamInterface* stream = reinterpret_cast<webrtc::MediaStreamInterface*>( data); webrtc::VideoTrackVector tracks = stream->GetVideoTracks(); // Only render the first track. if (!tracks.empty()) { webrtc::VideoTrackInterface* track = tracks[0]; main_wnd_->StartRemoteRenderer(track); } stream->Release(); break; } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

收到消息回调函数

OnMessage当建立socket连接时,用来接受服务器发送消息。其中调用OnSocketNotify

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void Win32Socket::OnSocketNotify(SOCKET socket, int event, int error) { case FD_READ: if (error != ERROR_SUCCESS) { ReportWSAError("WSAAsync:read notify", error, addr_); } else { SignalReadEvent(this); } break; case FD_WRITE: if (error != ERROR_SUCCESS) { ReportWSAError("WSAAsync:write notify", error, addr_); } else { SignalWriteEvent(this); } break; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

通过Win32Window::WndProc->OnSocketNotify->OnMessageFromPeer 表示收到远程的信息,其中会调用下面的OnAddStream等函数,被OnSocketNotify读函数调用,收到远程SDP等信息。

Win32Window::WndProc->OnSocketNotify->OnMessageFromPeer->SetRemoteDescription->void Conductor::OnAddStream 远程流调用函数,通过此方法接受远程信息,与socket读数据有点区别。

Win32Window::WndPro->void Conductor::OnIceCandidate(const webrtc::IceCandidateInterface* candidate)->SendMessage(writer.write(jmessage))->QueueUIThreadCallback(SEND_MESSAGE_TO_PEER, msg) 
收到ice信息。然后回调发送下一ice消息给远程。

如果收到SDP信息,在OnMessageFromPeer调用下面函数进行远程SDP设置。 
SetRemoteDescription->OnAddStream->main_wnd_->QueueUIThreadCallback(NEW_STREAM_ADDED, stream.release());通过此函数回调准备发送下一次的ICE信息。然后通过UIThreadCallback主动发送信息。

通过Win32Window::WndProc->OnSocketNotify-> OnIceCandidate 收到ice消息

void PeerConnectionClient::OnRead(rtc::AsyncSocket* socket) 读服务器的数据。

void MainWnd::VideoRenderer::OnFrame 表示接受视频数据。

重新VideoRenderer:此函数,这样能被调用。 
void OnFrame(const webrtc::VideoFrame& frame) override;

最后

以上就是优秀睫毛膏最近收集整理的关于webrtc源码分析的全部内容,更多相关webrtc源码分析内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(81)

评论列表共有 0 条评论

立即
投稿
返回
顶部