whatsapp 语音通话 音频编码(五)

2024-04-17 04:28

本文主要是介绍whatsapp 语音通话 音频编码(五),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Whatsapp VoiceCall

客户端通过websocket连接到服务器,客户端发起语音通话请求,并且完成必要的协商之后,就可以直接将语音数据发送给服务器,服务器接收到对方的语音数据之后也会通过websocket将语音数据转发给客户端

获取协商秘钥

XMPP 在发起语音通话请求的时候,需要带上一个秘钥,这个秘钥长32字节,通过特殊算法生成。这个算法需要三个参数:

  1. 自身jid
  2. 对方jid
  3. 时间戳(服务端自动获取,不需要生成)
        //发送获取秘钥请求JSONObject result = new JSONObject();result.put("command", "GetSecret");result.put("selfjid", "自己的@whatsapp.com");result.put("otherjid", "对方@whatsapp.com");SendCommand(result);//接收到服务器返回的消息, secret 字段是经过base64 编码,需要解码,解码之后是32字节{"secret": "Xh+LtW/gRxC92B4UK/gLAzqERAqL9U2ArNetO3Zy0h0=","command": "ResponseSecret"}

发起XMPP 语音请求

  1. 发起语音请求。这个请求需要通过xmpp 通道发送出去,发出去之后,WA服务器会回一个ack包,这个ack包需要通过websocket发给中转服务器
 <call to='接收方@s.whatsapp.net' id='随机生成32字节'><offer call-creator='发送方.0:0@s.whatsapp.net' call-id='随机生成32字节' device_class='2015'><privacy>联系人的token,  同步联系人的时候 privacy_token节点下 trusted_contact 数据 </privacy><audio rate='16000' enc='opus'/><net medium='3'/><capability ver='1'>AQT3CcT6</capability><enc v='2' type='msg'>从服务器获取的32字节秘钥序列化成pb之后加密</enc><encopt keygen='2'/></offer></call>
 //下面是消息pb 结构的一部分,需要将返回的32字节秘钥 设置到 Call->callKey 中,序列化之后加密message Message {optional string conversation = 1;optional SenderKeyDistributionMessage senderKeyDistributionMessage = 2;optional ImageMessage imageMessage = 3;optional ContactMessage contactMessage = 4;optional LocationMessage locationMessage = 5;optional ExtendedTextMessage extendedTextMessage = 6;optional DocumentMessage documentMessage = 7;optional AudioMessage audioMessage = 8;optional VideoMessage videoMessage = 9;optional Call call = 10;... ...... ...}message Call {optional bytes callKey = 1;optional string conversionSource = 2;optional bytes conversionData = 3;optional uint32 conversionDelaySeconds = 4;}
  1. 处理ack 回包。
    发送完第一个包之后,服务器会返回一个ack包, 需要将这个ack包转成xml格式,然后通过websocket 发送给服务器
      //xmpp 转xml 需要注意, 节点部分的值需要base64 之后再发过来<ack from='对方@s.whatsapp.net' class='call' type='offer' id='xxxx'><relay attribute_padding='1' peer_pid='0' self_pid='1' uuid='xxx' call-creator='xxx@s.whatsapp.net' call-id='xxx' joinable='1'><participant pid='0' jid='xxx@s.whatsapp.net'/><token id='0'>base64的内容</token><token id='1'>xxx</token><token id='2'>xxx</token><token id='3'>xxx</token><token id='4'>xxxx</token><key>xxxx</key><te2 protocol='1' relay_id='0' token_id='0'>base64的内容</te2><te2 protocol='1' relay_id='0' token_id='0'>base64的内容</te2><te2 relay_id='0' token_id='0'>xxx</te2><te2 relay_id='0' token_id='0'>xxx</te2><te2 protocol='1' relay_id='1' token_id='1'>xxx</te2><te2 protocol='1' relay_id='1' token_id='1'>xx</te2><te2 relay_id='1' token_id='1'>xxx</te2><te2 relay_id='1' token_id='1'>xxx</te2><te2 protocol='1' relay_id='2' token_id='3'>xxx</te2><te2 protocol='1' relay_id='2' token_id='3'>xxx</te2><te2 relay_id='2' token_id='3'>xxx</te2><te2 relay_id='2' token_id='3'>xxx</te2><te2 protocol='1' relay_id='3' token_id='2'>xxx</te2><te2 protocol='1' relay_id='3' token_id='2'>xxx</te2><te2 relay_id='3' token_id='2'>xxx</te2><te2 relay_id='3' token_id='2'>xxx</te2><te2 protocol='1' relay_id='4' token_id='4'>xxx</te2><te2 protocol='1' relay_id='4' token_id='4'>xxx</te2><te2 relay_id='4' token_id='4'>xxx</te2><te2 relay_id='4' token_id='4'>xxx</te2><hbh_key>xxx</hbh_key></relay><user jid='xxx@s.whatsapp.net'><device jid='xxx@s.whatsapp.net'/></user><rte>xxx</rte><uploadfieldstat/><userrate/><voip_settings uncompressed='1'>xxxx</voip_settings></ack>
 //将服务器回的ack 包发给中转服务器JSONObject result = new JSONObject();result.put("command", "VoiceAck");// 用于测试的音频文件ID,固定,正式部署的时候需要换成上传的文件result.put("file_uuid", "aee4d52d-6ba7-4a65-80d4-b7341b1115f0");result.put("ack", "服务器回的ack包打包成xml格式");SendCommand(result);
  1. 接收到的服务器的包必须回复ack,否则会被踢下线,下面几个常用的ack
		//接收的包<receipt from='xxx@s.whatsapp.net' id='xxx' t='xxx'><offer call-id='xxx' call-creator='xxx@s.whatsapp.net'/></receipt>//需要回复ack<ack id='xxx' to='xxx@s.whatsapp.net' class='receipt'/>
  //接收的包<call from='xxx@s.whatsapp.net' id='xxx' t='xxx'><preaccept call-id='xxx' call-creator='xxx@s.whatsapp.net'><audio rate='16000' enc='opus'/><encopt keygen='2'/><capability ver='1'>xxx</capability></preaccept></call>//需要回复ack<ack id='xxx' to='xxx.0:0@s.whatsapp.net' class='call' type='preaccept'/>
 //接收的包<call from='xxx@s.whatsapp.net' id='xxx' t='xxx'><relaylatency call-id='xxx' call-creator='xxx@s.whatsapp.net'><te latency='xxx'>xxx</te></relaylatency></call>//需要回复ack<ack id='xxx' to='xxx.0:0@s.whatsapp.net' class='call' type='relaylatency'/>
  1. 中转服务器会将一些需要发给WA服务器的包发过来,这些包需要转成xmpp 格式的数据发给WA 服务器
 <call to="xxx@s.whatsapp.net" id="xxx"><relaylatency call-creator="xxx.0:0@s.whatsapp.net" call-id="xxx"><te latency="xxx">xxx</te></relaylatency></call>

总结一下步骤:

1. 和中转服务器建立websocket 连接

2. 从中转服务器获取 加密秘钥

3. XMPP 发送call 请求,并且接收服务器返回的ack, 特别需要注意期间会收到很多包,都需要回ack,上面也列出了一些需要回ack的包

4. 将WA 服务器的ack包转成xml 格式发给中转服务器, 特别需要注意xml格式节点值需要base64 编码

5. 中转服务器会主动发送一些xml数据, 客户端需要将这些xml数据转成xmpp包发给服务器。

在这里插入图片描述

这篇关于whatsapp 语音通话 音频编码(五)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/910775

相关文章

探索蓝牙协议的奥秘:用ESP32实现高质量蓝牙音频传输

蓝牙(Bluetooth)是一种短距离无线通信技术,广泛应用于各种电子设备之间的数据传输。自1994年由爱立信公司首次提出以来,蓝牙技术已经经历了多个版本的更新和改进。本文将详细介绍蓝牙协议,并通过一个具体的项目——使用ESP32实现蓝牙音频传输,来展示蓝牙协议的实际应用及其优点。 蓝牙协议概述 蓝牙协议栈 蓝牙协议栈是蓝牙技术的核心,定义了蓝牙设备之间如何进行通信。蓝牙协议

人工和AI大语言模型成本对比 ai语音模型

这里既有AI,又有生活大道理,无数渺小的思考填满了一生。 上一专题搭建了一套GMM-HMM系统,来识别连续0123456789的英文语音。 但若不是仅针对数字,而是所有普通词汇,可能达到十几万个词,解码过程将非常复杂,识别结果组合太多,识别结果不会理想。因此只有声学模型是完全不够的,需要引入语言模型来约束识别结果。让“今天天气很好”的概率高于“今天天汽很好”的概率,得到声学模型概率高,又符合表达

完整的申请邓白氏编码的流程(手把手教你申请邓白氏编码

完整的申请邓白氏编码的流程(手把手教你申请邓白氏编码)  标签: 编码邓白氏编码申请流程苹果开发者账号申请 2016-07-08 16:13  2274人阅读  评论(2)  收藏  举报   分类: 技术  苹果开发  邓白氏编码申请 版权声明:本文为博主原创文章,未经博主允许不得转载。     申请公司的苹果开发者账号和企业级的苹

关于文章“python+百度语音识别+星火大模型+讯飞语音合成的语音助手”报错的修改

前言 关于我的文章:python+百度语音识别+星火大模型+讯飞语音合成的语音助手,运行不起来的问题 文章地址: https://blog.csdn.net/Phillip_xian/article/details/138195725?spm=1001.2014.3001.5501 1.报错问题 如果运行中报错,且报错位置在Xufi_Voice.py文件中的pcm_2_wav,如下图所示

编程精粹—— Microsoft 编写优质无错 C 程序秘诀 07:编码中的假象

这是一本老书,作者 Steve Maguire 在微软工作期间写了这本书,英文版于 1993 年发布。2013 年推出了 20 周年纪念第二版。我们看到的标题是中译版名字,英文版的名字是《Writing Clean Code ─── Microsoft’s Techniques for Developing》,这本书主要讨论如何编写健壮、高质量的代码。作者在书中分享了许多实际编程的技巧和经验,旨在

ubuntu 18.04 server源码编译安装freeswitch 1.10.7支持音视频通话、收发短信——筑梦之路

软件版本说明 ubuntu版本18.04:https://releases.ubuntu.com/18.04.6/ubuntu-18.04.6-live-server-amd64.iso freeswitch 版本1.10.7:https://files.freeswitch.org/freeswitch-releases/freeswitch-1.10.7.-release.tar.gz s

首次使用回声状态网络 (ESN) 和语音特征进行帕金森病 (PD) 预测

帕金森病(Parkinson's disease, PD)是一种使人衰弱的神经退行性疾病,它需要进行精确和早期的诊断,以便为患者提供有效的治疗和护理。这种疾病是由James Parkinson在1817年首次确定的,其特征是多巴胺生成神经元的退化。多巴胺的不足导致了一系列症状,包括静止性震颤、肌肉僵硬、运动迟缓(姿势不稳定)、以及其他重要特征,如睡眠障碍、心律失常、便秘和语音变化,这

jsp和Servlet中的响应(response)编码

<span style="font-size:18px;">  常见字符编码:iso-8859-1(不支持中文)、gb2312、gbk、gb18030(系统默认编码,中国的国标码)、utf-8(万国码,支持全世界的编码,所以我们使用这个)1. 响应编码* 当使用response.getWriter()来向客户端发送字符数据时,如果在之前没有设置编码,那么默认使用iso,因为iso不支持中文

编码表概述和常见编码表

l 编码表 • 由字符及其对应的数值组成的一张表 l 常见编码表 • ASCII/Unicode 字符集 • ISO-8859-1 • GB2312/GBK/GB18030 • BIG5 • UTF-8 计算机只能识别二进制数据,早期由来是电信号。 为了方便应用计算机,让它可以识别各个国家的文字。 就将各个国家的文字用

字符串到字节数组和字节数组到字符串的转换(编码和解码问题)

/*  * String(byte[] bytes, String charsetName):通过指定的字符集解码字节数组  * byte[] getBytes(String charsetName):使用指定的字符集合把字符串编码为字节数组  *  * 编码:把看得懂的变成看不懂的  * String -- byte[]  *  * 解码:把看不懂的变成看得懂的