Linux UI
linux UI层使用了GTK显示框架,将点击、输入等事件使用信号槽的机制,将界面和需要执行的动作关联起来,如点击加入会议涉及到PeerConnection创建和连接,这里clicked是Button触发的信号,而Button触发时会自动触发row-activated信号,所以下面的两个回调都会被调用到,OnClickedCallback获取用户输入的登录服务IP地址和端口号,并向服务器发起HTTP登录请求,而row-activated信号的回调PeerConnection初始化并创建和发送SDP包。代码实现上将PeerConnection和windows作为两个独立的组件,用conductor类管理起来。
g_signal_connect(button, “clicked”, G_CALLBACK(OnClickedCallback), this);
g_signal_connect(peer_list_, “row-activated”,
G_CALLBACK(OnRowActivatedCallback), this);
P2P的创建过程有些琐碎,这里罗列如下:
peer_connection_factory_ = webrtc::CreatePeerConnectionFactory(
nullptr /* network_thread */, nullptr /* worker_thread */,
nullptr /* signaling_thread */, nullptr /* default_adm */,
webrtc::CreateBuiltinAudioEncoderFactory(),
webrtc::CreateBuiltinAudioDecoderFactory(),
webrtc::CreateBuiltinVideoEncoderFactory(),
webrtc::CreateBuiltinVideoDecoderFactory(), nullptr /* audio_mixer */,
nullptr /* audio_processing */);
//这里config的一些配置包括dtls是否启用等标识
peer_connection_ = peer_connection_factory_->CreatePeerConnection(
config, nullptr, nullptr, this);
rtc::scoped_refptrwebrtc::AudioTrackInterface audio_track(
peer_connection_factory_->CreateAudioTrack(
kAudioLabel, peer_connection_factory_->CreateAudioSource(
cricket::AudioOptions())));
auto result_or_error = peer_connection_->AddTrack(audio_track, {kStreamId});
rtc::scoped_refptr video_device =
CapturerTrackSource::Create();
if (video_device) {
rtc::scoped_refptrwebrtc::VideoTrackInterface video_track_(
peer_connection_factory_->CreateVideoTrack(kVideoLabel, video_device));
main_wnd_->StartLocalRenderer(video_track_);
result_or_error = peer_connection_->AddTrack(video_track_, {kStreamId});
发送完登录请求和SDP请求之后,由网络线程一直检测来自网络的数据,并触发相应的函数,如更新列表和对端发来的数据,最终调用OnMessageFromPeer处理对端发来的数据,如果对端是新来的,则会创建InitializePeerConnection对象,这在主动发起会议时已经见过,如果是主动发起方回调了这个函数,就不会再创建这个对象了,但是依然要解析对端的SDP信息,SDP信息是JSON格式。
std::unique_ptrwebrtc::SessionDescriptionInterface session_description =
webrtc::CreateSessionDescription(type, sdp, &error);
peer_connection_->SetRemoteDescription(
DummySetSessionDescriptionObserver::Create(),
session_description.release());
if (type == webrtc::SdpType::kOffer) {
peer_connection_->CreateAnswer(
this, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions());
}
拿到的信息除了SDP外还可能是打洞信息,则也需要将他们保存下来。
std::unique_ptrwebrtc::IceCandidateInterface candidate(
webrtc::CreateIceCandidate(sdp_mid, sdp_mlineindex, sdp, &error));
if (!peer_connection_->AddIceCandidate(candidate.get())) {
RTC_LOG(WARNING) << “Failed to apply the received candidate”;
return;
}
MAC UI
这里以MAC平台示例说明如何使用WebRTC,下图是object c所写的应用程序的界面,即上一节UI层相关内容:
程序最开始的执行函数在examples/objc/AppRTCMobile/mac目录的main.m(object c下的c扩展文件以.m结尾,c++扩展以.mm结尾),这个main函数如下:
APPRTCAppDelegate.h文件
@interface APPRTCAppDelegate : NSObject
@end
APPRTCAppDelegate.m文件
@implementation APPRTCAppDelegate {
APPRTCViewController* _viewController;
NSWindow* _window;
}
main.m文件
#import <AppKit/AppKit.h>
#import “APPRTCAppDelegate.h”
int main(int argc, char* argv[]) {
@autoreleasepool {
[NSApplication sharedApplication];
APPRTCAppDelegate* delegate = [[APPRTCAppDelegate alloc] init];
[NSApp setDelegate:delegate];
[NSApp run];
}
}
这个函数是object的语法,NSA