一、使用AudioRecord采集录音,创建一个采集录音管理类AudioRecorderManager.java
public class AudioRecorderManager {
private static final String TAG = "AudioRecorderManager";
// 音频获取
private final static int SOURCE = MediaRecorder.AudioSource.MIC;
// 设置音频采样率,44100是目前的标准,但是某些设备仍然支 2050 6000 1025
private final static int SAMPLE_HZ = 44100;
// 设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道
private final static int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO;
// 音频数据格式:PCM 16位每个样本保证设备支持。PCM 8位每个样本 不一定能得到设备支持
private final static int FORMAT = AudioFormat.ENCODING_PCM_16BIT;
private AudioRecord mAudioRecord = null;
private int bufferSizeInBytes = 0;
private boolean start = false;
private Thread recordThread;
private int readsize = 0;
private int mBufferSize;
public interface AudioDataListener {
void audioData(byte[] data, int readSize);
}
private AudioDataListener audioDataListener;
public void setAudioDataListener(AudioDataListener audioDataListener) {
this.audioDataListener = audioDataListener;
}
public AudioRecorderManager() {
bufferSizeInBytes = AudioRecord.getMinBufferSize(SAMPLE_HZ, CHANNEL_CONFIG, FORMAT);
mAudioRecord = new AudioRecord(SOURCE, SAMPLE_HZ, CHANNEL_CONFIG, FORMAT, bufferSizeInBytes);
mBufferSize = 4 * 1024;
}
public void startRecord() {
recordThread = new Thread() {
@Override
public void run() {
if(mAudioRecord == null){
mAudioRecord = new AudioRecord(SOURCE, SAMPLE_HZ, CHANNEL_CONFIG, FORMAT, bufferSizeInBytes);
}
mAudioRecord.startRecording();
byte[] audioData = new byte[mBufferSize];
int readsize = 0;
while (start) {
try {
readsize += mAudioRecord.read(audioData, readsize, mBufferSize);
byte[] ralAudio = new byte[readsize];
//每次录音读取4K数据
System.arraycopy(audioData, 0, ralAudio, 0, readsize);
if (audioDataListener != null) {
audioDataListener.audioData(audioData, readsize);
}
readsize = 0;
Arrays.fill(audioData, (byte)0);
}catch(Exception e) {
e.printStackTrace();
}
}
}
};
start = true;
recordThread.start();
}
public void stopRecord() {
if(mAudioRecord != null){
start = false;
mAudioRecord.stop();
mAudioRecord.release();
mAudioRecord = null;
}
}
public boolean isStart()
{
return start;
}
}
采用AudioRecord进行录音,添加一个接口AudioDataListener类,该接口中audioData()方法便于把读取到的原始音频PCM数据回调出去进行编码成AAC。
二、获取到了原始数据PCM,然后采用MediaCodec进行编码为AAC。
1、初始化音频编码器
private MediaCodec audioEncodec;
private MediaFormat audioFormat;
private MediaCodec.BufferInfo audioBufferinfo;
initAudioEncodec(MediaFormat.MIMETYPE_AUDIO_AAC, 44100, 1);
private void initAudioEncodec(String mimeType, int sampleRate, int channelCount)
{
this.sampleRate = sampleRate;
audioBufferinfo = new MediaCodec.BufferInfo();
audioFormat = MediaFormat.createAudioFormat(mimeType, sampleRate, channelCount);
audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, ABITRATE);
audioFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 0);
}
2、初始化采集录音管理
private void initPCMRecord()
{
mAudioRecorderManager = new AudioRecorderManager();
mAudioRecorderManager.setAudioDataListener(new AudioRecorderManager.AudioDataListener() {
@Override
public void audioData(byte[] audioData, int readSize) {
if(mAudioRecorderManager.isStart())
{
//LogUtils.getInstance().I(TAG, "audioData = audioData " + audioData.length);
putPCMData(audioData, readSize);
}
}
});
}
3、将获取到的音频数据PCM添加到MediaCodec 编码器输入缓冲队列中
public void putPCMData(byte[] buffer, int size)
{
if(audioEncodecThread != null && buffer != null && size > 0)
{
int inputBufferindex = audioEncodec.dequeueInputBuffer(0);
if(inputBufferindex >= 0)
{
ByteBuffer byteBuffer = audioEncodec.getInputBuffers()[inputBufferindex];
byteBuffer.clear();
byteBuffer.put(buffer);
long pts = getAudioPts(size, sampleRate);
audioEncodec.queueInputBuffer(inputBufferindex, 0, size, pts, 0);
}
}
}
private long getAudioPts(int size, int sampleRate)
{
audioPts += (long)(1.0 * size / (sampleRate * 2 * 2) * 1000000.0);
return audioPts;
}
4、开始把音频数据编码为AAC,其中定义一个接口OnMediaInfoListener,该接口中定义了一个onAudioInfo方法,该方法可以把编码出来的AAC数据进行保存起来或者推流
private long audioPts = 0;
public void startAudioEncode() {
try {
audioEncodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);
audioEncodec.configure(audioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
audioEncodec.start();
startAudio();
} catch (IOException e) {
e.printStackTrace();
}
}
//开启一个线程进行编码
public void startAudio(){
audioEncodecThread = new Thread() {
@Override
public void run() {
isAudioEncoder = true;
pts = 0;
if(audioEncodec!=null){
while(isAudioEncoder)
{
int outputBufferIndex = audioEncodec.dequeueOutputBuffer(audioBufferinfo, 0);
if(outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED)
{
}
else
{
while(outputBufferIndex >= 0)
{
ByteBuffer outputBuffer = audioEncodec.getOutputBuffers()[outputBufferIndex];
outputBuffer.position(audioBufferinfo.offset);
outputBuffer.limit(audioBufferinfo.offset + audioBufferinfo.size);
if(pts == 0)
{
pts = audioBufferinfo.presentationTimeUs;
}
audioBufferinfo.presentationTimeUs = audioBufferinfo.presentationTimeUs - pts;
byte[] data = new byte[outputBuffer.remaining()];
outputBuffer.get(data, 0, data.length);
if(onMediaInfoListener != null)
{
onMediaInfoListener.onAudioInfo(data);
}
// mFlvPacker.onAudioData(outputBuffer, audioBufferinfo);
audioEncodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = audioEncodec.dequeueOutputBuffer(audioBufferinfo, 0);
}
}
}
}
}
};
audioEncodecThread.start();
}
private OnMediaInfoListener onMediaInfoListener;
public void setOnMediaInfoListener(OnMediaInfoListener onMediaInfoListener) {
this.onMediaInfoListener = onMediaInfoListener;
}
public interface OnMediaInfoListener
{
void onAudioInfo(byte[] data);
}
5、停止录音
public void stopAudio(){
try {
if(audioEncodec!=null){
isAudioEncoder = false;
audioEncodec.stop();
audioEncodec.release();
}
} catch (Exception e){
e.printStackTrace();
Log.e(TAG, "stopAudio e.getMessage(): " + e.getMessage());
}
}