WebRTC简介(二)

WebRTC简介(二)

Webrtc架构

image-20211129151851667.png

Webrtc协议栈

image-20211129151916955.png

WebRTC API

WebRTC 虽然底层实现极其复杂,但是面向开发者的API还是非常简洁的,主要分为三个方面:

MediaStream

MediaStream — MediaStream用来表示一个媒体数据流(通过getUserMedia接口获取),允许你访问输入设备,如麦克风和 Web摄像机,该 API 允许从其中任意一个获取媒体流。

以下是示例代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div>
        <button id="start">开始录制</button>
        <button id="stop">停止录制</button>
    </div>
    <div>
        <video autoplay controls id="stream"></video>
    </div>
    <script>
        // 只获取视频
        let constraints = {audio: false, video: true}; 
        let startBtn = document.getElementById('start')
        let stopBtn = document.getElementById('stop')
        let video = document.getElementById('stream')
        startBtn.onclick = function() {
            navigator.getUserMedia(constraints, function(stream) {
                video.srcObject = stream;
                window.stream = stream;
            }, function(err) {
                console.log(err)
            })
        }
        stopBtn.onclick = function() {
            video.pause();
        }
    </script>
</body>
</html>

RTCPeerConnection

RTCPeerConnection:一个RTCPeerConnection对象允许用户在两个浏览器之间直接通讯。
SDP: 用来描述当前连接者想要传输的内容,支持的协议类型,支持的编解码类型等。
RTCIceCandidate:表示一个ICE协议的候选者,简单的说,就是目标节点的IP以及端口。
RTCIceServer:表示一个ICE Server,其主要用于当前主机的IP发现,通过和ICE Server通讯,我们会得到一组可供连接使用的IP:Port候选值,双方通过交换ICE候选值来建立起连接。

RTCDataChannel

非音视频数据都是通过RTCDataChannel进行传输
DataChannel:数据通道( DataChannel)接口表示一个在两个节点之间的双向的数据通道,该通道可以设置成可靠传输或非可靠传输。

更多API与示例请参考官方示例,此处不再赘述, 官方示例地址:https://webrtc.github.io/samples/

Stun服务器和Signal服务器

WebRTC并不提供Stun服务器和Signal服务器,服务器端需要自己实现。

Stun服务器可以用google提供的实现stun协议的测试服务器(stun:stun.l.google.com:19302),Signal服务器则完全需要自己实现了,它需要在ClientA和ClientB之间传送彼此的SDP信息和candidate信息,ClientA和ClientB通过这些信息建立P2P连接来传送音视频数据。由于网络环境的复杂性,并不是所有的客户端之间都能够建立P2P连接,这种情况下就需要有个trun服务器做音视频数据的中转。

Stun/turn、Signal服务器的实现在WebRTC源码中都有示例。

Stun/turn有开源实现:coturn
image-20211129152734274.png

PeerJS

使用WebRTC原生API还是有一些难度的,但是有开源项目对其进行了二次封装,此处就说说peerjs

PeerJS提供了一个完整的、可配置的、易于使用的点对点 API,它构建在 WebRTC 之上,支持数据通道和媒体流。
Github地址:https://github.com/peers/peerjs
Star:9.4k
PeerServer 一个PeerJS的服务端,有助于 PeerJS 客户端之间建立连接
Github地址:https://github.com/peers/peerjs-server
Star:3.2k
coturn:TURN 和 STUN Server 的免费开源实现
Github地址:https://github.com/coturn/coturn
Star:6.6k

服务端代码示例:

const express = require('express');
const { ExpressPeerServer } = require('peer');

const app = express();

app.get('/', (req, res, next) => res.send('Hello world!'));

const server = app.listen(9000);

const peerServer = ExpressPeerServer(server, {
  path: '/peer-server'
});

app.use('/', peerServer);
app.use(express.static('public'));

学生端代码示例:

<!DOCTYPE html>
<html>
<head>
  <title>Realtime communication with WebRTC</title>
  <style>
    body {
      font-family: sans-serif;
    }

    video {
      max-width: 100%;
      width: 320px;
    }
  </style>
</head>

<body>
    <video id="video" autoplay playsinline></video>

    <div>
      <button id="readyButton">准备</button>
    </div>

    <script src="https://unpkg.com/peerjs@1.3.1/dist/peerjs.min.js"></script>
    <script>
        const video = document.getElementById('video');
        const readyButton = document.getElementById('readyButton');
        
        readyButton.addEventListener('click', e => {
            const peer = new Peer("dc8a395f-76c2-4607-a071-416ed4086d87", {
              host: 'localhost',
              port: 9000,
              path: '/peer-server'
            });
            
            /**
            const conn = peer.connect('e3c6447d-182d-4b80-a975-2dd13dbc1721');
            
            peer.on('connection', (conn) => {
              conn.on('data', (data) => {
                console.log(data);
              });
            });*/
            
            peer.on('call', call => {
                /**
                const getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
                getUserMedia({video: true, audio: false}, (stream) => {
                    call.on('stream', (remoteStream) => {
                      video.srcObject = remoteStream;
                    });
                  }, (err) => {
                    console.log('Failed to get local stream' ,err);
                  });*/
                console.log('---');
                call.on('stream', (remoteStream) => {
                    video.srcObject = remoteStream;
                });
            });

        });
        
    </script>
</body>
</html>

老师端代码示例:

<!DOCTYPE html>
<html>
<head>
  <title>Realtime communication with WebRTC</title>
  <style>
    body {
      font-family: sans-serif;
    }

    video {
      max-width: 100%;
      width: 320px;
    }
  </style>
</head>

<body>
    <video id="video" autoplay playsinline></video>

    <div>
      <button id="startButton">创建对等端</button>
      <button id="sendButton">发送</button>
      <button id="stopButton">停止</button>
    </div>

    <script src="https://unpkg.com/peerjs@1.3.1/dist/peerjs.min.js"></script>
    <script>
        const video = document.getElementById('video');
        const startButton = document.getElementById('startButton');
        const sendButton = document.getElementById('sendButton');
        
        startButton.addEventListener('click', e => {
            
        })
        
        sendButton.addEventListener('click', e => {
        
            const peer = new Peer("e3c6447d-182d-4b80-a975-2dd13dbc1721", {
              host: 'localhost',
              port: 9000,
              path: '/peer-server'
            });
            
            /**
            const conn = peer.connect('dc8a395f-76c2-4607-a071-416ed4086d87');
            
            conn.on('open', () => {
              conn.send('hi!');
              console.log('teacher has open !');
            });*/
            /**
            const getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
            getUserMedia({video: true, audio: false}, (stream) => {
              video.srcObject = stream;
              peer.call('dc8a395f-76c2-4607-a071-416ed4086d87', stream);
            }, (err) => {
              console.log('Failed to get local stream' ,err);
            });*/
        })
    </script>
</body>
</html>

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容