简述
socket.io是封装了原生websocket的一套插件,自带房间功能
相关链接:socket.io官网,socket.io常用api
mediasoup是封装了原生web-rtc的SFU结构型插件(原生的web-rtc是mesh结构)
启动步骤
- ubuntu系统(windows跑不起来,可用vmware),node.js,npm
- 项目下载:https://github.com/mkhahani/mediasoup-sample-app.git
- 复制粘贴cofig.example.js为config.js文件
- 修改config.js文件
//在根目录下创建certs目录,并放入2个证书(找后台同事要),对应以下路径
sslCrt: 'certs/fullchain.pem',
sslKey: 'certs/privkey.pem',
...
// WebRtcTransport settings
webRtcTransport: {
listenIps: [
{
ip: '10.20.10.209', //改为你本机的ip地址
announcedIp: null,
}
],
maxIncomingBitrate: 1500000,
initialAvailableOutgoingBitrate: 1000000,
}
-
安装依赖,npm install
browserify有时会安装不上,那么就单独安装一下
npm install browserify
browserify<官网> 的作用是将用到的众多资源(css,img,js,…) 打包成一个js文件,如下
browserify entry.js -o bundle.js
将entry.js及其中通过require引入的所有资源,全部打包成bundle.js文件输出
-
运行项目,npm start
源码图示
这个demo主要是展示 利用Mediasoup框架把 Local端 的音频流发送到 Remote端 显示出来,实现内容如下图 实线框 和 实线 部分:
注意:该demo代码只实现了上图 实线框 和 实线 中的功能,虚线框和虚线 的内容并没有实现
代码实现的结果:
创建一个房间,在一个页面中展示从 local 发送到 remote 端 的视频
源码解读
客户端 client.js (local 和 remote) | 服务端 server.js |
---|---|
1. 启动服务器,调用runExpressApp() | |
2. 开启https服务,调用runWebServer() | |
3. 开启socketIO功能,调用runSocketServer(),并定义socket的各种事件处理,用于响应客户端socket | |
4. 开启mediasoup服务端功能,调用runMediasoupWorker() | |
4.1 创建worker,await mediasoup.createWorker({… 注:一个 'worker’代表一个’mediasoup ‘C ++子进程,运行在单个CPU核心上,它可以处理多个’routers’ 参考文章 | |
4.2 定义worker失效事件,worker.on(‘died’, () => {…} | |
4.3 利用worker创建Router,await worker.createRouter(… 注:一个 'Router’相当于一个房间 | |
5. 客户端(local端)点击connect按钮,启动socket功能,socket = socketClient(serverUrl, opts); | |
6. 引入与信令服务器交互的方法,socket.request = socketPromise(socket); | |
7. 监听信令服务器的各种事件,socket.on(‘connect’, async () => {… | |
8. 当客户端与信令服务器的socket连通之后,向服务端请求mediasoup相关信息,const data = await socket.request(‘getRouterRtpCapabilities’); | |
9. 用请求到的rtp信息,加载mediasoup设备 device = new mediasoup.Device(); await device.load({ routerRtpCapabilities }); | |
10. 点击Start Webcam / Share Screen按钮,调用publish()方法 | |
11. 请求服务端创建Producer,const data = await socket.request(‘createProducerTransport’, { | |
12. 服务端监听到,socket.on(‘createProducerTransport’, async (data, callback) => { | |
12.1 服务端创建用于webrtc的Producer,创建完通知客户端 await mediasoupRouter.createWebRtcTransport({ | |
13. 客户端收到通知,创建本地mediasoup实例 const transport = device.createSendTransport(data); | |
14. 当本地mediasoup与信令服务器连通后,请求服务端的Producer接入webrtc transport.on(‘connect’, async ({ dtlsParameters }, callback, errback) => { socket.request(‘connectProducerTransport’, { dtlsParameters }) | |
15. 服务端监听到,socket.on(‘connectProducerTransport’, async (data, callback) => { | |
15.1 服务端的Producer接入webrtc,通知客户端 await producerTransport.connect({ dtlsParameters: data.dtlsParameters }); | |
16. 获取视频流,stream = await getUserMedia(transport, isWebcam); | |
16.1 当服务端的Producer连接webrtc的状态变为 connected 时,把本地视频流在local窗口展示 transport.on(‘connectionstatechange’, (state) => {… case ‘connected’: document.querySelector(’#local_video’).srcObject = stream; | |
16.2 到这里可以看到local窗口显示了本地视频 | |
17. 用本地mediasoup实例准备视频流信息 producer = await transport.produce(params); | |
18. 通知服务端的Producer来协商连通 local端-服务端 视频流的信息 const { id } = await socket.request(‘produce’, { | |
19. 服务端监听到,socket.on(‘produce’, async (data, callback) => { | |
19.1 与客户端协商好,将客户端的视频流接入webrtc中 producer = await producerTransport.produce({ kind, rtpParameters }); | |
19.3 同时通知其他客户端,socket.broadcast.emit(‘newProducer’); | |
20. 远端(remote端)点击Subscribe按钮,准备接收 local端 的视频流,调用subscribe() | |
21. 请求服务端创建Consumer const data = await socket.request(‘createConsumerTransport’, { | |
22. 服务端监听到,socket.on(‘createConsumerTransport’, async (data, callback) => { | |
22.1 服务端创建用于webrtc的Consumer,创建完通知远端 await mediasoupRouter.createWebRtcTransport({ | |
23. 远端收到通知,创建远端mediasoup实例 const transport = device.createRecvTransport(data); | |
24. 当远端mediasoup与信令服务器连通后,请求服务端的Consumer接入webrtc transport.on(‘connect’, ({ dtlsParameters }, callback, errback) => { socket.request(‘connectConsumerTransport’, { | |
25. 服务端监听到,socket.on(‘connectConsumerTransport’, async (data, callback) => { | |
25.1 服务端的Consumer接入webrtc,通知远端 await consumerTransport.connect({ dtlsParameters: data.dtlsParameters }); | |
26. 通知服务端的Consumer来协商连通 服务端-remote端 视频流的信息 const data = await socket.request(‘consume’, { rtpCapabilities }); | |
27. 服务端监听到,socket.on(‘consume’, async (data, callback) => { | |
27.1 与远端协商好,将从webrtc中收到的视频流引向远端 await createConsumer(producer, data.rtpCapabilities) | |
28.最后,从remote窗口也可看到从local端接收到的视频 |