WebRTC简介(二)
Webrtc架构
Webrtc协议栈
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
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>