webrtc一对一通话
目录
一对一通话原理 RTCPeerConnection 实现WebRTC音视频通话思路 部署到公网
1. 一对一通话原理
对于WebRTC应用开发人员而言,主要是关注RTCPeerConnection类,主要分为以下四块
信令设计; 媒体协商; 加入Stream/Track; 网络协商
1. 信令协议设计
采用json封装格式
join:加入房间 resp-join:当join房间后发现房间已经存在另一个人时则返回另一个人的uid;如果只有自己则不返回 leave:离开房间,服务器收到leave信令则检查同一房间是否有其他人,如果有其他人则通知他有人离开 new-peer:服务器通知客户端有新人加入,收到newpeer则发起连接请求 peer-leave:服务器通知客户端有人离开 offer:转发offer sdp answer:转发answer sdp candidate:转发candidate sdp join:加入房间
var jsonMsg = {
'cmd' : 'join' ,
'roomId' : roomId,
'uid' : localUserId,
} ;
resp-join:当join房间后发现房间已经存在另一个人时则返回另一个人的uid;如果只有自己则不返回
jsonMsg = {
'cmd' : 'resp‐join' ,
'remoteUid' : remoteUid
} ;
leave:离开房间,服务器收到leave信令则检查同一房间是否有其他人,如果有其他人则通知他有人离开
var jsonMsg = {
'cmd' : 'leave' ,
'roomId' : roomId,
'uid' : localUserId,
} ;
new-peer:服务器通知客户端有新人加入,收到newpeer则发起连接请求
var jsonMsg = {
'cmd' : 'new‐peer' ,
'remoteUid' : uid
} ;
peer-leave:服务器通知客户端有人离开
var jsonMsg = {
'cmd' : 'peer‐leave' ,
'remoteUid' : uid
} ;
offer:转发offer sdp
var jsonMsg = {
'cmd' : 'offer' ,
'roomId' : roomId,
'uid' : localUserId,
'remoteUid' : remoteUserId,
'msg' : JSON. stringify ( sessionDescription)
} ;
answer:转发answer sdp
var jsonMsg = {
'cmd' : 'answer' ,
'roomId' : roomId,
'uid' : localUserId,
'remoteUid' : remoteUserId,
'msg' : JSON. stringify ( sessionDescription)
} ;
candidate:转发candidate sdp
var jsonMsg = {
'cmd' : 'candidate' ,
'roomId' : roomId,
'uid' : localUserId,
'remoteUid' : remoteUserId,
'msg' : JSON. stringify ( candidateJson)
} ;
2 媒体协商
1. createOffer
基本格式
aPromise = myPeerConnection.createOffer([options]); [options]
var options = {
offerToReceiveAudio: true ,
offerToReceiveVideo: true ,
iceRestart: false ,
} ;
iceRestart:只有在处于活跃的时候,iceRestart=false才有作用。 测试:https://webrtc.github.io/samples/src/content/peerconnection/restart-ice/
2. createAnswer
基本格式
aPromise = RTCPeerConnection .createAnswer([ options ]); 目前createAnswer的options是无效的。
3. setLocalDescription
基本格式
aPromise = RTCPeerConnection .setLocalDescription(sessionDescription);
4. setRemoteDescription
基本格式
aPromise = pc.setRemoteDescription(sessionDescription);
3. 加入Stream/Track
1. addTrack
基本格式
rtpSender = rtcPeerConnection .addTrack(track,stream …); track:添加到RTCPeerConnection中的媒体轨(音频track/视频track) stream:getUserMedia中拿到的流,指定track所在的stream
4. 网络协商
1. addIceCandidate
基本格式:
aPromise = pc.addIceCandidate(候选人); candidate
属性 说明 candidate 候选者描述信息 sdpMid 与候选者相关的媒体流的识别标签 sdpMLineIndex 在SDP中 m=的索引值 usernameFragment 包括了远端的唯一标识
var candidateJson = {
'label' : event. candidate. sdpMLineIndex,
'id' : event. candidate. sdpMid,
'candidate' : event. candidate. candidate
} ;
注意Android和Web端的不同。
2. RTCPeerConnection
1. 构造函数:
语法:
pc = new RTCPeerConnection([ configuration ] );
2. configuration可选
bundlePolicy 一般用maxbundle
banlanced:音频与视频轨使用各自的传输通道
maxcompat:每个轨使用自己的传输通道
maxbundle:都绑定到同一个传输通道
iceTransportPolicy 一般用all
指定ICE的传输策略
relay:只使用中继候选者
all:可以使用任何类型的候选者
iceServers
其由RTCIceServer组成,每个RTCIceServer都是一个ICE代理的服务器
属性 含义 credential 凭据,只有TURN服务使用 credentialType 凭据类型,可以password或oauth urls 用于连接服中的ur数组 username 用户名,只有TURN服务使用
rtcpMuxPolicy 一般用require
rtcp的复用策略,该选项在收集ICE候选者时使用
选项 说明 negotiate 收集RTCP与RTP复用的ICE候选者,如果RTCP能复用就与RTP复用,如果不能复用,就将他们单独使用 require 只能收集RTCP与RTP复用的ICE候选者,如果RTCP不能复用,则失败
3. 重要事件
onicecandidate:收到候选者时触发的事件 ontrack:获取远端流 onconnectionstatechange PeerConnection的连接状态,参考:https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/connectionState
pc. onconnectionstatechange = function ( event) {
switch ( pc. connectionState) {
case "connected" :
break ;
case "disconnected" :
case "failed" :
break ;
case "closed" :
break ;
}
}
oniceconnectionstatechange ice连接事件 具体参考:https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/iceConnectionState
3. 实现WebRTC音视频通话
开发步骤
客户端显示界面 打开摄像头并显示到页面 websocket连接 join、newpeer、respjoin信令实现 leave、peerleave信令实现 offer、answer、candidate信令实现 综合调试和完善
1. 客户端显示界面
步骤:创建html页面 主要是input、button、video控件的布局。
2. 打开摄像头并显示到页面
3. websocket连接
4. join、newpeer、respjoin信令实现
思路:
点击加入按钮; 响应加入按钮事件; 将join发送给服务器; 服务器根据当前房间的人数做处理,如果房间已经有人则通知房间里面的人有新人加入(newpeer),并通知自己房间里面是什么人(respjoin)
5. leave、peerleave信令实现
思路:
点击离开按钮; 响应离开按钮事件; 将leave发送给服务器; 服务器处理leave,将发送者删除并通知房间(peerleave)的其他人; 房间的其他人在客户端响应peerleave事件
6. offer、answer、candidate信令实现
思路:
收到newpeer (handleRemoteNewPeer处理),作为发起者创建RTCPeerConnection,绑定事件响应函数,加入本地流; 创建offer sdp,设置本地sdp,并将offer sdp发送到服务器; 服务器收到offer sdp 转发给指定的remoteClient; 接收者收到offer,也创建RTCPeerConnection,绑定事件响应函数,加入本地流; 接收者设置远程sdp,并创建answer sdp,然后设置本地sdp并将answer sdp发送到服务器; 服务器收到answer sdp 转发给指定的remoteClient; 发起者收到answer sdp,则设置远程sdp; 发起者和接收者都收到ontrack回调事件,获取到对方码流的对象句柄; 发起者和接收者都开始请求打洞,通过onIceCandidate获取到打洞信息(candidate)并发送给对方 如果P2P能成功则进行P2P通话,如果P2P不成功则进行中继转发通话。
7. 综合调试和完善
思路:
点击离开时,要将RTCPeerConnection关闭(close); 点击离开时,要将本地摄像头和麦克风关闭; 检测到客户端退出时,服务器再次检测该客户端是否已经退出房间。 RTCPeerConnection时传入ICE server的参数,以便当在公网环境下可以进行正常通话。 启动coturn,安装:ubantu安装coturn穿透服务器
# nohup是重定向命令,输出都将附加到当前目录的 nohup. out 文件中; 命令后加 & , 后台执行起来后按
ctr+ c, 不会停止
sudo nohup turnserver ‐L 0.0 .0 .0 ‐a ‐u test: test ‐v ‐f ‐r nort. gov &
# 前台启动
sudo turnserver ‐L 0.0 .0 .0 ‐a ‐u test: test ‐v ‐f ‐r nort. gov
#然后查看相应的端口号3478 是否存在进程
sudo lsof ‐i: 3478
设置configuration,先设置为relay中继模式,只有relay中继模式可用的时候,才能部署到公网去(部署到公网后也先测试relay)。
var defaultConfiguration = {
bundlePolicy: "max-bundle" ,
rtcpMuxPolicy: "require" ,
iceTransportPolicy: "relay" ,
iceServers: [
{
"urls" : [
"turn:8.141.75.248:3478?transport=udp" ,
"turn:8.141.75.248:3478?transport=tcp"
] ,
"username" : "test" ,
"credential" : "test"
} ,
{
"urls" : [
"stun:8.141.75.248:3478"
]
}
]
} ;
pc = new RTCPeerConnection ( defaultConfiguration) ;
relay中继网络状况,命令:sudo sar -n DEV 1 局域网P2P