WebRTC 使用之 —— 使用 RTCPeerConnection 創建視頻鏈接 | 掘金技術徵文

接下來的例子,將展現如何使用 WebRTC 的 RTCPeerConnection API 創建視頻鏈接。html

建立工程

建立以下的工程:bash

一個 index.html + 一個main.js。async

在 html 中添加 video

在 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

Index.html 裏的佈局實現後,開始在 main.js 裏實現具體的功能。

Start 功能實現

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 功能實現

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 功能實現

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 實現的簡單的視頻鏈接功能就實現完成了。

Agora SDK 使用體驗徵文大賽 | 掘金技術徵文,徵文活動正在進行中

相關文章
相關標籤/搜索