系列文章目录
Webrtc从理论到实践一:初识
Webrtc从理论到实践二: 架构
Webrtc从理论到实践三: 角色
Webrtc从理论到实践四: 通信
Webrtc从理论到实践五: 编译webrtc源码
Webrtc从理论到实践六: Webrtc官方demo运行
Webrtc从理论到实践七: 官方demo源码走读(peerconnection_server)
文章目录
前言
本文源码基于webrtc m89版本,分析peerconnection_client 源码。相较于peerconnection_server,client的处理逻辑要更复杂的多,它除了要处理信令之外,还要进行控制界面,渲染视频,协商媒体信息等一系列工作。
一、peerconnection_client目录结构
简单介绍一下各个文件所承担的功能:
- main.cc,完成一些初始化以及主流程的控制工作
- main_wnd.cc,负责Windows操作界面的控制以及视频的渲染工作
- peer_connection_client.cc,负责信令的收发工作
- conductor.cc,利用Webrtc库实现音视频通信。媒体协商,音视频数据的采集以及从track中读取视频数据进行渲染等。
- defaults.h中保存了诸如GetPeerConnectionString(),GetDefaultServerName()和GetPeerName()等几个常用函数。
二、PeerConnection_client类图
接着我们再从类的角度来介绍一下client几个主要类的功能和关系。
- MainWindow接口,主要定义了两类接口,一类用于操作界面的切换,如SwitchToConnectUI(),另一类用于视频渲染,比如:StartLocalRenderer(webrtc::VideoTrackInterface* local_video);
- MainWnd类,继承了MainWindow类并且实现了MainWindow的所有接口,此外MainWnd也承担了视频渲染的工作,所以内部包含了VideoRenderer对象。
- VideoRender类继承自VideoSink类,可以获取到视频帧,并且转化成BITMAP图像交给MainWnd渲染。
- PeerConnectionClient类,用于信令处理与收发,如sign_in,sign_out,message和wait信令。
- Conductor类继承了MainWndCallback和PeerConnectionObserver类,可以接收来自MainWnd和PeerConnectionClient类的通知消息。
三、时序图
接下来,我们对照上面的时序图结合源码来介绍一下client的实现原理.
MainWnd对象创建
在wWinMain函数中首先先去解析命令行参数获取服务端的Ip和Port,如果没有指定,则传递默认值“localhost”和8888。
WindowsCommandLineArguments win_args;
int argc = win_args.argc();
char** argv = win_args.argv();
absl::ParseCommandLine(argc, argv);
// InitFieldTrialsFromString stores the char*, so the char array must outlive
// the application.
const std::string forced_field_trials =
absl::GetFlag(FLAGS_force_fieldtrials);
webrtc::field_trial::InitFieldTrialsFromString(forced_field_trials.c_str());
// Abort if the user specifies a port that is outside the allowed
// range [1, 65535].
if ((absl::GetFlag(FLAGS_port) < 1) || (absl::GetFlag(FLAGS_port) > 65535)) {
printf("Error: %i is not a valid port.\n", absl::GetFlag(FLAGS_port));
return -1;
}
const std::string server = absl::GetFlag(FLAGS_server);
接着创建MainWnd对象,然后调用其Create()方法创建一个Windows窗口,
MainWnd wnd(server.c_str(), absl::GetFlag(FLAGS_port),
absl::GetFlag(FLAGS_autoconnect), absl::GetFlag(FLAGS_autocall));
if (!wnd.Create()) {
RTC_NOTREACHED();
return -1;
}
我们可以进入到Create()函数中来具体看一下进行了哪些操作,除了常规的注册窗体类,创建窗体之外还包含了CreateChildWindows()创建各种子控件,比如标签,编辑框,按钮等。最后是切换到待连接的界面。
bool MainWnd::Create() {
RTC_DCHECK(wnd_ == NULL);
if (!RegisterWindowClass())
return false;
ui_thread_id_ = ::GetCurrentThreadId();
wnd_ =
::CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, kClassName, L"WebRTC",
WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, NULL, NULL, GetModuleHandle(NULL), this);
::SendMessage(wnd_, WM_SETFONT, reinterpret_cast<WPARAM>(GetDefaultFont()),
TRUE);
CreateChildWindows();
SwitchToConnectUI();
return wnd_ != NULL;
}
PeerConnectionClient和Conductor对象创建
当主界面创建好之后,就会创建PeerConnectionClient对象为连接信令服务器做准备。最后创建Conductor对象,并且将MainWnd和PeerConnection