自助语音验证码是通过拨打VOIP电话自动获取验证码,验证码可用来豆子笔记网站认证。这个纯粹是自己的兴趣驱动的。掌握了此项技术,你也可以应用于其它地方。
我是使用Asterisk实现的,Asterisk 是一个流行的开源通信平台,它提供了构建各种通信应用的灵活而强大的解决方案。它被广泛应用于企业内部电话系统、呼叫中心、语音邮件等场景。Asterisk 支持多种通信协议,包括 SIP、H.323、MGCP 和 SCCP,并且能够与传统的 PSTN 线路深度兼容。此外,Asterisk 还支持通过 Inter-Asterisk eXchange (IAX)协议进行语音 IP 传输,允许数据和语音同时在网络上传输。
自助语音验证码使用说明
你需要准备:
- 软电话,或者支持 VOIP 的电话机
- AST 账户,AST 账户从豆子工具小程序中获取,功能菜单为获取 AST 账户。
注意:该功能目前已经下架,这里仅作为备忘记录。
首先,使用获取到的账户配置你的电话。然后拨打 8000,即可自动获取验证码。如果您有什么问题,欢迎关注公众号【技术源泉】私信我。
技术实现
它的工作原理是:用户通过 VOIP 电话连接到 Asterisk,当拨打固定的数字 8000时,Asterisk 将调用 AGI 接口获取服务端的API生成验证码,然后将获取到的验证码拆分通过语音文件播报给用户,播报完毕后自动挂断。
我们根据自助语音验证码原理,将自助验证码实现分解为以下几个技术要点,只要我们解决以下技术要点,就可以实现自助语音验证码。
技术要点:
1,如何播放音频文件?音频文件从哪里来?如何播放动态数据?
2,如何存储用户信息?如何使用数据库存储用户信息?
3,如何获取验证码?
下面内容是我对各个技术点的对应解决方案。
1,Asterisk 自带 Playback 应用,可以通过它播放音频文件。音频文件需要我们提前录制好,并且转换为对应的音频格式,最简单的方法就是使用手机上的录音机。当在拨号计划中多次执行 Playback 应用,Asterisk 会将音频流自动连接起来。所以我们可以使用循环多次执行 Playback 应用即可。
2,Asterisk 使用配置文件写入 SIP 用户信息,但当写入新的 SIP 用户信息后,需要重新加载配置文件。为了方便和第三方对接,我们推荐使用数据库。Asterisk 支持数据库,并且可以实时获取用户信息。
3,Asterisk 支持 AGI 接口,我们可以使用 AGI 获取第三方应用的验证码,获取后和提前录制好的文件结合起来进行播放。
当掌握了这些技术点后,我们就可以灵活应用到其它解决方案。
下面我们来看具体实现:
1,音频文件处理。我们使用手机上的录音机来录制音频文件。Android 录音机录制的音频文件格式为 mp3,如果是 amr 格式,请使用豆子工具音频格式转换功能,转成 mp3 格式文件。IOS 录音机录制的音频文件格式为 m4a,请使用豆子工具音频格式转换功能,转成 mp3 格式文件。我们还需要使用 ffmpeg 将 mp3 文件转成 g711a 格式文件。这个 mp3 转 g711a 功能也可以在豆子工具中使用。
mp3 转 g711a 命令:
ffmpeg -i test.mp3 -acodec pcm_alaw -f alaw -ac 1 -ar 8000 -vn test.alaw
使用 ffplay 播放测试
ffplay -i test.alaw -f alaw -ac 1 -ar 8000
将制作好的音频文件存放在 asterisk sounds 目录,就可以在拨号计划中使用 Playback 应用调用它了。
2,配置实时数据。在Asterisk的源码中,有对应的配置SQL脚本,请根据具体的数据库选择对应的脚本。 比如使用PJSIP,就的使用它对应的表结构。
需要在数据库中创建对应的三张表ps_endpoints,ps_aors,ps_auths,参考源码中的脚本。创建表完毕后,我们需要插入PJSIP 测试数据:
insert into ps_endpoints(id,context,disallow,allow,auth,aors) values ('9000','vcode','all','ulaw,alaw,gsm','9000','9000');
insert into ps_aors(id,max_contacts) values('9000',1);
insert into ps_auths(id,auth_type,password,username) values('9000','userpass','123321','9000');
注意:数据库表中的字段和配置文件中的字段是一致的。
3,配置 Asterisk,这里以sqlite3为例,如果需要实时对接第三方应用,推荐使用Mysql或者Postgresql数据库。
在 res_config_sqlite3.conf 中添加如下内容:
[asterisk]
dbfile => /var/lib/asterisk/realtime.sqlite3
在 extconfig.conf 文件中添加如下内容:
ps_endpoints => sqlite3,asterisk
ps_auths => sqlite3,asterisk
ps_aors => sqlite3,asterisk
在 sorcery.conf 文件中添加如下内容:
[res_pjsip]
endpoint=realtime,ps_endpoints
auth=realtime,ps_auths
aor=realtime,ps_aors
使用 sqlite3 命令创建 realtime.sqlite3 数据库,并创建上面的三张 PJSIP 表,然后插入记录。
最后在软电话上测试是否可以注册成功。
虽然,我使用的 sqlite3 存储 pjsip 用户信息,但我还是推荐你使用 mysql 或者 postgresql。它的好处是可以对接第三方应用时,实时添加操作数据库,实时添加用户。而 sqlite3 会报错,提示数据库已锁定。虽然我通过同步数据库文件解决,但它不是一个实时的方案。它在并发操作这块还是有些欠缺。
4,Asterisk AGI 调用。Asterisk 支持 AGI 接口,它支持多种语言,并提供多种语言 SDK,例如 Ruby,Java,PHP,Python,C++,.Net,nodejs,Go。我使用的 Golang 语言,使用这个github.com/CyCoreSystems/agi AGI 库。
使用 go 编写的 agi 脚本,这是一个示例:
package main
import (
"github.com/CyCoreSystems/agi"
)
func main() {
a := agi.NewStdio()
// 设置通道变量
err := a.Set("MYVAR", "foo")
if err != nil {
panic("failed to set variable MYVAR")
}
m := a.Variables
// 获取AGI参数
callerid, ok := m["agi_callerid"]
if !ok {
a.Verbose("failed to get callerid", 1)
panic("failed to get callerid")
}
// 打印日志
a.Verbose(callerid, 4)
// 播放音频文件
a.StreamFile("bean", "", 0)
a.StreamFile("thanks", "", 0)
}
我们需要将编译之后的脚本文件放在/var/lib/asterisk/agi-bin/目录中。并执行chmod +x agidemo添加执行权限。
最后,就是几种常见错误的解决方法:
- 403 登录失败。解决:等待 1 分钟,等超时之后重新连接即可。一般是切换 IP 时或者换软电话登录会碰到。
- 401 登录失败。解决:检查账户和密码是否正确?检查连接地址是否正确?检查 Asterisk 是否启动?检查防火墙端口是否打开?
- 408 连接超时。解决:一般是 Asterisk 服务不通,检查 Asterisk 服务是否启动,检查防火墙是否打开?
- 可以拨通,没有声音?一般是 NAT 造成,配置这三个参数:rtp_symmetric,force_rport,rewrite_contact。
- SIP 客户端没有自动挂机?一般是没有设置 stun 造成的,在 SIP 客户端,设置 stun 即可。如果没有 stun server,可以设置这个
stun.l.google.com:19302 - AGI 脚本返回状态 4,正常应该为 0?查看网上资料,是 AGI 脚本中调用 Hangup 导致,将脚本中的 Hangup 去掉,放在拨号计划配置文件中执行 Hangup,可以解决这个问题。
AGI Script agidemo completed, returning 0
你如果喜欢,欢迎联系我交流。