web-dev-qa-db-ja.com

マイクからの音をリアルタイムで再生する

アプリケーションでマイクからの音を録音し、それを(ほぼ)リアルタイムで再生しようとしましたが、成功しませんでした。

録音と再生には、それぞれAudioRecordクラスとAudioTrackクラスを使用しています。私はさまざまなアプローチを試しましたが、着信音を録音してファイルに書き込んでみましたが、うまくいきました。また、AudioTrackを使用してそのファイルからサウンドを再生しようとしたところ、問題なく動作しました。問題は、書き込み後にファイルを読み取るのではなく、リアルタイムでサウンドを再生しようとするときです。

これがコードです:

//variables
private int audioSource = MediaRecorder.AudioSource.MIC;
private int samplingRate = 44100; /* in Hz*/
private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
private int bufferSize = AudioRecord.getMinBufferSize(samplingRate, channelConfig, audioFormat);
private int sampleNumBits = 16;
private int numChannels = 1;

// …

AudioRecord recorder = new AudioRecord(audioSource, samplingRate, channelConfig, audioFormat, bufferSize);
                recorder.startRecording();
                isRecording = true;

AudioTrack audioPlayer = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO,
                        AudioFormat.ENCODING_PCM_16BIT, bufferSize, AudioTrack.MODE_STREAM);

if(audioPlayer.getPlayState() != AudioTrack.PLAYSTATE_PLAYING)
    audioPlayer.play();

//capture data and record to file
int readBytes=0, writtenBytes=0;
do{
   readBytes = recorder.read(data, 0, bufferSize);

   if(AudioRecord.ERROR_INVALID_OPERATION != readBytes){
      writtenBytes += audioPlayer.write(data, 0, readBytes);
   }
}
while(isRecording);

「初期化されていないAudioTrackで呼び出されたplay()」が原因でJava.lang.IllegalStateExceptionがスローされます。

ただし、たとえばAudioTrackの初期化を変更して、サンプリングレート8000​​Hzとサンプル形式8ビット(16ビットではなく)を使用すると、例外がスローされなくなり、アプリケーションは実行されますが、恐ろしいノイズが発生します。

ファイルからAudioTrackを再生する場合、AudioTrackの初期化に問題はありません。44100と16ビットを試しましたが、適切に動作し、正しいサウンドを生成しました。

何か助け?

31
Jonny

すべてのネイティブAndroidオーディオは エンコード です。リアルタイムでのみ再生できます [〜#〜] pcm [〜#〜] フォーマットまたは、特別な streaming コーデックを使用します。これは、Androidでは簡単なことではないと思います。

ポイントは、オーディオを同時に録音/再生したい場合、独自のオーディオバッファーを作成し、そこにPCMエンコードされた生のオーディオサンプルをそこに保存する必要があるということです(あなたが考えているかどうかはわかりませんduh!またはこれがあなたの頭の上にあるかどうか、それで私は明確にするように努力しますが、あなた自身のガムを噛まないようにします)。

PCMはアナログ信号のデジタル表現であり、オーディオ samples は元の音響波の「スナップショット」のセットです。あらゆる種類の賢い数学者やエンジニアが、このデータを表すビット数を削減しようとする可能性を認識していたため、あらゆる種類の encoders が考案されました。エンコードされた(圧縮された)信号は、未加工のPCM信号とは大きく異なり、デコードする必要があります(en-cod-er +dec-oder =codec)特別なアルゴリズムとメディアストリーミングコーデックを使用している場合を除き、サンプルごとにエンコードされるのではなく、サンプルのフレーム全体が必要なフレームごとにエンコードされるため、エンコードした信号を再生することはできません。完全な信号でない場合は、このフレームをデコードします。

これを行う方法は、マイクバッファーからのオーディオサンプルを手動で保存し、それらを出力バッファーに手動で供給することです。あなたはそのためにいくつかのコーディングを行う必要がありますが、私はあなたが見て、それらのソースでピークを取ることができるいくつかのオープンソースアプリがあると信じています(もちろん、あなたが後であなたのアプリを売ろうと思っているのでない限り、それはです全く異なる議論)。

Android 2.3以降で開発していて、 ネイティブコード でのプログラミングをあまり怖がっていない場合は、 OpenSL ES を使用してみてください。 。OpenSL ESのAndroid固有の機能を一覧表示します こちら 。このプラットフォームでは、オーディオの操作がいくらか柔軟になり、アプリがオーディオ処理に大きく依存している場合は、必要なものだけを見つけることができます。

29
Phonon

「初期化されていないAudioTrackで呼び出されたplay()」が原因でJava.lang.IllegalStateExceptionがスローされます。

バッファサイズが小さすぎるためです。 「bufferSize + = 2048;」を試しましたが、それで問題ありません。

3
Haisea

同様の問題があり、マニフェストファイルにこの権限を追加することで解決しました。

<uses-permission Android:name="Android.permission.MODIFY_AUDIO_SETTINGS"/>
0
Ahmed