ストリーミングオーディオを使用する

はじめに



マイクから生データを受信するには、クラスが責任を負います android.media.AudioRecord



android.media.AudioRecord



。 内部バッファにデータを書き込むため、定期的にデータを収集する必要があります。



コンストラクター


オブジェクトを作成するには、次を指定する必要があります。

audioSource 録音はどこから来ましたか? 私たちの場合、これ MediaRecorder.AudioSource.MIC



sampleRateInHz ヘルツのサンプルレート。 ドキュメントは、44100Hzがすべてのデバイスでサポートされていると主張しています
channelconfig チャネル構成 たぶん CHANNEL_IN_MONO



CHANNEL_IN_MONO



または CHANNEL_IN_STEREO



CHANNEL_IN_STEREO



モノはどこでも動作します。



重要:これらの定数は、それらが示すチャネルの数と一致しません。 このパラメーターに1または2を渡すことはできません。

audioFormat コーデックとしてよく知られている入力データ形式。 たぶん ENCODING_PCM_16BIT



ENCODING_PCM_16BIT



または ENCODING_PCM_8BIT





bufferSizeInBytes 同じ内部バッファのサイズ。 それから、オーディオストリームを読み取ることができます。 読み取り部分のサイズはこの値を超えないようにしてください。 このパラメーターの最小許容値は、次の方法で取得できます getMinBufferSize()



getMinBufferSize()







オブジェクトは、作成中に必要なシステムリソースを取得しようとします。 彼がどれだけ成功したか、関数を呼び出すことで見つけることができます getState()



getState()



。 彼女が戻ったら STATE_INITIALIZED



STATE_INITIALIZED



、その後、すべてが正常である場合、 STATE_UNINITIALIZED



STATE_UNINITIALIZED



は、エラーが発生したことを意味します。



エラーの原因は2つあります。小さすぎるバッファーと無効なフォーマットです。 1つ目は getMinBufferSize()



呼び出すことで回避することgetMinBufferSize()



。 第二に、実際、彼による。



getMinBufferSize()


この静的メソッドは、 AudioRecord



オブジェクトが機能する内部バッファーの最小サイズを生成します。 パラメーターは、コンストラクターと同じ意味を持ちます。 書き込みにこの特定の値を使用することはお勧めできません。 システムがまだ何かでビジーである場合、プログラムはまだ行のすべてのデータを読み取る時間がない可能性があり、レコードに穴があります。 私は、サイズを10倍大きくするようアドバイスしました。



リスト形式


getMinBufferSize()



メソッドには素晴らしい機能があります- このデバイスに対して無効なパラメーターを誓うため ERROR_BAD_VALUE



ERROR_BAD_VALUE



または ERROR



ERROR



つまり、考えられるすべての組み合わせを調べて、デバイスがサポートしている形式を見つけることができます。



たとえば、次のように:

 int[] rates = {8000, 11025, 22050,44100, 48000, 96000 }; int[] chans = {AudioFormat.CHANNEL_IN_MONO, AudioFormat.CHANNEL_IN_STEREO}; int[] encs = {AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT}; for(int enc : encs) { for(int ch : chans) { for(int rate : rates) { int t = AudioRecord.getMinBufferSize(rate, ch, enc); if((t != AudioRecord.ERROR) && (t != AudioRecord.ERROR_BAD_VALUE)) { //   } } } }
      
      







データ読み取り


内部バッファからデータを取得するには、メソッドを使用します read()



read()



。 次の3つのバージョンがあります。 それらのパラメーター:

audioData データが書き込まれる配列
audioBuffer データが書き込まれるバッファ
offsetInBytes /

offsetInShorts
記録を開始するインデックス
sizeInShorts 要求されたデータブロックのサイズ。 ByteBuffer



およびbyte[]



単位、 short[]



短整数byte[]





すべてが正常であれば、メソッドはByteBuffer



またはbyte[]



バリアントである場合、またはshort[]



短整数を読み取る場合、読み取られたバイト数を返します。 呼び出し時にオブジェクトが正しく初期化されていなかった場合、 ERROR_INVALID_OPERATION返し 、パラメーターに何か問題がある場合-ERROR_BAD_VALUE



重要:メソッドは、要求された量のデータを読み取るまで呼び出しスレッドをブロックします。 内部バッファーに十分な数がない場合、 read()



はマイクから来るまで待機します。 したがって、メソッドは別のスレッドから呼び出す必要があります。そうしないと、アプリケーションがハングします。



アプローチ、リトリート、固定


プログラムがマイクからデータを受信できるように、AndroidManifestのxmlファイルで適切な解像度を指定する必要があります。

 <uses-permission android:name="android.permission.RECORD_AUDIO" />
      
      





記録を開始するには、メソッドを呼び出す必要があります startRecording()



startRecording()



、そして終了する- stop()



stop()



。 録音は何度でも開始および停止できます。



オブジェクトの処理が完了したら、メソッドを呼び出す必要があります release()



release()



。 オブジェクトによってキャプチャされたすべてのシステムリソースを解放します。 その後、オブジェクト使用できず 、オブジェクト参照する変数をnull



に設定する必要がありnull







重要:これら3つのメソッドは、前述のメソッドとは異なり、スローされます IllegalStateException



IllegalStateException



、それらが初期化されていない(つまり... ...)オブジェクトに対して、または間違った順序で呼び出された場合。 したがって、それらは「慎重に」処理する必要があります。 try



ブロックを介して。



使用例


以下のクラスは、上記のすべてを実行します。 さらに、彼は彼に登録済みを送ります Handler



受信したデータに関する Handler



メッセージ。 このデータは別のスレッドで処理されるため、まだ処理されていないデータを新しいデータで上書きしないように、循環バッファーが使用されます。



コードはAudioFormatInfo



クラスを使用します。 これは、記録フォーマットを記述する3つのフィールドを持つPOJOです: sampleRateInHz



audioFormat



およびaudioFormat





 package com.MyCompany; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import android.media.AudioFormat; import android.media.AudioRecord; import android.media.MediaRecorder; import android.os.Handler; import android.os.Process; //AudioFormatInfo - POJO   sampleRateInHz, channelConfig  audioFormat public class AudioReciever implements Runnable { private boolean mIsRunning; private List<Handler> handlers; private AudioFormatInfo format; private AudioRecord mRecord; private final int BUFF_COUNT = 32; public AudioReciever(AudioFormatInfo format) { this.format = format; handlers = new ArrayList<Handler>(); mIsRunning = true; mRecord = null; } public void addHandler(Handler handler) { handlers.add(handler); } public void stop() { mIsRunning = false; } @Override public void run() { //      Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO); mIsRunning = true; int buffSize = AudioRecord.getMinBufferSize(format.getSampleRateInHz(), format.getChannelConfig(), format.getAudioFormat()); if(buffSize == AudioRecord.ERROR) { System.err.println("getMinBufferSize returned ERROR"); return; } if(buffSize == AudioRecord.ERROR_BAD_VALUE) { System.err.println("getMinBufferSize returned ERROR_BAD_VALUE"); return; } //    short,   16-bit if(format.getAudioFormat() != AudioFormat.ENCODING_PCM_16BIT) { System.err.println("unknown format"); return; } //   .    , //      short[][] buffers = new short[BUFF_COUNT][buffSize >> 1]; mRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, format.getSampleRateInHz(), format.getChannelConfig(), format.getAudioFormat(), buffSize * 10); if(mRecord.getState() != AudioRecord.STATE_INITIALIZED) { System.err.println("getState() != STATE_INITIALIZED"); return; } try { mRecord.startRecording(); } catch(IllegalStateException e) { e.printStackTrace(); return; } int count = 0; while(mIsRunning) { int samplesRead = mRecord.read(buffers[count], 0, buffers[count].length); if(samplesRead == AudioRecord.ERROR_INVALID_OPERATION) { System.err.println("read() returned ERROR_INVALID_OPERATION"); return; } if(samplesRead == AudioRecord.ERROR_BAD_VALUE) { System.err.println("read() returned ERROR_BAD_VALUE"); return; } //    sendMsg(buffers[count]); count = (count + 1) % BUFF_COUNT; } try { try { mRecord.stop(); } catch(IllegalStateException e) { e.printStackTrace(); return; } } finally { //   mRecord.release(); mRecord = null; } } private void sendMsg(short[] data) { for(Handler handler : handlers) { handler.sendMessage(handler.obtainMessage(MSG_DATA, data)); } } }
      
      






All Articles