现在大部分手机相机都有声控功能,不过我的手机比较老,没有声控功能,于是动手写一个有声控功能的android相机,就算是一次编程实践。 声控功能需要使用语音唤醒,考虑到百度语音唤醒基本上免费,所以采用百度语音唤醒。获取百度资源的方法还算友善,步骤如下:
进入百度开放平台,注册账号,创建应用,拿到相对应的 appId,apiKey,secretKey。
下载语音识别Android SDK,我用的是baidu_speech_ASR_V3_20210628_cfe8c44_3.4.4.zip。这里面包括用于语音识别和语音唤醒的core库,还包括demo用的语音识别和语音唤醒app。可以用demo app测试系统、学习使用方法。
把下载的core库导入Project,建立app对core的依赖关系。
在core中找到授权管理类AuthUtil,将先前取得的appId,apiKey,secretKey写入相应位置。这些都是敏感信息,请妥善处置。
语音唤醒需要语音唤醒二进制资源文件WakeUp.bin,在百度开放平台的语音唤醒页面获取这个文件,下载文件之前先进行唤醒词评估,评估成功就可以下载生成的WakeUp.bin,具体做法和规则请参照语音唤醒页面。取得WakeUp.bin后将其导入core的assets资源文件夹中,替换原有的文件。我的WakeUp.bin文件中有四个唤醒词:拍照、茄子、切换镜头、关闭相机。
项目基于Jetpack Compose打造,采用Compose倡导的MVI架构。
View层,全部用Composable函数实现,基本上不需要Layout相关的各种XML文件。
Model层,用ViewModel管理状态的变化。
用户通过操作View层发出Intent(意图)给Model层,我觉得称为Action(动作)更确切,Model层根据Intent或Action更新状态,View层根据变化后的状态刷新UI。
系统构成如下: 用于声控快门的语音唤醒功能都在文件SpeechWakeUp.kt中,先定义了类SpeechWakeUp,语音唤醒功能都包括其中,后来觉得用纯函数实现可能更好,又写了以下几个语音唤醒有关的函数:
initWakeUp,初始化语音唤醒功能,ViewModel初始化时调用。
private const val tag = "SpeechWakeUp"
private lateinit var audioCameraViewModel: AudioCameraViewModel
private lateinit var wakUpEventManager: EventManager
fun initWakeUp(context: Context, viewModel: AudioCameraViewModel) {
audioCameraViewModel = viewModel
wakUpEventManager = EventManagerFactory.create(context, "wp")
wakUpEventManager.registerListener(eventListener)
}
startWakeUp,启动语音唤醒,用户启动声控快门时调用。
fun startWakeUp(context: Context) {
MyLog(tag, "start").print()
val params = AuthUtil.getParam()
params[SpeechConstant.ACCEPT_AUDIO_VOLUME] = false
params[SpeechConstant.WP_WORDS_FILE] = "assets:///WakeUp.bin"
InFileStream.setContext(context)
val json = JSONObject(params).toString()
wakUpEventManager.send(SpeechConstant.WA