Google Cloud Speech APIとNaoqiのストリーミング接合について

記憶から消える前に、どうやってつなげたかという基本的なメソッドだけを書いておく。pythonのソースをあげても良いのだが、著作権問題がよくわからないので、避けよう。
(1)Google APIの基本は以下のソースを利用する。これを(G)としよう。
https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/speech/grpc/transcribe_streaming.py
(2)ALAudioDevice側のストリーミング処理の基本ソースは、
http://www.baku-dreameater.net/archives/9331
を利用させていただいた。(R)とする
(3)基本は、(G)のpyaudioの部分をALAudioDeviceに置き換えることである。まず、main関数の冒頭に、(R)のロボットのIPとポート処理、qimessasingのオブジェクト生成部分を書き加える。ここは、それらを理解していれば簡単にできるだろう。それらに関連するライブラリをimportすることもおわすれなく。わすれたら、エラーになるのでその時直しても良い。その後、Google APIを利用する権限を持ったserviceオブジェクトの生成に入っている。
(4)record_audio関数の書き換え。
0、Queueからqueueオブジェクトを作る、ときに、chunkの制限を加えたが、これの必要性はチェックしていない。まあ、やったことはやったので、書いておく。次のように変更した。
buff = queue.Queue(chunk)
バッファが一杯になる値を加えたのだが。必要なのか?
1、audio_interfaceとaudio_streamのオブジェクト生成に関する部分は、pyaudioのものなので、削除する。したがってそのクローズ処理も不要である。
2、record_audioの引数の最後にappを加える。
3、削除した行の代わりに、次の3行を加える
player = EchoRobotHumanSpeech(app, buff, rate)
app.session.registerService("MyEchoRobotHumanSpeech", player)
alaudio = player.start("MyEchoRobotHumanSpeech")
EchoRobotHumanSpeechは、次に説明するALAudioDevice利用のためのクラスであり、MyEchoRobotHumanSpeechは、モジュール名でNaoqiがモジュールの識別子とするものである。
4、yield _audio_data_generator(buff)の直後に、
alaudio.robot_audio.unsubscribe("MyEchoRobotHumanSpeech")
を加える。モジュールの終了処理である。
(5)クラスEchoRobotHumanSpeechの定義。基本は、(R)のSoundDownloadPlayerクラスである。ただ、このクラスは、pyaudioでパソコンから出力するようになっているのだが、それは不要であるので削除する。代わりに、Google APIへのストリーミングアップロード処理を加える。
1、コンストラクタの引数に、buff, rateを加える。rateはグローバル変数のRATEを使っても良いが、プログラムの質的にはここに引数を与えた方が良い。
2、コンストラクタに、次の2行を加える。record_audioのなかでQueueから作られるbuffは全体として、決定的に重要な役割を果たしている。
self.buff = buff
self.rate = rate
3、startメソドには、次の2行だけを残して、全て削除する
self.robot_audio.setClientPreferences(serviceName, self.rate, 3, 0)
self.robot_audio.subscribe(serviceName)
最初のものはデバイスのプリファレンスで、3は、前方マイクから音を取得するもの。次のものは、ストリーミングの開始メソッド、その後、コールバックがprocessRemoteに設定され、音声データが次々にそのコルバックに送られる。
(6)コールバックの設定:ここで色々詰まった。一番わからなかったが、次のようにすれば良い。
1、オリジナルのコールバック、
def _fill_buffer(buff, in_data, frame_count, time_info, status_flags):
は不要なので削除する。
2、次の新しいコールバックを、クラスEchoRobotHumanSpeechの中に設定する。
def processRemote(self, nbOfChannels, nbOfSamplesByChannel, timeStamp, in_data):
self.buff.put(str(in_data))
#print("processRemote No." + str(self.count) + " / in_data = " + str(len(in_data))
#    + " サイズ = " + str(self.buff.qsize()))
return None
コメントを外して動かすと、コールバックがどのように呼び出されるか少しわかるだろう。
バッファにデータを文字列化して付け加えるというのも一つのポイントだが、これは、そうしないとエラーになるのですぐわかる。
(7)request_streamの日本語化などは、少し前の記事に詳細に書いたのでそれと同じである。
他は大きく変えなかったが、最終出力がラインフィードで同じ行を書き換える操作をしているので、何をしているかがわかりにくくなるから、常に改行してGoogleから送られてくるデータがどんなものかをわかるようにしたくらいだ。
できてしまえば簡単な感じなのだが、途中で分からなくて投げ出しそうになった。