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