webrtc通信过程
WebRTC Api
PeerConnection
WebRTC中最主要的就是一个叫做PeerConnection
的对象,这个是WebRTC中已经封装好的对象。每一路的音视频会话都会有唯一的一个PeerConnection
对象,WebRTC通过这个PeerConnection
对象进行视频的发起、传输、接收和挂断等操作。
PeerConnection中包含的属性如下:
- localDescription:本地描述信息,类型:
RTCSessionDescription
- remoteDescription:远端描述信息,类型:
RTCSessionDescription
- onicecandidate:传入一个回调方法,该回调方法有一个返回参数,返回参数类型为:
RTCIceCandidateEvent
, - onaddstream:传入一个回调方法,该回调方法有一个返回参数,返回参数类型为:``,如果检测到有远程媒体流传输到本地之后便会调用该方法。
- ondatachannel:(暂未用到)
- oniceconnectionstatechange:(暂未用到)
- onnegotiationneeded:(暂未用到)
- onremovestream:(暂未用到)
- onsignalingstatechange:(暂未用到)
PeerConnection
中还包含了一些方法:
- setLocalDescription:设置本地offer,将自己的描述信息加入到
PeerConnection
中,参数类型:RTCSessionDescription
- setRemoteDescription:设置远端的
answer
,将对方的描述信息加入到PeerConnection
中,参数类型:RTCSessionDescription
- createOffer:创建一个offer,需要传入两个参数,第一个参数是创建offer成功的回调方法,会返回创建好的offer,可以在这里将这个offer发送出去。第二个参数是创建失败的回调方法,会返回错误信息。
- createAnswer:创建一个
answer
,需要传入两个参数,第一个参数是创建answer
成功的回调方法,会返回创建好的answer
,可以在这里将这个answer
发送出去。第二个参数是创建失败的回调方法,会返回错误信息。 - addIceCandidate:将打洞服务器加入到配置信息中,参数类型:
RTCIceCandidate
- addStream:向
PeerConnection
中加入需要发送的数据流,参数类型:MediaStream
- close:
- createDTMFSender:
- createDataChannel:
- getLocalStreams:
- getRemoteStreams:
- getStats:
- getStreamById:
- removeStream:
- updateIce:
RTCSessionDescription
RTCSessionDescription
类型中包含了两个属性:
sdp:a read-only
DOMString
containing the SDP which describes the session.
type:这个指明了是视频的接收方还是发起方
This enum defines strings that describe the current state of the session description, as used in the
type
property. The session description's type will be specified using one of these values.Value Description answer
The SDP contained in the sdp
property is the definitive choice in the exchange. In other words, this session description describes the agreed-upon configuration, and is being sent to finalize negotiation.offer
The session description object describes the initial proposal in an offer/answer exchange. The session negotiation process begins with an offer being sent from the caller to the callee. pranswer
The session description object describe a provisional answer; that is, it's a response to a previous offer or provisional answer. rollback
This special type with an empty session description is used to roll back to the previous stable state.
Peer to Peer Connection 通信过程
用户A合用户B建立连接的过程(websocket通信)
新建websocket的连接
1
var conn = new WebSocket('ws://localhost:9090');
创建iceserver
1
2
3var configuration = {
"iceServers": [{ "urls": "stun:stun2.1.google.com:19302" }]
};A获取UserMedia
A创建PeerConnection
向本地视频中加入当前视频流stream
向PeerConnection中加入该stream
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21navigator.getUserMedia = (
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia
);
navigator.getUserMedia({ audio: false, video: true }, function(stream) {
//displaying local video stream on the page
localVideo.srcObject = stream;
// setup a new PeerConnection
yourConn = new RTCPeerConnection(configuration);
// setup stream listening
yourConn.addStream(stream);
}, function(error) {
console.log(error);
});A创建一个offer,把offer加入LocalDescription中
1
2
3
4
5
6
7
8
9// create an offer
yourConn.createOffer(function(offer) {
send({
type: "offer",
offer: offer
});
yourConn.setLocalDescription(offer);
}A监听iceCandicate服务器信息,收到event后把其中的candicate发送出去
1
2
3
4
5
6
7
8
9// 发送ICE候选到其他客户端
yourConn.onicecandidate = function(event) {
if (event.candidate) {
send({
type: "candidate",
candidate: event.candidate
});
}
};websocket的connection监听offer,
如果B收到offer,
B将offer存入peerConnection中setRemoteDescription, 并创建一个answer并返回给A:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48//when we got a message from a signaling server
conn.onmessage = function(msg) {
console.log("Got message", msg.data);
var data = JSON.parse(msg.data);
switch (data.type) {
case "login":
handleLogin(data.success);
break;
//when somebody wants to call us
case "offer":
handleOffer(data.offer, data.name);
break;
case "answer":
handleAnswer(data.answer);
break;
//when a remote peer sends an ice candidate to us
case "candidate":
handleCandidate(data.candidate);
break;
case "leave":
handleLeave();
break;
default:
break;
}
};
//when somebody sends us an offer
function handleOffer(offer, name) {
connectedUser = name;
//offer存入peerConnection中,
yourConn.setRemoteDescription(new RTCSessionDescription(offer));
//create an answer to an offer
yourConn.createAnswer(function(answer) {
yourConn.setLocalDescription(answer);
send({
type: "answer",
answer: answer
});
}, function(error) {
alert("Error when creating an answer");
});
};B收到了A发来的iceCandicate,将IceCandidate加入连接中
1
2
3
4//when we got an ice candidate from a remote user
function handleCandidate(candidate) {
yourConn.addIceCandidate(new RTCIceCandidate(candidate));
};B开始获取视音频数据,将视音频数据存入
PeerConnection
中,WebRTC便会自动将视音频数据发送给A。1
2
3
4
5
6//这里在连接建立的时候就提前设置好远程连接的监听,一旦B把A添加
//when a remote user adds stream to the peer connection, we display it
yourConn.onaddstream = function(e) {
remoteVideo.srcObject = e.stream;
};A接收到B返回的
answer
,将B返回的answer
设置为PeerConnection
的remoteDescription
。1
2
3
4//when we got an answer from a remote user
function handleAnswer(answer) {
yourConn.setRemoteDescription(new RTCSessionDescription(answer));
};这个时候WebRTC会将视音频数据自动发送给B,A和B就建立起了实时视音频通信。
全部代码
1 | //our username |
websocket代码:
1 | //require our websocket library |