获取PCM流
package com.ff.aac.audio;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.ff.aac.jni.AacEncoder;
import android.media.AudioRecord;
import android.media.MediaRecorder.AudioSource;
import android.os.SystemClock;
import android.util.Log;
/**
* 音频发送封装类
*/
public class DAudioRecord implements Runnable{
private final String TAG="DAudioRecord";
private int mFrequency;//采样率
private int mChannel;//声道
private int mSampBit;//采样精度
private AacEncoder encoder;
private AudioRecord mAudioRecord;
private boolean recordTag;
private int minBufferSize;
public DAudioRecord(int frequency,int channel,int sampbit){
this.mFrequency = frequency;
this.mChannel = channel;
this.mSampBit = sampbit;
}
public void init(){
if(mAudioRecord != null){
release();
}
try {
minBufferSize = AudioRecord.getMinBufferSize(mFrequency, mChannel, mSampBit);
mAudioRecord = new AudioRecord(AudioSource.MIC, mFrequency, mChannel, mSampBit, minBufferSize);
Log.i(TAG, "minBufferSize = " + minBufferSize);
} catch (Exception e) {
Log.i(TAG, "创建录音器出错");
}
}
public void startRecord(AacEncoder encoder){
this.recordTag = true;
this.encoder = encoder;
new Thread(this).start();
}
public void stopRecord(){
this.recordTag = false;
}
public void release(){
if(mAudioRecord != null){
try {
mAudioRecord.stop();
mAudioRecord.release();
encoder.stopSendRecodData();
} catch (Exception e) {
Log.i(TAG, "关闭录音出错");
}finally{
mAudioRecord = null;
encoder = null;
System.gc();
}
}
}
@Override
public void run() {
try {
boolean b = true;
while (b && recordTag) {
if(mAudioRecord.getState() == AudioRecord.STATE_INITIALIZED){
mAudioRecord.startRecording();
b = false;
}
Log.i(TAG, "录音开始初始化");
SystemClock.sleep(10);
}
byte[] audioData = new byte[512]; // 640
byte[] audioData1 = new byte[2048]; // inputSamples = 1024, maxOutputBytes = 768 ,maxInputBytes = 2048 (jni 中编码aac中获取到的信息)
int i = 0;
while (recordTag) {
int size = mAudioRecord.read(audioData, 0,audioData.length);
if (size == audioData.length) {
Log.i("AAC_JNI", "录音" + size);
for(int j = 0; j < size; j++){
audioData1[j + i * 512] = audioData[j];
}
i++;
if(i == 4){
this.encoder.sendRecordData(audioData1);
i = 0;
}
}
}
} catch (Exception e) {
Log.i(TAG, "录音过程出错 " + e.getMessage());
}
}
}
jni中结构体
struct AacDecoderInfo{
faacEncHandle hEncoder;
char* pcmBuffer;
char* aacBuffer;
int maxInputBytes;
int maxOutputBytes;
int bitSize;
int inputSamples;
FILE* ftOutFile;
};
struct AacDecoderInfo *aacDecoderInfo;jni中进行实时编码
JNIEXPORT void JNICALL Java_com_ff_aac_jni_AacEncoder_initAACEncoder
(JNIEnv *env, jobject obj){
unsigned long sampleRate = 8000;
unsigned int numChannels = 1;
unsigned long inputSamples;
unsigned long maxOutputBytes;
faacEncHandle hEncoder = faacEncOpen(sampleRate, numChannels, &inputSamples, &maxOutputBytes);
LOGD("inputSamples = %d, maxOutputBytes = %d, sampleRate = %d", inputSamples, maxOutputBytes);
faacEncConfigurationPtr pConfigPtr;
pConfigPtr = faacEncGetCurrentConfiguration(hEncoder);
if(!pConfigPtr){
LOGD("faacEncGetCurrentConfiguration ERROR!");
faacEncClose(hEncoder);
hEncoder = NULL;
return;
}
pConfigPtr->inputFormat = FAAC_INPUT_16BIT;//输入数据类型
pConfigPtr->outputFormat = 1; //0-Raw ; 1-ADTS
pConfigPtr->bitRate = 8000;
//pConfigPtr->useTns= 0;//瞬时噪声定形(temporal noise shaping,TNS)滤波器
//pConfigPtr->useLfe= 0;//低频效果
pConfigPtr->aacObjectType= LOW; //编码类型
pConfigPtr->shortctl=SHORTCTL_NORMAL;
pConfigPtr->quantqual=20;
pConfigPtr->mpegVersion = MPEG2;
int nRetVal = faacEncSetConfiguration(hEncoder, pConfigPtr);
LOGD("nRetVal = %d", nRetVal);
int nPCMBitSize = 16; // 量化位数
int m_nMaxInputBytes = inputSamples * nPCMBitSize / 8;
LOGD("m_nMaxInputBytes = %d", m_nMaxInputBytes);
char pbPCMBuffer[m_nMaxInputBytes]; // 读取PCM数据
char pbAACBuffer[maxOutputBytes];
FILE* fpOut = fopen("/storage/emulated/0/t/pcm2aac.aac", "wb");
aacDecoderInfo = malloc(sizeof(struct AacDecoderInfo));
aacDecoderInfo->hEncoder = hEncoder;
aacDecoderInfo->pcmBuffer = pbPCMBuffer;
aacDecoderInfo->aacBuffer = pbAACBuffer;
aacDecoderInfo->maxInputBytes = m_nMaxInputBytes;
aacDecoderInfo->maxOutputBytes = maxOutputBytes;
aacDecoderInfo->bitSize = nPCMBitSize;
aacDecoderInfo->inputSamples = inputSamples;
aacDecoderInfo->ftOutFile = fpOut;
isRecord = true;
}
/*
* http://blog.csdn.net/jwzhangjie/article/details/8782656 (如果不这样设置将导致编码失败)
*
* */
size_t read_int16(int16_t *outbuf, size_t num, unsigned char *inputbuf){
size_t i = 0 , j = 0;
unsigned char bufi[8];
while(i < num){
memcpy(bufi, inputbuf+j, (aacDecoderInfo->bitSize / 8));
j+= (aacDecoderInfo->bitSize / 8);
int16_t s = ((int16_t*)bufi)[0];
outbuf[i] = s;
i++;
}
return 0;
}
JNIEXPORT void JNICALL Java_com_ff_aac_jni_AacEncoder_sendRecordData
(JNIEnv *env, jobject obj, jbyteArray arr){
LOGD("sendRecordData isRecord = %d", isRecord);
jsize size = (*env)->GetArrayLength(env, arr);
LOGD("sendRecordData arr size = %d", size);
int inputSamples = size / (aacDecoderInfo->bitSize / 8);
LOGD("sendRecordData intputSamples = %d, default intputSamples = %d", inputSamples, aacDecoderInfo->inputSamples);
memset(aacDecoderInfo->aacBuffer, 0, aacDecoderInfo->maxOutputBytes);
char* cArr = (*env)->GetByteArrayElements(env,arr,false);
int pumbuff_size = size / (aacDecoderInfo->bitSize / 8);
int pumBuf[pumbuff_size];
read_int16(pumBuf, size, cArr);
int nRetVal = faacEncEncode(aacDecoderInfo->hEncoder, pumBuf, inputSamples, aacDecoderInfo->aacBuffer, aacDecoderInfo->maxOutputBytes);
LOGD("sendRecordData nRetVal = %d", nRetVal);
(*env)->ReleaseByteArrayElements(env, arr, cArr, 0);
fwrite(aacDecoderInfo->aacBuffer, 1, nRetVal, aacDecoderInfo->ftOutFile);
}
JNIEXPORT void JNICALL Java_com_ff_aac_jni_AacEncoder_stopSendRecodData
(JNIEnv *env, jobject obj){
fclose(aacDecoderInfo->ftOutFile);
faacEncClose(aacDecoderInfo->hEncoder);
free(aacDecoderInfo);
}java 调用
int frequency = 8000;
int channel = AudioFormat.CHANNEL_IN_MONO;
int sampbit = AudioFormat.ENCODING_PCM_16BIT;
audioRecord = new DAudioRecord(frequency, channel, sampbit);
audioRecord.init();
final AacEncoder encoder = new AacEncoder();
audioRecord.startRecord(encoder);
package com.ff.aac.jni;
public class AacEncoder {
static{
System.loadLibrary("aacdec");
}
public native void initAACEncoder();
public native void sendRecordData(byte[] data);
public native void stopSendRecodData();
}