learnAudio.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  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);
  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:%d", sum);
  274. sum *= (LEV_NUM-1);
  275. sum /=10000;
  276. if(sum >(LEV_NUM-1)) sum = LEV_NUM-1;
  277. learnRecSetVol(sum);
  278. if(sum > recordResult.maxVolume) recordResult.maxVolume=sum;//计算每一帧的最大音量
  279. pcmSum=0;
  280. frameVolNum=0;
  281. }
  282. #endif
  283. }
  284. static int player_cb(nwy_player_status state){
  285. MSG_INFO(1,"player_cb state=%d", state);
  286. if(0==state){//播放完毕了
  287. MSG_INFO(1,"pcm play finished");
  288. }
  289. }
  290. static void learnPlayStop(void){
  291. nwy_audio_player_stop();
  292. nwy_audio_player_close();
  293. }
  294. static bool learnPlayStart(void){
  295. if(NWY_SUCESS!=nwy_audio_player_open(player_cb)) return false;
  296. else return true;
  297. }
  298. void spkControl(bool status){
  299. if(true==status) sutPocStatus.spk=1;
  300. else sutPocStatus.spk=0;
  301. paControl(status);
  302. }
  303. LEARN_PLY_ENUM learnPlayStatus;
  304. static void learnPlyTask(void *param){
  305. unsigned char *pcmPtr;
  306. float output[T_FRAME_SIZE];
  307. short out[T_FRAME_SIZE];
  308. short tmp,i;
  309. unsigned char audioType;
  310. unsigned char vFileBuf[FRAME_PER_SIZE];
  311. unsigned int addr;
  312. MSG_INFO(1, "learnPlyTask start");
  313. appSleepCtl(ASLEEP_LEARN, 1);
  314. spkControl(true);
  315. audioType=learnAudio.playType;
  316. learnAudio.plyNum=0;
  317. if(audioType==0){//播放临时录音
  318. while(learnAudio.plyNum<learnAudio.frameNum){
  319. if(learnAudio.stopPlay==true) break;
  320. pcmPtr=learnAudio.pcm+1+learnAudio.plyNum*learnAudio.frameSize;
  321. //解码
  322. speex_bits_reset(&learnAudio.bits);
  323. speex_bits_read_from(&learnAudio.bits, pcmPtr, learnAudio.frameSize);
  324. speex_decode(learnAudio.speexCt, &learnAudio.bits, output);
  325. for(i=0;i<T_FRAME_SIZE;i++) out[i]=output[i];
  326. pcmPtr=(unsigned char *)out;
  327. //播放
  328. if(NWY_SUCESS != nwy_audio_player_play(pcmPtr, 320)){
  329. MSG_ERR(1, "frame 1 play error");
  330. learnPlayStatus=LEARN_PLY_FAILED;//播放出错
  331. break;
  332. }
  333. //播放完一帧
  334. learnAudio.plyNum++;
  335. }
  336. if(learnAudio.plyNum==learnAudio.frameNum) learnPlayStatus=LEARN_PLY_DONE;//播放成功,结束
  337. }else{//播放本地文件
  338. for(;;){
  339. if(learnAudio.fd<=0){
  340. MSG_ERR(1, "audio fd invalid");
  341. learnPlayStatus=LEARN_PLY_FAILED;
  342. break;
  343. }
  344. if(learnAudio.stopPlay==true) break;
  345. addr=4+1+learnAudio.plyNum*learnAudio.frameSize;
  346. nwy_sdk_fseek(learnAudio.fd, addr, NWY_SEEK_SET);
  347. nwy_sdk_fread(learnAudio.fd, vFileBuf, learnAudio.frameSize);
  348. //解码
  349. speex_bits_reset(&learnAudio.bits);
  350. speex_bits_read_from(&learnAudio.bits, vFileBuf, learnAudio.frameSize);
  351. speex_decode(learnAudio.speexCt, &learnAudio.bits, output);
  352. for(i=0;i<T_FRAME_SIZE;i++) out[i]=output[i];
  353. pcmPtr=(unsigned char *)out;
  354. //播放
  355. if(NWY_SUCESS != nwy_audio_player_play(pcmPtr, 320)){
  356. MSG_ERR(1, "frame 2 play error");
  357. learnPlayStatus=LEARN_PLY_FAILED;//播放出错
  358. break;
  359. }
  360. //播放完一帧
  361. if(++learnAudio.plyNum>=learnAudio.frameNum){
  362. learnPlayStatus=LEARN_PLY_DONE;//播放成功,结束
  363. break;
  364. }
  365. }
  366. }
  367. //释放资源
  368. learnPlayStop();
  369. if(learnAudio.speexCt!=NULL){
  370. speex_decoder_destroy(learnAudio.speexCt);
  371. speex_bits_destroy(&learnAudio.bits);
  372. learnAudio.speexCt=NULL;
  373. }
  374. if(learnAudio.fd>0){
  375. nwy_sdk_fclose(learnAudio.fd);
  376. learnAudio.fd=-1;
  377. }
  378. MSG_INFO(1, "learnPlyTask exit");
  379. learnPlyThread=NULL;
  380. spkControl(false);
  381. appSleepCtl(ASLEEP_LEARN, 0);
  382. nwy_exit_thread();
  383. }
  384. void learnPlayAudio(unsigned char type, const char *fname){
  385. char file[50];
  386. unsigned char size;
  387. int tmp=1;
  388. learnAudio.playType=type;
  389. if(NULL!=learnPlyThread){//使用线程播放吧
  390. MSG_INFO(1, "learnPlyTask is busy");
  391. return;
  392. }
  393. if(type != 0){//播放本地文件
  394. //只读方式打开文件
  395. snprintf(file, sizeof(file), "%s/%s.rec", SD_TOKEN, fname);
  396. learnAudio.fd=nwy_sdk_fopen(file, NWY_RDONLY);
  397. if(learnAudio.fd<0){
  398. MSG_ERR(1, "open %s.rec to play failed", fname);
  399. goto P_EXIT;
  400. }
  401. nwy_sdk_fread(learnAudio.fd, (unsigned char *)&learnAudio.frameNum, 4);
  402. nwy_sdk_fseek(learnAudio.fd, 4, NWY_SEEK_SET);
  403. nwy_sdk_fread(learnAudio.fd, &size, 1);
  404. learnAudio.frameSize=size;
  405. if(learnAudio.frameNum > MAX_FRAMES_TOTAL || learnAudio.frameSize != FRAME_PER_SIZE){
  406. MSG_ERR(1, "%s.rec header err:%d,%d", learnAudio.frameNum,learnAudio.frameSize);
  407. goto P_EXIT;
  408. }
  409. }
  410. //播放临时缓存中的语音/本地文件都需要初始化以下操作
  411. learnAudio.stopPlay=false;
  412. learnPlayStatus=LEARN_PLY_IDLE;
  413. //解码初始化
  414. learnAudio.speexCt=speex_decoder_init(speex_lib_get_mode(SPEEX_MODEID_NB));
  415. if(NULL==learnAudio.speexCt){
  416. MSG_ERR(1, "play decoder init failed");
  417. goto P_EXIT;
  418. }
  419. if(0!=speex_decoder_ctl(learnAudio.speexCt, SPEEX_SET_ENH, &tmp)){
  420. MSG_ERR(1, "player decoder ctl failed");
  421. goto P_EXIT;
  422. }
  423. speex_bits_init(&learnAudio.bits);
  424. //打开播放设备
  425. if(true!=learnPlayStart()){
  426. MSG_ERR(1, "play open failed");
  427. goto P_EXIT;
  428. }
  429. //申请线程
  430. learnPlyThread=nwy_create_thread("learnPlyTask", learnPlyTask, NULL, NWY_OSI_PRIORITY_NORMAL, THREAD_AUDIO_STACK_SIZE, 4);
  431. if(learnPlyThread==NULL){
  432. MSG_ERR(1, "play thread err");
  433. goto P_EXIT;
  434. }
  435. learnPlayStatus=LEARN_PLY_BUSY;
  436. MSG_INFO(1, "start play process ok");
  437. return;
  438. P_EXIT:
  439. MSG_INFO(1, "learnPlayAudio exit:%d",type);
  440. learnPlayStatus=LEARN_PLY_PRE_ERR;//播放准备失败
  441. if(learnAudio.speexCt != NULL){
  442. speex_decoder_destroy(learnAudio.speexCt);
  443. speex_bits_destroy(&learnAudio.bits);
  444. learnAudio.speexCt=NULL;
  445. }
  446. if(learnAudio.fd>0){
  447. nwy_sdk_fclose(learnAudio.fd);
  448. learnAudio.fd=-1;
  449. }
  450. if(learnPlyThread != NULL) learnPlayStop();
  451. }
  452. LEARN_PLY_ENUM learnPlyGetResult(void){return learnPlayStatus;}
  453. //获取当前播放的类型:0 播放的是临时录音 1 播放的是本地录音
  454. unsigned char learnGetAudioType(void){return learnAudio.playType;}
  455. void learnStopPlaying(void){
  456. learnAudio.stopPlay=true;
  457. }
  458. /*将临时语音保存到本地.rec文件中,覆盖式*/
  459. void recordSaveTmpToLocal(char *fileName){
  460. char file[50];
  461. int fd;
  462. unsigned int total;
  463. snprintf(file, sizeof(file), "%s/%s.rec", SD_TOKEN, fileName);
  464. fd = nwy_sdk_fopen(file, NWY_CREAT | NWY_RDWR|NWY_TRUNC);//清0式
  465. if(fd<0){
  466. MSG_WARN(1, "Save record file fopen failed,%s", fileName);
  467. return;
  468. }
  469. memcpy(file, (unsigned char *)&learnAudio.frameNum, 4);
  470. //memcpy(file+4, (unsigned char *)&learnAudio.frameSize, 2);
  471. nwy_sdk_fwrite(fd, file, 4);
  472. total=learnAudio.frameNum*learnAudio.frameSize+1;
  473. nwy_sdk_fwrite(fd, learnAudio.pcm, total);
  474. nwy_sdk_fclose(fd);
  475. MSG_INFO(1, "Save task %s:%d bytes done", fileName, total+4);
  476. }
  477. unsigned char *learnGetTmpAudioBuf(void){
  478. return learnAudio.pcm;
  479. }
  480. unsigned int learnGetTmpAudioLength(void){
  481. return learnAudio.frameNum*learnAudio.frameSize;
  482. }