一对一通话原理
对于我们WebRTC应用开发人员而言,主要是关注RTCPeerConnection类,我们以(1)信令设计;(2)媒体协商(3)加入Stream/Track;(4)网络协商四大块继续学习解通话原理
sdp有一个字段标记是offer(发起者)还是answer(接收端)
ontrack只是拿到对方码流对象,知道打通了链路才会拿到对方码流。(例如:出来订单号,但还没有发送快递出来)
onIceCandidate:回调事件,拿到对方码流对象后,拿到打洞地址发送给对方
a'd'dIceCandidate:加入到自己的RTCPeerConnection对象中
服务端通过ICE Request请求自己的外网地址,然后将信令(candidate)发送给对方。
当双方都拿到很多组candidate后就会进行链接尝试,看双方能否通,如果能同就可以做P2P,如果都不通就需要走中继器
如果能正常通信,两边就可以相互传递(音视频)数据,实现(音视频)通话
有一方离开发送leave命令,到信令服务器中,会把A从房间里删除掉,然后通知b,然后关闭接口
一、信令协议设计
采用json封装格式
- join 加入房间
- resp-join 当join房间后发现房间已经存在另一个人时则返回另一个人的uid;如果只有自己则不返回
- leave离开房间,服务器收到leave信令则检查同一房间是否有其他人,如果有其他人则通知他有人离开
- new-peer服务器通知客户端有新人加入,收到new-peer则发起连接请求
- peer-leave 服务器通知客户端有人离开
- offer转发offer sdp
- answer转发answer sdp
- candidate转发candidate sdp
join
const jsonMsg={
"cmd":"join",
"roomId":roomId,
"uid":localUserId
}
resp-join
jsonMsg = {
"cmd":'resp-json',
'remoteUid:remoteUID
}
leave
var jsonMsg - {
'cmd' : 'leave',
'roomId' : roomId,
'uid': localuserId,
}
roomTableMap:房间号的映射表
roomMap:房间内人员映射表
new-peer
var jsonMsg = {
'cmd' : 'new-peer',
'remoteUid' : uid
}
peer-leave
var jsonMsg = {
'cmd' : 'peer-leave',
'remoteuid' : uid
};
offer
var jsonMsg = {
'cmd' : 'offer' ,
'roomId' : roomId,
'uid': localuserId,
'remoteuid' :remoteUserId,
'msg': 3SON.stringify(sessionDescription)
};
candidate
var jsonMsg = {
'cmd': 'candidate' ,
'roomId' : roomId,
'uid': localuserId,
'remoteuid ' :remoteuserId,
'msg': ]SON.stringify(candidateJson)
};
二、媒体协商
-
createOffer
基本格式
aPromise = myPeerConnection.createOffer([options]);
-
[options]
var options = {
offerToReceivAudio: true, //告诉另一端,你是否想接收音频,默认true
offerToReceivevideo: true, //告诉另一端,你是否想接收视频,默认true
iceRestart: false, //是否在活跃状态重启ICE网络协商
};
iceRestart 如果设置为false,在活跃状态下不会再次进行打洞,只进行媒体协商(只有在处于活跃的时候,iceRestart=false才有作用)
-
createAnswer
基本格式
aPromise = RTCPeerConnection .createAnswer ([ options ]) ;
-
setLocalDescription
基本格式
aPromise = RTCPeerConnection .setLocalDescription (sessionDescription) ;
-
setRemoteDescription
基本格式
aPromise = pc.setRemoteDescription (sessionDescription) ;
三、加入Stream/Track
-
addTrack
基本格式
rtpSender = rtcPeerConnection.addTrack (track,stream ... ) ;
track:添加到RTCPeerConnection中的媒体轨(音频track/视频track)
stream: getUserMedia中拿到的流,指定track所在的stream
四、网络协商
-
addlceCandidate
基本格式
aPromise = pc .addIceCandidate (候选人);
主要是把condidate设到RTCPeerConnection内部
属性 | 说明 |
---|---|
candidate | 候选者描述信息 |
sdpMid | 与候选者相关的媒体流的识别标签在 |
sdpMLineIndex | SDP中m=的索引值 |
usernameFragment | 包括了远端的唯一标识 |
注意Android和Web端的不同。
RTCPeerConnection补充
构造函数
语法:
pc = new RTCPeerConnection([configuration])
configuration可选
-
bundlePolicy一般用max-bundle
banlanced:音频与视频轨使用各自的传输通道
max-compat:每个轨使用自己的传输通道
max-bundler都绑定到同一个传输通道
-
ice TransportPolicy一般用all
指定ICE的传输策略
relay:只使用中继候选者(本地测试时,用于判断网络是不是通的)
all:可以使用任何类型的候选者
-
iceServers
其由RTClceServer组成,每个RTClceServer都是一个ICE代理的服务器
属性 | 含义 |
---|---|
credential | 凭据,只有TURN服务使用(类似于密码) |
credentialType | 凭据类型,可以password或oauth |
urls | 用于连接服中的ur数组(IP地址列表) |
username | 用户名,只有TURN服务使用 |
-
rtcpMuxPolicy一般用require
rtcp的复用策略,该选项在收集ICE候选者时使用
选项 | 说明 |
negotiate | 收集RTCP与RTP复用的ICE候选者,如果RTCP能复用就与RTP复用,如果不能复用,就将他们单独使用 |
require | 只能收集RTCP与RTP复用的ICE候选者,如果RTCP不能复用,则失败 |
重要事件
- onicecandidate收到候选者时触发的事件
- ontrack获取远端流
- onconnectionstatechange PeerConnection的连接状态,参考: RTCPeerConnection: connectionState property
pc.onconnectionstatechange = function(event){
switch(pc.connectionstate){
case "connected":
// The connection has become fully connected
break;
case "disconnected":case "failed":
// one or more transports has terminated unexpectedly or in an error
break;
case "closed":
//The connection has been closed
break;
}
}
oniceconnectionstatechange ice连接事件具体参考:RTCPeerConnection: iceConnectionState property