系列文章目录
webrtc学习记录一【媒体录制MediaRecorder】
webrtc学习记录二【基于socket.io创建信令服务器聊天室】
目录
1.2、RTCpeerConnection媒体协商的实例方法
前言
记录webrtc学习过程中的要点,以便温故知新。本章主要是基于RTCPeerConnection,创建一套本机内的1v1音视频系统,没有通过UDP服务器和信令服务器的中转。
提示:以下是本篇文章正文内容,下面案例可供参考
一、媒体能力的协商过程
上图模拟了A和B进行互通时的媒体协商过程,
A需要创建一个offer信息,然后将offer信息通过setLocalDescription设置给peerConnection A;同时,发送offer到信令服务器。
信令服务器接收到A发送过来的offer之后,转发给B,B将来自A的offer信息通过setRemoteDescription设置到远端连接(因为对于B来说,A发送来的信息就是远端)
然后B创建一个answer,然后将answer信息通过setLocalDescription设置给peerConnection B;同时,发送answer信息到信令服务器。
信令服务器接收到B发送过来的answer之后,转发给A,A将来自B的answer信息通过setRemoteDescription设置到远端连接(因为对于A来说,B发送来的信息就是远端)
这样A和B的peerConnection就互相拿到了对方的sdp信息,从而能够实现互通。
1.1、RTCpeerConnection类的使用
上述流程的实现都是基于类RTCpeerConnection,因此下面就开始介绍一下它的用法和相关api
基本格式
var myPeerConnection = new RTCPeerConnection([configuration])
参数说明
参数 | 说明 |
configuration | 一个对象集合,包含许多配置项。一般主要配置ice服务器地址点对点连接。 |
configuration详细说明
configuration的详细参数包含如下:
参数 | 说明 |
iceServers | 最关键的一项,设置STUN 或 TURN服务的地址。不填则限制为本地 |
iceTransportPolicy | 指定ICE传输策略: relay:只是用中继候选者 all:可以使用任何类型的候选者,包含中继,host类型。但是国内网络基本只有中继能连通、 |
bundlePolicy | 'balanced',音轨与视轨分别使用音频和适配的通道,如2个音轨2个视轨,只要2个通道。 'max-compat',每个轨使用自己的传输通道,如3个视轨需要3个通道 'max-bundle',将音轨和视轨都绑定到同一个传输通道,只使用1个通道 |
rtcpMuxpolicy | 'negotiate',收集RTCP与复用RTP复用的ICE候选者,如果RTCP能复用就与RTP复用,如果不能复用,就将他们单独使用。 'require',只能收集RTCP与RTP复用的ICE候选者,如果RTCP不能复用,则失败。 默认是'require' |
peerIdentity | 建立对等连接时的标识字符串,可以不设置,默认是null |
certificates | 授权可以使用连接的一组证书,不设置会默认提供一个。 每一个可连通的候选者都需要一个证书,复用情况下有1个即可。 |
iceCandidatePoolSize | 16位的整数值,用于指定预取的ICE候选者的个数。 默认值为 0(意味着不会发生候选预取) 改变 ICE 候选池的大小可能会触发 ICE 收集的开始。 |
iceServers详细说明
数组类型,可以设置多个STUN或TURN服务地址,每一个都是一个ICE代理的服务。
属性 | 含义 |
credential | 凭据,只有TURN服务使用 |
credentialType | 凭据类型,可以是password或者oauth |
urls | 用于连接服务中的url数组 |
username | 用户名,只有TURN服务使用 |
常见配置示例:
const peerConnectionConfig = {
'iceServers': [
{
'urls': 'stun:stun.l.google.com:19302',
'credential': 'mypasswd',
'username': 'myusername'
}
]
}
const myPeerConnection = new RTCPeerConnection(peerConnectionConfig )
1.2、RTCpeerConnection媒体协商的实例方法
以上面创建的myPeerConnection 实例为例,下面介绍一些必须的示例方法。
createOffer
基本格式
aPromise = myPeerConnection.createOffer([offerOptions])
offerOptions
属性 | 含义 |
offerToRecieveAudio |
0或者1,0表示不传输音频,1表示传输音频 |
offerToRecieveVideo |
0或者1,0表示不传输视频,1表示传输视频 |
示例
myPeerConnection.createOffer({
offerToRecieveAudio: 0,
offerToRecieveVideo: 1,
}).then(desc => {
}).catch(err => console.log('本地offer创建失败', err))
createAnswer
基本格式
aPromise = myPeerConnection.createAnswer([answerOptions])
示例
this.pcRemote.createAnswer().then(desc => {
}).catch(err => console.log('远端answer创建失败', err))
setLocalDescription
方法中的sessionDescription取的就是offer和answer中返回的desc
基本格式
aPromise = myPeerConnection.setLocalDescription(sessionDescription)
示例
this.pcLocal.createOffer(offerOptions).then(desc => {
this.pcLocal.setLocalDescription(desc)
}).catch(err => console.log('本地offer创建失败', err))
setRemoteDescription
基本格式
aPromise = myPeerConnection.setRemoteDescription(sessionDescription)
示例
this.pcRemote.createAnswer().then(desc => {
this.pcRemote.setRemoteDescription(desc)
}).catch(err => console.log('远端answer创建失败', err))
addTrack
基本格式
rtpSender = myPeerConnection.addTrack(track,stream...)
参数说明
属性 | 说明 |
track | 添加到RTCPeerConnerction中的媒体轨 |
sdpMid | 指定track所在的stream |
示例:
this.localStream.getTracks().forEach(track => {
this.pcLocal.addTrack(track, this.localStream)
})
这里的localStream来自navigator.mediaDevices.getUserMedia,第一章的学习记录中有用到。
removeTrack
对应addTrack,移除轨道。
基本格式
myPeerConnection.removeTrack(rtpSender)
addIceCandidate
基本格式
aPromise = myPeerConnection.addIceCandidate(candidate)
candidate属性
属性 | 说明 |
candidate | 候选者描述信息 |
sdpMid | 与候选者相关的媒体流的识别标签 |
sdpMLineIndex | 在SDP中m=的索引值 |
usernameFragment | 包括了远端的唯一标识 |
1.3、RTCpeerConnection媒体协商的实例的事件。
onnegotiationneeded
进行媒体协商的时候触发的事件。
onicecandidate
当收到ice候选者的时候触发。
ontrack
媒体轨道添加的时候触发。
二、端对端连接的基本流程
了解了上述api之后,我们再详细的分解一下端对端连接的基本流程,为后续开发做好准备。
- 首先是A和B分别连接信令服务器signal,为后续通讯做准备。
- 然后A创建peerConnectionA连接,同时添加媒体流到本地视频窗口,以便显示本地视频内容。
- A的peerConnectionA连接创建完成后,开始创建offer,然后将offer信息设置到A的peerConnectionA中的setLocalDescription,并且A会对stun/turn服务器发起请求,期望stun/turn服务器返回A解析后的的候选者信息candidateA,同时将offer SDP信息发送给信令服务器。
- 信令服务器收到A的offer SDP信息后,马上通过信令服务器传给B。这时B需要先创建B的peerConnectionB,然后将前面信令服务器传过来的offer SDP通过setRemoteDescription设置到远端描述中(因为对于B来说,A传过来的信息就是远端信息)。接下来B开始创建answer,然后将B创建的answer SDP信息通过setLocalDescription设置到peerConnectionB的本地描述信息中。然后将B的candidate信息发送给stun/turn服务器上。同时将answer SDP信息发送给信令服务器。
- 信令服务器将answer SDP信息返回给A,A收到后将answer SDP信息通过setRemoteDescription设置到A的远端描述中。
- 当A收到了来自ICE服务器中返回的peerConnectionA的候选者信息candidateA后,将candidateA发送给信令服务器。
- 信令服务器接收到candidateA后,发送给peerConnectionB,peerConnectionB通过addIceCandidate方法,将candidateA设置给peerConnectionB
- 当B收到了来自ICE服务器中返回的peerConnectionB的候选者信息candidateB后,将candidateB发送给信令服务器。
- 信令服务器接收到candidateB后,发送给peerConnectionA,peerConnectionA通过addIceCandidate方法,将candidateB设置给peerConnectionA
- 至此,peerConnectionA和peerConnectionB就分别获取到了对方的candidate候选者信息,peerConnection的底层就会通过排序,链接检测,找到一个A和B之间的最优通信线路,这样就建立好了一个A和B之间的P2P通道。
- 最后通过ontrack事件,监听接收到的A的媒体流,展示到远端。这样A和B之间的p2p音视频互通就基本实现了。