learnAudio.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. #include "includes.h"
  2. #include "nwy_audio_api.h"
  3. #define THREAD_AUDIO_STACK_SIZE (1024*10)
  4. nwy_osiThread_t *learnRecThread=NULL;
  5. nwy_osiThread_t *learnPlyThread=NULL;
  6. unsigned char recPcm[320];
  7. bool recoderStatus=false;
  8. LEARN_REC_DEF learnAudio={NULL};
  9. typedef struct{
  10. unsigned short maxVolume;//最大音量
  11. float avSpeed;//录音平均语速
  12. int64_t time;//记录录音时长
  13. unsigned char charactorNum;//单词个数
  14. }LEARN_REC_RESULT_DEF;//录音结果
  15. LEARN_REC_RESULT_DEF recordResult;
  16. static void learnRecTask(void *param);
  17. static void processRecData(void);
  18. static int recordDataCb(unsigned char *pcm, unsigned int len);
  19. static void pcmVolProcess(unsigned char *pcm, unsigned int len);
  20. static void initRecResult(unsigned char charaNum){
  21. recordResult.maxVolume=0;
  22. recordResult.avSpeed=0;
  23. recordResult.time=nwy_get_ms();
  24. recordResult.charactorNum=charaNum;
  25. }
  26. static void recordResultMake(void){
  27. int64_t time;
  28. float tmp;
  29. time=nwy_get_ms();
  30. time = time-recordResult.time;
  31. if(time<1) time=1;//最小为1秒
  32. tmp=recordResult.charactorNum;
  33. recordResult.avSpeed = 1000*tmp/time;//单词/秒
  34. MSG_INFO(1, "Chara speed:%.1f,num:%d,t:%lldms", recordResult.avSpeed, recordResult.charactorNum,time);
  35. }
  36. /*获取本次录音过程中的最大音量值*/
  37. unsigned short learnGetRecordMaxVolume(void){
  38. //return (recordResult.maxVolume*LEV_NUM/0x7FFF);
  39. return recordResult.maxVolume;
  40. }
  41. #define SPEED_FACTOR 4
  42. /*获取本次录音的语速:单词/秒*/
  43. float learnGetRecordRecSpeed(void){
  44. float speedscore=getLearnSpeedParam()*recordResult.avSpeed*SPEED_FACTOR;
  45. if(speedscore>10) speedscore=10;
  46. return speedscore;
  47. }
  48. bool learnStartRecord(unsigned char charaNum){
  49. //初始化编码器
  50. #ifdef ENABLE_ENABLE_AMRNB
  51. if(AMRC_INIT_OK != wamr_encoder_init()){
  52. MSG_ERR(1, "wamr encoder init failed");
  53. goto R_END;
  54. }
  55. if(learnAudio.pcm==NULL) learnAudio.pcm=(unsigned char *)malloc((1+FRAME_PER_SIZE)*MAX_FRAMES_TOTAL);
  56. #endif
  57. #ifdef ENABLE_ENABLE_SPEEX
  58. int quality=FRAME_QULITY;
  59. int ret;
  60. learnAudio.speexCt = speex_encoder_init(speex_lib_get_mode(SPEEX_MODEID_NB));
  61. if(NULL==learnAudio.speexCt){
  62. MSG_ERR(1, "speex encoder init failed");
  63. goto R_END;
  64. }
  65. ret=speex_encoder_ctl(learnAudio.speexCt, SPEEX_SET_QUALITY, &quality);
  66. if(ret!=0){
  67. MSG_ERR(1, "speed encoder ctl failed");
  68. goto R_END;
  69. }
  70. speex_bits_init(&learnAudio.bits);
  71. if(learnAudio.pcm==NULL) learnAudio.pcm=(unsigned char *)malloc((FRAME_PER_SIZE)*MAX_FRAMES_TOTAL);
  72. #endif
  73. if(NULL==learnAudio.pcm){
  74. MSG_ERR(1, "recorder malloc buf failed");
  75. goto R_END;
  76. }
  77. MSG_INFO(1, "[mem malloc]%x",learnAudio.pcm);
  78. //创建线程去处理接收到的录音数据
  79. learnRecThread=nwy_create_thread("learnRecTask", learnRecTask, NULL, NWY_OSI_PRIORITY_NORMAL, THREAD_AUDIO_STACK_SIZE, 6);
  80. if(learnRecThread==NULL){
  81. MSG_ERR(1, "record rec thread err");
  82. goto R_END;
  83. }
  84. initRecResult(charaNum);
  85. if(NWY_SUCESS != nwy_audio_recorder_open(recordDataCb)){
  86. MSG_ERR(1, "recorder open failed");
  87. goto R_END;
  88. }
  89. if(NWY_SUCESS != nwy_audio_recorder_start()){
  90. MSG_ERR(1, "recorder start failed");
  91. nwy_audio_recorder_close();
  92. goto R_END;
  93. }
  94. appSleepCtl(ASLEEP_LEARN, 1);
  95. learnAudio.frameNum=0;
  96. learnAudio.frameSize=0;
  97. recoderStatus=true;
  98. return true;
  99. R_END:
  100. #ifdef ENABLE_ENABLE_AMRNB
  101. wamr_encoder_uninit();
  102. if(NULL != learnAudio.pcm){
  103. free(learnAudio.pcm);
  104. learnAudio.pcm=NULL;
  105. }
  106. #endif
  107. #ifdef ENABLE_ENABLE_SPEEX
  108. if(learnAudio.speexCt!=NULL){
  109. speex_encoder_destroy(learnAudio.speexCt);
  110. learnAudio.speexCt=NULL;
  111. }
  112. #endif
  113. if(NULL != learnRecThread){
  114. threadSendEvent(learnRecThread,OHPOC_EVENT_LEARN,0,NULL,NULL);//退出
  115. }
  116. }
  117. /*停止录音*/
  118. void learnStopRecord(void){
  119. if(recoderStatus==false) return;
  120. nwy_audio_recorder_stop();
  121. nwy_audio_recorder_close();
  122. recoderStatus=false;
  123. appSleepCtl(ASLEEP_LEARN, 0);
  124. recordResultMake();
  125. }
  126. /*录音接收处理线程*/
  127. static void learnRecTask(void *param){
  128. nwy_osiEvent_t event = {};
  129. MSG_INFO(1, "learnRecTask start");
  130. for(;;){
  131. nwy_wait_thead_event(nwy_get_current_thread(), &event,0);
  132. if(event.id==OHPOC_EVENT_LEARN){
  133. if(event.param1==0) break;
  134. else if(event.param1==1) processRecData();
  135. }
  136. }
  137. MSG_INFO(1, "learnRecTask exit");
  138. learnRecThread=NULL;
  139. nwy_exit_thread();
  140. }
  141. /*处理具体的录音数据*/
  142. static void processRecData(void){
  143. unsigned short outlen;
  144. unsigned int i;
  145. unsigned char *pcm=recPcm;
  146. pcmVolProcess(recPcm, 320);//计算平均音量
  147. #ifdef ENABLE_ENABLE_AMRNB
  148. unsigned char tbuf[100];
  149. int ret;
  150. ret=wamr_encoder_encode_frame((short *)pcm, 160, tbuf,sizeof(tbuf), &outlen, UMR122);
  151. if(AMRC_CODEC_SUCC != ret){
  152. MSG_WARN(1, "amrnb encode err");
  153. return 0;
  154. }
  155. if(outlen != FRAME_PER_SIZE){
  156. MSG_WARN(1, "amrnb encode size unfix:%d", outlen);
  157. return 0;
  158. }
  159. #endif
  160. #ifdef ENABLE_ENABLE_SPEEX
  161. #define T_FRAME_SIZE 160
  162. float input[T_FRAME_SIZE];
  163. short tmp;
  164. char tbuf[70];//不小于62
  165. for(i=0;i<T_FRAME_SIZE;i++){
  166. tmp=pcm[2*i+1];tmp <<= 8;
  167. tmp |= pcm[2*i];
  168. input[i]=tmp;
  169. }
  170. speex_bits_reset(&learnAudio.bits);
  171. speex_encode(learnAudio.speexCt, input, &learnAudio.bits);
  172. outlen=speex_bits_write(&learnAudio.bits, tbuf, sizeof(tbuf));
  173. #endif
  174. if(learnAudio.frameNum<MAX_FRAMES_TOTAL){
  175. if(learnAudio.frameNum==0) learnAudio.frameSize=outlen;
  176. #ifdef ENABLE_ENABLE_AMRNB
  177. i=learnAudio.frameNum*(1+FRAME_PER_SIZE);
  178. learnAudio.pcm[i++]=FRAME_PER_SIZE;
  179. #endif
  180. #ifdef ENABLE_ENABLE_SPEEX
  181. if(learnAudio.frameNum==0) learnAudio.pcm[0]=FRAME_PER_SIZE;//第一字节表示后面的音频帧长度(每帧)
  182. i=1+learnAudio.frameNum*(0+FRAME_PER_SIZE);
  183. #endif
  184. memcpy(learnAudio.pcm+i, tbuf, FRAME_PER_SIZE);
  185. if(++learnAudio.frameNum>=MAX_FRAMES_TOTAL){
  186. MSG_WARN(1, "record max buf, stop rec");
  187. learnRecSetStatus(LEARN_REC_OT);
  188. }
  189. }
  190. }
  191. //释放录音时的资源
  192. void learnRecordFree(void){
  193. if(NULL != learnRecThread){
  194. threadSendEvent(learnRecThread,OHPOC_EVENT_LEARN,0,NULL,NULL);//退出
  195. }
  196. #ifdef ENABLE_ENABLE_AMRNB
  197. wamr_encoder_uninit();
  198. #endif
  199. #ifdef ENABLE_ENABLE_SPEEX
  200. speex_encoder_destroy(learnAudio.speexCt);learnAudio.speexCt=NULL;
  201. speex_bits_destroy(&learnAudio.bits);
  202. #endif
  203. }
  204. /*释放已申请的临时缓存空间*/
  205. void learnRecordBufRelease(void){
  206. if(learnAudio.pcm==NULL) return;
  207. MSG_INFO(1, "[mem free]%x",learnAudio.pcm);
  208. free(learnAudio.pcm);
  209. learnAudio.pcm=NULL;
  210. }
  211. /*录音回调,不能在里面做太多事件*/
  212. static int recordDataCb(unsigned char *pcm, unsigned int len){
  213. if(len != 320) return;
  214. memcpy(recPcm, pcm, len);
  215. if(NULL != learnRecThread)
  216. threadSendEvent(learnRecThread, OHPOC_EVENT_LEARN, 1, NULL, NULL);//通知线程处理数据
  217. return 0;
  218. }
  219. #ifdef SAVE_PCM_SD
  220. int sdFd=-1;
  221. void pcmFileOpen(void){
  222. int fd;
  223. char file[50];
  224. if(sdFd>0) return;
  225. snprintf(file, sizeof(file), "%s/pcm_low.rec", SD_TOKEN);
  226. fd = nwy_sdk_fopen(file, NWY_CREAT | NWY_RDWR|NWY_TRUNC);//清0式
  227. if(fd<0){
  228. MSG_INFO(1,"open failed");
  229. return;
  230. }
  231. sdFd=fd;
  232. MSG_INFO(1,"open ok");
  233. }
  234. void pcmFileClose(void){
  235. if(sdFd<0){
  236. MSG_INFO(1,"no need close");
  237. return;
  238. }
  239. nwy_sdk_fclose(sdFd);
  240. MSG_INFO(1,"close ok");
  241. sdFd=-1;
  242. }
  243. void pcmSaveData(unsigned char *pcm, int len){
  244. if(sdFd<0){
  245. MSG_INFO(1,"not open");
  246. return;
  247. }
  248. nwy_sdk_fwrite(sdFd, pcm, len);
  249. }
  250. #endif
  251. static void pcmVolProcess(unsigned char *pcm, unsigned int len){
  252. #ifdef SAVE_PCM_SD
  253. pcmSaveData(pcm,len);
  254. #else
  255. //对语音数据进行平均音量分析,分析方法为累加,并求平均值,静音时是为0的值
  256. #define VOL_SUM_FRAME 5
  257. #define VOL_SHORT_LEV (VOL_SUM_FRAME*160)
  258. short *ptr=(short *)pcm;
  259. int i;
  260. static unsigned short frameVolNum=0;
  261. unsigned int sum=0,tmp;
  262. static unsigned int pcmSum=0;
  263. //char info[60];
  264. if(len != 320) return;
  265. for(i=0;i<160;i++){
  266. tmp=abs(ptr[i]);
  267. pcmSum += tmp;
  268. }
  269. if(++frameVolNum>=VOL_SUM_FRAME){
  270. sum=pcmSum/VOL_SHORT_LEV;
  271. //snprintf(info, sizeof(info), "[0]{%d}",sum);
  272. //nwy_usb_serial_send(info, strlen(info));
  273. //MSG_INFO(1, "pcm:%lu,%lu", sum,pcmSum);
  274. sum *= (LEV_NUM-0);
  275. sum /=4000;//10000;
  276. //MSG_INFO(1,"===%d",sum);
  277. if(sum >(LEV_NUM-0)) sum = LEV_NUM-0;
  278. learnRecSetVol(sum);
  279. if(sum > recordResult.maxVolume){
  280. recordResult.maxVolume=sum;//计算每一帧的最大音量
  281. //MSG_INFO(1,"=======%d", sum);
  282. }
  283. pcmSum=0;
  284. frameVolNum=0;
  285. }
  286. #endif
  287. }
  288. static int player_cb(nwy_player_status state){
  289. MSG_INFO(1,"player_cb state=%d", state);
  290. if(0==state){//播放完毕了
  291. MSG_INFO(1,"pcm play finished");
  292. }
  293. }
  294. static void learnPlayStop(void){
  295. nwy_audio_player_stop();
  296. nwy_audio_player_close();
  297. }
  298. static bool learnPlayStart(void){
  299. if(NWY_SUCESS!=nwy_audio_player_open(player_cb)) return false;
  300. else return true;
  301. }
  302. void spkControl(bool status){
  303. if(true==status) sutPocStatus.spk=1;
  304. else sutPocStatus.spk=0;
  305. paControl(status);
  306. }
  307. LEARN_PLY_ENUM learnPlayStatus;
  308. static void learnPlyTask(void *param){
  309. unsigned char *pcmPtr;
  310. float output[T_FRAME_SIZE];
  311. short out[T_FRAME_SIZE];
  312. short tmp,i;
  313. unsigned char audioType;
  314. unsigned char vFileBuf[FRAME_PER_SIZE];
  315. unsigned int addr;
  316. MSG_INFO(1, "learnPlyTask start");
  317. appSleepCtl(ASLEEP_LEARN, 1);
  318. spkControl(true);
  319. audioType=learnAudio.playType;
  320. learnAudio.plyNum=0;
  321. if(audioType==0){//播放临时录音
  322. while(learnAudio.plyNum<learnAudio.frameNum){
  323. if(learnAudio.stopPlay==true) break;
  324. pcmPtr=learnAudio.pcm+1+learnAudio.plyNum*learnAudio.frameSize;
  325. //解码
  326. speex_bits_reset(&learnAudio.bits);
  327. speex_bits_read_from(&learnAudio.bits, pcmPtr, learnAudio.frameSize);
  328. speex_decode(learnAudio.speexCt, &learnAudio.bits, output);
  329. for(i=0;i<T_FRAME_SIZE;i++) out[i]=output[i];
  330. pcmPtr=(unsigned char *)out;
  331. //播放
  332. if(NWY_SUCESS != nwy_audio_player_play(pcmPtr, 320)){
  333. MSG_ERR(1, "frame 1 play error");
  334. learnPlayStatus=LEARN_PLY_FAILED;//播放出错
  335. break;
  336. }
  337. //播放完一帧
  338. learnAudio.plyNum++;
  339. }
  340. if(learnAudio.plyNum==learnAudio.frameNum) learnPlayStatus=LEARN_PLY_DONE;//播放成功,结束
  341. }else{//播放本地文件
  342. for(;;){
  343. if(learnAudio.fd<=0){
  344. MSG_ERR(1, "audio fd invalid");
  345. learnPlayStatus=LEARN_PLY_FAILED;
  346. break;
  347. }
  348. if(learnAudio.stopPlay==true) break;
  349. addr=4+1+learnAudio.plyNum*learnAudio.frameSize;
  350. nwy_sdk_fseek(learnAudio.fd, addr, NWY_SEEK_SET);
  351. nwy_sdk_fread(learnAudio.fd, vFileBuf, learnAudio.frameSize);
  352. //解码
  353. speex_bits_reset(&learnAudio.bits);
  354. speex_bits_read_from(&learnAudio.bits, vFileBuf, learnAudio.frameSize);
  355. speex_decode(learnAudio.speexCt, &learnAudio.bits, output);
  356. for(i=0;i<T_FRAME_SIZE;i++) out[i]=output[i];
  357. pcmPtr=(unsigned char *)out;
  358. //播放
  359. if(NWY_SUCESS != nwy_audio_player_play(pcmPtr, 320)){
  360. MSG_ERR(1, "frame 2 play error");
  361. learnPlayStatus=LEARN_PLY_FAILED;//播放出错
  362. break;
  363. }
  364. //播放完一帧
  365. if(++learnAudio.plyNum>=learnAudio.frameNum){
  366. learnPlayStatus=LEARN_PLY_DONE;//播放成功,结束
  367. break;
  368. }
  369. }
  370. }
  371. //释放资源
  372. learnPlayStop();
  373. if(learnAudio.speexCt!=NULL){
  374. speex_decoder_destroy(learnAudio.speexCt);
  375. speex_bits_destroy(&learnAudio.bits);
  376. learnAudio.speexCt=NULL;
  377. }
  378. if(learnAudio.fd>0){
  379. nwy_sdk_fclose(learnAudio.fd);
  380. learnAudio.fd=-1;
  381. }
  382. MSG_INFO(1, "learnPlyTask exit");
  383. learnPlyThread=NULL;
  384. spkControl(false);
  385. appSleepCtl(ASLEEP_LEARN, 0);
  386. nwy_exit_thread();
  387. }
  388. void learnPlayAudio(unsigned char type, const char *fname){
  389. char file[50];
  390. unsigned char size;
  391. int tmp=1;
  392. learnAudio.playType=type;
  393. if(NULL!=learnPlyThread){//使用线程播放吧
  394. MSG_INFO(1, "learnPlyTask is busy");
  395. return;
  396. }
  397. if(type != 0){//播放本地文件
  398. //只读方式打开文件
  399. snprintf(file, sizeof(file), "%s/%s.rec", SD_TOKEN, fname);
  400. learnAudio.fd=nwy_sdk_fopen(file, NWY_RDONLY);
  401. if(learnAudio.fd<0){
  402. MSG_ERR(1, "open %s.rec to play failed", fname);
  403. goto P_EXIT;
  404. }
  405. nwy_sdk_fread(learnAudio.fd, (unsigned char *)&learnAudio.frameNum, 4);
  406. nwy_sdk_fseek(learnAudio.fd, 4, NWY_SEEK_SET);
  407. nwy_sdk_fread(learnAudio.fd, &size, 1);
  408. learnAudio.frameSize=size;
  409. if(learnAudio.frameNum > MAX_FRAMES_TOTAL || learnAudio.frameSize != FRAME_PER_SIZE){
  410. MSG_ERR(1, "%s.rec header err:%d,%d", learnAudio.frameNum,learnAudio.frameSize);
  411. goto P_EXIT;
  412. }
  413. }
  414. //播放临时缓存中的语音/本地文件都需要初始化以下操作
  415. learnAudio.stopPlay=false;
  416. learnPlayStatus=LEARN_PLY_IDLE;
  417. //解码初始化
  418. learnAudio.speexCt=speex_decoder_init(speex_lib_get_mode(SPEEX_MODEID_NB));
  419. if(NULL==learnAudio.speexCt){
  420. MSG_ERR(1, "play decoder init failed");
  421. goto P_EXIT;
  422. }
  423. if(0!=speex_decoder_ctl(learnAudio.speexCt, SPEEX_SET_ENH, &tmp)){
  424. MSG_ERR(1, "player decoder ctl failed");
  425. goto P_EXIT;
  426. }
  427. speex_bits_init(&learnAudio.bits);
  428. //打开播放设备
  429. if(true!=learnPlayStart()){
  430. MSG_ERR(1, "play open failed");
  431. goto P_EXIT;
  432. }
  433. //申请线程
  434. learnPlyThread=nwy_create_thread("learnPlyTask", learnPlyTask, NULL, NWY_OSI_PRIORITY_NORMAL, THREAD_AUDIO_STACK_SIZE, 4);
  435. if(learnPlyThread==NULL){
  436. MSG_ERR(1, "play thread err");
  437. goto P_EXIT;
  438. }
  439. learnPlayStatus=LEARN_PLY_BUSY;
  440. MSG_INFO(1, "start play process ok");
  441. return;
  442. P_EXIT:
  443. MSG_INFO(1, "learnPlayAudio exit:%d",type);
  444. learnPlayStatus=LEARN_PLY_PRE_ERR;//播放准备失败
  445. if(learnAudio.speexCt != NULL){
  446. speex_decoder_destroy(learnAudio.speexCt);
  447. speex_bits_destroy(&learnAudio.bits);
  448. learnAudio.speexCt=NULL;
  449. }
  450. if(learnAudio.fd>0){
  451. nwy_sdk_fclose(learnAudio.fd);
  452. learnAudio.fd=-1;
  453. }
  454. if(learnPlyThread != NULL) learnPlayStop();
  455. }
  456. LEARN_PLY_ENUM learnPlyGetResult(void){return learnPlayStatus;}
  457. //获取当前播放的类型:0 播放的是临时录音 1 播放的是本地录音
  458. unsigned char learnGetAudioType(void){return learnAudio.playType;}
  459. void learnStopPlaying(void){
  460. learnAudio.stopPlay=true;
  461. }
  462. /*将临时语音保存到本地.rec文件中,覆盖式*/
  463. void recordSaveTmpToLocal(char *fileName){
  464. char file[50];
  465. int fd;
  466. unsigned int total;
  467. snprintf(file, sizeof(file), "%s/%s.rec", SD_TOKEN, fileName);
  468. fd = nwy_sdk_fopen(file, NWY_CREAT | NWY_RDWR|NWY_TRUNC);//清0式
  469. if(fd<0){
  470. MSG_WARN(1, "Save record file fopen failed,%s", fileName);
  471. return;
  472. }
  473. memcpy(file, (unsigned char *)&learnAudio.frameNum, 4);
  474. //memcpy(file+4, (unsigned char *)&learnAudio.frameSize, 2);
  475. nwy_sdk_fwrite(fd, file, 4);
  476. total=learnAudio.frameNum*learnAudio.frameSize+1;
  477. nwy_sdk_fwrite(fd, learnAudio.pcm, total);
  478. nwy_sdk_fclose(fd);
  479. MSG_INFO(1, "Save task %s:%d bytes done", fileName, total+4);
  480. }
  481. unsigned char *learnGetTmpAudioBuf(void){
  482. return learnAudio.pcm;
  483. }
  484. unsigned int learnGetTmpAudioLength(void){
  485. return learnAudio.frameNum*learnAudio.frameSize;
  486. }