web技术分享| 实现WebRTC多个对等连接

幽映每白日,清辉照衣裳。这篇文章主要讲述web技术分享| 实现WebRTC多个对等连接相关的知识,希望能为你提供帮助。
流程简介

  • 【web技术分享| 实现WebRTC多个对等连接】通过MediaDevices.getUserMedia()获取音频和视频轨道。
  • 通过createOffer()启动与远程对等方的新 WebRTC 连接。
  • 用信令通信上传错误并控制启动或关闭会话。
  • 互换媒体和客户端信息
初始化操作元素
const startButton = document.getElementById(\'startButton\'); const callButton = document.getElementById(\'callButton\'); const hangupButton = document.getElementById(\'hangupButton\'); const video1 = document.querySelector(\'video#video1\'); const video2 = document.querySelector(\'video#video2\'); const video3 = document.querySelector(\'video#video3\'); callButton.disabled = true; hangupButton.disabled = true; startButton.onclick = start; callButton.onclick = call; hangupButton.onclick = hangup; let pc1Local; let pc1Remote; let pc2Local; let pc2Remote; const offerOptions = { offerToReceiveAudio: 1, offerToReceiveVideo: 1 };

开始采集音视频
function start() { startButton.disabled = true; navigator.mediaDevices .getUserMedia({ audio: true, video: true }) .then(stream => { video1.srcObject = stream; window.localStream = stream; callButton.disabled = false; }) .catch(e => console.log(e)); }

远端播放视频
function call() { callButton.disabled = true; hangupButton.disabled = false; const audioTracks = window.localStream.getAudioTracks(); const videoTracks = window.localStream.getVideoTracks(); if (audioTracks.length > 0) { console.log(`Using audio device: ${audioTracks[0].label}`); } if (videoTracks.length > 0) { console.log(`Using video device: ${videoTracks[0].label}`); } const servers = null; pc1Local = new RTCPeerConnection(servers); pc1Remote = new RTCPeerConnection(servers); pc1Remote.ontrack = gotRemoteStream1; pc1Local.onicecandidate = iceCallback1Local; pc1Remote.onicecandidate = iceCallback1Remote; pc2Local = new RTCPeerConnection(servers); pc2Remote = new RTCPeerConnection(servers); pc2Remote.ontrack = gotRemoteStream2; pc2Local.onicecandidate = iceCallback2Local; pc2Remote.onicecandidate = iceCallback2Remote; window.localStream.getTracks().forEach(track => pc1Local.addTrack(track, window.localStream)); pc1Local .createOffer(offerOptions) .then(gotDescription1Local, onCreateSessionDescriptionError); window.localStream.getTracks().forEach(track => pc2Local.addTrack(track, window.localStream)); pc2Local.createOffer(offerOptions) .then(gotDescription2Local, onCreateSessionDescriptionError); }

其他方法
function onCreateSessionDescriptionError(error) { console.log(`Failed to create session description: ${error.toString()}`); }function gotDescription1Local(desc) { pc1Local.setLocalDescription(desc); pc1Remote.setRemoteDescription(desc); pc1Remote.createAnswer().then(gotDescription1Remote, onCreateSessionDescriptionError); }function gotDescription1Remote(desc) { pc1Remote.setLocalDescription(desc); console.log(`Answer from pc1Remote\\n${desc.sdp}`); pc1Local.setRemoteDescription(desc); }function gotDescription2Local(desc) { pc2Local.setLocalDescription(desc); pc2Remote.setRemoteDescription(desc); pc2Remote.createAnswer().then(gotDescription2Remote, onCreateSessionDescriptionError); }function gotDescription2Remote(desc) { pc2Remote.setLocalDescription(desc); pc2Local.setRemoteDescription(desc); }function hangup() { console.log(\'Ending calls\'); pc1Local.close(); pc1Remote.close(); pc2Local.close(); pc2Remote.close(); pc1Local = pc1Remote = null; pc2Local = pc2Remote = null; hangupButton.disabled = true; callButton.disabled = false; }function gotRemoteStream1(e) { if (video2.srcObject !== e.streams[0]) { video2.srcObject = e.streams[0]; console.log(\'pc1: received remote stream\'); } }function gotRemoteStream2(e) { if (video3.srcObject !== e.streams[0]) { video3.srcObject = e.streams[0]; } }function iceCallback1Local(event) { handleCandidate(event.candidate, pc1Remote, \'pc1: \', \'local\'); }function iceCallback1Remote(event) { handleCandidate(event.candidate, pc1Local, \'pc1: \', \'remote\'); }function iceCallback2Local(event) { handleCandidate(event.candidate, pc2Remote, \'pc2: \', \'local\'); }function iceCallback2Remote(event) { handleCandidate(event.candidate, pc2Local, \'pc2: \', \'remote\'); }function handleCandidate(candidate, dest, prefix, type) { dest.addIceCandidate(candidate) .then(onAddIceCandidateSuccess, onAddIceCandidateError); }function onAddIceCandidateSuccess() { console.log(\'AddIceCandidate success.\'); }function onAddIceCandidateError(error) { console.log(`Failed to add ICE candidate: ${error.toString()}`); }

html
< div id="container"> < video id="video1" playsinline autoplay muted> < /video> < video id="video2" playsinline autoplay> < /video> < video id="video3" playsinline autoplay> < /video> < div> < button id="startButton"> Start< /button> < button id="callButton"> Call< /button> < button id="hangupButton"> Hang Up< /button> < /div> < /div>

CSS
body { font-family: \'Roboto\', sans-serif; font-weight: 300; margin: 0; padding: 1em; word-break: break-word; } button { background-color: #d84a38; border: none; border-radius: 2px; color: white; font-family: \'Roboto\', sans-serif; font-size: 0.8em; margin: 0 0 1em 0; padding: 0.5em 0.7em 0.6em 0.7em; } button:active { background-color: #cf402f; } button:hover { background-color: #cf402f; } button[disabled] { color: #ccc; } button[disabled]:hover { background-color: #d84a38; }div#container { margin: 0 auto 0 auto; max-width: 60em; padding: 1em 1.5em 1.3em 1.5em; } video { background: #222; margin: 0 0 20px 0; --width: 100%; width: var(--width); height: calc(var(--width) * 0.75); } button { margin: 0 20px 0 0; width: 83px; } button#hangupButton { margin: 0; } video { margin: 0 0 20px 0; --width: 40%; width: var(--width); height: calc(var(--width) * 0.75); } #video1 { margin: 0 20px 20px 0; }


    推荐阅读