# VOIP
小微提供的voip能力使得设备与腾讯小微小程序之间能够进行音视频通话。在Linux设备上,考虑到场景和设备性能的原因,目前只提供纯音频的通话能力,不提供视频能力。SDK提供音频拨打逻辑和音频流传输通道,录音、回声消除以及播放由设备端自行完成。音频格式为pcm,16bit。
voip功能在小微SDK中是一个可选功能,他是单独的so存在,默认提供,若您无需voip模块,在编译工程时需要定义__NO_VOIP
这个宏,或者不要引入voipSDK.h这个头文件,并且不要链接voip相关的lib。
小微的voip事实上是一个多人通话,只是目前在业务逻辑上仅开放了双人的通话,因此逻辑较为复杂,为了降低接入成本,一些错误处理逻辑并未暴露接口出来,出错后基本上挂断即可。voip的具体参数请参考头文件中的说明,这里对voip的流程进行说明。
# VOIP流程
为了便于使用,voip内部已经维护了一个状态机,确保同时只有一个通话正在进行,此时若有其他通话接入,将被直接拒绝,无需上层操作。
# 接口说明
# 1. int voip_service_start(VOIP_CALLBACK *callback, VOIP_INIT_PARAM *param);
初始化VOIP引擎,在logincomplete之后调用,只需要调用一次,无需反复start和stop。
# 2. int voip_service_stop();
彻底不需要VOIP的时候调用,一般无需调用
# 3. int voip_create_call(const char *username, const char *appId, int type);
发起主叫,注意这里只能给自己的绑定者拨打。
- username 和binder的username对应。
- appId 打给谁,填nullptr即可打给小微小程序
- type 0:默认,1:音视频 2:纯音频,Linux版本只支持纯音频
# 4. int voip_answer();
被叫时接听voip。
# 5. int voip_hangup();
挂断voip,一共有以下使用场景:
- 被叫时拒绝
- 主叫时在接通前取消
- 通话时主动挂断
# 6. int voip_send_audio_data(const unsigned char *pData, int dataLen, int playDelayMS);
通话开始后,发送音频数据,需要不断调用。需要按照回调的要求来采集并且发送。此接口调用频率和每次发送的数据量请参考on_voip_param_change
。
- pData pcm数据
- dataLen 数据长度
- playDelayMS 播放延时,根据经验来看,设计成100比较好
# 7.int voip_get_audio_data(unsigned char *pBuf, int bufLen);
接收音频数据,这里的无需关注返回值,若没有数据,调用此接口也会获得空的pcm音频。调用频率和send一致。获得数据后自行播放出来即可。
- pBuf 待写入的数据buf,SDK会将音频数据写进去,请严格计算
- bufLen pBuf的长度
# 回调逻辑
voip的回调一共有以下事件:
# 1.void (*on_voip_invited)(const char *fromUsername, int type)
设备被叫时会收到此回调,fromUsername为绑定者的username,type为通话类型,目前Linux版本只支持2,即纯音频通话,您必须处理此invite,否则对方会一直等待直到超时。
# 2.void (*on_voip_join_room)(int result, bool isMaster);
加入房间的结果。小微的voip事实上是一个多人通话,当您主动发起通话时,首先需要创建并且加入房间,然后邀请对方进入房间(邀请过程由SDK自动完成)。主叫时加入房间失败,通话直接结束。被叫加入房间失败,设备端需重试或调用int voip_hangup()
来拒绝(重试接口目前未开放,请直接挂断)。
- result 非0就失败,0成功
- isMasetr true就是主叫,false为被叫
# 3.void (*on_voip_invite_result)(int result);
作为主叫方邀请对方,发送的邀请结果。0成功非0失败,失败之后,需调用int voip_hangup()`来终止本次通话(理论上可以重新再邀请,但是本功能暂时保留)。这里一般来说很难失败。
# 4.void (*on_voip_cancel)(bool isMaster);
voip被取消,场景比较多。在通话开始前,作为主叫方,一般是对方拒绝接听;作为被叫方,一般是对方在还自己未选择接听或拒绝的时候就取消了通话。在通话开始后,对方主动挂断,也会收到此回调。无论如何,在收到本回调之后,都意味着通话正常结束。
# 5. void (*on_voip_talking)()
通话开始,可以开始发送和接收数据。这里其实是判断了房间人数从1变为2,即开始通话。
# 6. void (*on_voip_finish)()
通话非正常结束,一般是由于某个流程或网络突然中断等原因造成的。此时停止收发音频,退出voip即可,无需调用其它接口来停止本次通话。
# 7. void (*on_voip_param_change)(unsigned int sampleRate, unsigned int sampleLenInms, unsigned int channels, const char *extends);
voip房间参数改变,这个接口十分重要。房间创建好,通话正式开始前会收到此回调,理论上在通话过程中也会多次改变。收到此回调后,一定要按照要求来动态改变采样率、每帧数据长度和通道数。音频的格式永远是PCM,16位。
- sampleRate 采样率 ,如16000
- sampleLenInms 每次发送/接受数据的长度,单位ms,例如这里的值是30,那么就是每30ms发送和接收一次数据,数据真正的长度据此和sampleRate来计算即可。
- channels 几个通道,一般是1
- extends 更为复杂的配置参数,是一个PB,暂时reserved
# 8. 其它
剩下的回调可以暂时无视,在多人通话、UI展示、静音切换等场景下使用。若需要使用,请咨询我们。
# 接口调用逻辑
使用voip时,应按照以下流程操作。
- init SDK时,首先等待logincomplete。
- 调用
voip_service_start(...)
接口初始化voip引擎,此接口只需要调用一次。 - 主动发起通话时,调用
voip_create_call(...)
来发起;接听通话时,首先会收到on_voip_invited(...)
,然后调用voip_answer()
来接听。 - 在任何时候,若需要停止voip,调用
voip_hangup()
,包括主叫时放弃、被叫时拒绝和通话过程中挂断。 - 通话过程中持续调用
voip_send_video_data(...)
和voip_get_video_data()
来发送和接收音频流。 - 一般情况下无需调用
voip_service_stop()
,除非需要重置初始化参数。
# 总结流程图
# 主叫流程
# 被叫流程
# 常见问题
# 设备如何接听VOIP
理论上可以以任意的方式,例如手动按设备的某个按键。但是对于无屏音箱,我们推荐语音接听的方式。在收到被叫信息后,我们的推荐处理流程如下:
- step1 开始响铃,铃声我们跟头文件一起提供了。
- step2 可以去binderList查一下谁打来的,优先获取remark,没有就获取nickname,然后使用小微的TTS合成接口去合成“收到来自xxx的电话,接听还是拒绝”?
- step3 拿到TTS后,铃声降低,播放TTS,同时开始V2A请求,让小微返回“接听”或“拒绝”。这个过程若回声消除不行,可以在TTS播放完之后再发起V2A请求。