マイク入力のリアルタイム出力について

5,075 views
Skip to first unread message

ミケ猫@A

unread,
Feb 8, 2013, 1:23:54 AM2/8/13
to android-g...@googlegroups.com
スペース失礼します。
マイクを使ったアプリを作るべく、マイク入力について調べていたのですがどうしてもマイク入力(AudioRecord)からスピーカーに出力(AudioTrack track)するのに1秒程度のタイムラグが発生します。

このズレがどうして起こるのか、改善できるのかが不明なため、いろいろ調べてみたのですが結局わからなかったためここで質問させていただきました。
何か情報・解決策があれば教えていただきたいと思います。

記述方法は以下の状態です。

int bufSize = AudioRecord.getMinBufferSize(
SAMPLING_RATE,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT) * 2;[

// AudioRecordの作成
AudioRecord audioRec = new AudioRecord(
MediaRecorder.AudioSource.MIC,
SAMPLING_RATE,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
//AudioFormat.CHANNEL_CONFIGURATION_STEREO,

AudioFormat.ENCODING_PCM_16BIT,//AudioFormat.ENCODING_PCM_8BIT,
bufSize);

AudioTrack track = new AudioTrack(
//streamType どの音を出すかってこと?
AudioManager.STREAM_MUSIC,
//AudioManager = Androidで音量を調節するもの
//音楽音量(STREAM_MUSIC)
//sampleRateInHz:サンプリング周波数
SAMPLING_RATE,
//channelConfig(モノラル指定)
AudioFormat.CHANNEL_CONFIGURATION_MONO,
//audioFormat
AudioFormat.ENCODING_DEFAULT,
//bufferSizeInBytes:バイト単位のバッファサイズ
//サンプリングレートが44100でバッファサイズが44100なので、
//このAudioTrackには1秒分の音声データを格納することができます。
44100,
//mode(STREAMモード指定)
AudioTrack.MODE_STREAM
);

//再生
track.play();
audioRec.startRecording();

bIsRecording = true;

thread = new Thread(new Runnable(){
@Override
public void run() {

byte buf[] = new byte[bufSize];

// TODO Auto-generated method stub
while (bIsRecording) {
// 録音データ読み込み
audioRec.read(buf, 0, buf.length);

Log.v("AudioRecord", "read " + buf.length + " bytes");

track.write(buf, 0, buf.length);

}
// 録音停止
Log.v("AudioRecord", "stop");

}
});
thread.start();

MORIHIRO

unread,
Feb 8, 2013, 4:30:17 AM2/8/13
to android-g...@googlegroups.com
処理の流れとして、
  1秒程度の音声データがバッファに溜まる
   ↓
  音声を再生する
という作業を繰り返しているんでしょうから、タイムラグが発生するのは
当然のように思います(回避策は分かりません)。

ちなみに、これってリアルタイムボイスチェンジャーアプリとかでしょうか?

2013年2月8日金曜日 15時23分54秒 UTC+9 ミケ猫@A:

鷹見純

unread,
Feb 8, 2013, 9:54:20 AM2/8/13
to android-g...@googlegroups.com
ミケ猫様

[遅れについて]
MORIHIROさんの指摘のとおりです。
音声を取り込んでデジタルデータに変換するのにTc秒要するとします。
これは音声を発してからデジタルデータになるまでTc秒必要ということになります。
テータが用意されてから再生の処理を行いますので,再生が始まるまでTc秒遅れることになります。
ここでは,バッファのサイズが1秒分用意してあるので,デジタルデータを受け取り再生が始まると1秒遅れることになります。
これを遅延といいます。

[対策]
遅延を短くするには,バッファサイズを小さくすることで対応できます。
しかし,あまりバッファサイズが小さいとハードウェアが処理できなくなります。
AudioTrack, AudioRecordはgetMinBufferSizeメソッドがあり,実現可能な最小のサイズが得られます。
なお,Tcが短いとき処理時間も短くなり,余裕がなくなりますのでいろいろな工夫が必要となります。
たとえば,バッファをその都度準備するのではなく,ある程度大きなバッファを用意しておきsetPositionNotificationPeriodなどを使用し,
ハードウェアのマイクの処理とソフトウェアを並行動作させる必要があるかもしれません。

なお,マイクのデジタル化と,スピーカの再生の処理が完全に同期させることが難しいので,
バッファの管理には工夫が必要です。(参考文献に,「ゆらぎ」として紹介されています)
再生するときにデータが間に合わないと,雑音が発生します。


[参考文献]
VoIP関連が参考になると思います。
VoIPでは,音声の遅延が問題になりますので,いろいろな工夫が行われています。
とか,
が考え方の参考になるかもしれません。



鷹見

ミケ猫@A

unread,
Feb 10, 2013, 7:36:57 PM2/10/13
to android-g...@googlegroups.com
MORIHIRO様
takami様

詳しい回答ありがとうございます!
とても参考になりました。

なるほど、現状AudioRecordで音声を出力するには処理で遅れてしまうということなのですね。

MORIHIRO様のいう「リアルタイムボイスチェンジャー」ではなく、マイクから入力されたデータを利用してWindowsMediaPlayerの視覚エフェクトが出来ないかなと試してみたくて始めておりました。

最初はマイク入力でメーターが左右に振れる的なものを作ろうと考えていたのですがこの1秒のズレで手こずっているところです。

アプリの中には「AudioSpectrumMonitor」と言ったものもあるので何かやり方があるのではと考えて調べていましたが既存の方法では難しそうですね。

バッファにたまるデータの量と貯める量を自身で調節する必要があることがわかりましたので今度はその辺りから調べてみることにします。

ありがとうございました。

ミケ猫@A

unread,
Feb 10, 2013, 8:08:04 PM2/10/13
to android-g...@googlegroups.com
追加報告です。

よくよく見てみると、サンプリングレートのフィールドで保持していた値が「11025」に対して、指定した値が「44100」だったのがどうも原因っぽく、すべて「44100」で統一して処理を実施したところ、問題が解消されました。

まだまだ音声処理の概念を理解していないことが原因のようで、解消された理由もいまいちわかっておりませんが一先ずは問題が解消されたので報告させていただきます。

お騒がせして申し訳ありませんでした。 
Reply all
Reply to author
Forward
0 new messages