Android Things Developer Preview 2 支持 USB 音频,这意味着现在可以在外部 USB 扬声器上播放音乐,还可以通过 USB 麦克风录制音频。
这可以用于创建一个非常简单、愚蠢的 Android Things 音频助理、离线语音识别、文本到语音功能的完美场合。
与 “Alexa” 或 “Ok Google” 类似,我们的智能设备应始终监听 “Ok Things!” 关键词。一旦检测到,设备应该识别给定的命令,并使用文本到语音输出结果。
下面是我们将要实现的演示视频:
https://www.youtube.com/watch?v=FkDltIOgcNg
首先,我们应该将一些扬声器连接到 Android Things 板。
您不需要有 USB 音频扬声器。一个 HDMI 电视,或标准的 3.5 毫米插孔扬声器也能完成这项工作。我自己的扬声器(AmazonBasics A100)采用 USB 供电,这很方便,因为我可以直接为 Raspberry Pi 供电。
为了让我们的设备发声,我们将使用 Android 的文本到语音(TTS)API。这个 API 很容易使用,开始初始化 TTS 引擎:
ttsEngine = new TextToSpeech(context, new TextToSpeech.OnInitListener() {
@Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
ttsEngine.setLanguage(Locale.US);
ttsEngine.setPitch(1f);
ttsEngine.setSpeechRate(1f);
} else {
Log.w(TAG, "Could not open TTS Engine (onInit status=" + status + ")");
ttsEngine = null;
}
}
});
一旦初始化完成,我们可以在每次我们想要设备发声时调用以下方法:
ttsEngine.speak("text to speak", TextToSpeech.QUEUE_ADD, null, "UTTERANCE_ID");
无需额外的步骤! 给我们的 Android Things 设备提供离线语音只有几行代码。
现在事情变得复杂了。 我们将添加一些语音识别,使用语音到文本(STT)。
显然,你需要一个 USB 麦克风。 我以约 5 美元的价格购买了 MI-305。将它连接到 Raspberry Pi 的 USB 端口之一,它可以开箱即用。
有几种方法可以将语音识别添加到我们的应用程序中。
Android 上的理想之一就是启动 RecognizerIntent
语音操作。
private void startSpeechToTextActivity() {
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, "en-US");
try {
startActivityForResult(intent, SPEECH_REQUEST_CODE);
} catch (ActivityNotFoundException a) {
Log.e(TAG, "Your device does not support Speech to Text");
}
}
并覆写 onActivityResult
方法来接受声音识别数据。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == SPEECH_REQUEST_CODE) {
if (resultCode == RESULT_OK && data != null) {
List<String> result =
data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
String spokenText = result.get(0);
}
}
}
简单的代码,就能很好地集成到 Android 框架,感谢 onActivityResult
回调。
如果你已经使用过它,你可能知道它在我们的 Android 手机上运行得如何。
那么...不幸的是,在 Android Things,当我们使用这个 intent,我们收到以下消息:Your device does not support Speech to Text
。
在不久的将来,我很确定我们将会内置 Speech to Text 支持。
我们可以等待这一天的到来,但我们不耐烦。现在已经支持 USB 音频了,我们现在想玩。
这就是为什么我决定尝试三种不同的解决方案:
等等等等,我们的设备不支持语音转文本。但这不能阻止我们。
让我们手动安装这个功能,下载谷歌的语音搜索 apk,并将其安装在树莓派上
首先,我们使用 Play 商店网站在我们的手机上安装应用程序。 然后我们使用 adb
来知道刚刚安装的 apk 的位置,并把它拉(pull)到我们的电脑。最后,我们卸载应用程序(因为我们不需要在我们的手机上)。
$ adb shell pm path com.google.android.voicesearch
package:/data/app/com.google.android.voicesearch-1/base.apk
$ adb pull /data/app/com.google.android.voicesearch-1/base.apk
$ adb uninstall com.google.android.voicesearch
现在我们有了谷歌的语音搜索 apk,一个简单的 adb 命令可以让我们将它安装到 Android Things 设备上:
$ adb install base.apk
它工作了!!!! 1!-ish ...
在第一次启动时,你可能不得不接受一个 UI 对话框。
我再说一遍:“在纳米计算机上接受一个用户界面对话框”...“,可能没有屏幕,没有输入设备,什么都没有”。(提示:只需将 USB 鼠标暂时连接到 Rapsberry Pi,或者使用 Vysor,只需要执行一次)
另一个问题是:当语音搜索无法识别文本时,对话框会一直保留,直到您按下(在 Android 的东西上,当然没有后退按钮,直到添加一个物理按钮)。
嘿,我告诉过你这是 “快速和肮脏的方式”!
所以,添加一个物理 GPIO 按钮来取消对话框(丑陋)。更好(嗯,这取决于),反编译语音搜索apk
,修改 smali
代码自动删除该部分,并重新编译 apk。(出于法律上的原因,请不要这样做)。
下面是一个声音搜索语音识别器的视频,在按下按钮(源代码)后,将重复我说的一切:
https://www.youtube.com/watch?v=gRmLhrkIup0
优点:
缺点:
另一种解决方案是使用语音到文本在线服务,例如 Google Cloud Speech API 或 Microsoft Bing Speech API。
优点:
缺点:
解决方案 1 和 2 可以取决于您的需求。 但是,我想要一个离线的,非 hacky 的方式来添加语音识别到我的 Android Things 应用程序。所以,这就有了解决方案 3,采用 “开放源码语音识别工具包(CMU Pocketsphinx)集成到我的应用程序”。
幸运的是,Pocketsphinx 已经提供了一个 Android 示例。 如果你有兴趣,看看(易于阅读)示例源代码来了解他们的 API。
简而言之,将 Pocketsphinx 集成到您的 Android(或 Android Things)应用程序中包括:
SpeechRecognizer 需要一些设置。你需要给它一些关于在给定时刻,应该理解什么样的单词的背景。
例如,我想让它理解的第一件事是 “Ok Things” 句子。没有其他的。所以我设置了以下方法:
recognizer.addKeyphraseSearch("OKTHINGS_CONTEXT", "ok things");
然后,我告诉它开始听 “OKTHINGS_CONTEXT” 中的单词:
recognizer.startListening("OKTHINGS_CONTEXT");
从这一刻起,识别器将定期调用 onPartialResult
回调函数。当用户停止说话时,onEndOfSpeech
回调将被触发,这是您可以停止识别器的地方。停止识别器,将触发带有被识别语句的 onResult
方法作为方法参数。
一旦识别器检测到 “Ok Things” 关键短语,它应该切换上下文。不再是认识 “Ok Things” 的东西,而是识别订单,如 “打开电视机”,“播放音乐”,“现在几点?” 等。
提供一个上下文是至关重要的。 我发现 Sphinx 在提供一小组预定义的句子、关键词时工作得很好。相反,当使用 EN-US 词典的 133,000 个单词时,文本识别不是很好。
要创建您的语言模型,首先创建您希望识别的句子列表:
$ cat predefined.txt
<s> turn on the tv please </s>
<s> how is the weather </s>
<s> right now </s>
<s> what time is it </s>
<s> how are you today </s>
<s> play some music </s>
<s> tell me a joke </s>
然后,安装 cmuclmtk
和 sphinxbase
软件包,并将该文本文件转换为 Sphinx
语言模型二进制文件,如官方文档中所述:
$ text2wfreq < predefined.txt | wfreq2vocab > predefined.vocab
$ text2idngram -vocab predefined.vocab -idngram predefined.idngram < predefined.txt
$ idngram2lm -vocab_type 0 -idngram predefined.idngram -vocab predefined.vocab -arpa predefined.lm
$ sphinx_lm_convert -i predefined.lm -o predefined.lm.bin
这将生成一个可以放置在 assets/sync 目录中的预定义的 .lm.bin
文件。
然后,你可以配置 pocketsphinx 来使用这个语言模型,当在给定的上下文中(我命名为 PREDEFINEDACTIONS_CONTEXT
):
File model = new File(assetsDir, "predefined.lm.bin");
recognizer.addNgramSearch("PREDEFINEDACTIONS_CONTEXT", model);
现在,每当识别器在 OKTHINGS_CONTEXT
中检测到 Ok Things
关键短语时,就切换到 PREDEFINEDACTIONS_CONTEXT
,以便它可以识别您打算说的动作。
切换上下文的意思是 startListening
到给定的上下文,可选的超时(在这里是10秒)
recognizer.startListening("PREDEFINEDACTIONS_CONTEXT", 10_000);
注意
:如果您不想创建预定义的动作上下文,则可以配置 Sphinx,通过下载完整的 en-us 语言模型 来检测字典中的每个单词,并通过以下方式配置识别器:
recognizer.addNgramSearch("EN-US_CONTEXT", new File(assetsDir, "en-us.lm.bin"));
然而,这不是我会推荐的。首先,因为它会大大增加你的 apk 大小,然后因为识别不如一个给定的受限语言模型。
我在本文的介绍视频中使用了 pocketsphinx。
相关的源代码在 GitHub 上。
优点:
缺点:
使用 Android Things Developer Preview 2,您现在可以开始为您的项目添加文本到语音和语音到文本。文本到语音很容易集成,这是一个很好的功能,你可以添加到你的智能设备项目(几乎)没有额外的成本。
整合语音识别可能需要一点时间,但值得一试。
这个简单、愚蠢的助手可在 github.com/Nilhcem/audiofun-androingsings 上查看。
原文链接:http://nilhcem.com/android-things/control-your-devices-through-voice-with-usb-audio-support
观光\评论区