desc:录音测试,经测试单独录制音频毫无问题

main
xiaowusky 1 year ago
parent 6671c991c0
commit e4df5f1f55

@ -12,9 +12,6 @@ import android.view.Surface;
import com.common.commonlib.utils.LogUtils;
import org.easydarwin.PushHelper;
import org.easydarwin.easypusher.BuildConfig;
import java.io.IOException;
import java.nio.ByteBuffer;
@ -34,13 +31,15 @@ public class AudioEncoderCore extends MediaEncoderCore implements Runnable {
protected static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
private int mSampleRate = 8000;
private int mSampleRate = 44100;
private int mChannelCount = 1;
private int mBitRate = 16000;
private int mBitRate = 128000;
// private int mMaxInputSize = 16384;
private int mMaxInputSize = 1920;
int AUDIO_BUFFER_SIZE;
private AudioRecord mAudioRecord;
@ -63,14 +62,14 @@ public class AudioEncoderCore extends MediaEncoderCore implements Runnable {
format.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSampleRate);
format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, mChannelCount);
format.setInteger(MediaFormat.KEY_BIT_RATE, mBitRate);
format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, mMaxInputSize);
// format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, mMaxInputSize);
// Create a MediaCodec encoder, and configure it with our format. Get a Surface
// we can use for input and wrap it with a class that handles the EGL work.
try {
mEncoder = MediaCodec.createEncoderByType(MIME_TYPE);
} catch (IOException e) {
LogUtils.e(e);
e.printStackTrace();
}
mEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
@ -79,6 +78,8 @@ public class AudioEncoderCore extends MediaEncoderCore implements Runnable {
LogUtils.v(String.format("%s prepareEncoder, mEncoder = %s", getClass().getSimpleName(), mEncoder));
}
int minBufferSize;
@SuppressLint("MissingPermission")
private void prepareRecorder() {
switch (mChannelCount) {
@ -92,24 +93,25 @@ public class AudioEncoderCore extends MediaEncoderCore implements Runnable {
throw new IllegalArgumentException();
}
int minBufferSize = AudioRecord.getMinBufferSize(mSampleRate,
minBufferSize = AudioRecord.getMinBufferSize(mSampleRate,
mChannelConfig, AUDIO_FORMAT);
AUDIO_BUFFER_SIZE = 2 * minBufferSize;
mAudioRecord = new AudioRecord(
MediaRecorder.AudioSource.MIC, // source
MediaRecorder.AudioSource.CAMCORDER, // source
mSampleRate, // sample rate, hz
mChannelConfig, // channels
AUDIO_FORMAT, // audio format
minBufferSize); // buffer size (bytes)
AUDIO_BUFFER_SIZE); // buffer size (bytes)
}
@Override
public void start() {
if (!mRecording) {
// mRecording = true;
// mAudioRecord.startRecording();
//
// TaskUtils.execute(this);
mRecording = true;
mAudioRecord.startRecording();
new Thread(this).start();
}
}
@ -123,6 +125,87 @@ public class AudioEncoderCore extends MediaEncoderCore implements Runnable {
return null;
}
@Override
public void drainEncoder(boolean endOfStream) {
// LogUtils.v(String.format("%s drainEncoder: end = %b", getClass().getSimpleName(), endOfStream));
final int TIMEOUT_USEC = 10000;
if (VERBOSE) Log.d(TAG, "drainEncoder(" + endOfStream + ")");
if (endOfStream && isSurfaceInput()) {
if (VERBOSE) Log.d(TAG, "sending EOS to encoder");
mEncoder.signalEndOfInputStream();
}
ByteBuffer[] encoderOutputBuffers = mEncoder.getOutputBuffers();
while (true) {
int encoderStatus = mEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC);
if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
// no output available yet
if (!endOfStream) {
break; // out of while
} else {
if (VERBOSE) Log.d(TAG, "no output available, spinning to await EOS");
}
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
// not expected for an encoder
encoderOutputBuffers = mEncoder.getOutputBuffers();
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
// should happen before receiving buffers, and should only happen once
MediaFormat newFormat = mEncoder.getOutputFormat();
Log.d(TAG, "encoder output format changed: " + newFormat);
// now that we have the Magic Goodies, start the muxer
mTrackIndex = mMuxer.addTrack(newFormat);
} else if (encoderStatus < 0) {
Log.w(TAG, "unexpected result from encoder.dequeueOutputBuffer: " +
encoderStatus);
// let's ignore it
} else {
ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];
if (encodedData == null) {
throw new RuntimeException("encoderOutputBuffer " + encoderStatus +
" was null");
}
if (!mMuxer.isStarted()) {
mBufferInfo.size = 0;
}
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
// The codec config data was pulled out and fed to the muxer when we got
// the INFO_OUTPUT_FORMAT_CHANGED status. Ignore it.
if (VERBOSE) Log.d(TAG, "ignoring BUFFER_FLAG_CODEC_CONFIG");
mBufferInfo.size = 0;
}
if (mBufferInfo.size != 0) {
// adjust the ByteBuffer values to match BufferInfo (not needed?)
encodedData.position(mBufferInfo.offset);
encodedData.limit(mBufferInfo.offset + mBufferInfo.size);
mMuxer.writeSampleData(mTrackIndex, encodedData, mBufferInfo);
if (VERBOSE) {
Log.d(TAG, "sent " + mBufferInfo.size + " bytes to muxer, ts=" +
mBufferInfo.presentationTimeUs);
}
}
mEncoder.releaseOutputBuffer(encoderStatus, false);
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
if (!endOfStream) {
Log.w(TAG, "reached end of stream unexpectedly");
} else {
if (VERBOSE) Log.d(TAG, "end of stream reached");
}
break; // out of while
}
}
}
}
@Override
protected boolean isSurfaceInput() {
return false;
@ -131,14 +214,14 @@ public class AudioEncoderCore extends MediaEncoderCore implements Runnable {
@Override
public void run() {
while (mRecording) {
// drainEncoder(false);
// drainAudio(false);
drainAudio(false);
drainEncoder(false);
}
// drainAudio(true);
drainAudio(true);
mAudioRecord.stop();
// drainEncoder(true);
drainEncoder(true);
release();
}
@ -146,104 +229,32 @@ public class AudioEncoderCore extends MediaEncoderCore implements Runnable {
private void drainAudio(boolean endOfStream) {
// LogUtils.v(String.format("drainAudio %b", endOfStream));
ByteBuffer[] inputBuffers = mEncoder.getInputBuffers();
int bufferIndex = mEncoder.dequeueInputBuffer(-1); // wait indefinitely
if (bufferIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[bufferIndex];
ByteBuffer inputBuffer = mEncoder.getInputBuffer(bufferIndex);
inputBuffer.clear();
int len = mAudioRecord.read(inputBuffer, SAMPLES_PER_FRAME * 2); // read blocking
long ptsUs = System.nanoTime() / 1000;
// byte[] buffer = new byte[minBufferSize];
// int len = mAudioRecord.read(buffer, 0, minBufferSize); // read blocking
// long ptsUs = System.nanoTime() / 1000;
// if (len > 0) {
// inputBuffer.put(buffer);
// if (endOfStream) {
// mEncoder.queueInputBuffer(bufferIndex, 0, buffer.length, ptsUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
// } else {
// mEncoder.queueInputBuffer(bufferIndex, 0, buffer.length, ptsUs, 0);
// }
// }
int bytesRead = mAudioRecord.read(inputBuffer, AUDIO_BUFFER_SIZE);
long presentationTimeUs = System.nanoTime() / 1000;
if (endOfStream) {
mEncoder.queueInputBuffer(bufferIndex, 0, len, ptsUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
} else {
mEncoder.queueInputBuffer(bufferIndex, 0, len, ptsUs, 0);
}
}
}
@Override
public void drainEncoder(boolean endOfStream) {
final int TIMEOUT_USEC = 10000;
if (VERBOSE) Log.d(TAG, "drainEncoder(" + endOfStream + ")");
if (endOfStream && isSurfaceInput()) {
if (VERBOSE) Log.d(TAG, "sending EOS to encoder");
mEncoder.signalEndOfInputStream();
}
ByteBuffer mBuffer = ByteBuffer.allocate(10240);
ByteBuffer[] encoderOutputBuffers = mEncoder.getOutputBuffers();
int encoderStatus = mEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC);
if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
// no output available yet
if (!endOfStream) {
mEncoder.queueInputBuffer(bufferIndex, 0, bytesRead, presentationTimeUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
} else {
if (VERBOSE) Log.d(TAG, "no output available, spinning to await EOS");
}
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
// not expected for an encoder
encoderOutputBuffers = mEncoder.getOutputBuffers();
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
// should happen before receiving buffers, and should only happen once
MediaFormat newFormat = mEncoder.getOutputFormat();
Log.d(TAG, "encoder output format changed: " + newFormat);
// now that we have the Magic Goodies, start the muxer
// mTrackIndex = mMuxer.addTrack(newFormat);
} else if (encoderStatus < 0) {
Log.w(TAG, "unexpected result from encoder.dequeueOutputBuffer: " +
encoderStatus);
// let's ignore it
} else {
ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];
if (encodedData == null) {
throw new RuntimeException("encoderOutputBuffer " + encoderStatus +
" was null");
}
if (!mMuxer.isStarted()) {
mBufferInfo.size = 0;
}
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
// The codec config data was pulled out and fed to the muxer when we got
// the INFO_OUTPUT_FORMAT_CHANGED status. Ignore it.
if (VERBOSE) Log.d(TAG, "ignoring BUFFER_FLAG_CODEC_CONFIG");
mBufferInfo.size = 0;
mEncoder.queueInputBuffer(bufferIndex, 0, bytesRead,
presentationTimeUs, 0);
}
if (mBufferInfo.size != 0) {
encodedData.get(mBuffer.array(), 7, mBufferInfo.size);
encodedData.clear();
mBuffer.position(7 + mBufferInfo.size);
addADTStoPacket(mBuffer.array(), mBufferInfo.size + 7);
mBuffer.flip();
PushHelper.INSTANCE.pushData(mBuffer.array(), mBufferInfo.size + 7, mBufferInfo.presentationTimeUs / 1000);
if (BuildConfig.DEBUG)
Log.i(TAG, String.format("push audio stamp:%d", mBufferInfo.presentationTimeUs / 1000));
}
mEncoder.releaseOutputBuffer(encoderStatus, false);
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
if (!endOfStream) {
Log.w(TAG, "reached end of stream unexpectedly");
} else {
if (VERBOSE) Log.d(TAG, "end of stream reached");
}
}
}
}
private void addADTStoPacket(byte[] packet, int packetLen) {
packet[0] = (byte) 0xFF;
packet[1] = (byte) 0xF1;
packet[2] = (byte) (((2 - 1) << 6) + (11 << 2) + (1 >> 2));
packet[3] = (byte) (((1 & 3) << 6) + (packetLen >> 11));
packet[4] = (byte) ((packetLen & 0x7FF) >> 3);
packet[5] = (byte) (((packetLen & 7) << 5) + 0x1F);
packet[6] = (byte) 0xFC;
}
}

Loading…
Cancel
Save