Implementation Example of Audio Acquisition in Android Audio Development

  • 2021-08-31 09:19:31
  • OfStack

In an Android system, AudioRecord or MediaRecord is generally used to collect audio.

AudioRecord is a relatively low-level API, which can obtain one frame of PCM data, and then process these data.

MediaRecorder is an API based on AudioRecorder (AudioRecord will eventually be created to interact with AudioFlinger), which can directly convert the collected audio data into the encoding format for execution and save it.

The live broadcast technology uses AudioRecorder to collect audio data.

This paper mainly introduces, for example, AudioRecord for audio acquisition.

Basic API

Gets the minimum buffer size for storing audio data collected by AudioRecord.

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

AudioRecord construction method

According to the specific parameter configuration, request hardware resources to create an AudioRecord object that can be used to collect audio.

Parameter description:

Basic Concepts of Audio Acquisition

Audio acquisition 1 generally uses AudioRecod or MediaRecord

What is the source of audio acquisition?
MediaRecorder. AudioSource. MIC 1 is generally a microphone

Sampling rate (in Hertz)
Number of audio sampling points per second (8000/44100 Hz)

Vocal tract

AudioFormat.CHANNEL_IN_MONO Mono, 1 channel for sampling AudioFormat.CHANNEL_IN_STEREO two channels, two channels for sampling

Audio sampling accuracy

Specifies the format of sampled data and the size of each sample.

The data return format is PCM format

The bit width of each sample is 16bit

1 generally uses this AudioFormat.ENCODING_PCM_16BIT (official documentation indicates that this sampling accuracy is guaranteed to be supported by all devices)

Bit rate

Number of bits transmitted per second (bit). The unit is bps (Bit Per Second). The higher the bit rate, the faster the data transmission speed.

Sampling rate x sampling size x channel number
Sample size per second = 16bit (bit width) 2 (dual channel) 44100 (number of times per sample hz) = 1411200b = 1411.2 kbps

The larger the bit rate, the more data sampled and the larger the amount of data transmitted in a unit time.

audioResource

Sources of audio acquisition

audioSampleRate

Audio sampling rate

channelConfig

Vocal tract

audioFormat

Audio sampling accuracy, specifying the format of sampled data and the size of each sample.

bufferSizeInBytes

Buffer size of audio data collected by AudioRecord.


// Set the acquisition source to microphone 
private static final int AUDIO_RESOURCE = MediaRecorder.AudioSource.MIC;
// Set the sampling rate to 44100 The current sampling rate is commonly used, and the official document indicates that this value can be compatible with all settings 
private final static int AUDIO_SAMPLE_RATE = 44100;
// Set the number of channels to two channels 
private final static int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_STEREO;
// Set the sampling accuracy, and set the sampled data to PCM Encoding is performed, and the bit width of data collected each time is 16bit . 
private final static int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;

public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)

Start collecting

After starting the acquisition, the state changes to RECORDSTATE_RECORDING.


public void startRecording ()

Read the recorded content, and read the collected data to the buffer

The status code of the return value of the method call:

Abnormal situation:

1.ERROR_INVALID_OPERATION if the object wasn't properly initialized

2.ERROR_BAD_VALUE if the parameters don't resolve to valid data and indexes.

Condition is normal: the number of bytes that were read


public int read (ByteBuffer audioBuffer, int sizeInBytes)
public int read (byte[] audioData, int offsetInBytes, int sizeInBytes)
public int read (short[] audioData, int offsetInShorts, int sizeInShorts)

Stop acquisition

After the acquisition is stopped, the state changes to RECORDSTATE_STOPPED.


public void stop ()

Get the status of AudioRecord

Used to detect whether the AudioRecord ensures that appropriate hardware resources are obtained. Called after the AudioRecord object is instantiated.

STATE_INITIALIZED Initial complete

STATE_UNINITIALIZED not initialized


public int getState ()

Returns the current acquisition status of AudioRecord

public static final int RECORDSTATE_STOPPED = 1; Stop state

State after calling void stop ()

public static final int RECORDSTATE_RECORDING = 3; Collecting

State after calling startRecording ()


public int getRecordingState()

Basic Flow of AudioRecord Audio Acquisition

Authority


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

Construct an AudioRecord object.

Start collecting.

Read the collected data.

Stop collecting.

Construct an AudioRecord object

AudioRecord audioRecord = new AudioRecord(audioResource, audioSampleRate, channelConfig, audioFormat, bufferSizeInBytes);

Get the bufferSizeInBytes value

bufferSizeInBytes is the buffer size of the audio data collected by AudioRecord.

Note: This size cannot be set casually. AudioRecord provides the corresponding API to get this value.

this.bufferSizeInBytes = AudioRecord.getMinBufferSize(audioSampleRate, channelConfig, audioFormat);

The bufferSizeInBytes return lets you know whether the parameters passed in to AudioRecord. getMinBufferSize support the current hardware device.


if (AudioRecord.ERROR_BAD_VALUE == bufferSizeInBytes || AudioRecord.ERROR == bufferSizeInBytes) {
  throw new RuntimeException("Unable to getMinBufferSize");
}

//bufferSizeInBytes is available...

Start collecting

Before you start recording, you should first judge whether the state of AudioRecord under 1 has been initialized.


// Judge AudioRecord Is the state of initialized 
// In AudioRecord After the object is constructed, it is in the AudioRecord.STATE_INITIALIZED State. 
int state = audioRecord.getState();
if (state == AudioRecord.STATE_UNINITIALIZED) {
  throw new RuntimeException("AudioRecord STATE_UNINITIALIZED");
}

Start collecting


audioRecord.startRecording();
// Open a thread to read data 
new Thread(recordTask).start();

Read the collected data

As mentioned above, AudioRecord stores the data in the buffer when collecting data, so we only need to create a data stream to read the collected data from the buffer.

Create a data stream, read audio data from AudioRecord to the buffer, and write the data from the buffer to the data stream.

Because the IO operation is required, the process of reading data should be performed in child threads


public void startRecording ()
0

Stop acquisition


public void startRecording ()
1

A few small problems

After collecting data, the saved file is audio-record. pcm, which cannot be played by ordinary player. It is an original file without any playback format, so it cannot be recognized and played by the player.

There are two ways to solve the above problem

Play audio data in pcm format using AudioTrack. Convert pcm data into wav format data so that it can be recognized by the player.

Related articles: