你想要的流水线

1
docker run --name srs -it --env CANDIDATE=$CANDIDATE --network="host" -v ~/workspace/srs/conf/:/usr/local/srs/conf/ -v ~/workspace/srs/objs/:/usr/local/srs/objs/ registry.cn-hangzhou.aliyuncs.com/ossrs/srs:5 ./objs/srs -c conf/my.srs.conf
1
2
cd ~/workspace/httpx-static/httpx-static
./httpx-static -t 80 -s 443 -k server.key -c server.crt -r -proxy=http://127.0.0.1:1985/api/v1/ -proxy=http://127.0.0.1:1985/rtc/v1/ -proxy=http://127.0.0.1:8080/
1
go run server.go 8085

前言

首先要清楚 WebRtc 的三种基本架构:

  1. Mesh 架构

    • 完全去中心化的架构,作为纯 P2P 的代表,需要所有参与者都互相通信
    • 一个媒体流就需要 n-1 条链接,n 为参与者数量
    • 由于流量和流数量成正比,就算你选择性的获取链接,每个终端机器的负载量也是极高的,
  2. MCU 架构

    • 经典的中心化架构,也是我们所熟悉的 Server-Client 模式
    • 从设计初衷来看,这种架构原先是用于 RTSP 1 to n 的直播场景,会采用混流技术来减少流量占用
    • 当前多人直播场景会导致混多个流,每加入一个直播主就需要添加至少一条媒体流
    • 对服务器算力要求大,协议栈和技术复杂,部署和运维成本高
  3. SFU 架构

    • 伪装成 P2P 的 Peer-to-Server 架构
    • 服务器只负责转发媒体流,不参与媒体流的传输,只负责转发,不存储

需求

从需求出发

在制作 WebRtc 的多人线上会议直播时,我接手了之前留下的 Peer.js 和 Socket.io 编写的纯前端架构

我在编写直播录制的代码时,考虑到是不是得对每一个流建立一个录制器,这样就会极大地增加终端机的负载,对于每一个用户都是不想看到的

目标

把流量压力和算力压力转给服务器,终端机应该只负责采集和上传、下载

因此我需要一个基本上对用户透明的媒体服务器

调研后我就发现,在 Peer.js 的讨论区里就有人提到内存占用过大的问题,以及更换架构为 SFU 的解决方案

设计

信令服务器没必要也用 SRS 的,因此只需要它的媒体服务器功能

技术栈: Socket.io + SRS

实现

首先通读 SRS 的文档吧

SRS 文档解决 80%->90%->99% 的基础问题

从 docker 安装 SRS

1
2
# 换成服务器地址
CANDIDATE="127.0.0.1"
1
docker run --name srs -it --env CANDIDATE=$CANDIDATE --network="host" -v ~/workspace/srs/conf/:/usr/local/srs/conf/ -v ~/workspace/srs/objs/:/usr/local/srs/objs/ registry.cn-hangzhou.aliyuncs.com/ossrs/srs:5 ./objs/srs -c conf/my.srs.conf

为什么要使用 —network=”host”

由于容器内无法直接访问宿主机的 127.0.0.1,为了统一且方便,这种方式可以直接使用宿主机的网络端口

-v 挂载文件夹

通过这种方式能够方便的将宿主机的一个文件夹映射到容器内,这样可以直接修改配置文件,而不用进入容器再修改

但是我们还是需要 ./objs/srs -c conf/my.srs.conf

所以我们可以先

1
2
docker cp srs:/usr/local/srs/conf/ ~/workspace/srs/conf/
docker cp srs:/usr/local/srs/objs/ ~/workspace/srs/objs/

加载到本地,然后再修改配置文件

配置文件

在文末 mysrsconf-配置文件

https 的证书文件

到挂载好的文件夹下生成证书文件吧

1
2
3
4
cd ~/workspace/srs/conf/
openssl genrsa -out server.key 2048 &&
subj="/C=CN/ST=Beijing/L=Beijing/O=Me/OU=Me/CN=me.org" &&
openssl req -new -x509 -key server.key -out server.crt -days 365 -subj $subj

使用 httpx 实现 https 服务

httpx-static

1
2
git clone https://github.com/ossrs/httpx-static.git
cd httpx-static

编译 httpx-static

1
go build -mod=vendor .

运行 httpx-static

1
./httpx-static -t 80 -s 443 -k server.key -c server.crt -r -proxy=http://127.0.0.1:1985/api/v1/   -proxy=http://127.0.0.1:1985/rtc/v1/   -proxy=http://127.0.0.1:8080/

利用 DVR 录制流

SRS 自带 DVR 录制功能,只需要在配置文件中开启即可

接收回调的服务器

官方的拿来魔改就行

1
go run server.go 8085

可能还需要编写自己的对接代码

服务器准备完毕,可以通过浏览器访问服务器 IP 来验证是否正常运行了

如果想要通过前端来测试,可以参考 SRS-RTC-JS

由于我是笨蛋,我把 jquery 打不进去 npm 包,所以我直接用了 whep 和 whip 接口,也很好用

简单来说,直播流的地址可拆分如下

1
2
3
4
5
const url = https://127.0.0.1:1990/rtc/v1/whip/?app=live&stream=live_1
const host = '127.0.0.1'
const port = '1990' // http为 1985,https为 1990,我们做的是 https
const room = 'live' // 对应 app
const stream = `live_1`

my.srs.conf 配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
listen              1935;
max_connections 1000;
daemon off;
srs_log_tank console;

http_server {
enabled on;
listen 8080;
dir ./objs/nginx/html;
}

http_api {
enabled on;
listen 1985;
}
stats {
network 0;
}
rtc_server {
enabled on;
listen 8000;
candidate $CANDIDATE;
}

vhost __defaultVhost__ {
hls {
enabled on;
hls_fragment 6;
hls_key_url https://localhost:8080;
}
http_remux {
enabled on;
mount [vhost]/[app]/[stream].flv;
}
rtc {
enabled on;
rtmp_to_rtc off;
rtc_to_rtmp on;
}
dvr {
enabled on;
dvr_plan segment;
dvr_duration 6;
dvr_path ./objs/nginx/html/[app]/[stream].[timestamp].flv;
}
http_hooks{
enabled on;
on_dvr http://localhost:8085/api/v1/dvrs;
}
}