“Statement”

First of all, this series of articles are based on their own understanding and practice, if there is anything wrong, welcome to point out. Secondly, this is an introductory series, covering only enough knowledge, and there are many blog posts on the Internet for in-depth knowledge. Finally, I hope you can learn something.

preface

Of bridal chamber build, begin from foundation certainly above all frame, so how should we frame good, see next step.

1. Construct an AudioRecord

We start with the AudioRecord constructor, PublicAudioRecord (int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)

Let’s look at the five parameters of the construction method

  • AudioSource: An audio input source, such as a microphone, obtained from mediaRecord. audioSource.
  • SampleRateInHz: sampling rate of audio frequency. The sampling rate is 44100, that is, 44.1khz.
  • ChannelConfig: A sound channel for audio recording, including mono and stereo channels, defined in AudioFormat.
  • AudioFormat: audioFormat
  • BufferSizeInBytes: The size of the audio buffer. Different phone vendors have different implementations (3584 bytes on my OnePlus phone, for example).

static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)

Specific use is as follows:

private void createAudioRecord() { sampleRateInHz = 44100; channelConfig = AudioFormat.CHANNEL_IN_MONO; audioFormat = AudioFormat.ENCODING_PCM_16BIT; bufferSize = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat); audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRateInHz, channelConfig, audioFormat, bufferSize); Int state = audioRecord.getState(); Log.d(TAG, "createAudioRecord: state=" + state + " bufferSize=" + bufferSize); if (AudioRecord.STATE_INITIALIZED ! = state) {new Exception("AudioRecord cannot be initialized, please check the recording permission or whether other apps did not release the recorder "); } } private void initPCMFile() { pcmFile = new File(getExternalFilesDir(Environment.DIRECTORY_MUSIC), "raw.pcm"); Log.d(TAG, "initPCMFile: pcmFile=" + pcmFile); }Copy the code

2. Start recording and read recording count to PCM file

In the recording process, all the application needs to do is read(byte[], int, int), read(short[], int, int) or read(ByteBuffer, int);

if (pcmFile.exists()) { pcmFile.delete(); } isRecording = true; final byte[] buffer = new byte[bufferSize]; audioRecord.startRecording(); new Thread(new Runnable() { @Override public void run() { FileOutputStream fileOutputStr eam = null; try { fileOutputStream = new FileOutputStream(pcmFile); if (fileOutputStream ! = null) { while (isRecording) { int readStatus = audioRecord.read(buffer, 0,bufferSize); Log.d(TAG, "run: readStatus=" + readStatus); fileOutputStream.write(buffer); } } } catch (IOException e) { e.printStackTrace(); Log.e(TAG, "run: ", e); } finally { if (fileOutputStream ! = null) { try { fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } }).start(); }Copy the code

3. Stop recording to release resources

private void stopRecord() { isRecording = false; if (audioRecord ! = null) { audioRecord.stop(); } } protected void onDestroy() { super.onDestroy(); if (audioRecord ! = null) { audioRecord.release() ; } audioRecord = null;Copy the code

4. Details (figure out why the child thread is open to read recorded data)

The audioRecord read operation is a READ_BLOCKING operation that is released when buffersize is read. So when we see step 3 recording, we start a child thread to read and write data to the PCM file.

public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes) { return read(audioData, offsetInBytes, sizeInBytes,READ_BLOCKING); }

The state of the AudioRecord has two properties, recording state and initialization state, setting whether the recording state has been initialized in the first place

	public static final int STATE_UNINITIALIZED = 0;
	
	public static final int STATE_INITIALIZED = 1;
	


	public static final int RECORDSTATE_STOPPED = 1;
	
	public static final int RECORDSTATE_RECORDING = 3;
	/**
	* Lock to make sure mRecordingState updates are reflecting the actual state of 
	the object.
	*/
	private final Object mRecordingStateLock = new Object();
Copy the code

end…