今天聊一下WebRTC。很多开发者,可能会觉得有些陌生,或者直接感觉繁杂。因为WebRTC在iOS上的应用,只是编译都让人很是头痛。这些话,到此为止,以防让了解者失去信心。我们只传播正能量,再多的困难都是可以解决的。本博客会不断更新增加内容,不要怕长。首先看一下定义。WebRTC,名称源自网页实时通信(WebReal-TimeCommunication)的缩写,是一个支持网页浏览器进行实时语音对话或视频对话的技术,是谷歌2010年以6820万美元收购GlobalIPSolutions公司而获得的一项技术。2011年5月开放了工程的源代码,在行业内得到了广泛的支持和应用,成为下一代视频通话的标准。
WebRTC实现了基于网页的视频会议,标准是WHATWG
协议,目的是通过浏览器提供简单的javascript就可以达到实时通讯(Real-Time Communications
(RTC))能力。
WebRTC(Web Real-TimeCommunication)项目的最终目的主要是让Web开发者能够基于浏览器(ChromeFireFox...)轻易快捷开发出丰富的实时多媒体应用,而无需下载安装任何插件,Web开发者也无需关注多媒体的数字信号处理过程,只需编写简单的Javascript程序即可实现,W3C等组织正在制定Javascript 标准API,目前是WebRTC1.0版本,Draft状态;另外WebRTC还希望能够建立一个多互联网浏览器间健壮的实时通信的平台,形成开发者与浏览器厂商良好的生态环境。同时,Google也希望和致力于让WebRTC的技术成为HTML5标准之一,可见Google布局之深远。
WebRTC提供了视频会议的核心技术,包括音视频的采集、编解码、网络传输、显示等功能,并且还支持跨平台:windows,linux,mac,android。
架构组件介绍
(1) Your Web App
Web开发者开发的程序,Web开发者可以基于集成WebRTC的浏览器提供的webAPI开发基于视频、音频的实时通信应用。
(2)Web API
面向第三方开发者的WebRTC标准API(Javascript),使开发者能够容易地开发出类似于网络视频聊天的web应用,最新的标准化进程可以查看这里。
这些API可分成Network Stream API、 RTCPeerConnection、Peer-to-peer
Data API三类,详细的API说明可以看这里。
Network Stream API
MediaStream:MediaStream用来表示一个媒体数据流。
MediaStreamTrack在浏览器中表示一个媒体源。
RTCPeerConnection
RTCPeerConnection:
一个RTCPeerConnection对象允许用户在两个浏览器之间直接通讯。
RTCIceCandidate :表示一个ICE协议的候选者。
RTCIceServer:表示一个ICE Server。
Peer-to-peer Data API
DataChannel:数据通道( DataChannel)接口表示一个在两个节点之间的双向的数据通道 。
(3)WebRTC Native C++ API
本地C++ API层,使浏览器厂商容易实现WebRTC标准的Web API,抽象地对数字信号过程进行处理。
(4)Transport / Session
传输/会话层
会话层组件采用了libjingle库的部分组件实现,无须使用xmpp/jingle协议
a. RTP Stack协议栈
Real Time Protocol
b. STUN/ICE
可以通过STUN和ICE组件来建立不同类型网络间的呼叫连接。
c. Session Management
一个抽象的会话层,提供会话建立和管理功能。该层协议留给应用开发者自定义实现。
(5)VoiceEngine
音频引擎是包含一系列音频多媒体处理的框架,包括从视频采集卡到网络传输端等整个解决方案。
PS:VoiceEngine是WebRTC极具价值的技术之一,是Google收购GIPS公司后开源的。在VoIP上,技术业界领先,后面的文章会详细了解
a. iSAC
Internet Speech Audio Codec
针对VoIP和音频流的宽带和超宽带音频编解码器,是WebRTC音频引擎的默认的编解码器
采样频率:16khz,24khz,32khz;(默认为16khz)
自适应速率为10kbit/s ~ 52kbit/;
自适应包大小:30~60ms;
算法延时:frame + 3ms
b.iLBC
Internet Low Bitrate Codec
VoIP音频流的窄带语音编解码器
采样频率:8khz;
20ms帧比特率为15.2kbps
30ms帧比特率为13.33kbps
标准由IETF RFC3951和RFC3952定义
c.NetEQ for Voice
针对音频软件实现的语音信号处理元件
NetEQ算法:自适应抖动控制算法以及语音包丢失隐藏算法。使其能够快速且高解析度地适应不断变化的网络环境,确保音质优美且缓冲延迟最小。
是GIPS公司独步天下的技术,能够有效的处理由于网络抖动和语音包丢失时候对语音质量产生的影响。
PS:NetEQ
也是WebRTC中一个极具价值的技术,对于提高VoIP质量有明显效果,加以AECNRAGC等模块集成使用,效果更好。
d.Acoustic Echo Canceler (AEC)
回声消除器是一个基于软件的信号处理元件,能实时的去除mic采集到的回声。
e.Noise Reduction (NR)
噪声抑制也是一个基于软件的信号处理元件,用于消除与相关VoIP的某些类型的背景噪声(嘶嘶声,风扇噪音等等… …)
(6)VideoEngine
WebRTC视频处理引擎
VideoEngine是包含一系列视频处理的整体框架,从摄像头采集视频到视频信息网络传输再到视频显示整个完整过程的解决方案。
a. VP8
视频图像编解码器,是WebRTC视频引擎的默认的编解码器
VP8适合实时通信应用场景,因为它主要是针对低延时而设计的编解码器。
PS:VPx编解码器是Google收购ON2公司后开源的,VPx现在是WebM项目的一部分,而WebM项目是Google致力于推动的HTML5标准之一
b. Video Jitter Buffer
视频抖动缓冲器,可以降低由于视频抖动和视频信息包丢失带来的不良影响。
c. Image enhancements
图像质量增强模块
对网络摄像头采集到的图像进行处理,包括明暗度检测、颜色增强、降噪处理等功能,用来提升视频质量。
视频
WebRTC的视频部分,包含采集、编解码(I420/VP8)、加密、媒体文件、图像处理、显示、网络传输与流控(RTP/RTCP)等功能。
视频采集---video_capture
源代码在webrtcmodulesvideo_capturemain目录下,包含接口和各个平台的源代码。
在windows平台上,WebRTC采用的是dshow技术,来实现枚举视频的设备信息和视频数据的采集,这意味着可以支持大多数的视频采集设备;对那些需要单独驱动程序的视频采集卡(比如海康高清卡)就无能为力了。
视频采集支持多种媒体类型,比如I420、YUY2、RGB、UYUY等,并可以进行帧大小和帧率控制。
视频编解码---video_coding
源代码在webrtcmodulesvideo_coding目录下。
WebRTC采用I420/VP8编解码技术。VP8是google收购ON2后的开源实现,并且也用在WebM项目中。VP8能以更少的数据提供更高质量的视频,特别适合视频会议这样的需求。
视频加密--video_engine_encryption
视频加密是WebRTC的video_engine一部分,相当于视频应用层面的功能,给点对点的视频双方提供了数据上的安全保证,可以防止在Web上视频数据的泄漏。
视频加密在发送端和接收端进行加解密视频数据,密钥由视频双方协商,代价是会影响视频数据处理的性能;也可以不使用视频加密功能,这样在性能上会好些。
视频加密的数据源可能是原始的数据流,也可能是编码后的数据流。估计是编码后的数据流,这样加密代价会小一些,需要进一步研究。
视频媒体文件--media_file
源代码在webrtcmodulesmedia_file目录下。
该功能是可以用本地文件作为视频源,有点类似虚拟摄像头的功能;支持的格式有Avi。
另外,WebRTC还可以录制音视频到本地文件,比较实用的功能。
视频图像处理--video_processing
源代码在webrtcmodulesvideo_processing目录下。
视频图像处理针对每一帧的图像进行处理,包括明暗度检测、颜色增强、降噪处理等功能,用来提升视频质量。
视频显示--video_render
源代码在webrtcmodulesvideo_render目录下。
在windows平台,WebRTC采用direct3d9和directdraw的方式来显示视频,只能这样,必须这样。
网络传输与流控
对于网络视频来讲,数据的传输与控制是核心价值。WebRTC采用的是成熟的RTP/RTCP技术。
音频
WebRTC的音频部分,包含设备、编解码(iLIBC/iSAC/G722/PCM16/RED/AVT、NetEQ)、加密、声音文件、声音处理、声音输出、音量控制、音视频同步、网络传输与流控(RTP/RTCP)等功能。
音频设备---audio_device
源代码在webrtcmodulesaudio_devicemain目录下,包含接口和各个平台的源代码。
在windows平台上,WebRTC采用的是Windows Core Audio和Windows
Wave技术来管理音频设备,还提供了一个混音管理器。
利用音频设备,可以实现声音输出,音量控制等功能。
音频编解码---audio_coding
源代码在webrtcmodulesaudio_coding目录下。
WebRTC采用iLIBC/iSAC/G722/PCM16/RED/AVT编解码技术。
WebRTC还提供NetEQ功能---抖动缓冲器及丢包补偿模块,能够提高音质,并把延迟减至最小。
另外一个核心功能是基于语音会议的混音处理。
声音加密--voice_engine_encryption
和视频一样,WebRTC也提供声音加密功能。
声音文件
该功能是可以用本地文件作为音频源,支持的格式有Pcm和Wav。
同样,WebRTC也可以录制音频到本地文件。
声音处理--audio_processing
源代码在webrtcmodulesaudio_processing目录下。
声音处理针对音频数据进行处理,包括回声消除(AEC)、AECM(AEC
Mobile)、自动增益(AGC)、降噪(NS)、静音检测(VAD)处理等功能,用来提升声音质量。
网络传输与流控
和视频一样,WebRTC采用的是成熟的RTP/RTCP技术。
好了,这么多的概念内容之后我要切入正题,iOS才是我们真正关心的。下面就进入我们关心的内容。
Webrtc的ios框架编译
1.WebRTC的iOS框架的选择
目前两个比较活跃的开源WebRTC实现.
Google WebRTC:
项目地址是: https://code.google.com/p/webrtc/
Ericsson Research OpenWebRTC:
项目地址是: https://github.com/EricssonResearch/openwebrtc
我们戴维营教育为了给学生实战项目中运用WebRTC视频通话技术,选择Google的WebRTC项目来构建iOS
App的开发框架,因为目前Chrome浏览器和FireFox浏览器的WebRTC支持都是采用该项目.那么问题就来了,既然浏览器里都支持了
WebRTC,那我们再去移植编译它到iOS平台干嘛呢,直接用webview 不行? 对,还不行!
Apple在这方面已经严重拖后腿了.不过他有他牛逼的Facetime技术,可以随时随地的视频通话,但是他不开源,所以我们只能垂涎了.
故还是老老实实的移植WebRTC吧.非常幸运的是,Google
的Chromium项目开发者已经实现了其WebRTC的Objective-C的一套API了.
不过,丑话还是说在前头好,要从零开始集成WebRTC到我们的App中中,
简直就是噩梦;因为WebRTC项目和Chromium项目有一定的关联依赖关系,而且这些项目都是跨平台的大项目,采用了Google自己的一套编译系
统,相对我们日常的IDE来说要复杂的多.如果我们需要得到一个WebRTC的库或者框架,我们就需要忘记Xcode
IDE和Interface Builder这些高科技,我们要切换到终端环境下用命令行下的黑科技来征服这一切.
2.开始WebRTC源码下载
前提条件:
我现在用的Macbook,8G内存,运行OS X 10.9.5.
安装最新的git和subversions并确保其可正常工作.
Xcode 6.1.1 和 Command Line Tools.
中国大陆用户额外要求,快速的VPN,或者快速的shadowsocks服务.(FQ和给git和svn以及curl设置代理等).
2.1 创建一个编译目录
我们创建一个目录专门来存放项目编译工具和项目代码仓库等.确保该目录所在磁盘可用空间至少有8~10G.打开系统的终端工具进入到Shell:
wuqiong:~ apple$mkdir -p$HOME/opensource/webrtc_build/
2.2 下载Chromium的depot工具
在执行下面命令之前,请确保你已经连上快速VPN已经FQ了,或者你已经给git单独配置了有效的socksFQ代理,如果你这些都不是问题,就当我没说.
wuqiong:~ apple$cd$HOME/opensource/webrtc_build/wuqiong:webrtc_build apple$git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
这是一套Google用来编译Chromium或者WebRTC的构建工具,在我们后续的编译过程中也将使用它.为了命令行使用方便,我们把这些工具的路径加入到系统环境变量PATH中去:
wuqiong:webrtc_build apple$echo"export PATH=$PWD/depot_tools:$PATH" >$HOME/.bash_profile
然后需要关闭当前终端重新开启一个来上面设置的环境变量生效.或者在现在终端执行入门命令在当前终端里加载生效:
wuqiong:webrtc_build apple$source$HOME/.bash_profile
2.3 下载WebRTC的源码
在我们的编译工作目录webrtc_build下创建一个webtrtc子目录来存放代码,请执行下面命令:
wuqiong:webrtc_build apple$ mkdirwebrtc wuqiong:webrtc_build apple$cd
webrtc
在上面的检查工作没错之后,我们就需要开始把WebRTC项目的代码仓库下载一份到本地来.由于其仓库之大,大约一共需要下载6G+的东西.所以这一步非常需要有耐心.而且需要有稳定无障碍的互联网.
执行如下命令然后吧:
wuqiong:webrtc apple$ gclient config--name src http://webrtc.googlecode.com/svn/trunk wuqiong:webrtcapple$echo"target_os = ['ios']" >>.gclient wuqiong:webrtc apple$ gclient sync
--force
FQ快的去喝咖啡,慢的去约妹子吧.办完事情之后回来如果上面的命令都一切顺利,我们就可以往下走去开始编译了.
(为了方便大家,我已经把webrtc_build目录打包备份,这样大家可以省去大量的代码下载时间.打包文件有5G,正在寻找网盘存放,随后公布.)
2.4 编译WebRTC.framework
到了这一步,源码应该已经下载好了.这些源码可以编译为好几个平台,OS X, Linux, Windows, Android,
iOS等.这里我们只需要编译iOS平台的WebRTC,并制作成一个iOS的开发框架.这里我们不能用Xcode工具,因为这些项目压根就不支持
XCode.我们需要在终端命令行环境下去搞定这一切!
首先,为了我们装逼玩黑武器,我们需要在webrtc的项目代码目录下创建一个脚本,
这个脚本就是我为了简化命令的复杂度和提高使用的方便性专门编写的一个一键框架编译脚本,这个脚本就是今天的核心黑科技了.先创建一个空文件,然后赋予执行权限:
wuqiong:webrtc apple$ touchbuild_webrtc.sh wuqiong:webrtc apple$ chmod +x
build_webrtc.sh
然后用编辑器打开编辑刚刚创建的脚本文件,把如下脚本粘贴进去之后保存并关闭:
1 #!/bin/bash
2 # Script to build WebRTC.framework for iOS
3 # Copyright (C) 2015 戴维营教育 - All Rights Reserved
4 # Last revised 28/1/2015
5 #
6
7 function build_iossim_ia32() {
8 echo "*** building WebRTC for the ia32 iOS simulator";
9 export GYP_GENERATORS="ninja";
10 export GYP_DEFINES="build_with_libjingle=1 build_with_chromium=0 libjingle_objc=1 OS=ios target_arch=ia32";
11 export GYP_GENERATOR_FLAGS="$GYP_GENERATOR_FLAGS output_dir=out_ios_ia32";
12 export GYP_CROSSCOMPILE=1;
13 pushd src;
14 gclient runhooks;
15 ninja -C out_ios_ia32/Release-iphonesimulator iossim AppRTCDemo;
16
17 echo "*** creating iOS ia32 libraries";
18 pushd out_ios_ia32/Release-iphonesimulator/;
19 rm -f libapprtc_signaling.a;
20 popd;
21 mkdir -p out_ios_ia32/libs;
22 libtool -static -o out_ios_ia32/libs/libWebRTC-ia32.a out_ios_ia32/Release-iphonesimulator/lib*.a;
23 strip -S -x -o out_ios_ia32/libs/libWebRTC.a -r out_ios_ia32/libs/libWebRTC-ia32.a;
24 rm -f out_ios_ia32/libs/libWebRTC-ia32.a;
25 echo "*** result: $PWD/out_ios_ia32/libs/libWebRTC.a";
26
27 popd;
28 }
29
30 function build_iossim_x86_64() {
31 echo "*** building WebRTC for the x86_64 iOS simulator";
32 export GYP_GENERATORS="ninja";
33 export GYP_DEFINES="build_with_libjingle=1 build_with_chromium=0 libjingle_objc=1 OS=ios target_arch=x64 target_subarch=arm64";
34 export GYP_GENERATOR_FLAGS="$GYP_GENERATOR_FLAGS output_dir=out_ios_x86_64";
35 export GYP_CROSSCOMPILE=1;
36 pushd src;
37 gclient runhooks;
38 ninja -C out_ios_x86_64/Release-iphonesimulator iossim AppRTCDemo;
39
40 echo "*** creating iOS x86_64 libraries";
41 pushd out_ios_x86_64/Release-iphonesimulator/;
42 rm -f libapprtc_signaling.a;
43 popd;
44 mkdir -p out_ios_x86_64/libs;
45 libtool -static -o out_ios_x86_64/libs/libWebRTC-x86_64.a out_ios_x86_64/Release-iphonesimulator/lib*.a;
46 strip -S -x -o out_ios_x86_64/libs/libWebRTC.a -r out_ios_x86_64/libs/libWebRTC-x86_64.a;
47 echo "*** result: $PWD/out_ios_x86_64/libs/libWebRTC.a";
48
49 popd;
50 }
51
52 function build_iosdevice_armv7() {
53 echo "*** building WebRTC for armv7 iOS devices";
54 export GYP_GENERATORS="ninja";
55 export GYP_DEFINES="build_with_libjingle=1 build_with_chromium=0 libjingle_objc=1 OS=ios target_arch=armv7";
56 export GYP_GENERATOR_FLAGS="$GYP_GENERATOR_FLAGS output_dir=out_ios_armv7";
57 export GYP_CROSSCOMPILE=1;
58 pushd src;
59 gclient runhooks;
60 ninja -C out_ios_armv7/Release-iphoneos AppRTCDemo;
61
62 echo "*** creating iOS armv7 libraries";
63 pushd out_ios_armv7/Release-iphoneos/;
64 rm -f libapprtc_signaling.a;
65 popd;
66 mkdir -p out_ios_armv7/libs;
67 libtool -static -o out_ios_armv7/libs/libWebRTC-armv7.a out_ios_armv7/Release-iphoneos/lib*.a;
68 strip -S -x -o out_ios_armv7/libs/libWebRTC.a -r out_ios_armv7/libs/libWebRTC-armv7.a;
69 echo "*** result: $PWD/out_ios_armv7/libs/libWebRTC.a";
70
71 popd;
72 }
73
74 function build_iosdevice_arm64() {
75 echo "*** building WebRTC for arm64 iOS devices";
76 export GYP_GENERATORS="ninja";
77 export GYP_DEFINES="build_with_libjingle=1 build_with_chromium=0 libjingle_objc=1 OS=ios target_arch=arm64 target_subarch=arm64";
78 export GYP_GENERATOR_FLAGS="$GYP_GENERATOR_FLAGS output_dir=out_ios_arm64";
79 export GYP_CROSSCOMPILE=1;
80 pushd src;
81 gclient runhooks;
82 ninja -C out_ios_arm64/Release-iphoneos AppRTCDemo;
83
84 echo "*** creating iOS arm64 libraries";
85 pushd out_ios_arm64/Release-iphoneos/;
86 rm -f libapprtc_signaling.a;
87 popd;
88 mkdir -p out_ios_arm64/libs;
89 libtool -static -o out_ios_arm64/libs/libWebRTC-arm64.a out_ios_arm64/Release-iphoneos/lib*.a;
90 strip -S -x -o out_ios_arm64/libs/libWebRTC.a -r out_ios_arm64/libs/libWebRTC-arm64.a;
91 echo "*** result: $PWD/out_ios_arm64/libs/libWebRTC.a";
92
93 popd;
94 }
95
96 function combine_libs()
97 {
98 echo "*** combining libraries";
99 lipo -create src/out_ios_ia32/libs/libWebRTC.a
100 src/out_ios_x86_64/libs/libWebRTC.a
101 src/out_ios_armv7/libs/libWebRTC.a
102 src/out_ios_arm64/libs/libWebRTC.a
103 -output libWebRTC.a;
104 echo "The public headers are located in $PWD/src/talk/app/webrtc/objc/public/*.h";
105 }
106
107 function create_framework() {
108 echo "*** creating WebRTC.framework";
109 rm -rf WebRTC.framework;
110 mkdir -p WebRTC.framework/Versions/A/Headers;
111 cp ./src/talk/app/webrtc/objc/public/*.h WebRTC.framework/Versions/A/Headers;
112 cp libWebRTC.a WebRTC.framework/Versions/A/WebRTC;
113
114 pushd WebRTC.framework/Versions;
115 ln -sfh A Current;
116 popd;
117 pushd WebRTC.framework;
118 ln -sfh Versions/Current/Headers Headers;
119 ln -sfh Versions/Current/WebRTC WebRTC;
120 popd;
121 }
122
123 function clean()
124 {
125 echo "*** cleaning";
126 pushd src;
127 rm -rf out_ios_arm64 out_ios_armv7 out_ios_ia32 out_ios_x86_64;
128 popd;
129 echo "*** all cleaned";
130 }
131
132 function update()
133 {
134 gclient sync --force
135 pushd src
136 svn info | grep Revision > ../svn_rev.txt
137 popd
138 }
139
140 function build_all() {
141 build_iossim_ia32 && build_iossim_x86_64 &&
142 build_iosdevice_armv7 && build_iosdevice_arm64 &&
143 combine_libs && create_framework;
144 }
145
146 function run_simulator_ia32() {
147 echo "*** running webrtc appdemo on ia32 iOS simulator";
148 src/out_ios_ia32/Release-iphonesimulator/iossim src/out_ios_ia32/Release-iphonesimulator/AppRTCDemo.app;
149 }
150
151 function run_simulator_x86_64() {
152 echo "*** running webrtc appdemo on x86_64 iOS simulator";
153 src/out_ios_x86_64/Release-iphonesimulator/iossim -d 'iPhone 6' -s '8.1' src/out_ios_x86_64/Release-iphonesimulator/AppRTCDemo.app;
154 }
155
156 function run_on_device_armv7() {
157 echo "*** launching on armv7 iOS device";
158 ideviceinstaller -i src/out_ios_armv7/Release-iphoneos/AppRTCDemo.app;
159 echo "*** launch complete";
160 }
161
162 function run_on_device_arm64() {
163 echo "*** launching on arm64 iOS device";
164 ideviceinstaller -i src/out_ios_arm64/Release-iphoneos/AppRTCDemo.app;
165 echo "*** launch complete";
166 }
167
168 #运行命令行参数中第一个参数所指定的Shell函数
169 $@
这个编译脚本除了可以编译WebRTC项目自带的AppRTCDemo应用外,还可以编译出WebRTC.framework.
执行如下命令来编译我们所需要的全部:
wuqiong:webrtc apple$ ./build_webrtc.sh build_all
等上面命令完成之后,我们所需要的WebRTC框架就在当前目录下了.可以用ls命令查看之:
wuqiong:webrtc apple$ ls WebRTC.framework build_webrtc.sh libWebRTC.a srcwuqiong:webrtc apple$
第一个WebRTC.framework就是我们需要的框架了! 到此,我们的编译任务就完成了!不是吧..就这么简单?不是说起来超级麻烦吗?呵呵,装逼结束.繁琐的部分已经封装到了shell脚本里头去了.如果有兴趣可以去研究一下这个脚本.
2.5 WebRTC.framework的依赖.
如果项目使用了该框架,那么编译的时候需要在项目的Build Phases中添加如下库和框架:
libstdc++.6.dylib
libsqlite3.dylib
libc++.dylib
libicucore.dylib
Security.framework
CFNetwork.framework
GLKit.framework
AudioToolbox.framework
AVFoundation.framework
CoreAudio.framework
CoreMedia.framework
CoreVideo.framework
CoreGraphics.framework
OpenGLES.framework
QuartzCore.framework
重要提示
目前Google官方代码中在ARMv7平台有VP8视频编码的stackoverflow问题。
以iOS为例,建议直接使用CocoaPods上面的东西,名字是libjingle_peerconnection。
使用这个库里面的东西并不是很麻烦,但要搞清楚里面的逻辑却挺头大的,因为Google提供了一个例子,AppRTCDemo,里面由于使用了
很多Google自己的一个架构,把整个Demo搞得剧复杂无比,不过搞清楚原理后,只需要使用几个简单的API就可以实现WebRTC的通信。
WebRTC要工作起来,需要一下几个方面
1. 双方建立PeerConnection
2. 一端创建和发出Offer,另一端接收Offer后响应Answer
3. PeerConnection的两端交换SDP信息
建立PeerConnection需要ICE信息,里面提供的网络打洞穿墙等路径数据,
RTCIceServer*iceServer = [[RTCICEServeralloc]initWithURI:[NSURLURLWithString:YOUR_SERVER]username:USERNAME_OR_EMPTY_STRINGpassword:PASSWORD_OR_EMPTY_STRING]];RTCPeerConnectionFactory*pcFactory = [[RTCPeerConnectionFactoryalloc] init];RTCPeerConnection*peerConnection = [pcFactorypeerConnectionWithICEServers:iceServersconstraints:nildelegate:self];
一端创建Offer
RTCMediaConstraints *constraints = [RTCMediaConstraints alloc]initWithMandatoryConstraints: @[ [[RTCPair alloc]initWithKey:@"OfferToReceiveAudio"value:@"true"], [[RTCPair alloc]initWithKey:@"OfferToReceiveVideo"value:@"true"] ] optionalConstraints:nil]; [peerConnection createOfferWithConstraints:constraints];
这之后的动作都是通过peerConnection的delegate来完成的createOffer之后,会触发didCreateSessionDescription方法,可以在这个方法中来设置localDescription
- (void)peerConnection:(RTCPeerConnection*)peerConnectiondidCreateSessionDescription:(RTCSessionDescription*)sdp error:(NSError*)error {[peerConnection setLocalDescription:sdp] }
localDescription设置成功后,会触发didSetSessionDescriptionWithError的方法
- (void)peerConnection:(RTCPeerConnection*)peerConnection didSetSessionDescriptionWithError:(NSError *)error{if(peerConnection.signalingState ==RTCSignalingHaveLocalOffer) {// 通过Signaling
Channel发送Offer之类的信息} }
当另一端收到Offer时,要设置remoteDescription
RTCSessionDescription*remoteDesc=[[RTCSessionDescription alloc]initWithType:@"answer" sdp:sdp]; [peerConnection
setRemoteDescription:remoteDesc];
剩下的一些delegate都是跟ICE的candidate相关的,处理在建立PeerConnection时的P2P连接信息
- (void)peerConnection:(RTCPeerConnection*)peerConnection gotICECandidate:(RTCICECandidate *)candidate {// 获得Candidate信息,通过signaling channel发送给另一端}
当通过signaling
channel收到candidate信息后,添加到peerConnection,让P2P来处理打洞信息
RTCICECandidate*candidate= [[RTCICECandidate alloc]initWithMid:SDP_MIDindex:SDP_M_LINE_INDEXsdp:SDP_CANDIDATE]; [self.rtcPeerConnectionaddICECandidate:candidate];
最后一个是媒体数据处理,当peerConnection收到媒体数据时,会触发另一个方法
- (void)peerConnection:(RTCPeerConnection *)peerConnectionaddedStream:(RTCMediaStream *)stream { //Createa new renderviewwithasizeofyour choice RTCEAGLVideoView*renderView = [[RTCEAGLVideoView alloc]initWithFrame:CGRectMake(100,100)];[stream.videoTracks.lastObjectaddRenderer:self.renderView]; // RTCEAGLVideoView is a subclass ofUIView, so renderView // can be inserted into your view hierarchywhere it suits your application. }
总共这些方法就能够简单的让WebRTC工作起来,但还需要很多别的处理,比如iOS的默认speaker播放声音,音视频编解码,chrome用的v8,iOS用的是H264,还有很多问题要等待一一处理。今天先到这里后续再更新谢谢大家。