获取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(); }