在1v1視頻通話中,雖然有發起人和接收人的概念,但是消息的發送和接受是“沒有對象”的,也就是,通過服務器轉發的message中沒有指明接受消息的對象,這在房間裏最多容納兩個人的前提下不會產生問題,但是在多人通話的過程中,就失效了。
對於我來說,我採取的措施是在offer、answer和candidate消息中加入新的屬性,也就是“callee”, 即呼叫人,舉個例子:
function handleIceCandidate(event) {
//將本地的candidate發送給對方
console.log('icecandidate event: ', event);
if (event.candidate) {
sendMessage({
type: 'candidate',
label: event.candidate.sdpMLineIndex,
id: event.candidate.sdpMid,
candidate: event.candidate.candidate,
callee: id_list[i] //新加入的屬性,表示這個信息接收的對象
});
} else {
console.log('candidates end');
}
}
在信息的接收端,相應的,就多了一個判斷條件:
socket.on('message', function (message){
//各種判斷條件
else if (message.type === 'candidate' && isStarted && message.callee === socket.id) {
console.log("收到對方發來的candidate");
pc[i].addIceCandidate(candidate);
}
//其他代碼
}
這樣就避免了多個對象均接收到message卻搞不清應該是在呼叫哪個的困境。
在這個前提下,我就簡單講一講我多人視頻實現的思路。
-
設置一個“isNew”變量,用來表示新進入房間的用戶。也就是對於新用戶
isNew = true
,對於已經在房間裏的用戶,isNew = false
,對於第一個進入房間的人,,isNew = false
; -
當新用戶進入房間時,已有用戶會受到“join”信號,此時,已有用戶向新用戶發送“ready”信號,同時發送自己的id;新用戶每受到一個“ready”信號,就將信號中的id保存在一個列表中;
-
新用戶按照列表(id_list),以此與已有用戶建立連接。在與每個已有用戶建立連接之前,新用戶會發送一個帶有目標id的message(我取名叫“call”),對於已有用戶,只有id相符的
isCallee = ture
,只有在這個條件下,才能接受後續的來自新用戶的offer信息和candidate信息,否則不予響應,連接建立結束後,令isCallee = false
,開始建立新的連接; -
對於每一個已有的用戶,只需要實例化pc[n]和新用戶建立連接即可,(
n = pc.length
); -
當新用戶與每個已有用戶都建立連接後,
isNew = false
,等待其他新用戶的來臨。
按照這種方式,新進入房間的用戶能與每一個已經在房間的用戶建立連接,這樣邏輯關係也比較清楚。
當然,還有很多其他的方式可以實現,在這裏就不贅述了。