androi 直接使用AudioRecord.cpp 錄音的demo可執行程序,native層demo

       這個demo 直接使用AudioRecord.cpp 中提供的api,利用libmedia庫 寫一個c++程序,在android 的shell上運行,錄製音頻。
       爲什麼要這麼做,直接用android studio找一個錄音程序app demo它不香麼? 如果只是要個java的app,那是很方便,網上錄音的android app demo不少,使用Mediacodec或者AudioRecord, 但是要用來理解分析其內部的原理,從一個app demo上去分析那可真是費老大勁了,尤其對我這麼一個沒怎麼寫android app的程序員來說,跟蹤源碼從java 一路跳轉到jni, 最後還是到了 AudioRecord.cpp  ,所以這裏用一個c++的demo, 可香了,沒有Android studio的各種莫名其妙報錯,也沒有java的層層封裝,更沒有android 的種種權限問題, 這是一個純粹的c++的代碼,shell環境運行,擁有root權限。

       上代碼:(原本是從另一處博客摘抄過來https://blog.csdn.net/Romantic_Energy/article/details/50521970?utm_source=blogxgwz2,但是原博主寫得比較粗糙,故略作修改,並添上Android.mk, 代碼仍有很多缺陷,但是僅僅作爲demo而已,可以工作即ok, 基於android7.0 )
源碼文件 audio_record_test.cpp

#include<stdio.h>
#include<stdlib.h>


#if 1
#include <media/AudioRecord.h>
 using namespace android;
//==============================================
//	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");
		printf("[%d%s]EVENT_OVERRUN \n",__LINE__,__FUNCTION__);
	}
}
 
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";
	char 										strAudioFile[] 				= "./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
    size_t minFrameCount 	= 0;	// get from AudroRecord object
	int iWriteDataCount = 0;	// how many data are there write to file
	printf("[%d%s]thread enter ok!\n",__LINE__,__FUNCTION__);

	
	String16 pack_name("wang_test");
	

	printf("[%d%s]thread enter ok!\n",__LINE__,__FUNCTION__);
	
#if 1
	// log the thread id for debug info
	//LOGD("%s  Thread ID  = %d  \n", __FUNCTION__,  pthread_self());  
	printf("[%d%s]  Thread ID  = %d  \n", __LINE__,__FUNCTION__,  pthread_self());
	g_iInSampleTime = 0;
	g_pAudioRecordFile = fopen(strAudioFile, "wb+");	
	if(g_pAudioRecordFile == NULL)
	{
		printf("open file erro !\n");
	}
	
	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__);
		printf("[%d%s]AudioRecord.getMinFrameCount fail \n",__LINE__,__FUNCTION__);
		goto exit ;
	}
	
	//LOGE("sampleRateInHz = %d minFrameCount = %d iNbChannels = %d frameSize = %d ", 
	//	sampleRateInHz, minFrameCount, iNbChannels, frameSize);	
	printf("[%d%s]sampleRateInHz = %d minFrameCount = %d iNbChannels = %d frameSize = %d \n", 
		__LINE__,__FUNCTION__,sampleRateInHz, minFrameCount, iNbChannels, frameSize);
	
	bufferSizeInBytes = minFrameCount * frameSize;
	
	inBuffer = malloc(bufferSizeInBytes); 
	if(inBuffer == NULL)
	{		
		//LOGE("%s  alloc mem failed \n", __FUNCTION__);		
		printf("[%d%s]  alloc mem failed \n",__LINE__, __FUNCTION__);
		goto exit ; 
	}
 
	g_iNotificationPeriodInFrames = sampleRateInHz/10;	
	
	
	
	pAudioRecord  = new android::AudioRecord(pack_name);
	if(NULL == pAudioRecord)
	{
		//LOGE(" create native AudioRecord failed! ");
		printf(" [%d%s] create native AudioRecord failed! \n",__LINE__,__FUNCTION__);
		goto exit;
	}
	
	pAudioRecord->set( inputSource,
                                    sampleRateInHz,
                                    audioFormat,
                                    channelConfig,
                                    0,
                                    AudioRecordCallback,
                                    NULL,
                                    0,
                                    true); 
 
	if(pAudioRecord->initCheck() != android::NO_ERROR)  
	{
		//LOGE("AudioTrack initCheck error!");
		printf("[%d%s]AudioTrack initCheck error!\n",__LINE__,__FUNCTION__);
		goto exit;
	}
 
	if(pAudioRecord->setPositionUpdatePeriod(g_iNotificationPeriodInFrames) != android::NO_ERROR)
	{
		//LOGE("AudioTrack setPositionUpdatePeriod error!");
		printf("[%d%s]AudioTrack setPositionUpdatePeriod error!\n",__LINE__,__FUNCTION__);
		goto exit;
	}
	
	if(pAudioRecord->start()!= android::NO_ERROR)
	{
		//LOGE("AudioTrack start error!");
		printf("[%d%s]AudioTrack start error!\n",__LINE__,__FUNCTION__);
		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");
					printf("[%d%s]Write Audio Record Stream error\n",__LINE__,__FUNCTION__);
				}
			}			
 
			// 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");
			printf("[%d%s]pAudioRecord->read  readLen = 0\n",__LINE__,__FUNCTION__);
		}
	}
 
		
	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;
	}
#endif
	//LOGD("%s  Thread ID  = %d  quit\n", __FUNCTION__,  pthread_self());
	printf("[%d%s] Thread ID  = %d  quit\n", __LINE__,__FUNCTION__,  pthread_self());
	return NULL;
	
}

int main()
{
	printf("hello world! \n");	
	pthread_t record_pid ;
	if(pthread_create(&record_pid,NULL,AudioRecordThread,NULL)<0)
	{
		printf("%d%s pthread create erro !\n",__LINE__,__FUNCTION__);
	}
	
	while(1)
	{
		
	}
	return 0;
}
#else
#include<stdio.h>
#include<stdlib.h>
int main()
{
	printf("hello world! \n");
	return 0;
}
#endif

編譯文件 android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_C_INCLUDES := *你的源碼目錄/frameworks/av/include *你的源碼目錄/development/ndk/platforms/*sdk版本*/include/


LOCAL_SHARED_LIBRARIES:= liblog libmedia libutils libcutils
LOCAL_SRC_FILES:= \
audio_record_test.cpp
  
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE:= audio_record_test

LOCAL_CFLAGS += -g
#LOCAL_32_BIT_ONLY := true
include $(BUILD_EXECUTABLE)

最終結果,得到pcm 錄音文件:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章