如果是Android 平台可以使用ndk下的opensles进行采集,如果是Linux使用alsa 通用api,本文只贴openeles
audioReader.h
/*
* Copyright 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef NATIVE_AUDIO_AUDIO_RECORDER_H
#define NATIVE_AUDIO_AUDIO_RECORDER_H
#include <sys/types.h>
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
//#include "DataManager.h"
//#define MAXAUDIOSIZE 441*100
#define MAXAUDIONUM 5
struct SampleFormat{
uint32_t sampleRate = 44100000;
uint32_t framesPerBuf = 512;
uint16_t channels = 1;
uint16_t pcmFormat = 16; // 8 bit, 16 bit, 24 bit ...
uint32_t representation; // android extensions
};
class AudioRecorder {
private:
SLObjectItf recObjectItf_;
SLRecordItf recItf_;
SLAndroidSimpleBufferQueueItf recBufQueueItf_;
SLEngineItf slEngineItf_;
SLObjectItf slEngineObj_;
SampleFormat sampleInfo;
uint32_t audioBufCount;
//StreamDataPool<ImageNode> mStreamDataPool;
unsigned char mStart=0;
unsigned char *mFrameList[MAXAUDIONUM]={0};
unsigned char *mBuf=NULL;
unsigned long long mBufSize=0;
unsigned long long mMaxBufSize=0;
//ENGINE_CALLBACK callback_;
void *ctx_;
//uint8_t* audioBuf;
int mFrameSize = 512;
public:
static AudioRecorder *GetInstance(){
static AudioRecorder aRecorder;
return &aRecorder;
}
AudioRecorder();
~AudioRecorder();
void Init(SampleFormat *sampleFormat);
SLboolean Start();
SLboolean Stop();
void ProcessSLCallback(SLAndroidSimpleBufferQueueItf bq);
int32_t dbgGetDevBufCount(void);
int getAudio(unsigned char *Buf,int getSize,unsigned long long &getPos);
#ifdef ENABLE_LOG
AndroidLog *recLog_;
#endif
};
#endif // NATIVE_AUDIO_AUDIO_RECORDER_H
AudioReader.cpp
/*
* Copyright 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <cstring>
#include <cstdlib>
#include "AudioReader.h"
/*
* bqRecorderCallback(): called for every buffer is full;
* pass directly to handler
*/
void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *rec)
{
(static_cast<AudioRecorder *>(rec))->ProcessSLCallback(bq);
}
void AudioRecorder::ProcessSLCallback(SLAndroidSimpleBufferQueueItf bq)
{
// static FILE *audiofile = NULL;
SLresult result;
//static FILE *fp=fopen("./aaa.pcm","wb");
//ImagePool *p = DataManager::GetInstance()->GetNewImagePool(AUDIO_DATA, mFrameSize);
/*char tmpBuf[4096];
result = (*bq)->Enqueue(bq, tmpBuf, mFrameSize);
printf("result=%d,mFrameSize=%d\n",result,mFrameSize);
if(fp){
fwrite(tmpBuf,1,mFrameSize,fp);
}
return;*/
unsigned int startPos=mBufSize%mMaxBufSize;
if(mMaxBufSize-startPos>=mFrameSize){
result = (*bq)->Enqueue(bq, mBuf+startPos, mFrameSize);
//printf("result1=%d,mFrameSize=%d\n",result,mFrameSize);
//if(fp){
//fwrite(mBuf+startPos,1,mFrameSize,fp);
//}
}
else{//设置好mMaxBufSize是mFrameSize的整数倍,就不会出现下面的情况
char tmpBuf[4096]={0};
int rightSize=mMaxBufSize-startPos;
int leftSize=mFrameSize-rightSize;
result = (*bq)->Enqueue(bq, tmpBuf, rightSize);
//printf("result2=%d,mFrameSize=%d\n",result,mFrameSize);
memcpy(mBuf+startPos, tmpBuf,rightSize);
memcpy(mBuf,tmpBuf+rightSize,leftSize);
//if(fp){
// fwrite(mBuf,1,leftSize,fp);
//}
}
mBufSize+=mFrameSize;
// printf("bufSize=%d\n",mBufSize);
/*ImageNode node(p->mIndex);
mStreamDataPool.writeData(&node);
if (result != SL_RESULT_SUCCESS)
{
printf("error\n");
}*/
//printf("ProcessSLCallback\n");
}
int AudioRecorder::getAudio(unsigned char *Buf,int getSize,unsigned long long &getPos){
if(getPos + (unsigned long long)getSize > mBufSize){
//等待新数据
return 0;
}
if(getPos + (unsigned long long)getSize + mMaxBufSize < mBufSize){
//延时超过一个缓冲区
getPos=mBufSize-getSize;
}
unsigned long long tmp=getPos;
//printf("getPosquMAXAUDIOSIZE=%lld,640qu44100=%d\n",getPos%44100,640%44100);
unsigned int startPos= getPos % mMaxBufSize;
if(mMaxBufSize-startPos>=getSize){
//printf("getSize=%d,getPos=%lld,startpos=%d,MAXAUDIOSIZE=%d\n",getSize,getPos,startPos,MAXAUDIOSIZE);
memcpy(Buf,mBuf+startPos,getSize);
}
else{
int rightSize=mMaxBufSize-startPos;
int leftSize=getSize-rightSize;
memcpy(Buf,mBuf+startPos, rightSize);
memcpy(Buf+rightSize,mBuf, leftSize);
// printf("getSize=%lld,startpos=%d,rightSize=%d,leftSize=%d\n",getSize,startPos,rightSize,leftSize);
}
return getSize;
}
void ConvertToSLSampleFormat(SLAndroidDataFormat_PCM_EX *pFormat,
SampleFormat *pSampleInfo)
{
// assert(pFormat);
memset(pFormat, 0, sizeof(*pFormat));
pFormat->formatType = SL_DATAFORMAT_PCM;
// Only support 2 channels
// For channelMask, refer to wilhelm/src/android/channels.c for details
if (pSampleInfo->channels <= 1)
{
pFormat->numChannels = 1;
pFormat->channelMask = SL_SPEAKER_FRONT_LEFT;
}
else
{
pFormat->numChannels = 2;
pFormat->channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
}
pFormat->sampleRate = pSampleInfo->sampleRate;
pFormat->endianness = SL_BYTEORDER_LITTLEENDIAN;
pFormat->bitsPerSample = pSampleInfo->pcmFormat;
pFormat->containerSize = pSampleInfo->pcmFormat;
/*
* fixup for android extended representations...
*/
pFormat->representation = pSampleInfo->representation;
switch (pFormat->representation)
{
case SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT:
pFormat->bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_8;
pFormat->containerSize = SL_PCMSAMPLEFORMAT_FIXED_8;
pFormat->formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
break;
case SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT:
pFormat->bitsPerSample =
SL_PCMSAMPLEFORMAT_FIXED_16; // supports 16, 24, and 32
pFormat->containerSize = SL_PCMSAMPLEFORMAT_FIXED_16;
pFormat->formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
break;
case SL_ANDROID_PCM_REPRESENTATION_FLOAT:
pFormat->bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_32;
pFormat->containerSize = SL_PCMSAMPLEFORMAT_FIXED_32;
pFormat->formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
break;
case 0:
break;
default:
break;
}
}
void AudioRecorder::Init(SampleFormat *sampleFormat)
{
printf("AudioRecorder Init in\n");
if(mStart==1){
printf("audio input already opened\n");
return ;
}
mStart=1;
memcpy(&sampleInfo, sampleFormat, sizeof(SampleFormat));
SLresult result;
uint32_t bufSize = sampleInfo.framesPerBuf * sampleInfo.channels *
sampleInfo.pcmFormat;
result = slCreateEngine(&slEngineObj_, 0, NULL, 0, NULL, NULL);
result = (*slEngineObj_)->Realize(slEngineObj_, SL_BOOLEAN_FALSE);
result = (*slEngineObj_)->GetInterface(slEngineObj_, SL_IID_ENGINE, &slEngineItf_);
// slEngine = slEngineItf_;
bufSize = (bufSize + 7) >> 3;
mFrameSize = (bufSize + 3) & ~3;
mMaxBufSize=16000*3/mFrameSize*mFrameSize;//缓冲区3秒数据
if(mBuf==NULL)
mBuf=new unsigned char[mMaxBufSize];
//audioBuf = new uint8_t[mFrameSize];
SLAndroidDataFormat_PCM_EX format_pcm;
ConvertToSLSampleFormat(&format_pcm, &sampleInfo);
// configure audio source
SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE,
SL_IODEVICE_AUDIOINPUT,
SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};
SLDataSource audioSrc = {&loc_dev, NULL};
//int size = DataManager::GetInstance()->GetPoolSize(AUDIO_DATA);
for(int i=0;i<MAXAUDIONUM;i++)
if(mFrameList[i]==NULL)//没有考虑mFrameSize发生改变的情况
mFrameList[i]=new unsigned char[mFrameSize];
// configure audio sink
SLDataLocator_AndroidSimpleBufferQueue loc_bq = {
SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, (SLuint32)MAXAUDIONUM};//
SLDataSink audioSnk = {&loc_bq, &format_pcm};
// create audio recorder
// (requires the RECORD_AUDIO permission)
const SLInterfaceID id[2] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
SL_IID_ANDROIDCONFIGURATION};
const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
result = (*slEngineItf_)->CreateAudioRecorder(slEngineItf_, &recObjectItf_, &audioSrc, &audioSnk, sizeof(id) / sizeof(id[0]), id, req);
// SLASSERT(result);
// Configure the voice recognition preset which has no
// signal processing for lower latency.
SLAndroidConfigurationItf inputConfig;
result = (*recObjectItf_)
->GetInterface(recObjectItf_, SL_IID_ANDROIDCONFIGURATION,
&inputConfig);
if (SL_RESULT_SUCCESS == result)
{
SLuint32 presetValue = SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
(*inputConfig)
->SetConfiguration(inputConfig, SL_ANDROID_KEY_RECORDING_PRESET,
&presetValue, sizeof(SLuint32));
}
result = (*recObjectItf_)->Realize(recObjectItf_, SL_BOOLEAN_FALSE);
if (SL_RESULT_SUCCESS != result)
{
printf("audio input Realize error\n");
return;
}
result =
(*recObjectItf_)->GetInterface(recObjectItf_, SL_IID_RECORD, &recItf_);
if (SL_RESULT_SUCCESS != result)
{
printf("audio input GetInterface error\n");
return;
}
result = (*recObjectItf_)
->GetInterface(recObjectItf_, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
&recBufQueueItf_);
if (SL_RESULT_SUCCESS != result)
{
printf("audio input GetInterface error\n");
return;
}
result = (*recBufQueueItf_)
->RegisterCallback(recBufQueueItf_, bqRecorderCallback, this);
if (SL_RESULT_SUCCESS != result)
{
printf("audio input RegisterCallback error\n");
return ;
}
printf("audio input AudioRecorder Init out\n");
Start();
}
SLboolean AudioRecorder::Start(void)
{
printf("AudioRecorder Start in\n");
audioBufCount = 0;
SLresult result;
// in case already recording, stop recording and clear buffer queue
result = (*recItf_)->SetRecordState(recItf_, SL_RECORDSTATE_STOPPED);
if (SL_RESULT_SUCCESS != result)
{
printf("SetRecordState error\n");
return -1;
}
result = (*recBufQueueItf_)->Clear(recBufQueueItf_);
if (SL_RESULT_SUCCESS != result)
{
printf("Clear error\n");
return -1;
}
//int size = DataManager::GetInstance()->GetPoolSize(AUDIO_DATA);
//mStreamDataPool.setSize(size);
for (int i = 0; i < MAXAUDIONUM; i++)
{
//ImagePool *p = DataManager::GetInstance()->GetNewImagePool(AUDIO_DATA, mFrameSize);
result = (*recBufQueueItf_)->Enqueue(recBufQueueItf_, mFrameList[i], mFrameSize);
printf("Enqueue here \n");
if (SL_RESULT_SUCCESS != result)
{
printf("Enqueue error\n");
return -1;
}
}
result = (*recItf_)->SetRecordState(recItf_, SL_RECORDSTATE_RECORDING);
if (SL_RESULT_SUCCESS != result)
{
printf("SetRecordState error\n");
return -1;
}
printf("AudioRecorder Start out\n");
return (result == SL_RESULT_SUCCESS ? SL_BOOLEAN_TRUE : SL_BOOLEAN_FALSE);
}
SLboolean AudioRecorder::Stop(void)
{
// in case already recording, stop recording and clear buffer queue
if(mStart==0){
printf("audio input not open\n");
return SL_BOOLEAN_FALSE;
}
SLuint32 curState;
SLresult result = (*recItf_)->GetRecordState(recItf_, &curState);
if (curState == SL_RECORDSTATE_STOPPED)
{
return SL_BOOLEAN_TRUE;
}
result = (*recItf_)->SetRecordState(recItf_, SL_RECORDSTATE_STOPPED);
result = (*recBufQueueItf_)->Clear(recBufQueueItf_);
mStart=0;
return SL_BOOLEAN_TRUE;
}
AudioRecorder::AudioRecorder()
{
}
AudioRecorder::~AudioRecorder()
{
// destroy audio recorder object, and invalidate all associated interfaces
if (recObjectItf_ != NULL)
{
(*recObjectItf_)->Destroy(recObjectItf_);
}
if(mBuf)
delete []mBuf;
for(int i=0;i<MAXAUDIONUM;i++)
if(mFrameList[i])
delete []mFrameList[i];
}
CmakeLists.txt 加上 OpenSLES
大功告成