tools-ossrs

SRS简介

SRS是一个开源的(MIT协议)简单高效的实时视频服务器,支持RTMP、WebRTC、HLS、HTTP-FLV、SRT、MPEG-DASH和GB28181等协议。 SRS媒体服务器和FFmpegOBSVLCWebRTC等客户端配合使用,提供流的接收和分发的能力,是一个典型的发布 (推流)和订阅(播放)服务器模型。 SRS支持互联网广泛应用的音视频协议转换,比如可以将RTMPSRT, 转成HLSHTTP-FLVWebRTC等协议。

k8s安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
相关设置:
Container Image: ossrs/srs:5
Command/Args:
命令: ./objs/srs -c conf/flv/rtmp2rtc.conf #配置见文尾
# 命令: ./objs/srs -c conf/flv/realtime.flv.conf //废弃,由上面的配置替换
Environments:
CANDIDATE: iexxk.com #替换成域名,这样能同时兼容内外网,内网做个host映射可以直接走内网
TZ: Asia/Shanghai
Container Ports(Host端口): 1935 默认推流端口,地面站那边修改不了,导致只能用host进行映射暴露
数据卷:
配置目录: /usr/local/srs/conf/flv
数据目录:/usr/local/srs/srs_dvr_data
NodePort端口映射:
1935 #默认推流端口
# 18080 // realtime.flv.conf配置才需要
8080 #web、安卓拉流
1985 #ios拉流(webrtc)
30353 #udp端口,webrtc拉流需要

nginx代理

1
2
3
4
5
6
7
8
9
10
11
# ossrs代理地址
upstream ossrs_server {
server ossrs:8080;
}
location /view-live/ {
rewrite ^/view-live/(.*) /$1 break;
proxy_pass http://ossrs_server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

流程

虚拟ip处需要映射

Web: 外网ip80/443绑定节点的ingress的80/443

Ossrs: 外网ip1935绑定k8s里面的ossrs服务的Container Ports(Host端口)1935或者nodeport,不采用nodeport是因为要内网外网都要能访问ossrs,关键是内网对外网域名做了隔离,因此这里用本机的hosts映射(可以升级到dns下发)

graph LR
G[OBS推流]-->C
C[域名] -->|解析| A[移动光猫]
A -->|LAN| B(飞塔防火墙)
B -->|虚拟ip| E[K8S的Ingress]
E -->|域名匹配| F[前端web/nginx]
F -->|nginx代理|U[ossrs]
C-->|hosts映射节点ip|E

V[VLC]-->|web flv拉流|U
K[IOS]-->|ios webrtc拉流|U

测试

  1. 安装obs,用srs在线的测试工具也可以。

  2. 来源->加号->浏览器->url里面输入要直播的网址https://www.baidu.com/s?word=在线时间

  3. 控制按钮->设置->直播->

    服务:自定义

    服务器:rtmp://iexxk.com/drone/

    推码流:1

  4. 点击开始直播

播放:

内网测试(ok):

内网域名测试(ok):

外网测试:

webrtc和WHEP区别

WHEP:可以代理,但是也无法将一个域名根据环境解析为内网ip和外网ip,内网和外网是通过dns解析的,只能解析一个。在rtc里面启用保留域名,也无法解决,candidate里面会出现2个域名一个ip,优先还是走的ip

1
2
3
4
5
6
7
8
rtc_server {
enabled on;
listen 30353; # UDP port
# @see https://ossrs.net/lts/zh-cn/docs/v4/doc/webrtc#config-candidate
candidate $CANDIDATE;
# 启用保留域名
keep_api_domain on;
}

webrtc:直接连接,延迟更低,必须开放1985,无法修改

使用webrtc时,需要在web前端(nginx)做个代理,并要将该端口映射到外网1985上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# ossrs webrtc代理地址
upstream ossrs_webrtc {
server ossrs:1985;
}
server {
listen 1985 ssl;
server_name iexxk.com;

ssl_certificate /etc/nginx/cert/iexxk.com.pem;
ssl_certificate_key /etc/nginx/cert/iexxk.com.key;

location /rtc/v1/play/ {
proxy_pass http://ossrs_webrtc;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

常见问题

  1. 在内网无法访问外网域名的时候,虽然通过host映射到内网,但是webrtc播放的时候还是解析成了外网ip

    使用webrtc播放时可以在浏览器控制台能看到如下信息

    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
    Got answer:  v=0
    o=SRS/5.0.213(Bee) 140129754604224 2 IN IP4 0.0.0.0
    s=SRSPlaySession
    t=0 0
    a=ice-lite
    a=group:BUNDLE 0 1
    a=msid-semantic: WMS drone/1
    m=audio 9 UDP/TLS/RTP/SAVPF 111
    c=IN IP4 0.0.0.0
    a=ice-ufrag:881501t3
    a=ice-pwd:d11em20o3z9k02c97228yq5937ptj776
    a=fingerprint:sha-256 35:65:58:9A:E6:78:8F:D5:E6:F1:8F:E5:74:AD:A4:1E:3A:DF:B4:CE:21:3C:C9:CB:4A:9D:25:7A:87:53:FB:47
    a=setup:passive
    a=mid:0
    a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
    a=sendonly
    a=rtcp-mux
    a=rtcp-rsize
    a=rtpmap:111 opus/48000/2
    a=rtcp-fb:111 transport-cc
    a=ssrc:10186 cname:2yaj11875760968e
    a=ssrc:10186 label:audio-803h25y4
    a=candidate:0 1 udp 2130706431 172.16.10.44 30353 typ host generation 0
    a=candidate:1 1 udp 2130706431 iexxk.com 30353 typ host generation 0
    m=video 9 UDP/TLS/RTP/SAVPF 106
    c=IN IP4 0.0.0.0
    a=ice-ufrag:881501t3
    a=ice-pwd:d11em20o3z9k02c97228yq5937ptj776
    a=fingerprint:sha-256 35:65:58:9A:E6:78:8F:D5:E6:F1:8F:E5:74:AD:A4:1E:3A:DF:B4:CE:21:3C:C9:CB:4A:9D:25:7A:87:53:FB:47
    a=setup:passive
    a=mid:1
    a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
    a=sendonly
    a=rtcp-mux
    a=rtcp-rsize
    a=rtpmap:106 H264/90000
    a=rtcp-fb:106 transport-cc
    a=rtcp-fb:106 nack
    a=rtcp-fb:106 nack pli
    a=fmtp:106 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
    a=ssrc:10187 cname:2yaj11875760968e
    a=ssrc:10187 label:video-29515r30
    a=candidate:0 1 udp 2130706431 172.16.10.44 30353 typ host generation 0
    a=candidate:1 1 udp 2130706431 iexxk.com 30353 typ host generation 0

    注意最后两行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    使用内网ip的时候,输出如下信息
    a=candidate:0 1 udp 2130706431 172.16.10.102 30353 typ host generation 0
    a=candidate:1 1 udp 2130706431 iexxk.com 30353 typ host generation 0
    使用内网域名的时候,输出如下信息,内网做了dns解析,假域名能解析到内网主机
    a=candidate:0 1 udp 2130706431 172.16.10.44 30353 typ host generation 0
    a=candidate:1 1 udp 2130706431 iexxk.com 30353 typ host generation 0
    使用外网域名的时候,输出如下信息,17.176.159.182这个域名刚好在内网无法访问,因此内网无法播放外网地址
    a=candidate:0 1 udp 2130706431 17.176.159.182 30353 typ host generation 0
    a=candidate:1 1 udp 2130706431 exxk.com 30353 typ host generation 0

    真域名做了host映射,但是似乎不会从host拿,应该是从dns里面拿取了

    从下图可以知道,是通过1985的接口,拿到了udp的端口数据。

配置

rtmp2rtc.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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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 30353; # UDP port
# @see https://ossrs.net/lts/zh-cn/docs/v4/doc/webrtc#config-candidate
candidate $CANDIDATE;
}

vhost __defaultVhost__ {
rtc {
enabled on;
# @see https://ossrs.net/lts/zh-cn/docs/v4/doc/webrtc#rtmp-to-rtc
rtmp_to_rtc on;
# @see https://ossrs.net/lts/zh-cn/docs/v4/doc/webrtc#rtc-to-rtmp
rtc_to_rtmp on;
}
http_remux {
enabled on;
mount [vhost]/[app]/[stream].flv;
}

hls {
enabled on;
hls_path ./objs/nginx/html;
hls_fragment 10;
hls_window 20;
hls_wait_keyframe off;
}

tcp_nodelay on min_latency on;

play {
gop_cache off;
queue_length 10;
mw_latency 100;
}

publish {
mr off;
}

dvr {
enabled on;
dvr_apply all;
dvr_plan session;
dvr_path ./srs_dvr_data/[app]/[stream]/[2006]-[01]-[02]/[timestamp].[2006]-[01]-[02]_[15].[04].[05]_[999].mp4;
dvr_duration 30;
dvr_wait_keyframe on;
time_jitter full;
}

}

realtime.flv.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
listen 1935;
max_connections 1000;
daemon off;
srs_log_tank console;
http_server {
enabled on;
listen 18080;
dir ./objs/nginx/html;
}
vhost __defaultVhost__ {
http_remux {
enabled on;
mount [vhost]/[app]/[stream].flv;
}

hls {
enabled on;
hls_path ./objs/nginx/html;
hls_fragment 10;
hls_window 20;
hls_wait_keyframe off;
}

tcp_nodelay on min_latency on;

play {
gop_cache off;
queue_length 10;
mw_latency 100;
}

publish {
mr off;
}

dvr {
enabled on;
dvr_apply all;
dvr_plan session;
dvr_path ./srs_dvr_data/[app]/[stream]/[2006]-[01]-[02]/[timestamp].[2006]-[01]-[02]_[15].[04].[05]_[999].mp4;
dvr_duration 30;
dvr_wait_keyframe on;
time_jitter full;
}
}