随手记
首页 分类 成员 关于

webrtc

发表于: 2020-10-10 00:00:00 by arvin

分类于:javascript

阅读:

什么是WebRTC

很久很久之前~~,其实也不太久,浏览器是不支持相互之间直接建立信道进行通信,就像我想从页面a和页面b之间进行数据交流,一般都是a发送到服务器上,服务器把a的消息中转到b上,反之亦然,这样一段消息要有两次通信,还要首受到两次通讯的带宽限制,像是视频音频之类的数据流直接打出了GG,所以就WebRTC诞生啦~ WebRTC就是个JavaScript接口,能够通过浏览器调用摄像头、话筒,然后建立两个浏览器之前的信道,这个信道可以发送任数据,而不通过服务器

示例

1.搭建本地服务

首先我们先建立个本地服务,我用的是express,假定你已经安装了Node.js,接下来进入命令行工具,为你的应用创建一个目录,然后进入此目录并将其作为当前工作目录。

mkdir myapp
cd myapp

然后通过命令,创建一个 package.json 文件

npm init -y

接下来在 myapp 目录下安装 Express 并将其保存到依赖列表中

npm install express --save

然后安装ws(是一种易于使用,运行迅速且经过全面测试的WebSocket客户端)

npm install ws --save

安装skyrtc(一个集成的nodejs编写的WebRTC服务端库)

npm install skyrtc --save

安装uuid(能够快速生成随机的UID)

npm install uuid --save

安装完成后,在根目录下新建server.js,并写入内容

const express = require('express')
const app = express()
const port = process.env.PORT || 3000;
const path = require("path");

app.use(express.static(path.join(__dirname, 'public')));

app.get('/',(req,res)=>{
    res.send('hello world')
})

app.listen(port, () => {
    console.log(`Example app listening on http://localhost:${port}`)
})

在命令行输入

node server.js

打开http://localhost:3000看到”Hello World!”,说明本地服务好啦! 但是每次都要执行修改都要重新启动服务,所以我们安装一个nodemon来监听测目录中的文件更改,并自动重新启动

npm install nodemon --save

然后修改根目录下的package.json文件中的scripts为

    "scripts": {
        "start": "nodemon server.js"
    },

然后在命令行输入命令

npm run start

打开http://localhost:3000看到”Hello World!”,修改server.js中的sender

app.get('/',(req,res)=>{
    res.send('hello webrtc')
})

刷新[http://localhost:3000]页面,你会发现没有重启服务,页面也变成了hello webrtc

然后在根目录新建public/demo.html 并写入

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        video {
            vertical-align: top;
            background: #ccc;
        }
    </style>
</head>
<body>
    <div id="app">
        <button onclick="openWebRTC()">开始</button>
        <button onclick="closeWebRTC()">结束</button>
        <video id="oVideo1" autoplay></video>
        <video id="oVideo2" autoplay></video>
    </div>
</body>
<script>
    let subscriberPeerConnection = null;
    let publisherPeerConnection = null;
    let localStream = null;

    // 开始
    function openWebRTC() {
        console.log("拉取摄像头权限")
        navigator.mediaDevices.getUserMedia({
            audio: true,
            video: {
                width: {exact: 720},
                height: {exact: 405}
            }
        }).then((stream) => {
            console.log('拉取摄像头权限成功')
            console.log('摄像头数据流放入视频1')
            document.getElementById('oVideo1').srcObject = localStream = stream;//摄像头1

            createSubscriber();//建立连接
            createPublisher();//建立连接
        }).catch(function (error) {
            console.log('拉取摄像头权限失败', err)
        });
    }


    // 建立连接
    function createSubscriber() {
        console.log('创建本地计算机到远端的WebRTC连接1')
        subscriberPeerConnection = new RTCPeerConnection({"iceServers": [{"urls": "stun:stun.l.google.com:19302"}]})


        subscriberPeerConnection.ontrack = function (event) {
            console.log('远端的WebRTC连接1 触发的轨道事件')
            console.log('远端的WebRTC连接1 数据流放入视频2')
            document.getElementById('oVideo2').srcObject = event.streams[0];
        }

        // 当获得新的源之后,需要将该源的信息发送给远端信号服务器,并分发至其他端的RTCPeerConnection。其他RTCPeerConnection通过addIceCandidate()方法将新candidate 中携带的信息,将新的源描述信息添加进它的备选池中;
        subscriberPeerConnection.onicecandidate = function (event) {
            console.log('远端的WebRTC连接1 添加新的RTCICECandidate对象')

            if (publisherPeerConnection) {
                console.log('远端的WebRTC连接2 将远端的WebRTC连接1 添加的candidate中携带的信息,将新的源描述信息添加进它的备选池中')

                publisherPeerConnection.addIceCandidate(event.candidate).then(() => {
                    console.log('添加成功');
                }).catch(function (error) {
                    console.log('添加失败');
                });
            }
        }
    }

    // 建立接受者连接
    function createPublisher() {
        console.log('创建本地计算机到远端的WebRTC连接2')
        publisherPeerConnection = new RTCPeerConnection({"iceServers": [{"urls": "stun:stun.l.google.com:19302"}]})

        console.log('将视频1中轨道信息全部添加到远端的WebRTC连接2')
        localStream.getTracks().forEach((track) => {
            publisherPeerConnection.addTrack(track, localStream);
        });

        publisherPeerConnection.onicecandidate = function (event) {
            console.log('远端的WebRTC连接2 添加新的RTCICECandidate对象')

            if (subscriberPeerConnection) {
                console.log('远端的WebRTC连接1 将远端的WebRTC连接2 添加的candidate中携带的信息,将新的源描述信息添加进它的备选池中')

                subscriberPeerConnection.addIceCandidate(event.candidate).then(() => {
                    console.log('添加成功');
                }).catch(function (error) {
                    console.log('添加成功');
                });
            }
        }

        console.log('远端的WebRTC连接2 启动创建一个SDP offer')
        publisherPeerConnection.createOffer({
            offerToReceiveAudio: true,
            offerToReceiveVideo: true
        }).then((desc) => {
            // 更改与连接关联的本地描述。此描述指定连接本地端的属性,包括媒体格式
            console.log('远端的WebRTC连接1和远端的WebRTC连接2 更改与连接关联的本地描述,保持与新建的SDP offe一致')
            publisherPeerConnection.setLocalDescription(desc);
            subscriberPeerConnection.setRemoteDescription(desc);

            subscriberPeerConnection.createAnswer().then((desc2) => {
                subscriberPeerConnection.setLocalDescription(desc2);
                publisherPeerConnection.setRemoteDescription(desc2);
            }).catch(function (error) {
            });
        }).catch(function (error) {
        });
    }

    function closeWebRTC() {
        localStream.getTracks().forEach(track => {
            track.stop();
        });
        publisherPeerConnection.close();
        subscriberPeerConnection.close();
    }
</script>
</html>

打开http://localhost:3000/demo.html并刷新就可以体验基本的webrtc功能啦