はじめに
マイクから生データを受信するには、クラスが責任を負います
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つのバージョンがあります。
-
read(byte[] audioData, int offsetInBytes, int sizeInBytes)
-
read(short[] audioData, int offsetInShorts, int sizeInShorts)
-
read(ByteBuffer audioBuffer, int sizeInBytes)
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)); } } }