//#define LOG_NDEBUG 0 #define LOG_TAG "sample_ai" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tsemaphore.h" #include #include "sample_ai2ao_config.h" #include "sample_ai2ao.h" #include static int ParseCmdLine(int argc, char **argv, SampleAI2AOCmdLineParam *pCmdLinePara) { alogd("sample_ai2ao path:[%s], arg number is [%d]", argv[0], argc); int ret = 0; int i=1; memset(pCmdLinePara, 0, sizeof(SampleAI2AOCmdLineParam)); while(i < argc) { if(!strcmp(argv[i], "-path")) { if(++i >= argc) { aloge("fatal error! use -h to learn how to set parameter!!!"); ret = -1; break; } if(strlen(argv[i]) >= MAX_FILE_PATH_SIZE) { aloge("fatal error! file path[%s] too long: [%d]>=[%d]!", argv[i], strlen(argv[i]), MAX_FILE_PATH_SIZE); } strncpy(pCmdLinePara->mConfigFilePath, argv[i], MAX_FILE_PATH_SIZE-1); pCmdLinePara->mConfigFilePath[MAX_FILE_PATH_SIZE-1] = '\0'; } else if(!strcmp(argv[i], "-h")) { alogd("CmdLine param:\n" "\t-path /home/sample_ai2ao.conf\n"); ret = 1; break; } else { alogd("ignore invalid CmdLine param:[%s], type -h to get how to set parameter!", argv[i]); } i++; } return ret; } static ERRORTYPE loadSampleAI2AOConfig(SampleAI2AOConfig *pConfig, const char *conf_path) { int ret; char *ptr; CONFPARSER_S stConfParser; sprintf(pConfig->mPcmFilePath, "/tmp/mictester_result.wav"); pConfig->mSampleRate = 44100; pConfig->mBitWidth = 16; pConfig->mChannelCnt = 2; pConfig->mFrameSize = 1024; pConfig->mTunnelMode = 1; pConfig->mCapDurationSec = 10; ret = createConfParser(conf_path, &stConfParser); if(ret < 0) { aloge("load conf fail"); return FAILURE; } memset(pConfig, 0, sizeof(SampleAI2AOConfig)); ptr = (char*)GetConfParaString(&stConfParser, SAMPLE_AI2AO_PCM_FILE_PATH, NULL); strncpy(pConfig->mPcmFilePath, ptr, MAX_FILE_PATH_SIZE-1); pConfig->mPcmFilePath[MAX_FILE_PATH_SIZE-1] = '\0'; pConfig->mSampleRate = GetConfParaInt(&stConfParser, SAMPLE_AI2AO_PCM_SAMPLE_RATE, 0); pConfig->mBitWidth = GetConfParaInt(&stConfParser, SAMPLE_AI2AO_PCM_BIT_WIDTH, 0); pConfig->mChannelCnt = GetConfParaInt(&stConfParser, SAMPLE_AI2AO_PCM_CHANNEL_CNT, 0); pConfig->mFrameSize = GetConfParaInt(&stConfParser, SAMPLE_AI2AO_PCM_FRAME_SIZE, 0); pConfig->mTunnelMode = GetConfParaInt(&stConfParser, SAMPLE_AI2AO_TUNNEL_MODE, 0); pConfig->mCapDurationSec = GetConfParaInt(&stConfParser, SAMPLE_AI2AO_CAP_DURATION, 0); alogd("parse info: mPcmFilePath[%s]", pConfig->mPcmFilePath); alogd(" mSampleRate[%d], mBitWidth[%d], mChannelCnt[%d], mFrameSize[%d], mTunnleMode[%d], mCapTime[%d]", pConfig->mSampleRate, pConfig->mBitWidth, pConfig->mChannelCnt, pConfig->mFrameSize, pConfig->mTunnelMode, pConfig->mCapDurationSec); destroyConfParser(&stConfParser); return SUCCESS; } void config_AIO_ATTR_S_by_SampleAI2AOConfig(AIO_ATTR_S *dst, SampleAI2AOConfig *src) { memset(dst, 0, sizeof(AIO_ATTR_S)); dst->u32ChnCnt = src->mChannelCnt; dst->enSamplerate = (AUDIO_SAMPLE_RATE_E)src->mSampleRate; dst->enBitwidth = (AUDIO_BIT_WIDTH_E)(src->mBitWidth/8-1); } void PcmDataAddWaveHeader(SampleAI2AOContext *ctx) { struct WaveHeader{ int riff_id; int riff_sz; int riff_fmt; int fmt_id; int fmt_sz; short audio_fmt; short num_chn; int sample_rate; int byte_rate; short block_align; short bits_per_sample; int data_id; int data_sz; } header; SampleAI2AOConfig *pConf = &ctx->mConfigPara; memcpy(&header.riff_id, "RIFF ", 4); header.riff_sz = ctx->mPcmSize + sizeof(struct WaveHeader) - 8; memcpy(&header.riff_fmt, "WAVE ", 4); memcpy(&header.fmt_id, "fmt ", 4); header.fmt_sz = 16; header.audio_fmt = 1; // s16le header.num_chn = pConf->mChannelCnt; header.sample_rate = pConf->mSampleRate; header.byte_rate = pConf->mSampleRate * pConf->mChannelCnt * pConf->mBitWidth/8; header.block_align = pConf->mChannelCnt * pConf->mBitWidth/8; header.bits_per_sample = pConf->mBitWidth; memcpy(&header.data_id, "data", 4); header.data_sz = ctx->mPcmSize; fseek(ctx->mFpPcmFile, 0, SEEK_SET); fwrite(&header, 1, sizeof(struct WaveHeader), ctx->mFpPcmFile); } ERRORTYPE aoDataListener(void *cookie, MPP_CHN_S *pChn, MPP_EVENT_TYPE event, void *pEventData) { SampleAI2AOContext *pCtx = (SampleAI2AOContext*)cookie; int ret; pcmFrameNode *pNode; switch (event) { case MPP_EVENT_RELEASE_AUDIO_BUFFER: pthread_mutex_lock(&pCtx->mPcmlock); pNode = list_first_entry(&pCtx->mPcmUsingList, pcmFrameNode, mList); pthread_mutex_unlock(&pCtx->mPcmlock); ret = AW_MPI_AI_ReleaseFrame(pCtx->mAIODev, pCtx->mAIChn, &pNode->frame, NULL); if (SUCCESS != ret) { aloge("release frame to ai fail! ret: %#x", ret); } else { pthread_mutex_lock(&pCtx->mPcmlock); list_move_tail(&pNode->mList, &pCtx->mPcmIdleList); pthread_mutex_unlock(&pCtx->mPcmlock); } break; default: alogd("unknown event: [%d]", event); break; } return 0; } static SampleAI2AOContext *gp_Ctx; void signalHandler(int signo) { alogd("detect signal, ready to finish test..."); if (gp_Ctx != NULL) { gp_Ctx->mOverFlag = TRUE; } else { aloge("Are you kidding me?! you must kill it by youself!"); } } #define TUNNEL_MODE //#define NON_TUNNEL_MODE int main(int argc, char *argv[]) { int result = 0; alogd("Hello, sample_ai2ao!"); SampleAI2AOContext stContext; memset(&stContext, 0, sizeof(SampleAI2AOContext)); gp_Ctx = &stContext; int disp_fd = -1; //parse command line param if(ParseCmdLine(argc, argv, &stContext.mCmdLinePara) != 0) { //aloge("fatal error! command line param is wrong, exit!"); result = -1; goto _exit; } char *pConfigFilePath; if(strlen(stContext.mCmdLinePara.mConfigFilePath) > 0) { pConfigFilePath = stContext.mCmdLinePara.mConfigFilePath; } else { pConfigFilePath = DEFAULT_SAMPLE_AI2AO_CONF_PATH; } //parse config file. if(loadSampleAI2AOConfig(&stContext.mConfigPara, pConfigFilePath) != SUCCESS) { aloge("fatal error! no config file or parse conf file fail"); result = -1; goto _exit; } //open pcm file stContext.mFpPcmFile = fopen(stContext.mConfigPara.mPcmFilePath, "wb"); if(!stContext.mFpPcmFile) { aloge("fatal error! can't open pcm file[%s]", stContext.mConfigPara.mPcmFilePath); result = -1; goto _exit; } else { alogd("sample_ai produce file: %s", stContext.mConfigPara.mPcmFilePath); fseek(stContext.mFpPcmFile, 44, SEEK_SET); // 44: size(WavHeader) } //init mpp system stContext.mSysConf.nAlignWidth = 32; AW_MPI_SYS_SetConf(&stContext.mSysConf); result = AW_MPI_SYS_Init(); if (SUCCESS != result) { goto _exit; } //enable ai&ao dev stContext.mAIODev = 0; config_AIO_ATTR_S_by_SampleAI2AOConfig(&stContext.mAIOAttr, &stContext.mConfigPara); AW_MPI_AI_SetPubAttr(stContext.mAIODev, &stContext.mAIOAttr); //AW_MPI_AI_Enable(stContext.mAIODev); //create ai channel. //ERRORTYPE result; BOOL bSuccessFlag = FALSE; stContext.mAIChn = 0; while(stContext.mAIChn < AIO_MAX_CHN_NUM) { result = AW_MPI_AI_CreateChn(stContext.mAIODev, stContext.mAIChn); if(SUCCESS == result) { bSuccessFlag = TRUE; alogd("create ai channel[%d] success!", stContext.mAIChn); break; } else if (ERR_AI_EXIST == result) { alogd("ai channel[%d] exist, find next!", stContext.mAIChn); stContext.mAIChn++; } else if(ERR_AI_NOT_ENABLED == result) { aloge("audio_hw_ai not started!"); break; } else { aloge("create ai channel[%d] fail! result[0x%x]!", stContext.mAIChn, result); break; } } if(FALSE == bSuccessFlag) { stContext.mAIChn = MM_INVALID_CHN; aloge("fatal error! create ai channel fail!"); goto _exit; } //create ao channel. bSuccessFlag = FALSE; stContext.mAOChn = 0; while(stContext.mAOChn < AIO_MAX_CHN_NUM) { result = AW_MPI_AO_CreateChn(stContext.mAIODev, stContext.mAOChn); if(SUCCESS == result) { bSuccessFlag = TRUE; alogd("create ao channel[%d] success!", stContext.mAOChn); break; } else if (ERR_AO_EXIST == result) { alogd("ao channel[%d] exist, find next!", stContext.mAOChn); stContext.mAOChn++; } else if(ERR_AO_NOT_ENABLED == result) { aloge("audio_hw_ao not started!"); break; } else { aloge("create ao channel[%d] fail! result[0x%x]!", stContext.mAOChn, result); break; } } if(FALSE == bSuccessFlag) { stContext.mAOChn = MM_INVALID_CHN; aloge("fatal error! create ao channel fail!"); goto _exit; } AIO_ATTR_S stAIOAttr; memset(&stAIOAttr, 0, sizeof(AIO_ATTR_S)); memcpy(&stAIOAttr, &stContext.mAIOAttr, sizeof(AIO_ATTR_S)); stAIOAttr.mPcmCardId = PCM_CARD_TYPE_AUDIOCODEC; AW_MPI_AO_SetPubAttr(stContext.mAIODev, stContext.mAOChn, &stContext.mAIOAttr); AW_MPI_AO_Enable(stContext.mAIODev, stContext.mAOChn); //register vo callback MPPCallbackInfo voCallback = {&stContext, aoDataListener}; AW_MPI_AO_RegisterCallback(stContext.mAIODev, stContext.mAOChn, &voCallback); //bind ai and ao MPP_CHN_S AIChn = {MOD_ID_AI, stContext.mAIODev, stContext.mAIChn}; MPP_CHN_S AOChn = {MOD_ID_AO, stContext.mAIODev, stContext.mAOChn}; if (stContext.mConfigPara.mTunnelMode) { AW_MPI_SYS_Bind(&AIChn, &AOChn); } bSuccessFlag = FALSE; stContext.mClockChnAttr.nWaitMask = 0; stContext.mClockChnAttr.nWaitMask |= 1<