您的位置:首页 > 编程语言 > C语言/C++

Android Native C++ 层中使用AudioRecord录制PCM音频

2016-01-15 10:23 686 查看
Android应用程序很少会用到Android Native C++ 层中AudioRecord来录制PCM,但也不是完全没有需求,至少这么做可以在不懂C++的程序员面前装装逼!

直接在Native C++层录制和处理PCM数据可以避免数据拷贝到虚拟机,再由虚拟机拷回到Native C++层;虽然这个消耗笔者认为应该不大,但是没有具体分析过虚拟机,不清楚,有知道的朋友请告诉一下。

本文描述了在Android Native C++ 层中使用AudioRecord录制PCM音频的一般方法,希望对有此需求的童鞋有所帮助。

C++层的AudioRecord类位于源码目录\frameworks\av\include\media\AudioRecord.h中,定义如下:

namespace android {

class audio_track_cblk_t;
// ----------------------------------------------------------------------------
class AudioRecord : virtual public RefBase
{
public:
static const int DEFAULT_SAMPLE_RATE = 8000;
...
} //end of calss
} //end of namespace android


可以看到AudioRecord位于android名字空间中,继承于RefBase,这个基类是智能指针引用计数用的,而
class AudioRecord : virtual public RefBase
虚继承是为了解决菱形继承问题,让从不同的路径继承过来的同一个类在子类内存中只有一个拷贝。

以下是具体代码:

#include <media/AudioRecord.h>

//==============================================
//	Audio Record Defination
//==============================================

static pthread_t		g_AudioRecordThread;
static pthread_t *	g_AudioRecordThreadPtr = NULL;

volatile bool 			g_bQuitAudioRecordThread = false;
volatile int 				g_iInSampleTime = 0;
int 								g_iNotificationPeriodInFrames = 8000/10;
// g_iNotificationPeriodInFrames should be change when sample rate changes.

static void *	AudioRecordThread( void *inArg );
void StartAudioRecordThread();
void StopAudioRecordThread();

void AudioRecordCallback(int event, void* user, void *info)
{
if(event == android::AudioRecord::EVENT_NEW_POS)
{
g_iInSampleTime += g_iNotificationPeriodInFrames;
//if(g_iInSampleTime > g_iNotificationPeriodInFrames*100)
//		g_bQuitAudioRecordThread = true;
}
else if (event == android::AudioRecord::EVENT_MORE_DATA)
{
android::AudioRecord::Buffer* pBuff = (android::AudioRecord::Buffer*)info;
pBuff->size = 0;
}
else if (event == android::AudioRecord::EVENT_OVERRUN)
{
LOGE(" EVENT_OVERRUN \n");
}
}

static void *	AudioRecordThread( void *inArg )
{
uint64_t  						inHostTime 				= 0;
void *								inBuffer 					= NULL;
audio_source_t 				inputSource 			= AUDIO_SOURCE_MIC;
audio_format_t 				audioFormat 			= AUDIO_FORMAT_PCM_16_BIT;
audio_channel_mask_t 	channelConfig 		= AUDIO_CHANNEL_IN_MONO; //AUDIO_CHANNEL_IN_STEREO;
int 									bufferSizeInBytes = 1600;
int 									sampleRateInHz 		= 8000;
android::AudioRecord *	pAudioRecord 		= NULL;
FILE * 									g_pAudioRecordFile 		= NULL;
char 										strAudioFile[] 				= "/mnt/sdcard/external_sd/AudioRecordFile.pcm";

int iNbChannels 		= 1;	// 1 channel for mono, 2 channel for streo
int iBytesPerSample = 2; 	// 16bits pcm, 2Bytes
int frameSize 			= 0;	// frameSize = iNbChannels * iBytesPerSample
int minFrameCount 	= 0;	// get from AudroRecord object
int iWriteDataCount = 0;	// how many data are there write to file

// log the thread id for debug info
LOGD("%s  Thread ID  = %d  \n", __FUNCTION__,  pthread_self());
g_iInSampleTime = 0;
g_pAudioRecordFile = fopen(strAudioFile, "wb+");

iNbChannels = (channelConfig == AUDIO_CHANNEL_IN_STEREO) ? 2 : 1;
frameSize 	= iNbChannels * iBytesPerSample;

android::status_t 	status = android::AudioRecord::getMinFrameCount(
&minFrameCount, sampleRateInHz, audioFormat, channelConfig);

if(status != android::NO_ERROR)
{
LOGE("%s  AudioRecord.getMinFrameCount fail \n", __FUNCTION__);
goto exit ;
}

LOGE("sampleRateInHz = %d minFrameCount = %d iNbChannels = %d frameSize = %d ",
sampleRateInHz, minFrameCount, iNbChannels, frameSize);

bufferSizeInBytes = minFrameCount * frameSize;

inBuffer = malloc(bufferSizeInBytes);
if(inBuffer == NULL)
{
LOGE("%s  alloc mem failed \n", __FUNCTION__);
goto exit ;
}

g_iNotificationPeriodInFrames = sampleRateInHz/10;

pAudioRecord  = new android::AudioRecord();
if(NULL == pAudioRecord)
{
LOGE(" create native AudioRecord failed! ");
goto exit;
}

pAudioRecord->set( inputSource,
sampleRateInHz,
audioFormat,
channelConfig,
0,
AudioRecordCallback,
NULL,
0,
true,
0);

if(pAudioRecord->initCheck() != android::NO_ERROR)
{
LOGE("AudioTrack initCheck error!");
goto exit;
}

if(pAudioRecord->setPositionUpdatePeriod(g_iNotificationPeriodInFrames) != android::NO_ERROR)
{
LOGE("AudioTrack setPositionUpdatePeriod error!");
goto exit;
}

if(pAudioRecord->start()!= android::NO_ERROR)
{
LOGE("AudioTrack start error!");
goto exit;
}

while (!g_bQuitAudioRecordThread)
{
inHostTime = UpTicks();
int readLen = pAudioRecord->read(inBuffer, bufferSizeInBytes);
int writeResult = -1;

if(readLen > 0)
{
iWriteDataCount += readLen;
if(NULL != g_pAudioRecordFile)
{
writeResult = fwrite(inBuffer, 1, readLen, g_pAudioRecordFile);
if(writeResult < readLen)
{
LOGE("Write Audio Record Stream error");
}
}

// write PCM data to file or other stream,implement it yourself
writeResult = WriteAudioData(
g_iInSampleTime,
inHostTime,
inBuffer,
readLen);

//LOGD("readLen = %d  writeResult = %d  iWriteDataCount = %d", readLen, writeResult, iWriteDataCount);
}
else
{
LOGE("pAudioRecord->read  readLen = 0");
}
}

exit:

if(NULL != g_pAudioRecordFile)
{
fflush(g_pAudioRecordFile);
fclose(g_pAudioRecordFile);
g_pAudioRecordFile = NULL;
}

if(pAudioRecord)
{
pAudioRecord->stop();
delete pAudioRecord;
pAudioRecord == NULL;
}

if(inBuffer)
{
free(inBuffer);
inBuffer = NULL;
}

LOGD("%s  Thread ID  = %d  quit\n", __FUNCTION__,  pthread_self());
return NULL;
}


呕心沥血所作,有用请点赞!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Android Native C C++