Androidアプリで音声がぶつぶつするときの傾向と対策
REALITY iOSエンジニアのメタルおじさんです。好きなメタルはシンフォニックメタルとメロディックスピードメタルとヴァイキングメタルです。趣味で音楽制作をしています。
先日、「終わりなき挑戦プロジェクト」が開催されました。
プロジェクトの趣旨については上記の記事に詳しく書かれているのでここでは割愛しますが、このプロジェクトで私はREALITY Androidアプリの音声周りの改善を行うことになりました。
(あれ?さっきiOSエンジニアって書いてなかった?と思われたかもしれませんが…実は私はAndroidエンジニアとしての経験の方が長いのです。)
(あと、Androidエンジニアのチーム内に音声処理に詳しい人がいなかった、という理由もありますが…REALITY株式会社ではAndroidと音声に詳しいエンジニアを募集中です!)
Androidで配信を視聴していると、音声がぶつぶつするという問題を調査しました。そもそも「音声がぶつぶつしている」とは言うものの、具体的にどういうふうに音声データがおかしくなっているのか、環境によるものなのかアプリの実装によるものなのか、よくわかっていなかったので調査しました。
音声のぶつぶつとは
音声の再生中に「ぶつぶつする」要因は大きく2つ考えられます。
1. 再生する音声データに無音区間が存在する。
2. 再生する音声データに非連続区間が存在する。
どちらであるかは音声の波形やスペクトログラムを見ればわかります。
スペクトログラムというのは音声に含まれる低い音の成分から高い音の成分まで、どの音域にどのくらいのエネルギーがあるかを表した図です。下の方が低音成分、上の方が高音成分です。明るい色になっているほどその帯域でのエネルギーが強いということになります。
正常な音声の波形
波形が連続的かつ周期的に変化しています。
人の声や楽器の音のスペクトログラムは、たいていどこか特定の帯域のみに色の濃い場所があります。上の例だと、下のほうがすごく明るいです。
再生する音声データに無音区間が存在する
波形の一部に振れていない箇所があります。無音ということは低音域から高音域までどこにもエネルギーがない状態なので、スペクトログラムは暗くなります。
再生する音声データに非連続区間が存在する
波形の一部に極端な変化・周期的でない変化があります。該当箇所のスペクトログラムは明るくなっています。
スペクトログラムが下から上まで均等に色濃くなる場合というのは、テレビの砂嵐のようなノイズや、レコードの針が飛ぶようなプチっとしたノイズが発生した場合です(若い人には伝わらない気がする)。
1. 再生する音声データに無音区間が存在する。
2. 再生する音声データに非連続区間が存在する。
どちらの場合も、1箇所存在するだけなら「ぶつぶつ」というほどのものではないですが(一瞬プチっと不快なノイズとしては聴こえる)、1秒間に数回〜数十回くらいの頻度で発生すると「ぶつぶつ」すると感じます。
REALITYで調べる
では、REALITYのAndroidで配信を視聴していると、音声がぶつぶつするは無音区間の問題なのか非連続区間の問題なのか、どちらなのでしょうか?それを調べるためにはAndroidの端末から出力される音声を記録して解析する必要があります。
Android 11からスクリーンレコード機能が搭載されたので、これを使って端末の画面を録画したり音声出力を記録したりすることができます。
タップして、
録音の部分をタップして、
「デバイスの音声」を選択してから「開始」ボタンをタップ。
録画を止める時は通知領域にある「タップして停止」です。
するとなんの通知もなく録画を終了しますが、録画された内容は端末のMovies/screen-XXX-YYY.mp4のようなファイルに保存されます(XXXの部分は作成時の日付、YYYの部分は時間です)。
以下のコマンドでファイル名の一覧を出力できます。
adb shell ls /sdcard/Movies
ファイル名がわかれば、以下のコマンドで取り出すことができます。
adb pull /sdcard/Movies/screen-20201022-001227.mp4
※20201022-001227の部分は仮の数字です。実際のファイル名に合わせて置き換えてください。
もしくは、Android StudioのDevice File Explorerタブから取り出すこともできます。
取り出した録画データはmp4ファイルですが、このままだと音声を解析するためのソフトに読み込めないので、音声のみを取り出してwavファイルに変換しました。mp4をwavに変換するにはffmpegを使うのが簡単です。
ffmpeg -i screen-20201022-001227.mp4 audio.wav
※screen-20201022-001227.mp4, audio.wav の部分はファイル名なので適宜変更してください。ただし出力ファイル名の末尾に .wav は付けるようにしてください。
これで、Android端末の音声出力をaudio.wavに保存できました。
音声を調べてみた
以下は上記の方法でAndroidの画面を録画しながらREALITYの視聴中を行い、音声がぶつぶつ状態になっていた時の音声です。
これを見ると、特に無音区間があるわけではなさそうですし、スペクトログラムに下から上まで明るい箇所が見えます。なので、音声がぶつぶつする原因は先程挙げた2つの原因のうち再生する音声データに非連続区間が存在する。の方だとわかりました。
つまり、サーバーからの音声データの到着が遅れているからぶつぶつするわけではないということです。当初は「回線が不安定だからパケットの到着が遅れてぶつぶつするんじゃない?それは環境によるからこちらではどうしようもないじゃん?」と疑っていたりもしましたが、そうではなかったのです!
ちなみに、サーバーに残っていたアーカイブ音声を同様に調べた結果、上のような「ぶつぶつ」のスペクトログラムは見られませんでした。
よって、
・ネットワークの不調ではない
・サーバーに残っていた音声データはぶつぶつしていない
・Androidで再生するとぶつぶつする
この結果からAndroidの音声再生処理に何かしらの問題がありそうだということがわかったので、該当箇所のコードを注意深く調べました。そして、音声の再生を一時停止したときに音声データ出力スレッドを止めていなかったとか再生開始の関数を呼ぶたびに音声データ出力スレッドが増殖していたとか…詳細はREALITYに固有のコードになるのでここでは触れませんが、問題を見つけて修正することができました。
終わりなき挑戦プロジェクトの音声安定化で改善したのはこれだけではないのですが、一つの大きな改善でした。
以上、「音声がぶつぶつしている」原因とその見分け方、そしてAndroid端末の音声出力を記録する方法を紹介しました。音声を扱うアプリを作っていて「なんか音がぶつぶつするな?」と思った時の調査に役立てばと思います。