一种FreeSWITCH流量镜像WebSocket音频推流方案
环境:CentOS 7.9_x64
FreeSWITCH版本: 1.10.11(docker 23.0.6部署)
Python版本:3.9.12
之前遇到过一个需求:
在不影响生产系统业务(FreeSWITCH服务)的情况下,实时推送WebSocket格式语音流给解析服务器,以完成后续服务(比如实时辅助、实时质检等)。
今天整理下该需求的可行性验证笔记并提供示例代码,如需商业使用请参考文章自行实现。
本文使用的FreeSWITCH是基于docker部署,如有使用docker部署FreeSWITCH的需求,可参考如下文章:
一、整体结构
为了演示方便,本文使用基于主机的流量镜像方案,生产环境可使用交换机的镜像口来替换。
此外,关于编码方面,这里做下简化:
1)流量镜像rtp编码是g711a(pcma);
2)ws推流的目标编码是 L16(16k);
整体结构如下:

二、流量镜像环境准备及策略实现
1、环境说明
整体结构如下:

说明:
1)192.168.137.100机器部署freeswitch,并配置流量镜像推流;
2)192.168.137.101机器部署流量镜像推流程序、ws模拟服务程序;
2、推流策略实现及效果验证
这里使用iptables的tee模块实现流量镜像功能,为了演示方便,这里使用udp流量全推的方案。
1)推流策略配置
流量镜像配置示例:
[root@host100 pbx]# cat /root/tee1.sh
#! /bin/bash
iptables -t mangle -F
iptables -t mangle -I PREROUTING 1 -p udp -j TEE --gateway 192.168.137.101
iptables -t mangle -I POSTROUTING 1 -p udp -j TEE --gateway 192.168.137.101
iptables -t mangle -L -v
[root@host100 pbx]#

2)推流效果验证
在100机器上执行如下命令:
nc -u 192.168.137.108 33330
输入 123456 ,然后执行 ctrl + d 键进行发送。
在101机器上进行抓包:
tcpdump -i enp0s3 udp port 33330 -vvvvvvvvvvvvvvvv
使用tcpdump验证效果如下:

使用wireshark验证效果如下:

三、搭建ws验证服务器
为了方便方案验证,这里使用python模拟个ws服务器,该服务器会将收到的音频数据存储为本地pcm文件以便验证。
这里用的python3.9环境,环境部署可参考如下文章:
配合验证的ws服务器代码如下(wsServer2.py):
import os,json,time
from websockets.sync.server import serve
gPcmDir="pcmFiles"
def handler(ws):
callid,tag = "",0
fout,fName = None,""
clientId = id(ws)
for msg in ws:
#print("%s,len msg : %d "% (fName,len(msg)))
#msg2 = "I got your message: {}".format(msg)
#websocket.send(msg)
if type(msg) == str:
#if msg.find("initConfig") > -1:
print(msg)
dtmp = json.loads(msg)
var1 = dtmp.get("call_id")
if var1 : call_id = var1
var2 = dtmp.get("tag")
if None != var2 : tag = var2
print(call_id,tag)
#fName = "%s-%d.pcm" % (call_id,role)
fName = "%s/%s.pcm" % (gPcmDir,tag)
if None == fout : fout = open(fName,"wb")
if "end" == dtmp.get("type"):
fout.close()
if type(msg) == bytes:
fout.write(msg)
return None
def main():
if not os.path.isdir(gPcmDir):os.makedirs(gPcmDir)
with serve(handler, "0.0.0.0", 8765) as server:
server.serve_forever()
if __name__ == "__main__":
main()
启动脚本如下(start.sh)
#! /bin/bash
#pydir=$PWD
pydir=/root/python39
export CFLAGS="-I$pydir/include"
export LDFLAGS="-L$pydir/lib"
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$pydir/lib
$pydir/bin/python3.9 wsServer2.py
运行效果如下:

四、核心功能实现
这里列举下核心功能,并提供python示例代码。
1、从抓包数据中提取alaw音频
关键点如下:
1)抓包功能通过libpcap实现;
2)解析sdp获取rtp端口信息;
3)根据rtp协议从payload中解析并提取音频数据;
4)使用ffmpeg将提取的alaw格式音频转换为wav格式,以便验证音频的正确性;
示例代码如下(pcap2alaw.py):

完整代码可从如下渠道获取:
2、alaw音频转换成pcm音频(L16)
alaw2pcm示例代码:
import os,struct,socket
import ctypes as ct
import audioop
rawFile = b"g711a_export1.raw"
sampwidth = 4
i,step = 0,160//sampwidth
fout = open("pcm_export1.raw","wb")
with open(rawFile,"rb") as fin:
while True:
data = fin.read(step)
if not data : break
data2 = audioop.alaw2lin(data, sampwidth)
fout.write(data2)
提取的音频导入效果如下:


关于pcm音频的播放可参考如下文章:
3、pcm音频以ws格式发送
pcm转ws示例代码如下(pcm2ws.py):

完整代码可从如下渠道获取:
运行效果如下:

五、WebSocket音频推流方案
这里描述下独立程序的推流方案,即:所有功能都在一个程序里面实现,比如单独的python脚本。
1、模块设计
模块设计如下:

2、程序设计
大致设计思路如下:
1)启动独立线程ThrdLiveCap,使用libpcap实时抓取流量镜像过来的数据,并将数据推送到指定队列;
2)启动独立线程ThrdPktParse,解析sip协议,提取uuid、rtp端口等关键信息,并将解析的数据存储到全局缓存中;
3)启动独立线程ThrdRtp2Ws,监测并启动独立线程,进行ws推流;
3、示例代码
这里提供下示例代码。

完整代码可从如下渠道获取:
4、运行效果
1)编写拨号方案
内容如下:
<extension name="playTest">
<condition field="destination_number" expression="^10087$">
<action application="answer"/>
<action application="playback" data="local_stream://moh"/>
</condition>
</extension>
2)注册1000分机,拨打10087号码,在101机器上启动rtp2ws脚本、wsServer脚本,可成功接收rtp文件。
运行效果如下:

文件导入效果如下(s16le 16K):

可正常播放。
对应的pcm文件可从文末提供的渠道获取。
六、资源下载
本文相关资源及运行环境,可从如下渠道获取:


一种FreeSWITCH流量镜像WebSocket音频推流方案的更多相关文章
- H3C交换机流量镜像
今天需要对交换机进行本地流量镜像,在此记录: 交换机:H3C S5120 配置本地端口镜像时,用户首先要创建一个本地镜像组,然后为本地镜像组配置源端口和目的端口. 表1-1 配置本地端口镜像 操作 命 ...
- idou老师教你学Istio12 : Istio 实现流量镜像
微服务为我们带来了快速开发部署的优秀特性,而如何降低开发和变更的风险成为了一个问题.Istio的流量镜像,也称为影子流量,是将生产流量镜像拷贝到测试集群或者新的版本中,在引导实时流量之前进行测试,可以 ...
- Kube-OVN 0.6.0 发布,支持 IPv6、流量镜像及更多功能
Kube-OVN 是一个基于 OVN 的 Kubernetes 开源网络系统. 本次更新主要包含了以下内容: 1. 支持流量镜像 在安装 Kube-OVN 时可以开启 mirror 选项,会自动在每个 ...
- 在 Istio 中实现 Redis 集群的数据分片、读写分离和流量镜像
Redis 是一个高性能的 key-value 存储系统,被广泛用于微服务架构中.如果我们想要使用 Redis 集群模式提供的高级特性,则需要对客户端代码进行改动,这带来了应用升级和维护的一些困难.利 ...
- unity5打包机制下,一种资源打ab和资源管理的方案
unity5打包机制下,一种资源打ab和资源管理的方案.1.打ab: 1.设置平台 2.清楚所有资源的assetbundlename: string[] abNameArr = AssetDataba ...
- FreeSWITCH第三方库(音频)的简单介绍(一)
FreeSWITCH使用了大量的第三方库,本文档主要介绍音频相关库的信息: 视频相关库的信息介绍参考:http://www.cnblogs.com/yoyotl/p/5488890.html 其他相关 ...
- 一种Docker image镜像的取代方案
在http://openvz.org/Download/templates/precreated中有很多压缩的镜像文件,可以将这些文件下载后采用import方式使用镜像,也可以采用我原来的博文:doc ...
- linux 双网卡桥接,实现网卡流量镜像与转发
确认本地是否存在brctl,如果不存在请先安装: 1.确定你的镜像端口,比如eth1: 2.将实际数据通过的端口,比如eth0和镜像端口绑成一个bridge: brctl addbr br0 brct ...
- springboot整合docker部署(两种构建Docker镜像方式)--2019-3-5转
原文:https://www.cnblogs.com/shamo89/p/9201513.html 项目结构 package hello; import org.springframework.boo ...
- springboot整合docker部署(两种构建Docker镜像方式)
项目结构 package hello; import org.springframework.boot.SpringApplication; import org.springframework.bo ...
随机推荐
- 异常分析 JedisConnectionException: java.net.SocketTimeoutException: Read timed out
问题描述 测试Redis分布式锁的时候,如果一次执行大量数据,系统会报出如下异常: JedisConnectionException: java.net.SocketTimeoutExceptio ...
- 聊聊常见的几款Agent平台:字节Coze、腾讯元器、文心智能体
你好,小钗在医疗AI.教育AI.管理AI有丰富的经验 关注公众号,回复1,与我交个朋友吧 之前我们探讨过公司AI能力的评判方式: 这里主要涉及两个方面:工程能力以及行业KnowHow. 对于一般公司, ...
- 玩转AI新声态 | 玩转TTS/ASR/YuanQI 打造自己的AI助手
前言 halo, 各位佬友这是我24年写的整理一下发出来, 可能有点老了, ai发展这么快...... 本次带来的是腾讯云玩转AI新声态语音产品应用实践,利用 TTS / ASR / 元器智能体 打造 ...
- NFS常用操作
查看连接的NFS Client netstat | grep :nfs
- SM30里DEC数据显示0
需求:DEC数据在维护的时候显示0 1,设置数据元素对于的域带转换历程. 2,写转换历程函数(注意两个历程的输入和输出类型,这个需要修改) FUNCTION conversion_exit_zdays ...
- 函数使用十四:BAPI_PO_CREATE1
*&---------------------------------------------------------------------* *& Report ZBAPI_PO_ ...
- 函数使用十五:BAPI_PO_RELEASE
*&---------------------------------------------------------------------* *& Report ZBAPI_PO_ ...
- HyperWorks变形域和控制柄方法
变形域和控制柄方法 使用变形域和控制柄方法进行网格变形时,网格模型被分割成若干个变形子域,位于变形域上的控制柄常常用来控制变形域形状的变化.当控制柄移动时,变形域的形状随之变化,进而影响变形域内部节点 ...
- [CF1394D] Boboniu and Jianghu
D - Boboniu and Jianghu 设\(dp[i][0/1]\)表示当前链从下往上是不增/减的,那么当\(u\)与\(v\)(其中\(fa[v]=u\))的\(b\)不相同时,\(dp[ ...
- springBoot启动 Error running Application. Command line is too long. Shorten the command line via JAR manifest or via a classpath file and rerun.
1. 打开SpringBoot启动配置 2.选择shorten command line 3.apply保存就行了