将手机电话通话声音通过udp传输到局域网的Python脚本
--本地AI电话机器人
-
上一篇:手机转SIP-手机做中继网关-落地线路对接软交换呼叫中心
-
一、前 言
前面我们通过两个篇章《手机SIM卡通话中随时插入录音语音片段(Android方案)》《手机SIM卡通话中随时插入录音语音片段(Windows方案)》,阐述了【手机打电话过程中,随机插播预录语音片段】的功能和根据对方手机按下DTMF按键,播放不同IVR应答语音片段给对方手机的能力。
在AI电话沟通时,由于手机性能和算力的局限性,通常AI交互的模型和算法无法部署到手机上。这样的话就需要将拦截到的手机通话的声音数据,通过网络(局域网或互联网)将语音包传输给AI算力服务器。由其对语音进行ASR识别和语义理解,并生成最终的应答TTS语音,反馈回手机注入到电话通话中。
当前市面上主流的实时语音流的传输方式主要有两种:
1)SIP/WebRTC协议及配套的RTP/RTCP语音数据传输。
2)直接将语音数据以udp广播或组播的方式分发给局域网内多个设备。
前面我们花了很多的篇章和研发力量在SIP协议,对接开源的FreeSwitch和VOS与呼叫中心上,(详情可参考文章《蓝牙电话与FreeSwitch服务器和UA坐席的通话》)。
事实上手机电话通话做AI呼叫,本质上跟SIP协议没有太大的依赖关系。手机APP提取到通话声音后,完全可以把这个声音数据直接传给局域网内的AI服务器,或者让手机自己的AI模型来消费和应答这个声音会话。(众所周知,SIP协议无法处理"通话号码带逗号-实现拨通后自动拨出分机号 "这样的能力,但你直接传的话就没有这种问题)
本文就是基于这样的场景,使局域网内部署的一台AI服务器,就可以通过udp数据包,同时处理多台Android手机发来的AI呼叫请求,并生成对应TTS语音应答。
由于数据交互全在局域网内进行,因此其****【端到端】通话的时延可以得到最大程度的保证****(TTL只有1跳或2跳,路由的路径非常短)。这样既能利用AI算力服务器的堆叠密度,又能同时处理和响应多路手机SIM卡的电话通话。实现高效的AI呼叫和成本的压缩。
体验和下载地址:
智能拨号器App: http://120.78.211.195:8060/Dialer.apk
拨号器声音 (Python源码):http://120.78.211.195:8060/sdk/dialer_audio_py.zip
当前商用方案是蓝牙电话的方案,需要依赖一个外置的USB蓝牙的配件,插入到手机上,才能拦截到电话通话的声音数据。因此需要额外购买一个USB蓝牙配件。
USB蓝牙配件购买路径 (参考):https://item.jd.com/100049950520.html
- 二、方案的依赖配件
关注过我们博客的朋友都知道:目前拦截手机通话声音的蓝牙电话方案,需要将USB蓝牙的配件插入到手机上,才能在手机APP拦截到电话通话的事件和声音数据。
这个方案最大的好处是:不限制手机,市面上任何品牌型号的Android手机,拿来装上app,插上USB配件后,就能拦截到电话通话语音。普适性非常的广。市面上任何新的手机和二手的手机都支持这样用。依赖的手机配件如下图所示:

买来的USB蓝牙配件,可以直接插在手机上使用。但是因为是公共的标准配件,需要有一个USB转typec的转接头才能插到Android手机上,没有的话可以去京东淘宝拼多多买一个即可,非常的便宜。
- 三、方案的依赖界面
蓝牙电话方案使用Android手机APP,通过插入手机的USB蓝牙来直接拦截电话通话的声音。因此为了能让它将语音数据和通话事件公开到手机所在的局域网中,需要对【智能拨号器app】进行一个基础的默认设置,如下图所示:

【智能拨号器app】的设置选项卡中,点击右上角齿轮图标,打开【APP应用设置】界面后,将原先默认的"SIP协议栈:连接SIP平台"关闭为"协议栈:手机IVR-AI语音处理"。
APP应用设置中,做了这个默认设置切换了之后,APP拦截到的电话通话声音将不再进行SIP协议的转发,而是在手机APP自身和局域网内,广播寻址找到【远程声音设备】进行电话通话声音数据的播放和输出。
- 四、Python客户端的命令行菜单
本文的Python脚本的源代码,即为拨号器的远程声音设备的标准输入输出的源文件,它支持Windows/Linux/MacOS三大平台(用DeepSeek帮我写的,MacOS暂时没有这个电脑来调试,不知道是否能运行和有声音,^V^,但Windows11和Ubuntu18.04肯定能用)。
详细的Windows和Ubuntu操作系统的安装和配置步骤,已在附件下载路径《dialer_audio_py.zip》压缩包中的README.md文件内容中描述的很清楚了。
此处简要的列举一下,执行了【
pip install sounddevice numpy colorama
python main.py
】命令之后,随便输入help或直接按下Enter键,打印的命令行提示内容,如下所示:

进去后输入help 按提示逐个输入discover / bind 21ea5105736c3285 绑定后手机app上会弹框出来提示是否接受远程声音设备的绑定-需要手机APP上允许。
至此,即可使用 call 10086 / hangup / dtmf 2 等指令,正常在windows11中使用python连接局域网内的智能拨号器app来实时通话啦。
用户可以简单的使用如下指令,来完成一个外呼的手机通话,对手机进行远程操控:
如常用的拨打10086等待接通后说话 call 10086
通话中发送DTMF数字 dtmf 2
拨打完毕后挂断电话 hangup
- 五、拨号器声音程序架构
其实有Python脚本的源代码之后,什么架构啊、交互时序和指令内容啊,都是多余的。有啥不懂的直接跳转去看代码即可,反正就六七个py文件而已,非常的简洁易懂。
但这里为了便于理解,还是画蛇添足一次:Python脚本作为【远程声音设备】的程序,主要使用udp+tcp结合的方式来进行工作的。
UDP协议负责进行广播找人、寻址和绑定双方的目标设备,以及电话通话时直接传输上行和下行的全双工的语音数据。UDP占用42700-42703的udp端口。
TCP协议负责建立稳定的连接,保证通话的事件和状态能够准时、完整的在局域网双方设备之间进行数据交换。TCP占用电脑的随机端口和手机的42700端口。
它们之间的逻辑架构,如下图所示:

- 六、Python程序的传输端口和交互指令
Python脚本做为拨号器的远程声音设备,交互指令和状态机总体还是比较简单的,交互指令的时序图如下:(它主要分为三个阶段:UDP发现、TCP连接、电话通话)

交互执行的详细json格式内容如下:
|--------------|------------------------------------------------------------------------------------------------------------------|
| 指令描述 | 指令json格式内容 |
| UDP设备发现 | { "type": "REQUEST_AUDIO", "sn": "设备GUID或空字符串" } |
| 声音源响应 | { "type": "RESPONSE_AUDIO", "sn": "f87cca772abcf96f", "company": "设备厂商", "ip": "192.168.31.241", "port": 42700 } |
| | |
| Call消息 | { "type": "Call", "number": "13800138000", "call_type": "normal" } |
| Answer消息 | { "type": "Answer" } |
| Hangup消息 | { "type": "Hangup" } |
| DTMF消息 | { "type": "DTMF", "digit": "1", "duration": 100 } |
| | |
| 外呼响应 | { "type": "OnCallDialing", "number": "13800138000" } |
| 呼叫振铃事件 | { "type": "OnCallProgress", "number": "13800138000" } |
| 电话被接通 | { "type": "OnCallConnected", "number": "13800138000" } |
| 被拒接 | { "type": "OnCallReject", "reason": "用户拒接" } |
| 主动取消 | { "type": "OnCallCancel", "reason": "用户取消" } |
| 接通后挂断 | { "type": "OnCallHangup", "reason": "正常结束" } |
详细的交互指令内容,见上述附件下载路径《dialer_audio_py.zip》压缩包中的README.md文件内容所述,需要的可自行下载后查阅。
- 七、总结
经本篇章这么一顿操作,我们也算是部分的代码开源了。从文中各个章节的描述上看,其实局域网内的数据交互,是非常的简洁的。事实上也本就该如此,如果不考虑目前AI算力和芯片差异,真正的【端到端】AI通话,就应该是【手机-手机】通话,跟网络(局域网或互联网)没有半毛钱关系。
只是因为当前手机算力不足,没法跑AI的大模型,才引出了将手机通话的语音传递到AI算力服务器上。AI响应完毕后转成TTS语音数据再返回手机做注入而已。
这样就引出了【1个AI算力服务器+多个Android手机】这样复用的高效率组合,这样的场景下,很明显,直接使用UDP或RTP,将语音数据通过一个udp端口发到AI服务器,使AI服务器能够同时处理多路语音的呼叫,是正常的标准做法。
我们通过这种方式,在【拦截手机打电话的声音】基础之上,很容易就能扩充出:通话中【随机插播预录语音片段】、AI外呼、AI来电接听等高级功能。
本文的UDP寻址和电话语音数据的交互方式,对同方向的语音和视频类应用,也具有一定的参考意义。