Update: 同上一篇还是在做聊天室,本篇主要讲述语音部分
在线传输主要使用了 webRTC,这块以后看多了会再细讲。 不同于 socket 的是:客户端端对客户端端通过服务端进行验证之后,端对端直接进行 stream 传输
1.创建 webRTC 连接
先上代码,等有空了再细谈
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
var isCaller = true;
// 与信令服务器的WebSocket连接
var socket = new WebSocket("ws://127.0.0.1:3000");
// stun和turn服务器
var iceServer = {
iceServers: [
{
url: "stun:stun.l.google.com:19302"
},
{
url: "turn:numb.viagenie.ca",
username: "webrtc@live.com",
credential: "muazkh"
}
]
};
// 创建PeerConnection实例 (参数为null则没有iceserver,即使没有stunserver和turnserver,仍可在局域网下通讯)
var pc = new webkitRTCPeerConnection(iceServer);
// 发送ICE候选到其他客户端
pc.onicecandidate = function(event) {
if (event.candidate !== null) {
socket.send(
JSON.stringify({
event: "_ice_candidate",
data: {
candidate: event.candidate
}
})
);
}
};
// 如果检测到媒体流连接到本地,将其绑定到一个video标签上输出
pc.onaddstream = function(event) {
document.getElementById("remoteVideo").src = URL.createObjectURL(
event.stream
);
};
// 发送offer和answer的函数,发送本地session描述
var sendOfferFn = function(desc) {
pc.setLocalDescription(desc);
socket.send(
JSON.stringify({
event: "_offer",
data: {
sdp: desc
}
})
);
},
sendAnswerFn = function(desc) {
pc.setLocalDescription(desc);
socket.send(
JSON.stringify({
event: "_answer",
data: {
sdp: desc
}
})
);
};
// 获取本地音频和视频流
navigator.webkitGetUserMedia(
{
audio: true,
video: true
},
function(stream) {
//绑定本地媒体流到video标签用于输出
document.getElementById("localVideo").src = URL.createObjectURL(stream);
//向PeerConnection中加入需要发送的流
pc.addStream(stream);
//如果是发起方则发送一个offer信令
if (isCaller) {
pc.createOffer(sendOfferFn, function(error) {
console.log("Failure callback: " + error);
});
}
},
function(error) {
//处理媒体流创建失败错误
console.log("getUserMedia error: " + error);
}
);
//处理到来的信令
socket.onmessage = function(event) {
var json = JSON.parse(event.data);
console.log("onmessage: ", json);
//如果是一个ICE的候选,则将其加入到PeerConnection中,否则设定对方的session描述为传递过来的描述
if (json.event === "_ice_candidate") {
pc.addIceCandidate(new RTCIceCandidate(json.data.candidate));
} else {
pc.setRemoteDescription(new RTCSessionDescription(json.data.sdp));
// 如果是一个offer,那么需要回复一个answer
if (json.event === "_offer") {
pc.createAnswer(sendAnswerFn, function(error) {
console.log("Failure callback: " + error);
});
}
}
};