Android Things 教程:通过 USB Audio 声控设备

Android Things Developer Preview 2 支持 USB 音频,这意味着现在可以在外部 USB 扬声器上播放音乐,还可以通过 USB 麦克风录制音频。

这可以用于创建一个非常简单、愚蠢的 Android Things 音频助理、离线语音识别、文本到语音功能的完美场合。

“OK 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 设备提供离线语音只有几行代码。

添加一些语音识别(Speech-To-Text)

现在事情变得复杂了。 我们将添加一些语音识别,使用语音到文本(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 音频了,我们现在想玩。

这就是为什么我决定尝试三种不同的解决方案:

解决方案 #1:“快速和肮脏” 的方式

等等等等,我们的设备不支持语音转文本。但这不能阻止我们。

让我们手动安装这个功能,下载谷歌的语音搜索 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

优点

  • 快速集成(只需安装 apk,就完成了)。 伟大的原型
  • 语音识别功能非常好(当然,如果你的英语不错)
  • 一旦 Android Things 本地支持语音到文本,你可能不需要修改你的源代码。只需卸载非官方的语音搜索 apk,你就完成了

缺点

  • 到目前为止,这很 hack
  • 可能需要外部显示(首次启动/搜索失败时)
  • 如果你开始反编译 apk,或者做其他类似的疯狂的东西,可以把你带到监狱

解决方案 #2:“快速和云”的方式

另一种解决方案是使用语音到文本在线服务,例如 Google Cloud Speech API 或 Microsoft Bing Speech API。

优点:

  • 工作得很好
  • 支持多种语言
  • 保持你的 apk 大小

缺点:

  • 需要互联网连接
  • 超过配额限额后按使用付费。

解决方案 #3:“开源”的方式

解决方案 1 和 2 可以取决于您的需求。 但是,我想要一个离线的,非 hacky 的方式来添加语音识别到我的 Android Things 应用程序。所以,这就有了解决方案 3,采用 “开放源码语音识别工具包(CMU Pocketsphinx)集成到我的应用程序”。

幸运的是,Pocketsphinx 已经提供了一个 Android 示例。 如果你有兴趣,看看(易于阅读)示例源代码来了解他们的 API。

简而言之,将 Pocketsphinx 集成到您的 Android(或 Android Things)应用程序中包括:

  • 添加一个本地(x86/arm)库,捆绑在一个 .aar 文件中
  • 将一些文件(识别器可以理解的所有文字的语言模型/字典)添加到 assets 目录
  • 创建一个 SpeechRecognizer 的实例。

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>

然后,安装 cmuclmtksphinxbase 软件包,并将该文本文件转换为 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

尚未评分
您的评分将帮助我们做出更好的玩法

观光\评论区

Copyright © 2017 玩点什么. All Rights Reserved.