Whatsapp VoiceCall
客户端通过websocket连接到服务器,客户端发起语音通话请求,并且完成必要的协商之后,就可以直接将语音数据发送给服务器,服务器接收到对方的语音数据之后也会通过websocket将语音数据转发给客户端。
websocket连接并不是和whatsapp 服务器连接
获取协商秘钥
XMPP 在发起语音通话请求的时候,需要带上一个秘钥,这个秘钥长32字节,通过特殊算法生成。whatsapp 服务器接收到秘钥之后会解密,然后校验时间戳。这个算法需要三个参数:
- 自身jid
- 对方jid
- 时间戳
//发送json 格式命令,获取秘钥
{"otherjid": "otherjid@whatsapp.com","command": "GetSecret","selfjid": "121312312@whatsapp.com"
}
//服务器回复秘钥, 注意秘钥是经过base64编码, 接收方需要解码,解码之后是32字节的二进制数据
{"secret": "DTGFOJCrTK+o6GhWfAeUkrq5VN9eHkwfkiDHKOkKRhY=","command": "ResponseSecret"
}
发起XMPP 语音通话请求
当获取到加密秘钥之后,就可以构造xmpp的语音通话请求包,然后将这个包发送给whatsapp 服务器,这样对方手机就会响铃。
1 构造语音通过请求
下面是一个xmpp 语音请求包
<call to='xxx@s.whatsapp.net' id='xxx'><offer call-creator='xxx:0@s.whatsapp.net' call-id='xxxx'device_class='2015'><audio rate='16000' enc='opus' /><net medium='3' /><capability ver='1'>AQT3C84a</capability><enc v='2' type='pkmsg'>MwiFBhIhBRE+8IYJ4rTvOJV4VfxcXvcTontZBz0bx7bxUpfOFQ5HGiEFYl47S8HlKrOoMqMxT8oxn4HuBal5baxV+fvQD58Hmw8icjMKIQVZ6HEY7yA5wTA2AJPYNSPy/iEcVCqTQG0TADBl/pB1AxACGAAiQKLYdXauXiPQPUeo+eQzDPkxH8cuBDXvPxuw/hfFkP1rlmTiP5sF5XLAV8iI+dZUOG3uUgwUzzP3ZIDhyRfa23Wodd1H/R+mHiif2YvCAjDQ9ekH</enc><encopt keygen='2' /></offer>
</call>
call-id: 32 字节长度的字符串,用来唯一标识通话请求,如果需要挂断就需要使用 这个call-id。
enc: 这个字段是一个加密的字段,和普通的 文本消息加密方式一样。 只是内容不同。构造一个Message 对象,将第一步获取到的秘钥 设置到callKey 字段,然后加密。
2 发送/确认 语音通话请求
转发语音数据
当发送XMPP 的确认包之后,就需要将语音数据尽快发给whatsapp 的服务器,否则超时会自动断开,此时需要将语音数据编码成opus格式,然后 通过websocket 发送到中转服务器, 中转服务器会负责语音数据的加密以及转发。并且中转服务器也会通过websocket 将接收到的数据转发给客户端,流程图如下