HowTo文档

如何在 XSwitch 中对接 SRS

SRS 是一个简单、高效的优秀的开源实时音视频服务器,支持 RTMP/WebRTC/HLS/HTTP-FLV/SRT/MPEG-DASH/GB28181、Linux/Windows/macOS、X86_64/ARMv7/AARCH64/M1/RISCV/LOONGARCH/MIPS 等协议和技术。

本文假定你已经熟悉 SRS,也假定你已经熟悉 XSwitch。如果你还不熟悉 SRS,请参阅文末的链接查看 SRS 文档,如果你还不熟悉 XSwitch,可以试试XSwitch 快速入门

背景

FreeSWITCH 是一个开源的软交换平台和 MCU,而 SRS 是一个开源的实时音视频服务器和 SFU。很久之前通过 RTMP 对接过 SRS。现在 SRS 已支持 WebRTC 以及 WHIP 协议,在 SRS 创始人 winlin 的推动下,我们开始了相关的对接工作。

为什么要对接?因为 FreeSWITCH 和 SRS 各有所长。这就像大家经常问到的问题一样——SRS 是否能实现 MCU 呢?FreeSWITCH 是否能实现 SFU 功能?其实答案都是一样的——能,但是为什么要实现?理论上,只要有足够的if-else,任何功能都可以实现,但任何实现都需要考虑实现成本和维护成本。其实从漫长的软件生命周期来说,开源软件的生命周期还是比较长的,相对而言,软件的维护成本比开发成本更高。SRS 在级联、直播、低延迟直播等场景已经做得很好了,而且还有 Janus、Kurento、MediaSoup、Poin 等各种 SFU,FreeSWITCH 再去做意义就不是很大,同理,SRS 本身也不是很有必要自己实现一个 MCU。各自把自己擅长的部分做好。

具体计划是,先在 XSwitch 中对接 SRS。XSwitch 是基于 FreeSWITCH 做的商业化产品,XSwitch 中已经有了很多 WHIP 和 WebRTC 相关的支持,因此实现起来比较简单。等实现初步的对接流程后,我们会实现一个开源的模块,让使用开源版本的 FreeSWITCH 用户也可以对接 SRS,SRS 用户也可以使用 FreeSWITCH 作为 MCU。

本文仅讨论 XSwitch 与 SRS 的对接。可以使用 XSwitch 社区版免费测试。

架构和流程

XSwitch 相当于传统的软交换系统和 MCU,一个 SDP 可以支持双向的推拉流。而 SRS 的推拉流是分开的,推和拉分别需要一个 SDP。

SRS 和 FreeSWITCH 都是服务器端的软件,因此,谁从谁推拉流就有两种实现方式。

XSwitch 从 SRS 推拉流

XSwitch 作为客户端向 SRS 推流,从 SRS 拉流。如下图。

其中,红色代表推流,蓝色代表拉流,黑色是双向流。

SRS 从 XSwitch 推拉流

XSwitch 也支持 WHIP 协议,但 SRS 尚未实现客户端模式的推拉流。

关于 XSwitch 中的 WHIP 推拉流,详见如何在 XSwitch 中使用 WebRTC

启动 SRS

启动镜像:

export CANDIDATE="192.168.x.x"
docker run --rm -it -d --name srs -p 1935:1935 -p 1985:1985 -p 8080:8080 --env CANDIDATE=$CANDIDATE -p 8000:8000/udp ossrs/srs:6 ./objs/srs -c conf/docker.conf

打开 http://localhost:8080/ 可以查看 SRS 的 Web 页面,上面有推拉流相关的 Demo。一般使用livestream这个流进行演示。

注意:,SRS 在6.0.52以下的版本中有个 Bug 会导致 Crash,参见 https://github.com/ossrs/srs/pull/3591

如果你不使用 Docker,也可以使用以下命令自行编译运行:

git clone -b develop https://gitee.com/ossrs/srs.git &&
cd srs/trunk && ./configure && make && ./objs/srs -c conf/srs.conf

在 Windwows 页面推流

在使用 windows 页面使用 localhost 推流,需要在操作系统做如下配置

查看本地设置netsh.exe interface portproxy show all

# 设置
netsh.exe interface portproxy add v4tov4 listenaddress=127.0.0.1 listenport=8080 connectaddress=192.168.0.1 connectport=8080
netsh.exe interface portproxy add v4tov4 listenaddress=127.0.0.1 listenport=1985 connectaddress=192.168.0.1 connectport=1985
netsh.exe interface portproxy add v4tov4 listenaddress=127.0.0.1 listenport=8000 connectaddress=192.168.0.1 connectport=8000

# 清除
netsh.exe interface portproxy delete v4tov4 listenaddress=127.0.0.1 listenport=8080
netsh.exe interface portproxy delete v4tov4 listenaddress=127.0.0.1 listenport=1985
netsh.exe interface portproxy delete v4tov4 listenaddress=127.0.0.1 listenport=8000

启动 XSwitch

参见XSwitch 入门XSwitch 下载安装指南 安装 XSwitch,并熟悉 XSwitch 的使用。注意:XSwitch 6.0.0 以上的版本才支持 SRS 对接,推荐使用 6.0.7 以上版本。

xrtc Endpoint

XSwitch 中实现了一个 xrtc Endpoint,除 XSwitch 标准 Endpoint 参数外,还支持如下参数:

  • video_use_audio_ice:在 Bundle 模式,视频使用音频的 ICE 绑定信息。
  • rtp_payload_space:指定视频的 RTP 载荷值,不指定有时候会有冲突。
  • absolute_codec_string:音视频编码,一般为OPUS,H264,在呼叫字符串中使用时其中的逗号要使用\转义。
  • url:SRS 推拉流 URL。

XSwitch 推流到 SRS

XSwitch 是一个软交换平台和 MCU。SRS 对接在 XSwitch 内实现为一个 Endpoint。

推流,从本地 mp4 文件中读取视频流:

bgapi originate {video_use_audio_ice=true,rtp_payload_space=106,absolute_codec_string=OPUS\,H264,url=http://localhost:1985/rtc/v1/whip/?app=live&stream=livestream}xrtc/auto_answer &playback(/tmp/test.mp4)

呼叫一个null Channel,桥接到 SRS 推流:

bgapi originate {null_video_codec=H264}null/1234 &bridge({video_use_audio_ice=true,rtp_payload_space=106,absolute_codec_string=OPUS\,H264,url=http://localhost:1985/rtc/v1/whip/?app=live&stream=livestream}xrtc/auto_answer)

如果你手上有 SIP 视频话机,可以将一个视频话机(如 1006)的视频流推给 SRS,如:

bgapi originate user/1006 &bridge({video_use_audio_ice=true,rtp_payload_space=106,absolute_codec_string=OPUS\,H264,url=http://localhost:1985/rtc/v1/whip/?app=live&stream=livestream}xrtc/auto_answer)

除上述命令外,你也可以直接在视频话机上发起呼叫。呼叫前确保 XSwitch 中有相应的路由。如,在 XSwitch 中,添加一个路由:

  • 目的地:livestream
  • 最大号长:10
  • 目的地类型:系统
  • 目的地:代码如下
bridge {video_use_audio_ice=true,rtp_payload_space=106,absolute_codec_string=OPUS\,H264,url=http://localhost:1985/rtc/v1/whip/?app=live&stream=livestream}xrtc/auto_answer

直接使用视频话机呼叫livestream,可以直接推流到 SRS 的livestream流。

可以通过以下方法在 SRS 侧观看视频流:

WHEP Play:http://localhost:1985/rtc/v1/whip-play/?app=live&stream=livestream

通过 RTC 播放器可以查看拉流效果:webrtc://localhost/live/livestream

XSwitch 拉流

  • RTC 推流到:webrtc://localhost/3000/livestream
  • WHIP Publish:http://localhost:1985/rtc/v1/whip/?app=3000&stream=livestream

可以在 XSwitch 中使用命令拉流到视频会议,其中3000是视频会议号:

conference 3000 bgdial {video_use_audio_ice=true,rtp_payload_space=106,absolute_codec_string=OPUS\,H264,url=http://localhost:1985/rtc/v1/whip-play/?app=3000&stream=livestream}xrtc/auto_answer

注意:上面仅是简单的会议,在 XSwitch 中,会议名称是形如:会议号-域这样的格式,如3000-xswitch.cn

通过 Webhook 自动将 SRS 流拉到 XSwitch 视频会议中

上面的命令都是手工执行的,用起来比较笨。为了让整套系统聪明一点,可以在 SRS 侧配置 Webhook,这样,当 SRS 侧有人推流时,XSwitch 可以自动启动会议,并把相应的流拉入会议。

要配置 SRS 的 Webhook,使用以下步骤:

启动 SRS 镜像并进入 Shell:

export CANDIDATE="192.168.x.x"
docker run --rm -it -d --name srs -p 1935:1935 -p 1985:1985 -p 8080:8080 --env CANDIDATE=$CANDIDATE -p 8000:8000/udp ossrs/srs:v6.0.36 bash

修改/usr/local/srs/conf/docker.conf,在vhost下增加 callback 相关配置:

http_hooks {
        enabled on;
        on_publish http://xswitch:8081/api/whip/srs;
        on_unpublish http://xswitch:8081/api/whip/srs;
    }

运行 SRS:

/usr/local/srs/objs/srs -c conf/docker.conf

在 SRS 侧推流,会调用http_hooks回调,XSwitch 会收到on_publish回调,收到后 XSwitch 会自动拉流到跟流同名的视频会议。

注意,为了能在 XSwitch 中接收 Webhook 请求,需要在xtra_config.lua中开启srs_api_url配置项。目前,开启该参数后 XSwitch 侧对/api/whip/srs没有鉴权,请注意保护。

开启后,在 XSwitch 侧使用 SIP 终端呼叫会议号3000,会自动进入会议3000-xswitch.cn。在 SRS 侧推流:

  • app: 3000-xswitch.cn
  • stream: livestream 或其他

注意:不同的推流终端用不同的stream以免冲突,用相同的app以便加入同一个会议。

控制时序图大致如下图所示,其中箭头方向为控制信号发送请求的方向,不是流的发送方向。

使用

如果你不使用完整版的 XSwitch,也可以使用不带 UI 的 XSwitch。xswitch-free 是小樱桃科技推出的免费版 Docker 镜像,可以用于在没有 UI 的情况下测试 XSwitch 的各种功能。

简单推拉流

可以使用上述 XSwitch 中同样的命令推拉流。

配置 verto.conf 添加 Webhook Handler

启动 xswitch-free docker,参见 https://github.com/rts-cn/xswitch-free

弹出配置文件:

make eject

在 verto.conf 中添加 HTTP 配置,参见:http://rts.cn/freeswitch/FreeSWITCH-Explained/Modules/mod-verto/RESTful-Verto_8454242/#docusaurus_skipToContent_fallback

<vhosts>
        <vhost domain="localhost">
          <param name="alias" value="seven.local freeswitch.org"/>
          <!-- <param name="root" value="/usr/local/freeswitch/htdocs"/> -->
          <!-- <param name="script_root" value="/usr/local/freeswitch/scripts"/> -->
          <param name="index" value="index.html"/>
<!--
          <param name="auth-realm" value="FreeSWITCH"/>
          <param name="auth-user" value="freeswitch"/>
          <param name="auth-pass" value="rocks"/>
-->
          <rewrites>
            <rule expression="^/api" value="whip.lua"/>
          </rewrites>
        </vhost>
--[[
Restful by Seven Du.

GET    /channels
GET    /channels/uuid
POST   /channels
PUT    /channels/uuid
DELETE /channels/uuid
DELETE /channels
]]

function headers()
    stream:write("HTTP/1.0 200 OK\r\n")
    if (accept == "application/json") then
        stream:write("Content-Type: application/json\r\n")
    else
        stream:write("Content-Type: text/plain\r\n")
    end
    stream:write("\r\n")
end

-- print(env:serialize())


api = freeswitch.API()
method = env:getHeader("Request-Method")
http_uri = env:getHeader("HTTP-Request-URI")
http_query = env:getHeader("HTTP-QUERY")
accept = env:getHeader("Accept")
uuid = string.sub(http_uri, "11") -- remove /channels/ from uri
freeswitch.consoleLog("ERR", "[" .. method .. "]\n")
-- freeswitch.consoleLog("ERR", http_uri .. "\n")
-- freeswitch.consoleLog("ERR", http_query .. "\n")

if (method == "GET") then
    ret = "OK I'm FreeSWITCH MCU"
elseif (method == "POST") then
    dialstr = "{}xrtc/auto_answer"
    print(dialstr)
    ret = api:execute("originate", dialstr)
    ...
end
headers()
stream:write(ret .. "\n")

重启 Docker,在 SRS 侧添加 Webhook。

以上只是一个示例,如果你用于生产环境,可以使用一个真正的 Web 服务器接收 Web 请求,并通过 ESL 或 XCC 等 API 控制 FreeSWITCH 打开 xrtc Channel 加入一个会议。

XSwitch 实现的 API 接口:https://docs.xswitch.cn/dev-guide/api/ ,供大家参考实现。

其他

XSwitch 的默认配置有一些安全设置,不允许任意的人任意的流进入视频会议,因此,您可能需要多熟悉一下 XSwitch。如果有任何问题,欢迎给我产反馈

如果你需要一个开源的 FreeSWITCH 解决方案,可以看这里:http://freeswitch.org.cn/blog/2023/08/use_srs/

参考

一台服务器启动多版本XSwitch