learnAudio.c 14 KB

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