本篇博客主要分为两部分,第一部分为leave信令的实现,即当有客户端离开房间后,服务端和其他在房间内的客户需知晓。第二部分为媒体协商和网络协商相关API。
本系列博客主要记录一对一WebRTC视频通话实现过程中的一些重点,代码全部进行了注释,便于理解WebRTC整体实现。
一对一WebRTC视频通话系列往期博客
一对一WebRTC视频通话系列(一)------ 创建页面并显示摄像头画面
一对一WebRTC视频通话系列(二)------websocket和join信令实现
一对一WebRTC视频通话系列(三)------leave和peer-leave信令实现
-
- 一、leave信令实现
-
- [1.1 客户端:](#1.1 客户端:)
- [1.2 服务端](#1.2 服务端)
- 二、媒体协商和网络协商API
一、leave信令实现
1.1 客户端:
javascript
//监听离开按钮点击事件
document.getElementById('leaveBtn').onclick = function () {
console.log("leaveBtn clicked");
doLeave();
}
javascript
function doLeave() {
var jsonMsg = {
'cmd': 'leave',
'roomId': roomId,
'uid': localUserId,
};
var message = JSON.stringify(jsonMsg); //将json对象转换为字符串
zeroRTCEngine.sendMessage(message); //设计方法:用实现方法而不是直接用变量
console.info("doLeave message: " + message);
}
1.2 服务端
修改signal_server.js
文件,在监听客户端发送的消息处添加leave信令
代码
javascript
// 监听客户端发送的消息
conn.on("text", function (str) {
console.info("Received msg:"+str);
var jsonMsg = JSON.parse(str);
switch(jsonMsg.cmd){
case SIGNAL_TYPE_JOIN:
handleJoin(jsonMsg, conn);
break;
case SIGNAL_TYPE_LEAVE:
handleLeave(jsonMsg);
break;
}
});
handleLeave()函数
:在某个用户离开房间时,向其他房间内在线的用户发送通知,告知某个用户离开了当前房间。实现原理是通过哈希表(roomMap
)来存储房间内的用户信息,当某个用户离开房间时,从哈希表中移除该用户,并遍历房间内其他在线用户,发送通知。
首先,代码会打印一条日志,显示用户ID(uid
)和房间ID(roomId
)。
然后,代码会获取存储房间信息的Map(roomMap
)。
如果房间不存在,代码会打印一条错误日志,然后返回。
从roomMap
中移除用户ID(uid
)。
如果房间内还有其他在线用户,遍历房间内所有用户(clients
)。
对于每个在线用户,会创建一个JSON
消息,内容包括用户离开房间的事件类型(SIGNAL_TYPE_PEER_LEAVE
)和离开的用户ID(remoteUid
)。
将JSON消息转换为字符串(msg
),并通过WebSocket发送给该用户(remoteClient
)。
最后,代码会打印一条日志,通知用户离开房间。
javascript
// 处理用户离开房间
function handleLeave(message){
// 获取房间ID和用户ID
var roomId = message.roomId;
var uid = message.uid;
console.log(" uid:" + uid + " leave room: "+roomId);
// 获取房间Map
var roomMap = roomTableMap.get(roomId);
if(roomMap == null){
console.error("roomId:" + roomId + " is not exist");
return;
}
roomMap.remove(uid);
if(roomMap.size() >= 1){
var clients = roomMap.getEntrys();
for(var i in clients){
jsonMsg = {
'cmd':SIGNAL_TYPE_PEER_LEAVE,
'remoteUid':uid
}
// 给所有房间内其他用户发送用户离开消息
var msg = JSON.stringify(jsonMsg);
var remoteUid = clients[i].key;
var remoteClient =roomMap.get(remoteUid);
if(remoteClient){
console.info("notify peer"+ remoteClient.uid +"uid" + uid + "leave room");
remoteClient.conn.sendText(msg);
}
}
}
}
运行结果:
客户1:
客户2:
服务端:
二、媒体协商和网络协商API
媒体协商
createOffer
基本格式:aPromise = myPeerConnection.createOffer([options])
;
javascript
var options = {
offerToReceiveAudio: true, // 告诉另一端,你是否想接收音频,默认true
offerToReceiveVideo: true, // 告诉另一端,你是否想接收视频,默认true
iceRestart: false, // 是否在活跃状态重启ICE网络协商
};
createAnswer
基本格式:aPromise = RTCPeerConnection .createAnswer([ options ])
; 目前createAnswer的options是无效的。setLocalDescription
基本格式:aPromise = RTCPeerConnection .setLocalDescription(sessionDescription)
;setRemoteDescription
基本格式:aPromise = pc.setRemoteDescription(sessionDescription)
;
https://webrtc.github.io/samples/src/content/peerconnection/restartice/
活跃状态下,页面源代码中iceRestart
默认为true
javascript
offerOptions.iceRestart = true
修改iceRestart
为flase
,则响应如下,不再进行ice candidate交换
网络协商
addIceCandidate
基本格式:aPromise = pc.addIceCandidate
(候选人);
candidate
注意Android
和Web
端的不同。
属性 | 说明 |
---|---|
candidate | 候选者描述信息 |
sdpMid | 与候选者相关的媒体流的识别标签 |
sdpMLineIndex | 在SDP中 m=的索引值 |
usernameFragment | 包括了远端的唯一标识 |
javascript
var candidateJson = {
'label': event.candidate.sdpMLineIndex,
'id': event.candidate.sdpMid,
'candidate': event.candidate.candidate
};