#include "includes.h" #include "nwy_audio_api.h" #define THREAD_AUDIO_STACK_SIZE (1024*10) nwy_osiThread_t *learnRecThread=NULL; nwy_osiThread_t *learnPlyThread=NULL; unsigned char recPcm[320]; bool recoderStatus=false; LEARN_REC_DEF learnAudio={NULL}; typedef struct{ unsigned short maxVolume;//最大音量 float avSpeed;//录音平均语速 int64_t time;//记录录音时长 unsigned char charactorNum;//单词个数 }LEARN_REC_RESULT_DEF;//录音结果 LEARN_REC_RESULT_DEF recordResult; static void learnRecTask(void *param); static void processRecData(void); static int recordDataCb(unsigned char *pcm, unsigned int len); static void pcmVolProcess(unsigned char *pcm, unsigned int len); static void initRecResult(unsigned char charaNum){ recordResult.maxVolume=0; recordResult.avSpeed=0; recordResult.time=nwy_get_ms(); recordResult.charactorNum=charaNum; } static void recordResultMake(void){ int64_t time; float tmp; time=nwy_get_ms(); time = time-recordResult.time; if(time<1) time=1;//最小为1秒 tmp=recordResult.charactorNum; recordResult.avSpeed = 1000*tmp/time;//单词/秒 MSG_INFO(1, "Chara speed:%.1f,num:%d,t:%lldms", recordResult.avSpeed, recordResult.charactorNum,time); } /*获取本次录音过程中的最大音量值*/ unsigned short learnGetRecordMaxVolume(void){ //return (recordResult.maxVolume*LEV_NUM/0x7FFF); return recordResult.maxVolume; } #define SPEED_FACTOR 4 /*获取本次录音的语速:单词/秒*/ float learnGetRecordRecSpeed(void){ float speedscore=getLearnSpeedParam()*recordResult.avSpeed*SPEED_FACTOR; if(speedscore>10) speedscore=10; return speedscore; } bool learnStartRecord(unsigned char charaNum){ //初始化编码器 #ifdef ENABLE_ENABLE_AMRNB if(AMRC_INIT_OK != wamr_encoder_init()){ MSG_ERR(1, "wamr encoder init failed"); goto R_END; } if(learnAudio.pcm==NULL) learnAudio.pcm=(unsigned char *)malloc((1+FRAME_PER_SIZE)*MAX_FRAMES_TOTAL); #endif #ifdef ENABLE_ENABLE_SPEEX int quality=FRAME_QULITY; int ret; learnAudio.speexCt = speex_encoder_init(speex_lib_get_mode(SPEEX_MODEID_NB)); if(NULL==learnAudio.speexCt){ MSG_ERR(1, "speex encoder init failed"); goto R_END; } ret=speex_encoder_ctl(learnAudio.speexCt, SPEEX_SET_QUALITY, &quality); if(ret!=0){ MSG_ERR(1, "speed encoder ctl failed"); goto R_END; } speex_bits_init(&learnAudio.bits); if(learnAudio.pcm==NULL) learnAudio.pcm=(unsigned char *)malloc((FRAME_PER_SIZE)*MAX_FRAMES_TOTAL); #endif if(NULL==learnAudio.pcm){ MSG_ERR(1, "recorder malloc buf failed"); goto R_END; } MSG_INFO(1, "[mem malloc]%x",learnAudio.pcm); //创建线程去处理接收到的录音数据 learnRecThread=nwy_create_thread("learnRecTask", learnRecTask, NULL, NWY_OSI_PRIORITY_NORMAL, THREAD_AUDIO_STACK_SIZE, 6); if(learnRecThread==NULL){ MSG_ERR(1, "record rec thread err"); goto R_END; } initRecResult(charaNum); if(NWY_SUCESS != nwy_audio_recorder_open(recordDataCb)){ MSG_ERR(1, "recorder open failed"); goto R_END; } if(NWY_SUCESS != nwy_audio_recorder_start()){ MSG_ERR(1, "recorder start failed"); nwy_audio_recorder_close(); goto R_END; } appSleepCtl(ASLEEP_LEARN, 1); learnAudio.frameNum=0; learnAudio.frameSize=0; recoderStatus=true; return true; R_END: #ifdef ENABLE_ENABLE_AMRNB wamr_encoder_uninit(); if(NULL != learnAudio.pcm){ free(learnAudio.pcm); learnAudio.pcm=NULL; } #endif #ifdef ENABLE_ENABLE_SPEEX if(learnAudio.speexCt!=NULL){ speex_encoder_destroy(learnAudio.speexCt); learnAudio.speexCt=NULL; } #endif if(NULL != learnRecThread){ threadSendEvent(learnRecThread,OHPOC_EVENT_LEARN,0,NULL,NULL);//退出 } } /*停止录音*/ void learnStopRecord(void){ if(recoderStatus==false) return; nwy_audio_recorder_stop(); nwy_audio_recorder_close(); recoderStatus=false; appSleepCtl(ASLEEP_LEARN, 0); recordResultMake(); } /*录音接收处理线程*/ static void learnRecTask(void *param){ nwy_osiEvent_t event = {}; MSG_INFO(1, "learnRecTask start"); for(;;){ nwy_wait_thead_event(nwy_get_current_thread(), &event,0); if(event.id==OHPOC_EVENT_LEARN){ if(event.param1==0) break; else if(event.param1==1) processRecData(); } } MSG_INFO(1, "learnRecTask exit"); learnRecThread=NULL; nwy_exit_thread(); } /*处理具体的录音数据*/ static void processRecData(void){ unsigned short outlen; unsigned int i; unsigned char *pcm=recPcm; pcmVolProcess(recPcm, 320);//计算平均音量 #ifdef ENABLE_ENABLE_AMRNB unsigned char tbuf[100]; int ret; ret=wamr_encoder_encode_frame((short *)pcm, 160, tbuf,sizeof(tbuf), &outlen, UMR122); if(AMRC_CODEC_SUCC != ret){ MSG_WARN(1, "amrnb encode err"); return 0; } if(outlen != FRAME_PER_SIZE){ MSG_WARN(1, "amrnb encode size unfix:%d", outlen); return 0; } #endif #ifdef ENABLE_ENABLE_SPEEX #define T_FRAME_SIZE 160 float input[T_FRAME_SIZE]; short tmp; char tbuf[70];//不小于62 for(i=0;i=MAX_FRAMES_TOTAL){ MSG_WARN(1, "record max buf, stop rec"); learnRecSetStatus(LEARN_REC_OT); } } } //释放录音时的资源 void learnRecordFree(void){ if(NULL != learnRecThread){ threadSendEvent(learnRecThread,OHPOC_EVENT_LEARN,0,NULL,NULL);//退出 } #ifdef ENABLE_ENABLE_AMRNB wamr_encoder_uninit(); #endif #ifdef ENABLE_ENABLE_SPEEX speex_encoder_destroy(learnAudio.speexCt);learnAudio.speexCt=NULL; speex_bits_destroy(&learnAudio.bits); #endif } /*释放已申请的临时缓存空间*/ void learnRecordBufRelease(void){ if(learnAudio.pcm==NULL) return; MSG_INFO(1, "[mem free]%x",learnAudio.pcm); free(learnAudio.pcm); learnAudio.pcm=NULL; } /*录音回调,不能在里面做太多事件*/ static int recordDataCb(unsigned char *pcm, unsigned int len){ if(len != 320) return; memcpy(recPcm, pcm, len); if(NULL != learnRecThread) threadSendEvent(learnRecThread, OHPOC_EVENT_LEARN, 1, NULL, NULL);//通知线程处理数据 return 0; } #ifdef SAVE_PCM_SD int sdFd=-1; void pcmFileOpen(void){ int fd; char file[50]; if(sdFd>0) return; snprintf(file, sizeof(file), "%s/pcm_low.rec", SD_TOKEN); fd = nwy_sdk_fopen(file, NWY_CREAT | NWY_RDWR|NWY_TRUNC);//清0式 if(fd<0){ MSG_INFO(1,"open failed"); return; } sdFd=fd; MSG_INFO(1,"open ok"); } void pcmFileClose(void){ if(sdFd<0){ MSG_INFO(1,"no need close"); return; } nwy_sdk_fclose(sdFd); MSG_INFO(1,"close ok"); sdFd=-1; } void pcmSaveData(unsigned char *pcm, int len){ if(sdFd<0){ MSG_INFO(1,"not open"); return; } nwy_sdk_fwrite(sdFd, pcm, len); } #endif static void pcmVolProcess(unsigned char *pcm, unsigned int len){ #ifdef SAVE_PCM_SD pcmSaveData(pcm,len); #else //对语音数据进行平均音量分析,分析方法为累加,并求平均值,静音时是为0的值 #define VOL_SUM_FRAME 5 #define VOL_SHORT_LEV (VOL_SUM_FRAME*160) short *ptr=(short *)pcm; int i; static unsigned short frameVolNum=0; unsigned int sum=0,tmp; static unsigned int pcmSum=0; //char info[60]; if(len != 320) return; for(i=0;i<160;i++){ tmp=abs(ptr[i]); pcmSum += tmp; } if(++frameVolNum>=VOL_SUM_FRAME){ sum=pcmSum/VOL_SHORT_LEV; //snprintf(info, sizeof(info), "[0]{%d}",sum); //nwy_usb_serial_send(info, strlen(info)); //MSG_INFO(1, "pcm:%lu,%lu", sum,pcmSum); sum *= (LEV_NUM-0); sum /=4000;//10000; //MSG_INFO(1,"===%d",sum); if(sum >(LEV_NUM-0)) sum = LEV_NUM-0; learnRecSetVol(sum); if(sum > recordResult.maxVolume){ recordResult.maxVolume=sum;//计算每一帧的最大音量 //MSG_INFO(1,"=======%d", sum); } pcmSum=0; frameVolNum=0; } #endif } static int player_cb(nwy_player_status state){ MSG_INFO(1,"player_cb state=%d", state); if(0==state){//播放完毕了 MSG_INFO(1,"pcm play finished"); } } static void learnPlayStop(void){ nwy_audio_player_stop(); nwy_audio_player_close(); } static bool learnPlayStart(void){ if(NWY_SUCESS!=nwy_audio_player_open(player_cb)) return false; else return true; } void spkControl(bool status){ if(true==status) sutPocStatus.spk=1; else sutPocStatus.spk=0; paControl(status); } LEARN_PLY_ENUM learnPlayStatus; static void learnPlyTask(void *param){ unsigned char *pcmPtr; float output[T_FRAME_SIZE]; short out[T_FRAME_SIZE]; short tmp,i; unsigned char audioType; unsigned char vFileBuf[FRAME_PER_SIZE]; unsigned int addr; MSG_INFO(1, "learnPlyTask start"); appSleepCtl(ASLEEP_LEARN, 1); spkControl(true); audioType=learnAudio.playType; learnAudio.plyNum=0; if(audioType==0){//播放临时录音 while(learnAudio.plyNum=learnAudio.frameNum){ learnPlayStatus=LEARN_PLY_DONE;//播放成功,结束 break; } } } //释放资源 learnPlayStop(); if(learnAudio.speexCt!=NULL){ speex_decoder_destroy(learnAudio.speexCt); speex_bits_destroy(&learnAudio.bits); learnAudio.speexCt=NULL; } if(learnAudio.fd>0){ nwy_sdk_fclose(learnAudio.fd); learnAudio.fd=-1; } MSG_INFO(1, "learnPlyTask exit"); learnPlyThread=NULL; spkControl(false); appSleepCtl(ASLEEP_LEARN, 0); nwy_exit_thread(); } void learnPlayAudio(unsigned char type, const char *fname){ char file[50]; unsigned char size; int tmp=1; learnAudio.playType=type; if(NULL!=learnPlyThread){//使用线程播放吧 MSG_INFO(1, "learnPlyTask is busy"); return; } if(type != 0){//播放本地文件 //只读方式打开文件 snprintf(file, sizeof(file), "%s/%s.rec", SD_TOKEN, fname); learnAudio.fd=nwy_sdk_fopen(file, NWY_RDONLY); if(learnAudio.fd<0){ MSG_ERR(1, "open %s.rec to play failed", fname); goto P_EXIT; } nwy_sdk_fread(learnAudio.fd, (unsigned char *)&learnAudio.frameNum, 4); nwy_sdk_fseek(learnAudio.fd, 4, NWY_SEEK_SET); nwy_sdk_fread(learnAudio.fd, &size, 1); learnAudio.frameSize=size; if(learnAudio.frameNum > MAX_FRAMES_TOTAL || learnAudio.frameSize != FRAME_PER_SIZE){ MSG_ERR(1, "%s.rec header err:%d,%d", learnAudio.frameNum,learnAudio.frameSize); goto P_EXIT; } } //播放临时缓存中的语音/本地文件都需要初始化以下操作 learnAudio.stopPlay=false; learnPlayStatus=LEARN_PLY_IDLE; //解码初始化 learnAudio.speexCt=speex_decoder_init(speex_lib_get_mode(SPEEX_MODEID_NB)); if(NULL==learnAudio.speexCt){ MSG_ERR(1, "play decoder init failed"); goto P_EXIT; } if(0!=speex_decoder_ctl(learnAudio.speexCt, SPEEX_SET_ENH, &tmp)){ MSG_ERR(1, "player decoder ctl failed"); goto P_EXIT; } speex_bits_init(&learnAudio.bits); //打开播放设备 if(true!=learnPlayStart()){ MSG_ERR(1, "play open failed"); goto P_EXIT; } //申请线程 learnPlyThread=nwy_create_thread("learnPlyTask", learnPlyTask, NULL, NWY_OSI_PRIORITY_NORMAL, THREAD_AUDIO_STACK_SIZE, 4); if(learnPlyThread==NULL){ MSG_ERR(1, "play thread err"); goto P_EXIT; } learnPlayStatus=LEARN_PLY_BUSY; MSG_INFO(1, "start play process ok"); return; P_EXIT: MSG_INFO(1, "learnPlayAudio exit:%d",type); learnPlayStatus=LEARN_PLY_PRE_ERR;//播放准备失败 if(learnAudio.speexCt != NULL){ speex_decoder_destroy(learnAudio.speexCt); speex_bits_destroy(&learnAudio.bits); learnAudio.speexCt=NULL; } if(learnAudio.fd>0){ nwy_sdk_fclose(learnAudio.fd); learnAudio.fd=-1; } if(learnPlyThread != NULL) learnPlayStop(); } LEARN_PLY_ENUM learnPlyGetResult(void){return learnPlayStatus;} //获取当前播放的类型:0 播放的是临时录音 1 播放的是本地录音 unsigned char learnGetAudioType(void){return learnAudio.playType;} void learnStopPlaying(void){ learnAudio.stopPlay=true; } /*将临时语音保存到本地.rec文件中,覆盖式*/ void recordSaveTmpToLocal(char *fileName){ char file[50]; int fd; unsigned int total; snprintf(file, sizeof(file), "%s/%s.rec", SD_TOKEN, fileName); fd = nwy_sdk_fopen(file, NWY_CREAT | NWY_RDWR|NWY_TRUNC);//清0式 if(fd<0){ MSG_WARN(1, "Save record file fopen failed,%s", fileName); return; } memcpy(file, (unsigned char *)&learnAudio.frameNum, 4); //memcpy(file+4, (unsigned char *)&learnAudio.frameSize, 2); nwy_sdk_fwrite(fd, file, 4); total=learnAudio.frameNum*learnAudio.frameSize+1; nwy_sdk_fwrite(fd, learnAudio.pcm, total); nwy_sdk_fclose(fd); MSG_INFO(1, "Save task %s:%d bytes done", fileName, total+4); } unsigned char *learnGetTmpAudioBuf(void){ return learnAudio.pcm; } unsigned int learnGetTmpAudioLength(void){ return learnAudio.frameNum*learnAudio.frameSize; }