全称是: Web browser Real Time Communication
特点如下:
- 是基于浏览器的实时音视频(数据)通信技术
- 免插件
- 开源
- 已被W3C纳入HTML5标准
- 跨平台,跨浏览器,跨移动应用
- Mac OSX、Windows、iOS、Android、Linux
最初是谷歌2010年以6820万美元收购Global IP Solutions(GIPS)公司而获得的一项技术,它使得Web中的实时通讯成为可能,是一项能够在浏览器内部进行实时音频和视频通信的技术
当浏览器实现对应音视频组件后,开发者可以容易地通过JS API 实现他们自己的RTC web 应用
现在已经被推为W3C的标准,名称为WebRTC
已经支持 | 不支持 |
---|---|
Chrome,FireFox,Opera,微软edge,Safari | IE |
- YY
- skype
- VoIP电话:KC网络电话;
- 在线教育:猿题库
多年前开始,腾讯QQ视频聊天室购买的国外Global IP(GIPS)公司技术 | |
---|---|
- Chrome
- Chrome for Android
- Firefox
- Opera
- Native C++、Java and Objective-C bindings
功能划分
- 获取音频和视频数据
- 传输音频和视频数据
- 传输任意二进制数据
API划分:三个JS接口
- MediaStream (又叫getUserMedia)
- RTCPeerConnection (C++)
- RTCDataChannel
- 抽象表示一个音频或者视频流
- 可包含多个音视频记录
- 通过
navigator.getUserMedia()
获取
(参考:https://w3c.github.io/mediacapture-main/archives/20140909/getusermedia.html )
getUserMedia
:
JS
var constraints = {video: true};
function successCallback(stream) {
var video = document.querySelector("video")
video.src = window.URL.createObjectURL(stream);
}
function errorCallback(error) {
console.log("navigator.getUserMedia error:", error);
}
navigator.getUserMedia(constraints, successCallback, errorCallback);
Objective-C
- (RTCVideoTrack *)createLocalVideoTrackBackCamera {
RTCVideoTrack *videoTrack = nil;
RTCMediaConstraints *constraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:nil optionalConstraints:nil];
[videoSource setUseBackCamera:YES];
RTCPeerConnectionFactory *factory = [[RTCPeerConnectionFactory alloc] init];
RTCAVFoundationVideoSource *videoSource = [factory avFoundationVideoSourceWithConstraints:constraints];
videoTrack = [factory videoTrackWithSource:videoSource trackId:[self videoTrackId]];
return videoTrack;
}
- (RTCMediaStream *)createLocalMediaStream {
RTCMediaStream *localStream = _peerConnection.localStreams[0];
[localStream removeVideoTrack:localStream.videoTracks[0]];
RTCMediaConstraints *videoConstraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:nil optionalConstraints:nil];
RTCVideoTrack *localVideoTrack = [self localVideoTrackWithConstraints:videoConstraints];
if (localVideoTrack) {
[localStream addVideoTrack:localVideoTrack];
[self didReceiveLocalVideoTrack:localVideoTrack];
}
return localStream;
}
其中的 constraints
介绍下:
控制MediaStream的内容:媒体类型、分辨率、帧率;
JS
video: {
mandatory: {
minWidth: 640,
minHeight: 360
},
optional [{
minWidth: 1280,
minHeight: 720
}]
}
Objective-C
//RTCMediaConstraints.h
RTC_EXTERN NSString * const kRTCMediaConstraintsMinAspectRatio;
RTC_EXTERN NSString * const kRTCMediaConstraintsMaxAspectRatio;
RTC_EXTERN NSString * const kRTCMediaConstraintsMaxWidth;
RTC_EXTERN NSString * const kRTCMediaConstraintsMinWidth;
RTC_EXTERN NSString * const kRTCMediaConstraintsMaxHeight;
RTC_EXTERN NSString * const kRTCMediaConstraintsMinHeight;
RTC_EXTERN NSString * const kRTCMediaConstraintsMaxFrameRate;
RTC_EXTERN NSString * const kRTCMediaConstraintsMinFrameRate;
RTC_EXPORT
@interface RTCMediaConstraints : NSObject
- (instancetype)init NS_UNAVAILABLE;
/** Initialize with mandatory and/or optional constraints. */
- (instancetype)initWithMandatoryConstraints:
(nullable NSDictionary<NSString *, NSString *> *)mandatory
optionalConstraints:
(nullable NSDictionary<NSString *, NSString *> *)optional
NS_DESIGNATED_INITIALIZER;
@end
- 信令处理
- 编解码协商
- 点对点传输
- 通讯安全保护
- 带宽管理(手机可以调得质量差点、PC可以质量高)
- 。。。
(编码采用的最初不是采用的h264,而是VP8, 最新版本已经支持)
JS
pc = new RTCPeerConnection(null);
pc.onaddstream = gotRemoteStram;
pc.addStream(localStream);
pc.createOffer(gotOffer);
function gotOffer(desc) {
pc.setLocalDescription(desc);
sendOffer(desc);
}
function gotAnswer(desc) {
pc.setRemoteDescription(desc);
}
function gotRemoteStream(e) {
attachMediaStream(remoteVideo, e.stream);
}
Objective-C
- (void)startSignalingIfReady {
self.state = kARDAppClientStateConnected;
// Create peer connection.
RTCMediaConstraints *constraints = [self offerConstraints];
RTCConfiguration *config = [[RTCConfiguration alloc] init];
[config setIceServers:_iceServers];
_peerConnection = [_factory peerConnectionWithConfiguration:config
constraints:constraints
delegate:self];
if(self.startLocalMedia){
[_peerConnection addStream:self.localStream];
[self sendOffer];
}
}
- (void)sendOffer {
RTCMediaStream *localStream = [self createLocalMediaStream];
[_peerConnection removeStream:localStream];
[_peerConnection addStream:localStream];
[_peerConnection offerForConstraints:[self offerConstraints] completionHandler:^(RTCSessionDescription * _Nullable sdp, NSError * _Nullable error) {
// [self peerConnection:_peerConnection didCreateSessionDescription:sdp error:error];
}];
}
- (void)waitForAnswer {
[self drainMessageQueueIfReady];
}
- (void)drainMessageQueueIfReady {
if (!_peerConnection || !_hasReceivedSdp) {
return;
}
for (ARDSignalingMessage *message in _messageQueue) {
[self processSignalingMessage:message];
}
[_messageQueue removeAllObjects];
}
- (void)processSignalingMessage:(ARDSignalingMessage *)message {
switch (message.type == kARDSignalingMessageTypeAnswer) {
case kARDSignalingMessageTypeAnswer:
case kARDSignalingMessageStartCommunication:{
ARDStartCommunicationMessage *sdpMessage = (ARDStartCommunicationMessage *) message;
[_peerConnection setRemoteDescription:sdpMessage.sessionDescription completionHandler:^(NSError * _Nullable error) {
// some code when remote description was set (was a delegate before - see below)
}];
break;
}
default:
break;
}
}
#pragma mark - RTCPeerConnectionDelegate
- (void)peerConnection:(RTCPeerConnection *)peerConnection didAddStream:(RTCMediaStream *)stream {
RTCVideoTrack *videoTrack = stream.videoTracks[0];
[self.remoteVideoTrack addRenderer:self.remoteView];
}
比如:如果两个人私有路由器都是192.168开头 ,会被认为是同一个网络下。。就需要这个
理想中的
但实际中:
- 双方需要交换 'Session Description' 对象:
- 某一方支持什么格式以及将要发什么格式
- 某一方建立点对点通讯的网络信息
- 可以用任何消息机制和消息协议来进行交换
信令服务原理图:
手摇电话 呼叫总部 | 接线员起到的就是类似"信令服务"的作用 |
---|---|
- 在有防火墙和地址转换时P2P需要UDP打洞:
- NAT后不能直接向广域网那样IP直接连接
- 采用UDP进行防火墙和NAT进行穿越
- STUN/TURN/ICE服务
只有 UDP 能打洞,TCP无法打洞,TCP需要建立连接,会容错。应该避免容错。
Client --UDP--》 Server (获知外网 IP 地址,端口号)
不是所有 NAT 网络都能打洞成功,连接就会建立失败,只能服务器中转。
为什么要有打洞服务:
- IPv4用完
- 私有地址一致,用了同一网段,不能用内网地址,需要用外网地址。
为什么需要外网地址而非内网地址 | 匿名聊天中,你知道你是在和一个昵称(内网地址)叫张三的人聊天,其实你是在和一个UserId(外网地址)聊天 |
---|---|
理想中的
现实中的:
几个服务的辨析:
- STUN (Session Traversal Utilities for NAT) 只能UDP,告诉我暴露在广域网的地址IP port ,我通过映射的广域网地址进行P2P数据通信。
- TURN( Traversal Using Relays around for NAT)UDP或TCP, 打洞失败后,提供服务器中转数据,通话双方数据都通过服务器,占服务器带宽较大 - 为了确保通话在绝大多数环境下可以正常工作。跨网只能用服务器中转(测试发现的) ,使用TURN这种情况在视频通话中占10%
- ICE 网络连接服务
WebRTC的时序图:
部署STUN和TURN
一般是一个APP提供
- WebRTC stunserver, turnserver
- rfc5766-turn-server
- restund
NAT路由器
只能UDP,告诉我暴露在广域网的地址IP port ,我通过映射的广域网地址进行P2P数据通信。
网络拓扑结构:
- UDP或TCP, 打洞失败后,提供服务器中转数据,通话双方数据都通过服务器,占服务器带宽较大
- 为了确保通话在绝大多数环境下可以正常工作。跨网只能用服务器中转(测试发现的) ,使用TURN这种情况在视频通话中占10%
ICE(Interactive Connectivity Establishment)
- 是一个用来建立P2P连接的编程框架
- 尝试去找出建立视频通话的最佳路径
-
Apple的Safari浏览器目前不支持WebRTC标准
-
我们需要移植WebRTC的C/C++代码实现
-
用Objective-C封装成iOS的WebRTC开发框架
-
github.com/webrtc/apprtc
Get the code:
http://www.webrtc.org/native-code/development
Browse code
https://chromium.googlesource.com/external/webrtc/+/master
Changes Log:
https://chromium.googlesource.com/external/webrtc
华为调查,WebRTC市场与前景
- Enterprise communications
- Telecom service providers
- Consumer web & mobile apps
- M2M & loT
- WebRTC PaaS Providers & APIs
市场上也有比较成熟的产品,比如: https://talky.io