Androidレコーディングの実装(AudioRecord)



Android Recording Implementation



4037756-1669f986572787d7.jpg

前回の記事では、録音にMediaRecorderを使用する方法を紹介しました。 Androidレコーディングの実装(MediaRecorder) 次に、AudioRecordを使用した録音について引き続き見ていきましょう。

AudioRecord

まず、Androidヘルプドキュメントのクラスの概要を見てください。AndioRecordクラスの主な機能は、さまざまなJavaアプリケーションがオーディオリソースを管理できるようにして、のサウンド入力ハードウェアによって収集されたサウンドを録音できるようにすることです。プラットホーム。この関数の実装は、AudioRecordオブジェクトのサウンドデータを「プル同期」(読み取りから読み取り)することによって行われます。録音プロセスでは、アプリケーションが行う必要があるのは、次の3つのクラスメソッドのいずれかを介してAudioRecordオブジェクトの録音データを時間内に取得することだけです。サウンドデータを取得するためにAudioRecordクラスによって提供される3つのメソッドは、read(byte []、int、int)、read(short []、int、int)、read(ByteBuffer、int)です。どちらの方法を選択する場合でも、ユーザーの音声データの保存形式を事前に設定しておく必要があります。



録音を開始するとき、AudioRecordは関連するサウンドバッファを初期化する必要があります。これは主に新しいサウンドデータを保存するために使用されます。このバッファのサイズは、オブジェクトの構築中に指定できます。これは、AudioRecordオブジェクトが読み取られる(同期される)前に録音できる時間(つまり、一度に録音できるサウンドの量)を示します。音声データはオーディオハードウェアから読み取られ、データサイズは記録されたデータ全体のサイズ(複数回読み取ることができます)を超えません。つまり、バッファ容量のデータは毎回初期化されます。

コレクションは非常に単純で、AudioRecordオブジェクトを作成してから、さまざまな構成パラメーターを渡すだけで済みます。一般的な録音の簡単なプロセスは次のとおりです。



  1. オーディオソース:オーディオを収集するためのデータソースとしてマイクを使用できます。

  2. サンプリングレート:1秒間にサウンドデータがサンプリングされる回数。サンプリングレートが高いほど、音質は良くなります。

  3. オーディオチャンネル:モノラル、デュアルチャンネルなど。



  4. オーディオ形式:通常、元のオーディオサンプルであるPCM形式が使用されます。

  5. バッファサイズ:オーディオデータ書き込みバッファの総数。最小のバッファーは、AudioRecord.getMinBufferSizeで取得できます。 (オーディオはバッファーにキャプチャされてから、バッファーから読み取られます)。

コードは次のように実装されています。

public class AudioRecorder { private static AudioRecorder audioRecorder // Audio source: audio input - microphone private final static int AUDIO_INPUT = MediaRecorder.AudioSource.MIC // Sampling Rate // 44100 is the current standard, but some devices still support 22050, 16000, 11025 // The sampling frequency is generally divided into three levels of 22.05KHz, 44.1KHz, and 48KHz. private final static int AUDIO_SAMPLE_RATE = 16000 // audio channel mono private final static int AUDIO_CHANNEL = AudioFormat.CHANNEL_IN_MONO // Audio format: PCM encoding private final static int AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT // buffer size: buffer byte size private int bufferSizeInBytes = 0 // Recording object private AudioRecord audioRecord // recording status private Status status = Status.STATUS_NO_READY // file name private String fileName // Recording file collection private List filesName = new ArrayList() private AudioRecorder() { } / / singleton mode public static AudioRecorder getInstance() { if (audioRecorder == null) { audioRecorder = new AudioRecorder() } return audioRecorder } /** * Create a recording object */ public void createAudio(String fileName, int audioSource, int sampleRateInHz, int channelConfig, int audioFormat) { / / Get the buffer byte size bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat) audioRecord = new AudioRecord(audioSource, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes) this.fileName = fileName } /** * Create a default recording object * @param fileName filename */ public void createDefaultAudio(String fileName) { mContext = ctx mHandler = handler / / Get the buffer byte size bufferSizeInBytes = AudioRecord.getMinBufferSize(AUDIO_SAMPLE_RATE, AUDIO_CHANNEL, AUDIO_ENCODING) audioRecord = new AudioRecord(AUDIO_INPUT, AUDIO_SAMPLE_RATE, AUDIO_CHANNEL, AUDIO_ENCODING, bufferSizeInBytes) this.fileName = fileName status = Status.STATUS_READY } /** * start recording * @param listener Audio stream listener */ public void startRecord(final RecordStreamListener listener) { if (status == Status.STATUS_NO_READY || TextUtils.isEmpty(fileName)) { Throw new IllegalStateException('The recording has not been initialized, please check if the recording permission is disabled~') } if (status == Status.STATUS_START) { Throw new IllegalStateException('recording') } Log.d('AudioRecorder','===startRecord==='+audioRecord.getState()) audioRecord.startRecording() new Thread(new Runnable() { @Override public void run() { writeDataTOFile(listener) } }).start() } /** * Stop recording */ public void stopRecord() { Log.d('AudioRecorder','===stopRecord===') if (status == Status.STATUS_NO_READY || status == Status.STATUS_READY) { Throw new IllegalStateException('recording has not started') } else { audioRecord.stop() status = Status.STATUS_STOP release() } } /** * Cancel recording */ public void canel() { filesName.clear() fileName = null if (audioRecord != null) { audioRecord.release() audioRecord = null } status = Status.STATUS_NO_READY } /** * Release resources */ public void release() { Log.d('AudioRecorder','===release===') / / If there is a pause recording try { if (filesName.size() > 0) { List filePaths = new ArrayList() for (String fileName : filesName) { filePaths.add(FileUtils.getPcmFileAbsolutePath(fileName)) } //Clear filesName.clear() / / Convert multiple pcm files into wav files mergePCMFilesToWAVFile(filePaths) } else { //This is because fileName.size will be greater than 0 as long as it is recorded, and fileName is null when there is no recording. / / will report null pointer NullPointerException // Convert a single pcm file to a wav file //Log.d('AudioRecorder', '=====makePCMFileToWAVFile======') //makePCMFileToWAVFile() } } catch (IllegalStateException e) { throw new IllegalStateException(e.getMessage()) } if (audioRecord != null) { audioRecord.release() audioRecord = null } status = Status.STATUS_NO_READY } /** * Write audio information to a file * @param listener Audio stream listener */ private void writeDataTOFile(RecordStreamListener listener) { // new a byte array is used to store some byte data, the size is the buffer size byte[] audiodata = new byte[bufferSizeInBytes] FileOutputStream fos = null int readsize = 0 try { String currentFileName = fileName if (status == Status.STATUS_PAUSE) { //If it is pause recording, add a number after the file name to prevent the duplicated file content from being overwritten. currentFileName += filesName.size() } filesName.add(currentFileName) File file = new File(FileUtils.getPcmFileAbsolutePath(currentFileName)) if (file.exists()) { file.delete() } Fos = new FileOutputStream(file)// Create a file with access bytes } catch (IllegalStateException e) { Log.e('AudioRecorder', e.getMessage()) throw new IllegalStateException(e.getMessage()) } catch (FileNotFoundException e) { Log.e('AudioRecorder', e.getMessage()) } / / Set the recording status to the recording state status = Status.STATUS_START while (status == Status.STATUS_START) { readsize = audioRecord.read(audiodata, 0, bufferSizeInBytes) if (AudioRecord.ERROR_INVALID_OPERATION != readsize && fos != null) { try { fos.write(audiodata) if (listener != null) { / / used to expand business listener.recordOfByte(audiodata, 0, audiodata.length) } } catch (IOException e) { Log.e('AudioRecorder', e.getMessage()) } } } try { if (fos != null) { Fos.close()// close the write stream } } catch (IOException e) { Log.e('AudioRecorder', e.getMessage()) } } }

AudioRecorder録音されたサウンドデータは、オーディオハードウェアから読み取られます。エンコード形式はPCM形式ですが、PCM音声データをオーディオファイルとして保存した場合、プレーヤーで再生できないため、データのエンコードと圧縮を行うには、最初にコードを記述する必要があります。以下は、PCM音声データのWAVファイルへの変換を実装しています。

/** * Convert a pcm file to a wav file * @param pcmPath pcm file path * @param destinationPath target file path (wav) * @param deletePcmFile delete source file * @return */ public static boolean makePCMFileToWAVFile(String pcmPath, String destinationPath, boolean deletePcmFile) { byte buffer[] = null int TOTAL_SIZE = 0 File file = new File(pcmPath) if (!file.exists()) { return false } TOTAL_SIZE = (int) file.length() // Fill in parameters, bitrate, and more. Here is the 16-bit mono 8000 hz WaveHeader header = new WaveHeader() // length field = size of the content (TOTAL_SIZE) + // The size of the header field (excluding the first 4 bytes of identifier RIFF and the 4 bytes of fileLength itself) header.fileLength = TOTAL_SIZE + (44 - 8) header.FmtHdrLeth = 16 header.BitsPerSample = 16 header.Channels = 2 header.FormatTag = 0x0001 header.SamplesPerSec = 8000 header.BlockAlign = (short) (header.Channels * header.BitsPerSample / 8) header.AvgBytesPerSec = header.BlockAlign * header.SamplesPerSec header.DataHdrLeth = TOTAL_SIZE byte[] h = null try { h = header.getHeader() } catch (IOException e1) { Log.e('PcmToWav', e1.getMessage()) return false } If (h.length != 44) // WAV standard, the header should be 44 bytes, if not 44 bytes, the file will not be converted. return false / / Delete the target file first File destfile = new File(destinationPath) if (destfile.exists()) destfile.delete() // Synthesized pcm file data, written to the target file try { buffer = new byte[1024 * 4] // Length of All Files, Total Size InputStream inStream = null OutputStream ouStream = null ouStream = new BufferedOutputStream(new FileOutputStream( destinationPath)) ouStream.write(h, 0, h.length) inStream = new BufferedInputStream(new FileInputStream(file)) int size = inStream.read(buffer) while (size != -1) { ouStream.write(buffer) size = inStream.read(buffer) } inStream.close() ouStream.close() } catch (FileNotFoundException e) { Log.e('PcmToWav', e.getMessage()) return false } catch (IOException ioe) { Log.e('PcmToWav', ioe.getMessage()) return false } if (deletePcmFile) { file.delete() } Log.i('PcmToWav', 'makePCMFileToWAVFile success!' + new SimpleDateFormat('yyyy-MM-dd hh:mm').format(new Date())) return true }

概要:AudioRecorderの録音は、MediaRecorderよりも使いにくいですが、利点は明らかです。 AudioRecorderは、ハードウェアを直接操作して、録音中にオーディオストリームデータを取得します。このプロセスはリアルタイム処理であり、さまざまなオーディオエンコーディングを実装するために使用できます。一時停止機能、一時停止記録機能の実装については本日ここでは説明しませんので、imhxlブロガーの共有をお読みになることをお勧めします http://blog.csdn.net/imhxl/article/details/52190451