接下來的例子,將展現如何使用 WebRTC 的 RTCPeerConnection API 創建視頻鏈接。html
建立以下的工程:bash
一個 index.html + 一個main.js。async
在 index.html 中,添加兩個 video,分別是 localVideo 和 remoteVideo,用於模擬創建視頻鏈接的兩端。ide
在建立三個按鈕:Start、Call、Hang Up,用來模擬視頻創建過程當中的操做:佈局
Start:localVideo 打開攝像頭並顯示視頻post
Call:localVideo 向 remoteVideo 發出請求,並顯示 remoteVideo 的視頻ui
Hang Up:remoteVideo 掛斷spa
所以 index.html 的代碼爲:code
<!DOCTYPE html>
<html>
<body>
<div id="container">
<video id="localVideo" playsinline autoplay muted></video>
<video id="remoteVideo" playsinline autoplay></video>
<div class="box">
<button id="startButton">Start</button>
<button id="callButton">Call</button>
<button id="hangupButton">Hang Up</button>
</div>
</div>
<script src="js/main.js" async></script>
</body>
</html>
複製代碼
顯示的效果以下:cdn
Start 功能要實現 localVideo 打開攝像頭並顯示視頻的功能。
這時候須要用到 getUserMedia 這個 API。
代碼以下:
let localStream;
const startButton = document.getElementById('startButton');
startButton.addEventListener('click', start);
async function start() {
console.log('Requesting local stream');
startButton.disabled = true;
try {
const stream = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
console.log('Received local stream');
localVideo.srcObject = stream;
localStream = stream;
callButton.disabled = false;
} catch (e) {
alert(`getUserMedia() error: ${e.name}`);
}
}
複製代碼
只要點擊 Start,就會在網頁上展現當前的視頻,以下:
![image-20190603030244840](/Users/koude/Library/Application Support/typora-user-images/image-20190603030244840.png)
Call 功能要實現 localVideo 向 remoteVideo 發出請求,並顯示 remoteVideo 的視頻。
Call 功能是一個核心功能,會爲兩端的視頻創建鏈接,須要用到 RTCPeerConnection 這個 API。
首先獲取 localVideo 和 remoteVideo 這兩個 Video,並建立兩個變量來分別表明這兩個 Video 的 PeerConnection,localVideo 爲 pc1,remoteVideo 爲 pc2:
const localVideo = document.getElementById('localVideo');
const remoteVideo = document.getElementById('remoteVideo');
let pc1;
let pc2;
複製代碼
而後獲取 Call 按鈕,併爲其分配點擊事件:
const callButton = document.getElementById('callButton');
callButton.addEventListener('click', call);
async function call() {
}
複製代碼
在 call() 裏面就要使用到 RTCPeerConnection 來創建鏈接,一個是 pc1,一個是 pc1,而後 pc1 向 pc2 創建鏈接:
async function call() {
callButton.disabled = true;
hangupButton.disabled = false;
console.log('Starting call');
caches
pc1 = new RTCPeerConnection();
console.log('Created local peer connection object pc1');
pc1.addEventListener('icecandidate', e => onIceCandidate(pc1, e));
pc2 = new RTCPeerConnection({});
console.log('Created remote peer connection object pc2');
pc2.addEventListener('icecandidate', e => onIceCandidate(pc2, e));
pc2.addEventListener('track', gotRemoteStream);
localStream.getTracks().forEach(track => pc1.addTrack(track, localStream));
console.log('Added local stream to pc1');
try {
console.log('pc1 createOffer start');
const offer = await pc1.createOffer(offerOptions);
await onCreateOfferSuccess(offer);
} catch (e) {
}
}
async function onCreateOfferSuccess(desc) {
console.log(`Offer from pc1\n${desc.sdp}`);
console.log('pc1 setLocalDescription start');
try {
await pc1.setLocalDescription(desc);
} catch (e) {
}
console.log('pc2 setRemoteDescription start');
try {
await pc2.setRemoteDescription(desc);
} catch (e) {
}
console.log('pc2 createAnswer start');
// Since the 'remote' side has no media stream we need
// to pass in the right constraints in order for it to
// accept the incoming offer of audio and video.
try {
const answer = await pc2.createAnswer();
await onCreateAnswerSuccess(answer);
} catch (e) {
}
}
function gotRemoteStream(e) {
if (remoteVideo.srcObject !== e.streams[0]) {
remoteVideo.srcObject = e.streams[0];
console.log('pc2 received remote stream');
}
}
async function onCreateAnswerSuccess(desc) {
console.log(`Answer from pc2:\n${desc.sdp}`);
console.log('pc2 setLocalDescription start');
try {
await pc2.setLocalDescription(desc);
} catch (e) {
}
console.log('pc1 setRemoteDescription start');
try {
await pc1.setRemoteDescription(desc);
} catch (e) {
}
}
async function onIceCandidate(pc, event) {
try {
await (getOtherPc(pc).addIceCandidate(event.candidate));
} catch (e) {
}
}
const offerOptions = {
offerToReceiveAudio: 1,
offerToReceiveVideo: 1
};
function getName(pc) {
return (pc === pc1) ? 'pc1' : 'pc2';
}
function getOtherPc(pc) {
return (pc === pc1) ? pc2 : pc1;
}
複製代碼
至此,只要點擊 Call,就會創建鏈接,由於這裏用到的視頻是同一臺電腦的,因此畫面以下:
Hang Up 功能要實現掛斷 remoteVideo 的視頻鏈接的功能。很好實現,只要將 pc1和pc2的鏈接關閉就行,代碼以下:
const hangupButton = document.getElementById('hangupButton');
hangupButton.addEventListener('click', hangup);
function hangup() {
console.log('Ending call');
pc1.close();
pc2.close();
pc1 = null;
pc2 = null;
hangupButton.disabled = true;
callButton.disabled = false;
}
複製代碼
點擊 Hang Up 以後的畫面以下:
至此一個使用 WebRTC 的 RTCPeerConnection API 實現的簡單的視頻鏈接功能就實現完成了。