编辑语:
为助力“玄铁杯”RISC-V应用创新大赛的顺利进行,协助参赛者快速上手操作大赛提供的RISC-V开发套件,OCC推出RISC-V大赛开发套件解析系列内容,从硬件特点到例程开发为开发者详细解读大赛开发套件。
自上期内容开始,我们开启了D1 哪吒开发板HaaS-UI的开发介绍,并为大家演示了D1 哪吒开发板如何基于HaaS-UI实现Wi-Fi配网。本期我们将为大家介绍HaaS-UI的语音AI服务,旨在为准备基于D1 哪吒开发板开发离线语音功能或在线语音功能的开发者提供指导和借鉴。
01
概述
1.1 语音AI服务(Voice)
语音AI服务,简称Voice。服务框架采用通用的C/S架构,服务端提供离线语音功能和在线语音等功能。客户端可以接收服务端发出的事件,也可以向服务端发送控制命令。
02
编程语言
2.1 C/C++
Voice服务端是由C语言开发完成。Voice客户端支持C++开发。
2.2 JavaScript
Voice客户端支持JS语言开发。JavaScript(简称“JS”) 是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。虽然它是作为开发Web页面的脚本语言而出名,但是它也被用到了很多非浏览器环境中,JavaScript 基于原型编程、多范式的动态脚本语言,并且支持面向对象、命令式、声明式、函数式编程范式。下文演示了Voice客户端开发的实例。视频:完成一个ASR效果需要编写的代码下图:对应ASR效果
2.3 Vue.JS
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式JavaScript框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用(SPA)提供驱动。Vue.JS 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。Vue.JS 自身不是一个全能框架——它只聚焦于视图层。因此它非常容易学习,非常容易与其它库或已有项目整合。另一方面,在与相关工具和支持库一起使用时,Vue.JS 也能驱动复杂的单页应用。下面动图展示的就是通过Vue.JS开发的界面。
03
依赖库
3.1 ALSA库
- 库名:libasound.so.2
- 官方主页:
https://www.alsa-project.org/main/index.php/Main_Page
ALSA是Advanced Linux Sound Architecture,高级Linux声音架构的简称。它在Linux操作系统上提供了音频和MIDI(Musical Instrument Digital Interface,音乐设备数字化接口)的支持。
- 有效支持所有类型的音频接口,从消费级声卡到专业的多声道音频接口。
- 完全模块化的声音驱动器。
- SMP 和线程安全设计。
- 用户空间库 (alsa-lib) 用于简化应用程序编程并提供更高级别的功能。
- 支持较旧的 Open Sound System (OSS) API,为大多数 OSS 程序提供二进制兼容性。在RVB-D1 开发板JS轻应用平台中,Voice服务使用ALSA-LIB库定时读取定量录音数据后,交给算法处理。
3.2 D-Bus库
- 库名:libdbus-1.so.3
D-Bus是一种高级的进程间通信机制,它由freedesktop.org项目提供,使用AFL和GPL双许可证发行。D-Bus 提供system守护进程(用于“添加新硬件设备”或“打印队列更改”等事件)和per-user-login-session守护进程(用于用户应用程序之间的一般 IPC 需求)。此外,消息总线建立在通用的一对一消息传递框架之上,任何两个应用程序都可以使用该框架进行直接通信(无需通过消息总线守护进程)。
目前,通信应用程序在一台计算机上,或者通过未加密的 TCP/IP 进行,适合在具有共享 NFS 主目录的防火墙后面使用。D-Bus最主要的用途是在Linux桌面环境为进程提供通信,同时能将Linux桌面环境和Linux内核事件作为消息传递到进程。D-Bus的主要概率为总线,注册后的进程可通过总线接收或传递消息,进程也可注册后等待内核事件响应,例如等待网络状态的转变或者计算机发出关机指令。目前,D-Bus已被大多数Linux发行版所采用,开发者可使用D-Bus实现各种复杂的进程间通信任务。在RVB-D1 开发板JS轻应用平台中,Voice服务使用D-Bus通信机制对外提供事件信号(Signal)和方法(Method Call)。Voice服务使用的是D-Bus的系统总线(System Bus)。
语音AI服务和D-Bus的关系图:
3.3 XML库
由于D-Bus的安全策略,服务“org.voice.server”需要设置own,配置文件存放于/etc/dbus-1/system.d/voice-dbus.conf。
该文件的解析依赖于libexpat.so库
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> <busconfig> <policy user="root"> <allow own="org.voice.server"/> <allow send_destination="org.voice.server"/> <allow send_interface="org.voice.server"/> <allow receive_sender="org.voice.server" receive_type="signal"/> </policy> <policy context="default"> <deny own="org.voice.server"/> <deny send_destination="org.voice.server"/> <deny receive_sender="org.voice.server" receive_type="signal"/> </policy> </busconfig>
若没有该配置文件,运行voice服务会报错误如下:
Name Error (Connection ":1.1" is not allowed to own the service "org.voice.server" due to security policies in the configuration file)
04
Voice服务启动
运行Voice客户端前,需要先启动Voice服务端,一般系统初始化过程中会默认启动Voice服务,若没有启动,则可执行如下命令启动:
/usr/bin/voice-service
查看服务是否成功启动,执行命令:输出信息中出现 string "org.voice.server" 则说明服务启动成功。
dbus-send --system --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ListNames
05
Voice 客户端开发
5.1 D-Bus 接口
介绍Voice客户端开发必须要先郑重介绍其D-Bus接口,因为客户端开发基于D-Bus接口。
5.1.1 D-Bus API
D-Bus接口采用的是字符串形式,如下,定义了服务名、服务路径、服务接口。Voice 客户端通过这些字符串可以访问到Voice 服务。
5.1.1.1 D-Bus 服务名
"org.voice.server"
5.1.1.2 D-Bus 服务路径
"/org/voice/path"
5.1.1.3 D-Bus 服务接口
"org.voice.interface"
5.1.1.4 D-Bus BUS 类型
DBUS_BUS_SYSTEM
5.1.1.5 D-Bus Signal
下个章节会介绍这些信号是如何使用的。
名字 |
说明 |
"SessionBegin" |
会话开始信号。 |
"SessionEnd" |
会话结束信号。 |
"ASRBegin" |
开始ASR识别信号,云端识别到语音的第一个词时会发送该事件 |
"ASRChanged" |
ASR中间结果信号,云端识别到语音的过程中上报的事件 |
"ASREnd" |
ASR识别结束信号 |
"NLP" |
NLP结束信号 |
"TTSBegin" |
TTS开始信号 |
"TTSEnd" |
TTS结束信号 |
5.1.1.6 DBUS MethodCall
名字 |
说明 |
"Start" |
开启语音服务 |
"Stop" |
关闭语音服务 |
"GetState" |
获取状态 |
"ASR" |
调用该API进行ASR |
"NLP" |
调用该API进行NLP |
"TTS" |
调用该API进行TTS |
5.2 用户使用示例(JS)
5.2.1 库文件
为了方便用户编程,JS层封装了一个Voice库,该库屏蔽了D-Bus相关的细节,用纯JS的方式(无本地方法)提供了API。用户只需要包含“voice.js”库,即可使用该APIs。
import voice from 'libs/voice.js'
5.2.2 Voice对象定义
function() { var self = this; this.voice = new voice("voice"); }
5.2.3 事件监听
通过JS编程,可以监听Voice服务发上来的事件。如下示例,介绍了如何监听Voice服务的各个事件。本文也提供了Linux命令行的方法监听Voice服务,可以更好的配合调
dbus-monitor --profile --system interface='org.voice.interface'
5.2.3.1 监听sessionBegin事件
function() { var self = this; this.voice.on("sessionBegin", (props) => { console.log(props); //此处可以暂停其它业务,播放session应答音等操作 }); }
5.2.3.2 监听ASR事件
function() { var self = this; this.voice.on("ASRBegin", (props) => { //...... }); this.voice.on("ASRChanged", (props) => { //...... }); this.voice.on("ASREnd", (props) => { //...... }); }
5.2.3.3 监听NLP事件
function() { var self = this; this.voice.on("NLP", (props) => { //...... }); }
5.2.3.4 监听TTS事件
function() { var self = this; this.voice.on("TTSBegin", (url) => { //play }); this.voice.on("TTSEnd", (url) => { //... }); }
5.2.4 服务的开启和关闭
通过JS编程,也可以将Voice服务强制关闭,需要注意的是关闭后,其客户端也将接收不到Voice服务的事件,除非调用“Start”方法将服务开启。通常情况下,不建议将Voice服务频繁的开关。本文提供Linux命令行的方法开关Voice服务:
dbus-send --system --print-reply --type=method_call --dest=org.voice.server /org/voice/path org.voice.interface.Start
5.2.4.1 关闭服务
function() { this.voice.stop(); }
5.2.4.2 开启服务
function() { this.voice.start(); //语音AI服务默认开启,不需要用户开启,只有当用户关闭后,才需要开启。 }
5.2.5 客户端退出
注意:Voice客户端退出时,需要用户主动调用destroy函数。destroy函数中会断开D-Bus链接,清除定时器资源。如果没有执行该操作,反复进行 new voice()的操作,会造成内存泄漏。
06
下期预告
有关D1 哪吒开发板HaaS-UI语音AI的介绍就到这里,下期我们将带大家了解D1 哪吒开发板如何基于HaaS-UI实现视频播放功能。欢迎大家持续关注本系列内容。
2022“玄铁杯”RISC-V应用创新大赛报名即将截止,还没有报名的小伙伴赶快点击下方图片报名参加吧。