FC2ブログ

スマフォのアプリを作りたい(18):音声認識と同時に録音

   プログラミング [2020/04/02]
だいぶ間が空いちゃいましたが、ハマりまくってたためです。
ここ数か月掛けてもなお、思ってたような成果が出せてません。
さるだから、仕方ない。
春っぽくなって、野外の活動を始めたので、こっちに割ける時間が減ったのもある。

巷は新型コロナで大変な状況のようですが、そろそろ圏内でも染った話が頻繁になってきた。
ヤバイかな。さるもリスクの高い年齢だし、タバコ吸いまくってるし、染りたくないなぁ。

ともかく、「スマフォのアプリを作りたい」続けます。

音声認識させてみたんだけど、結局、100%の音声認識(テキスト化)は不可能なのは、凡そ見当がついてました。
どうも、話す内容がちゃんとした「文章」になってないとあまり正確な認識はしないらしい。
頭の中で「文章」を組み立ててから話始める人なんかそうそういない。
それに、話す側の発音(訛り)の問題とか、周囲の雑音が思いのほか影響するみたいです。
一度、空調送風音の大き目の場所でタブレットの内蔵マイクで試してみたら、ほとんどまともに変換してくれませんでした。

そんな場合、認識させた音声そのものを録音しておいたら、相手、あるいは本人が聴いたときは、判別できるんではないだろうか。
この分野は、未だ人間様の言語認識能力の方が高いはず。

というわけで、
音声認識はさせておくんだけど、同時に録音(ファイル化)がしたいってことです。


◆フレームワークに何を使うか
ちょっと、React Nativeの事例をみると、録音(ファイル化)してみたという記事はたくさん見つかる。
素直に、そのパッケージを使ってやればいいのかな。

でも、react-native-google-speech-apiのコードを見てた時、音声データが定期的に送られてくる箇所があった。
そのデータをGoogle Cloudに送り込んでるんだけど、それと同時にファイルに突っ込めないのだろうか。
効率よさそう。
とは、思ったものの・・・・

そういうレベルで制御しているサンプルは見つけられず、

react-native-google-speech-apiパッケージ内で使っていた「MediaRecorder」というAndroidのマルチメディアフレームワークの使い方を検索してみました。
参考:https://developer.android.com/guide/topics/media/mediarecorder?hl=ja
録音にも使えそうです。
でも、
・バッファによる入力部とファイル保存部のデータ受け渡しの処理は見られません。
・Android固有の処理ということになります。iOSのときには、同等の別の処理が必要ということになります。
 (なので、置き場所や「切り替え方」も意識しないといけなくなります。)
※そういえば。導入してみたreact-native-google-speech-apiの仕様が気に入らなくて修正しちゃいました(前々回の記事)が、iOS側もいずれ何とかしないといけないんですね。

ちょっと悩んだけど、面倒だなと思って、結局react-native-audioを使うサンプルをマネしてみることに。
参考:https://blog.leko.jp/post/rn-audio-record/


◆react-native-audioのインストール

1)「npm install react-native-audio --save」
react-native-google-speech-apiで四苦八苦したことが記憶に新しいので、少し不安もありましたが、やってみました。

----コマンドプロンプト-----------------------------
C:\WINDOWS\system32>cd /d d:\appmake\proj\vtchat

d:\AppMake\proj\VTChat>npm install react-native-audio --save
npm WARN @typescript-eslint/eslint-plugin@1.13.0 requires a peer of eslint@^5.0.0 but none is installed. You must install peer dependencies yourself.
npm WARN @typescript-eslint/parser@1.13.0 requires a peer of eslint@^5.0.0 but none is installed. You must install peer dependencies yourself.



+ react-native-audio@4.3.0
added 1 package from 1 contributor and audited 957442 packages in 67.884s

21 packages are looking for funding
run `npm fund` for details

found 19 vulnerabilities (4 low, 15 moderate)
run `npm audit fix` to fix them, or `npm audit` for details

・────────────────────────────────・
│ │
│ New minor version of npm available! 6.12.1 -> 6.14.2 │
│ Changelog: https://github.com/npm/cli/releases/tag/v6.14.2 │
│ Run npm install -g npm to update! │
│ │
・────────────────────────────────・
---------------------------------------------------

余計なnpmの宣伝も出たけど、成功した模様。

2)「react-native link react-native-audio」(不要かも)
参考サイトではやるとあるのですが、
さるの環境ではやらなくてよかったコマンドのようです。

とりあえず、「react-native link・・・」すると以下のメッセージ。
----コマンドプロンプト-----------------------------
d:\AppMake\proj\VTChat>react-native link react-native-audio
info Linking "react-native-audio" iOS dependency
info iOS module "react-native-audio" has been successfully linked
info Linking "react-native-audio" Android dependency
info Android module "react-native-audio" has been successfully linked
---------------------------------------------------

これも何事もなく終わってくれるんですが、「react-native run-android」したら、
----コマンドプロンプト-----------------------------

error React Native CLI uses autolinking for native dependencies, but the following modules are linked manually:
- react-native-audio (to unlink run: "react-native unlink react-native-audio")
This is likely happening when upgrading React Native from below 0.60 to 0.60 or above. Going forward, you can unlink this dependency via "react-native unlink " and it will be included in your app automatically. If a library isn't compatible with autolinking, disregard this message and notify the library maintainers.
Read more about autolinking: https://github.com/react-native-community/cli/blob/master/docs/autolinking.md

---------------------------------------------------

てなエラーになります。
なので、結局「react-native unlink・・・」しました。
----コマンドプロンプト-----------------------------
d:\AppMake\proj\VTChat>react-native unlink react-native-audio
info Unlinking "react-native-audio" iOS dependency
info iOS module "react-native-audio" has been successfully unlinked
info Unlinking "react-native-audio" Android dependency
info Android module "react-native-audio" has been successfully unlinked
---------------------------------------------------


3)「android/app/src/main/AndroidManifest.xml」修正
これもまた、さる環境ではreact-native-google-speeck-apiのときにやってたので済み。


◆録音処理の味見
先に挙げたサイトの説明を参考に実装してみました。
ところが、以下の実装(一部抜粋)だとthis.record()=>AudioRecorder.startRecording()でExceptionが発生しました。
----Speech.js--------------------------------------

const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,
{
title: 'Record Audio Permission',
message:
'App needs access to your microphone ' +
'so you can convert speech to text.',
buttonNeutral: 'Ask Me Later',
buttonNegative: 'Cancel',
buttonPositive: 'OK',
},
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
console.log('permission granted');
this.startListening();
await this.setUp();
await this.record();

} else {
console.log('permission denied');
}

---------------------------------------------------

そこで、録音関連の処理とstartListening()と順番を変えてみたところ、Exceptionは発生しなくなった。
----Speech.js--------------------------------------


if (granted === PermissionsAndroid.RESULTS.GRANTED) {
console.log('permission granted');
await this.setUp();
await this.record();

this.startListening();
} else {
console.log('permission denied');
}

---------------------------------------------------

録音はされたようだけど、音声認識はされません。

録音された音声ファイルは、以下のコマンドで取り出せました。
----コマンドプロンプト-----------------------------
d:\AppMake\Android\Sdk\platform-tools>adb pull /data/user/0/com.vtchat/filesvoice.aac C:\temp\
/data/user/0/com.vtchat/filesvoice.aac: 1 file pulled. 3.1 MB/s (187558 bytes in 0.057s)
---------------------------------------------------

参考:https://qiita.com/t2low/items/cb37cec5f864c4748e14
※ソース上で、「AudioUtils.DocumentDirectoryPath」とされているのが「/data/user/0/com.vtchat/files」になっているのをデバッガで確認。

取り出したファイルを再生しても見ました。音質は良くありませんでしたが、確かにしゃべったことが録音されてました。

GoogleSpeechApiのlogcat(Log.i())メッセージによると、どうも音声データがGoogleSpeechApi側に渡ってこなくなっているみたいです。
さもありなんな現象です。

単にマイク入力をファイル化するだけなら、最初の方で上げた参考サイト(https://blog.leko.jp/post/rn-audio-record/)のやり方でOKということです。

でも今回、そうではないので、もう一回調べ直し・・・・



◆実装方針の再検討
やっぱり、1入力ソース(音声)を2つのパッケージで共有するなんて・・・そんな使い方は想定されてしていないのかもしれないし。
複数アプリとかの場合ですが、Androidの制限について書かれてました。
参考:https://developer.android.com/guide/topics/media/sharing-audio-input?hl=ja
まあ、これには該当しないけど、Andoid8以前?だと「フォアグラウンド」に居ないと音声が受け取れない的な気になる記述もあります。

ちょっと悩んだ挙句、Android/iOS共通コード部分のみでの実現は諦めました。
だって、既に音声認識のところで、独自コード(今のところAndroid側のみだけど)にしちゃってるし。
行きがかり上、react-native-google-speech-apiに付けたしするのが、纏まりとしてはいいんではないだろうかと考えました。


さて、-google-speech-apiの既存処理からバッファ渡しでもらえるのはPCMの音源データかと思うので、ファイル化するときは圧縮したいですよね。
Androidでエンコードしてファイル化までやってくれるのないかしらと調べましたがなさそうです。
もう少し低レベルだとMediaCodecというのがあります。
エンコードはMediaCodecで、ファイル書き出しは標準的なファイルIOでということになるんでしょうかね。

「Android MedeiaCodec PCM to AAC」で検索すると、「やってみたが上手く行かないけど・・・」な記事&サンプルは少し引っかかる。あとは動画圧縮と一緒になってたりして、「それだけ」のものがなかなか見つかりません。
さるにコード理解力が備わってないので、コード量が多いとそれだけでテンション下がって見たくなくなる。

トラぶった記事を読んでいると、「AACへのエンコードだと、ADTSとかのヘッダを付けないと再生できるファイル化できない」とも読める例もあった。

ちょっと面倒になってきたので、スマフォで簡単に再生できるのは何だ?とちょっと再検索したらMP3の方が簡単だとの記述を発見。
「Android MediaCodec MP3 エンコード」で検索してみたけど、ピッタリする感じの例が出てきません。なんで?

MediaCodecは、MP3のエンコードはサポートしていないのね。
参考:https://developer.android.com/guide/topics/media/media-formats

MediaCodecの詳細は、Andoid本家の説明を見ます。
参考:https://developer.android.com/reference/android/media/MediaCodec
参考:https://qiita.com/imatomi/items/bd9d49cfb1f73383ca12
でも、盛沢山に書いてあって、単語も分かりにくい。
<読んでて思ったこと>
Creation:
・MediaCodecListを使って、サポートしている圧縮形式を列挙してその中から選べってこと?
・注意書きもイミフ。ともかくフレームレートは後で指定しろと言っているようだ。
・CreateDecorder/EncoderByTypeでもよい?その後に「望ましいフォーマット?」が扱えないとかなんとか。
→まあ、EncodeByTypeでいいんじゃね?
Creating secure decodes:
・その下の表の中でCSDっていきなり略すなよ。
・表の中のAACのところに書いてあるESDSってなんだよ。Elementary Stream Descriptor・・・ですかね。
・デコードするときにコーデック固有データなるものを、データバッファとは別に指定する必要があるそうだ。
→まあ、デコード時の話だから関係ないっか・・・いやいや録音したら、再生するから後で何かあるかも。
DataProcessing:
・表のProcessingModeのバッファ配列とバッファを使うのって意味は何?
→ともかくInputは-google-speech-apiの元々の処理の流れ(同期)で、Outputは非同期で処理できるんだろうか。サンプルを検索したときもそんな感じのものは見かけなかった。ここの下のAsynchronous Processing using Buffersの説明では、全部非同期型で処理しようとしてます。

・・・やって見るしかないですかね。

さて、AACエンコードの事例で言われていたADTSについてです。
ADTS(Audio Data Transport Stream)とは、AAC圧縮音声データのコンテナ(ファイル形式)の一つだそうです。「データブロックの区切りごとにADTSヘッダー」が入ってないといけないらしい。
参考:https://www.wdic.org/w/TECH/ADTS
コンテナの形式としては、ADIFというのもある。
ADIF(Audio Data Interchange Format)の場合、ファイル先頭に「0x41 0x44 0x49 0x46」で始まるヘッダが入っているらしい。ただし、Andoridではサポートされていないとなっています。
また、コンテナに入っていないRAW AACというのもあり、これもファイル拡張子が.aacだそうだ。
でも、先の参考:https://developer.android.com/guide/topics/media/media-formatsでの書き方では「ADTS Raw AAC」という書き方になっていて、どっちなの?判断付かない。

そうこう悩んでいるのも嫌になりました。
前に発見したあった以下のサイト。
参考:http://ja.uwenku.com/question/p-rqjccowd-s.html
AACではないが、動くサンプルとして.m4aファイルを作っているコードが載ってる。

これをマネしちゃいます。
※.m4aはAndroidの標準のプレイヤー?で再生できないとの記述もあったけど、
 どうせ、最終的には作っているアプリでやることになると思うのでこの際は目をつむります。

ファイルへの出力は、MediaMuxerっていうクラスを使ってるみたいで、割と簡単そう。


いつもと同じでこの後も長ーくなりそうなので、一旦ここで話を切ります。

ではこの辺で、御機嫌よう。
m(__)m
スポンサーサイト





コメントの投稿

非公開コメント

カレンダー
01 | 2024/02 | 03
- - - - 1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 - -
プロフィール

さるもすなる

Author:さるもすなる
さるです。別HPサイト「さるもすなる」から侵食してきました。 山菜/きのこ、それとタイトルにしたPPバンド籠のことをメインに徒然に・・・・暇を持て余したさるの手仕事:男手芸のブログってことで。

最新記事
最新コメント
月別アーカイブ
カテゴリ
天気予報

-天気予報コム- -FC2-
本家のHPのトップ
山菜や茸の話です
PPバンドの籠作品と作り方です
投稿をお待ちしております



PVアクセスランキング にほんブログ村 にほんブログ村 ハンドメイドブログへ



マニュアルのお申し込み



検索フォーム
リンク
RSSリンクの表示
ブロとも申請フォーム

この人とブロともになる

QRコード
QR