audio_demo.c 23 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006
  1. /*================================================================
  2. Copyright (c) 2020 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
  3. Quectel Wireless Solution Proprietary and Confidential.
  4. =================================================================*/
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <stdlib.h>
  8. #include "ql_api_osi.h"
  9. #include "ql_log.h"
  10. #include "audio_demo.h"
  11. #include "ql_osi_def.h"
  12. #include "ql_audio.h"
  13. #include "ql_fs.h"
  14. #include "ql_i2c.h"
  15. #include "quec_pin_index.h"
  16. #include "ql_gpio.h"
  17. #define QL_AUDIO_LOG_LEVEL QL_LOG_LEVEL_INFO
  18. #define QL_AUDIO_LOG(msg, ...) QL_LOG(QL_AUDIO_LOG_LEVEL, "ql_audio", msg, ##__VA_ARGS__)
  19. #define QL_AUDIO_LOG_PUSH(msg, ...) QL_LOG_PUSH("ql_AUDIO", msg, ##__VA_ARGS__)
  20. #if !defined(audio_demo_no_err)
  21. #define audio_demo_no_err(x, action, str) \
  22. do \
  23. { \
  24. if(x != 0) \
  25. { \
  26. QL_AUDIO_LOG(str); \
  27. {action;} \
  28. } \
  29. } while( 1==0 )
  30. #endif
  31. /* for headset_det */
  32. #ifdef QL_APP_FEATURE_HEADSET_DET
  33. #define QL_HEADSET_DETECT_PIN QUEC_PIN_DNAME_GPIO_8
  34. #define QL_HEADSET_DETECT_GPIO QUEC_GPIO_DNAME_GPIO_8
  35. #define QL_HEADSET_DETECT_FUNC_GPIO 0
  36. #define QL_HEADSET_DETECT_DEBOUNCE_TIME 300 //unit: ms
  37. #define DEMO_HEADSET_DETECT_PLUG_IN 1
  38. #define DEMO_HEADSET_DETECT_PLUG_OUT 0
  39. ql_task_t headset_det_task = NULL;
  40. ql_timer_t headset_det_debounce_timer = NULL;
  41. #endif
  42. #define ID_RIFF 0x46464952
  43. #define ID_WAVE 0x45564157
  44. #define ID_FMT 0x20746d66
  45. #define FORMAT_PCM 1
  46. #define CHECK_AUDIO_CORRECT 0
  47. #define CHECK_AUDIO_INVALID_PARAMETER 1
  48. #define CHECK_AUDIO_WAV_ERR 2
  49. #define CHECK_AUDIO_MP3_ERR 3
  50. #define CHECK_AUDIO_AMR_ERR 4
  51. struct wav_header{
  52. unsigned int riff_id;
  53. unsigned int riff_sz;
  54. unsigned int riff_fmt;
  55. unsigned int fmt_id;
  56. unsigned int fmt_sz;
  57. unsigned short audio_format;
  58. unsigned short num_channels;
  59. unsigned int sample_rate;
  60. unsigned int byte_rate;
  61. unsigned short block_align;
  62. unsigned short bits_per_sample;
  63. unsigned int data_id;
  64. unsigned int data_sz;
  65. };
  66. typedef struct
  67. {
  68. PCM_HANDLE_T recorder;
  69. PCM_HANDLE_T player;
  70. }ql_demo_poc_t;
  71. #ifdef QL_APP_FEATURE_AUDIO_RECORD
  72. static uint8 *pcm_buffer = NULL;
  73. static uint pcm_data_size = 0;
  74. #endif
  75. static bool ring_tone_start = 0;
  76. ql_task_t ql_play_task = NULL;
  77. static int play_callback(char *p_data, int len, enum_aud_player_state state)
  78. {
  79. if(state == AUD_PLAYER_START)
  80. {
  81. QL_AUDIO_LOG("player start run");
  82. }
  83. else if(state == AUD_PLAYER_FINISHED)
  84. {
  85. QL_AUDIO_LOG("player stop run");
  86. }
  87. else
  88. {
  89. QL_AUDIO_LOG("type is %d", state);
  90. }
  91. return QL_AUDIO_SUCCESS;
  92. }
  93. #ifdef QL_APP_FEATURE_AUDIO_RECORD
  94. static int record_callback(char *p_data, int len, enum_aud_record_state state)
  95. {
  96. if(state == AUD_RECORD_START)
  97. {
  98. QL_AUDIO_LOG("recorder start run");
  99. }
  100. else if(state == AUD_RECORD_CLOSE)
  101. {
  102. QL_AUDIO_LOG("recorder stop run");
  103. }
  104. else if(state == AUD_RECORD_CALL_INT)
  105. {
  106. QL_AUDIO_LOG("recorder int from ring/call");
  107. }
  108. else if(state == AUD_RECORD_DATA)
  109. {
  110. if(len <= 0)
  111. return -1;
  112. if(pcm_data_size > RECORD_BUFFER_MAX){
  113. return -1;
  114. }
  115. else{
  116. memcpy(pcm_buffer+pcm_data_size, p_data, len);
  117. pcm_data_size += len;
  118. }
  119. }
  120. return QL_AUDIO_SUCCESS;
  121. }
  122. #endif
  123. static void ql_audio_demo_thread(void *param)
  124. {
  125. QL_AUDIO_LOG("enter audio demo");
  126. //ql_ext_codec_cb_init(); //用户使用外置codec或外置DAC播放时,可参考此demo
  127. //test_pcm();
  128. //test_mp3();
  129. //test_wav();
  130. //test_amr();
  131. //test_amr_stream();
  132. #ifdef QL_APP_FEATURE_AUDIO_RECORD
  133. //test_record_file();
  134. //test_record_stream();
  135. //test_poc_full_duplex();
  136. //test_poc_half_duplex();
  137. #endif
  138. QL_AUDIO_LOG("test done, exit audio demo");
  139. ql_rtos_task_delete(NULL);
  140. }
  141. static int check_wav_file(QFILE fd)
  142. {
  143. int ret = 0;
  144. struct wav_header hdr;
  145. ret = ql_fseek(fd, 0, SEEK_SET);
  146. if(ret < 0)
  147. {
  148. return -1;
  149. }
  150. ret = ql_fread(&hdr, sizeof(hdr), 1, fd);
  151. if(ret < sizeof(hdr))
  152. {
  153. ql_fseek(fd, 0, SEEK_SET);
  154. return -1;
  155. }
  156. if( (hdr.riff_id != ID_RIFF) || (hdr.riff_fmt != ID_WAVE)
  157. || (hdr.fmt_id != ID_FMT) )
  158. {
  159. return -1;
  160. }
  161. if(hdr.audio_format != FORMAT_PCM)
  162. {
  163. return -1;
  164. }
  165. return 0;
  166. }
  167. static int check_mp3_file(QFILE fd)
  168. {
  169. int64 ret = 0;
  170. char head[10] = {0};
  171. ret = ql_fseek(fd, 0, SEEK_SET);
  172. if(ret < 0)
  173. {
  174. return -1;
  175. }
  176. ret = ql_fread(head, sizeof(head), 1, fd);
  177. if(ret < sizeof(head))
  178. {
  179. ql_fseek(fd, 0, SEEK_SET);
  180. return -1;
  181. }
  182. if(strncmp(head, "ID3", 3) == 0)
  183. {
  184. return 0;
  185. }
  186. else if( (head[0] == 0xFF) && (head[1] & 0xF0) == 0xF0 )
  187. {
  188. return 0;
  189. }
  190. return 1;
  191. }
  192. static int check_amr_file(QFILE fd)
  193. {
  194. return 0;
  195. }
  196. //Whether the audio format is correct?
  197. int check_audio_format(char *fname)
  198. {
  199. int err = CHECK_AUDIO_CORRECT;
  200. if (fname == NULL)
  201. return CHECK_AUDIO_INVALID_PARAMETER;
  202. char *dot = strrchr(fname, '.');
  203. if (dot == NULL)
  204. return CHECK_AUDIO_INVALID_PARAMETER;
  205. QFILE fd = ql_fopen(fname, "r");
  206. if(fd<0)
  207. {
  208. return CHECK_AUDIO_INVALID_PARAMETER;
  209. }
  210. if(!check_wav_file(fd))
  211. {
  212. if (strcasecmp(dot, ".wav") != 0)
  213. {
  214. err = CHECK_AUDIO_WAV_ERR;
  215. }
  216. }
  217. else if(!check_mp3_file(fd))
  218. {
  219. if (strcasecmp(dot, ".mp3") != 0)
  220. {
  221. err = CHECK_AUDIO_MP3_ERR;
  222. }
  223. }
  224. else if(!check_amr_file(fd))
  225. {
  226. if (strcasecmp(dot, ".amr") != 0)
  227. {
  228. err = CHECK_AUDIO_AMR_ERR;
  229. }
  230. }
  231. ql_fclose(fd);
  232. return err;
  233. }
  234. static void ql_audio_play_thread(void *ctx)
  235. {
  236. int err = 0;
  237. ql_event_t event = {0};
  238. while(1)
  239. {
  240. err = ql_event_try_wait(&event);
  241. audio_demo_no_err(err, continue, "wait event failed");
  242. switch(event.id)
  243. {
  244. case QL_AUDIO_RINGTONE_PLAY:
  245. do
  246. {
  247. err = ql_aud_play_file_start("ring_tone.mp3", QL_AUDIO_PLAY_TYPE_LOCAL, NULL);
  248. if(err)
  249. {
  250. ring_tone_start = FALSE;
  251. break;
  252. }
  253. ql_aud_wait_play_finish(QL_WAIT_FOREVER);
  254. }while(ring_tone_start);
  255. break;
  256. }
  257. }
  258. }
  259. #ifdef QL_APP_FEATURE_AUDIO_RECORD
  260. void test_poc_full_duplex(void)
  261. {
  262. QL_PCM_CONFIG_T config = {0};
  263. int err = 0, cnt_read=0, cnt_write;
  264. char *buffer = NULL;
  265. static ql_demo_poc_t *demo_poc = NULL;
  266. config.channels = 1; //单声道
  267. config.samplerate = 16000;
  268. ql_set_audio_path_earphone();
  269. ql_aud_set_volume(QL_AUDIO_PLAY_TYPE_VOICE, AUDIOHAL_SPK_VOL_6); //POC mode use the param of voice call
  270. buffer = calloc(1, 1024);
  271. audio_demo_no_err(!buffer, return, "no memory");
  272. demo_poc = calloc(1, sizeof(ql_demo_poc_t));
  273. audio_demo_no_err(!demo_poc, return, "no memory");
  274. demo_poc->recorder = ql_aud_pcm_open(&config, QL_AUDIO_FORMAT_PCM, QL_PCM_BLOCK_FLAG|QL_PCM_READ_FLAG, QL_PCM_POC);
  275. audio_demo_no_err(!demo_poc->recorder, goto exit, "player created failed");
  276. demo_poc->player = ql_aud_pcm_open(&config, QL_AUDIO_FORMAT_PCM, QL_PCM_BLOCK_FLAG|QL_PCM_WRITE_FLAG, QL_PCM_POC);
  277. audio_demo_no_err(!demo_poc->player, goto exit, "player created failed");
  278. err = ql_aud_start_poc_mode(QL_POC_TYPE_FULL_DUPLEX);
  279. audio_demo_no_err(err, goto exit, "player created failed");
  280. while(1)
  281. {
  282. memset(buffer, 0, 1024);
  283. cnt_read = ql_pcm_read(demo_poc->recorder, buffer, 640);
  284. audio_demo_no_err((cnt_read<=0), goto exit, "read data failed");
  285. cnt_write = ql_pcm_write(demo_poc->player, buffer, cnt_read);
  286. audio_demo_no_err((cnt_write!=cnt_read), goto exit, "read data failed");
  287. }
  288. exit:
  289. if(buffer)
  290. {
  291. free(buffer);
  292. }
  293. ql_aud_stop_poc_mode(); //users must call "ql_aud_stop_poc_mode" then call "ql_pcm_close", otherwise may leed to some errors
  294. if(demo_poc)
  295. {
  296. if(demo_poc->player)
  297. {
  298. ql_pcm_close(demo_poc->player);
  299. }
  300. if(demo_poc->recorder)
  301. {
  302. ql_pcm_close(demo_poc->recorder);
  303. }
  304. free(demo_poc);
  305. }
  306. }
  307. void test_poc_half_duplex(void)
  308. {
  309. PCM_HANDLE_T recorder = NULL;
  310. PCM_HANDLE_T player = NULL;
  311. QL_PCM_CONFIG_T config;
  312. void *data = NULL;
  313. int size, total_size = 0, cnt=0, write_cnt=0;
  314. config.channels = 1; //单声道
  315. config.samplerate = 16000;
  316. config.amrwb_param.amrwb_mode = AMRWB_MODE_2385;
  317. data = calloc(1, 200*1024);
  318. if(data == NULL)
  319. {
  320. goto exit;
  321. }
  322. ql_set_audio_path_earphone();
  323. ql_aud_set_volume(QL_AUDIO_PLAY_TYPE_VOICE, AUDIOHAL_SPK_VOL_6); //POC mode use the param of voice call
  324. recorder = ql_aud_pcm_open(&config, QL_AUDIO_FORMAT_PCM, QL_PCM_BLOCK_FLAG|QL_PCM_READ_FLAG, QL_PCM_POC);
  325. audio_demo_no_err(!recorder, goto exit, "recorder created failed");
  326. player = ql_aud_pcm_open(&config, QL_AUDIO_FORMAT_PCM, QL_PCM_BLOCK_FLAG|QL_PCM_WRITE_FLAG, QL_PCM_POC);
  327. audio_demo_no_err(!player, goto exit, "player created failed");
  328. int err = ql_aud_start_poc_mode(QL_POC_TYPE_HALF_DUPLEX);
  329. audio_demo_no_err(err, goto exit, "poc mode start failed");
  330. err = ql_aud_poc_switch(QL_POC_MODE_REC);
  331. audio_demo_no_err(err, goto exit, "poc mode switch failed");
  332. //start record
  333. while(total_size < 200*1024)
  334. {
  335. size = ql_pcm_read(recorder, data+total_size, 1024);
  336. if(size <= 0)
  337. {
  338. break;
  339. }
  340. total_size += size;
  341. }
  342. err = ql_aud_poc_switch(QL_POC_MODE_PLAY);
  343. audio_demo_no_err(err, goto exit, "poc mode switch failed");
  344. while(write_cnt < total_size)
  345. {
  346. if(total_size - write_cnt > PACKET_WRITE_MAX_SIZE) //单次最多可写入 PACKET_WRITE_MAX_SIZE 字节
  347. {
  348. cnt = ql_pcm_write(player, data+write_cnt, PACKET_WRITE_MAX_SIZE);
  349. }
  350. else
  351. {
  352. cnt = ql_pcm_write(player, data+write_cnt, total_size - write_cnt);
  353. }
  354. if(cnt <= 0)
  355. {
  356. QL_AUDIO_LOG("write failed");
  357. goto exit;
  358. }
  359. write_cnt += cnt;
  360. }
  361. while(ql_pcm_buffer_used(player)) //in poc mode, player will not stop if not ql_aud_stop_poc_mode called
  362. {
  363. ql_rtos_task_sleep_ms(20); //wait the write buffer empty
  364. }
  365. ql_rtos_task_sleep_ms(200);
  366. exit:
  367. ql_aud_stop_poc_mode(); //users must call "ql_aud_stop_poc_mode" then call "ql_pcm_close", otherwise may leed to some errors
  368. ql_pcm_close(recorder);
  369. ql_pcm_close(player);
  370. if(data)
  371. {
  372. free(data);
  373. }
  374. QL_AUDIO_LOG("test done");
  375. }
  376. #endif
  377. void ql_audio_app_init(void)
  378. {
  379. QlOSStatus err = QL_OSI_SUCCESS;
  380. ql_task_t ql_audio_task = NULL;
  381. QL_AUDIO_LOG("audio demo enter");
  382. err = ql_rtos_task_create(&ql_audio_task, 4096*2, APP_PRIORITY_NORMAL, "ql_audio", ql_audio_demo_thread, NULL, 5);
  383. if(err != QL_OSI_SUCCESS)
  384. {
  385. QL_AUDIO_LOG("audio task create failed");
  386. }
  387. err = ql_rtos_task_create(&ql_play_task, 4096, APP_PRIORITY_NORMAL, "ql_audio", ql_audio_play_thread, NULL, 2);
  388. if(err != QL_OSI_SUCCESS)
  389. {
  390. QL_AUDIO_LOG("audio task create failed");
  391. }
  392. }
  393. void test_amr_stream(void)
  394. {
  395. PCM_HANDLE_T PCM = NULL;
  396. QL_PCM_CONFIG_T config;
  397. void *data = NULL;
  398. int total_size = 0, cnt=0, write_cnt=0;
  399. config.channels = 1; //单声道
  400. config.samplerate = 16000;
  401. config.amrwb_param.amrwb_mode = AMRWB_MODE_2385;
  402. #ifdef QL_APP_FEATURE_AUDIO_RECORD
  403. int size=0;
  404. PCM = ql_aud_pcm_open(&config, QL_AUDIO_FORMAT_AMRWB, QL_PCM_BLOCK_FLAG|QL_PCM_READ_FLAG, QL_PCM_LOCAL);
  405. if(PCM == NULL)
  406. {
  407. QL_AUDIO_LOG("open pcm failed");
  408. goto exit;
  409. }
  410. data = malloc(100*1024);
  411. if(data == NULL)
  412. {
  413. goto exit;
  414. }
  415. QL_AUDIO_LOG("start read");
  416. //start record
  417. while(total_size < 10*1024)
  418. {
  419. size = ql_pcm_read(PCM, data+total_size, 41);
  420. if(size <= 0)
  421. {
  422. break;
  423. }
  424. total_size += size;
  425. }
  426. QL_AUDIO_LOG("exit record");
  427. if(total_size <= 0)
  428. {
  429. QL_AUDIO_LOG("read pcm failed");
  430. goto exit;
  431. }
  432. QL_AUDIO_LOG("size is %d", total_size);
  433. if(ql_pcm_close(PCM) != 0)
  434. {
  435. QL_AUDIO_LOG("close pcm failed");
  436. goto exit;
  437. }
  438. PCM = NULL;
  439. #endif
  440. PCM = ql_aud_pcm_open(&config, QL_AUDIO_FORMAT_AMRWB, QL_PCM_BLOCK_FLAG|QL_PCM_WRITE_FLAG, QL_PCM_LOCAL);
  441. if(PCM == NULL)
  442. {
  443. QL_AUDIO_LOG("open pcm failed");
  444. goto exit;
  445. }
  446. while(write_cnt < total_size)
  447. {
  448. if(total_size - write_cnt > PACKET_WRITE_MAX_SIZE) //单次最多可写 PACKET_WRITE_MAX_SIZE 字节
  449. {
  450. cnt = ql_pcm_write(PCM, data+write_cnt, PACKET_WRITE_MAX_SIZE);
  451. }
  452. else
  453. {
  454. cnt = ql_pcm_write(PCM, data+write_cnt, total_size - write_cnt);
  455. }
  456. if(cnt <= 0)
  457. {
  458. QL_AUDIO_LOG("write failed");
  459. goto exit;
  460. }
  461. write_cnt += cnt;
  462. }
  463. ql_aud_data_done();
  464. ql_aud_wait_play_finish(QL_WAIT_FOREVER);
  465. QL_AUDIO_LOG("play finish");
  466. exit:
  467. if(PCM != NULL)
  468. {
  469. ql_pcm_close(PCM);
  470. }
  471. if(data != NULL)
  472. {
  473. free(data);
  474. data = NULL;
  475. }
  476. }
  477. #ifdef QL_APP_FEATURE_AUDIO_RECORD
  478. void test_record_stream(void)
  479. {
  480. ql_aud_config config = {0};
  481. int cnt = 0, total_cnt=0, err;
  482. config.amrwb_param.amrwb_mode = AMRWB_MODE_2385;
  483. pcm_buffer = malloc(RECORD_BUFFER_MAX);
  484. if(!pcm_buffer){
  485. return;
  486. }
  487. /* 录音 */
  488. if(ql_aud_record_stream_start_ex(&config, QL_REC_TYPE_MIC, QL_AUDIO_FORMAT_AMRWB, record_callback))
  489. {
  490. QL_AUDIO_LOG("record fail");
  491. goto exit;
  492. }
  493. ql_rtos_task_sleep_s(5); //record 5s
  494. ql_aud_record_stop();
  495. if(pcm_data_size <= 0){
  496. QL_AUDIO_LOG("data invalid");
  497. goto exit;
  498. }
  499. /* 读取录音文件用于播放,此处也可调用 ql_aud_play_file_start,或者ql_pcm_open+ql_pcm_write去播放 */
  500. ql_set_audio_path_speaker();
  501. ql_set_volume(TEST_PLAY_VOLUME);
  502. while(total_cnt < pcm_data_size)
  503. {
  504. if(pcm_data_size - total_cnt > PACKET_WRITE_MAX_SIZE) //单次最多可播放 PACKET_WRITE_MAX_SIZE 字节
  505. {
  506. cnt = PACKET_WRITE_MAX_SIZE;
  507. err = ql_aud_play_stream_start(QL_AUDIO_FORMAT_AMRWB, pcm_buffer+total_cnt, cnt, QL_AUDIO_PLAY_TYPE_LOCAL, play_callback);
  508. }
  509. else
  510. {
  511. cnt = pcm_data_size - total_cnt;
  512. err = ql_aud_play_stream_start(QL_AUDIO_FORMAT_AMRWB, pcm_buffer+total_cnt, cnt, QL_AUDIO_PLAY_TYPE_LOCAL, play_callback);
  513. }
  514. if(err < 0)
  515. {
  516. QL_AUDIO_LOG("start failed");
  517. goto exit;
  518. }
  519. else
  520. {
  521. QL_AUDIO_LOG("play %d bytes, total %d", cnt, total_cnt);
  522. total_cnt += cnt;
  523. }
  524. }
  525. ql_aud_data_done();
  526. ql_aud_wait_play_finish(QL_WAIT_FOREVER);
  527. ql_aud_player_stop();
  528. QL_AUDIO_LOG("test successful");
  529. exit:
  530. if(pcm_buffer){
  531. free(pcm_buffer);
  532. pcm_buffer = NULL;
  533. pcm_data_size = 0;
  534. }
  535. }
  536. void test_record_file(void)
  537. {
  538. ql_aud_config config = {0};
  539. config.samplerate = 8000;
  540. ql_aud_adc_cfg adc_cfg={0};
  541. adc_cfg.adc_gain = QL_ADC_GAIN_LEVEL_12;
  542. ql_aud_dac_cfg dac_cfg={0};
  543. dac_cfg.dac_gain = 0xff;//32db
  544. if(ql_aud_record_file_start(TEST_RECORD_WAV_NAME, &config, QL_REC_TYPE_MIC, NULL) != QL_AUDIO_SUCCESS)
  545. {
  546. QL_AUDIO_LOG("record failed");
  547. return;
  548. }
  549. QL_AUDIO_LOG("record start");
  550. ql_rtos_task_sleep_s(3); //record 3s
  551. ql_aud_set_adc_gain(&adc_cfg);
  552. ql_rtos_task_sleep_s(3); //record 3s
  553. ql_aud_record_stop();
  554. QL_AUDIO_LOG("record finish, start play");
  555. ql_aud_set_dac_gain(&dac_cfg);
  556. ql_set_audio_path_speaker();
  557. if(ql_aud_play_file_start(TEST_RECORD_WAV_NAME, QL_AUDIO_PLAY_TYPE_LOCAL, play_callback))
  558. {
  559. QL_AUDIO_LOG("play failed");
  560. return;
  561. }
  562. ql_aud_wait_play_finish(QL_WAIT_FOREVER);
  563. ql_aud_player_stop();
  564. QL_AUDIO_LOG("test successful");
  565. }
  566. #endif
  567. void test_mp3(void)
  568. {
  569. //检测MP3文件格式是否正确,防止误将其他格式的文件命名为MP3格式
  570. //int err = check_audio_format(TEST_MP3_FILE_NAME);//路径为客户预置音频文件放置的路径
  571. //if(err)
  572. //{
  573. //QL_AUDIO_LOG("err = %d",err);
  574. //return;
  575. //}
  576. if(ql_aud_play_file_start(TEST_MP3_FILE_NAME, QL_AUDIO_PLAY_TYPE_LOCAL, play_callback))
  577. {
  578. QL_AUDIO_LOG("play failed");
  579. return;
  580. }
  581. ql_aud_wait_play_finish(QL_WAIT_FOREVER);
  582. if(ql_aud_play_file_start(TEST_MP3_FILE_NAME, QL_AUDIO_PLAY_TYPE_LOCAL, play_callback))
  583. {
  584. QL_AUDIO_LOG("play failed");
  585. return;
  586. }
  587. ql_aud_wait_play_finish(QL_WAIT_FOREVER);
  588. ql_aud_player_stop(); //播放结束,释放播放资源
  589. QL_AUDIO_LOG("test mp3 successful");
  590. }
  591. void test_wav(void)
  592. {
  593. int cnt = 0;
  594. //检测WAV文件格式是否正确,防止误将其他格式的文件命名为WAV格式
  595. //int err = check_audio_format(TEST_WAV_FILE_NAME);//路径为客户预置音频文件放置的路径
  596. //if(err)
  597. //{
  598. //QL_AUDIO_LOG("err = %d",err);
  599. //return;
  600. //}
  601. if(ql_aud_play_file_start(TEST_WAV_FILE_NAME, QL_AUDIO_PLAY_TYPE_LOCAL, play_callback))
  602. {
  603. QL_AUDIO_LOG("play failed");
  604. return;
  605. }
  606. ql_aud_wait_play_finish(QL_WAIT_FOREVER);
  607. QL_AUDIO_LOG("play %d times ok", ++cnt);
  608. if(ql_aud_play_file_start(TEST_WAV_FILE_NAME, QL_AUDIO_PLAY_TYPE_LOCAL, play_callback))
  609. {
  610. QL_AUDIO_LOG("play failed");
  611. return;
  612. }
  613. ql_aud_wait_play_finish(QL_WAIT_FOREVER);
  614. QL_AUDIO_LOG("play %d times ok", ++cnt);
  615. ql_aud_player_stop(); //播放结束,释放播放资源
  616. QL_AUDIO_LOG("test wav successful");
  617. }
  618. void test_amr(void)
  619. {
  620. int cnt = 0;
  621. //检测AMR文件格式是否正确,防止误将其他格式的文件命名为AMR格式
  622. //int err = check_audio_format(TEST_AMR_FILE_NAME);//路径为客户预置音频文件放置的路径
  623. //if(err)
  624. //{
  625. //QL_AUDIO_LOG("err = %d",err);
  626. //return;
  627. //}
  628. if(ql_aud_play_file_start(TEST_AMR_FILE_NAME, QL_AUDIO_PLAY_TYPE_LOCAL, play_callback))
  629. {
  630. QL_AUDIO_LOG("play failed");
  631. }
  632. ql_aud_wait_play_finish(QL_WAIT_FOREVER);
  633. QL_AUDIO_LOG("play %d times ok", ++cnt);
  634. if(ql_aud_play_file_start(TEST_AMR_FILE_NAME, QL_AUDIO_PLAY_TYPE_LOCAL, play_callback))
  635. {
  636. QL_AUDIO_LOG("play failed");
  637. }
  638. ql_aud_wait_play_finish(QL_WAIT_FOREVER);
  639. QL_AUDIO_LOG("play %d times ok", ++cnt);
  640. ql_aud_player_stop(); //播放结束,释放播放资源
  641. QL_AUDIO_LOG("test wav successful");
  642. }
  643. void test_pcm(void)
  644. {
  645. PCM_HANDLE_T PCM = NULL;
  646. QL_PCM_CONFIG_T config;
  647. void *data = NULL;
  648. int size=0, write_cnt=0, cnt=0;
  649. ql_aud_dac_cfg dac_cfg={0};
  650. dac_cfg.dac_gain = 0xff;//32db
  651. config.channels = 1; //单声道
  652. config.samplerate = 8000;
  653. #ifdef QL_APP_FEATURE_AUDIO_RECORD
  654. PCM = ql_pcm_open(&config, QL_PCM_BLOCK_FLAG|QL_PCM_READ_FLAG);
  655. if(PCM == NULL)
  656. {
  657. QL_AUDIO_LOG("open pcm failed");
  658. goto exit;
  659. }
  660. data = malloc(50*1024);
  661. if(data == NULL)
  662. {
  663. goto exit;
  664. }
  665. QL_AUDIO_LOG("start read");
  666. size = ql_pcm_read(PCM, data, 50*1024);
  667. if(size <= 0)
  668. {
  669. QL_AUDIO_LOG("read pcm failed");
  670. goto exit;
  671. }
  672. QL_AUDIO_LOG("size is %d", size);
  673. if(ql_pcm_close(PCM) != 0)
  674. {
  675. QL_AUDIO_LOG("close pcm failed");
  676. goto exit;
  677. }
  678. PCM = NULL;
  679. #endif
  680. ql_set_audio_path_speaker();
  681. PCM = ql_pcm_open(&config, QL_PCM_BLOCK_FLAG|QL_PCM_WRITE_FLAG);
  682. if(PCM == NULL)
  683. {
  684. QL_AUDIO_LOG("open pcm failed");
  685. goto exit;
  686. }
  687. QL_AUDIO_LOG("start write");
  688. ql_aud_set_dac_gain(&dac_cfg);
  689. while(write_cnt < size)
  690. {
  691. if(size - write_cnt > PACKET_WRITE_MAX_SIZE) //单次最多可播放 PACKET_WRITE_MAX_SIZE 字节
  692. {
  693. cnt = ql_pcm_write(PCM, data+write_cnt, PACKET_WRITE_MAX_SIZE);
  694. }
  695. else
  696. {
  697. cnt = ql_pcm_write(PCM, data+write_cnt, size - write_cnt);
  698. }
  699. if(cnt <= 0)
  700. {
  701. QL_AUDIO_LOG("write failed");
  702. goto exit;
  703. }
  704. write_cnt += cnt;
  705. }
  706. ql_aud_data_done();
  707. ql_aud_wait_play_finish(QL_WAIT_FOREVER);
  708. QL_AUDIO_LOG("play done");
  709. if(ql_pcm_close(PCM) != 0)
  710. {
  711. QL_AUDIO_LOG("close pcm failed");
  712. goto exit;
  713. }
  714. PCM = NULL;
  715. QL_AUDIO_LOG("play finish");
  716. exit:
  717. if(PCM != NULL)
  718. {
  719. ql_pcm_close(PCM);
  720. }
  721. if(data != NULL)
  722. {
  723. free(data);
  724. data = NULL;
  725. }
  726. }
  727. /*
  728. ES8311寄存器组,用户可以对照ES8311手册在此修改寄存器
  729. g_codecInitRegList: 初始化codec时会将此结构体中的配置发送给codec
  730. g_codecrecRegList: 开始播放时会将此结构体中的配置发送给codec
  731. g_codecplayRegList: 开始录音时会将此结构体中的配置发送给codec
  732. g_codecCloseRegList:关闭codec时会将此结构体中的配置发送给codec
  733. 播放时的调用流程: g_codecInitRegList --> g_codecplayRegList --> g_codecCloseRegList
  734. 录音时的调用流程: g_codecInitRegList --> g_codecrecRegList --> g_codecCloseRegList
  735. */
  736. ql_codec_reg_t g_codecInitRegList[] = ES8311_INIT_CONFIG;
  737. ql_codec_reg_t g_codecrecRegList[] = ES8311_PLAY_CONFIG;
  738. ql_codec_reg_t g_codecplayRegList[] = ES8311_RECORD_CONFIG;
  739. ql_codec_reg_t g_codecCloseRegList[] = ES8311_CLOSE_CONFIG;
  740. typedef struct
  741. {
  742. uint8_t addr;
  743. uint8_t data;
  744. } extcodecReg_t;
  745. ql_audio_errcode_e ql_app_es8311_read_reg(uint8 RegAddr, uint8 *p_value)
  746. {
  747. uint8 retry_count = 5;
  748. while(retry_count--)
  749. {
  750. if(QL_I2C_SUCCESS == ql_I2cRead(QL_CUR_IIC_CHANNEL, ES8311_I2C_SLAVE_ADDR, RegAddr, p_value, 1))
  751. {
  752. return QL_AUDIO_SUCCESS;
  753. }
  754. }
  755. QL_EXT_CODEC_LOG("es311 read reg err 0x%x", RegAddr);
  756. return QL_AUDIO_CODEC_RD_FAIL;
  757. }
  758. ql_audio_errcode_e ql_app_es8311_write_reg(uint8 RegAddr, uint8 RegData)
  759. {
  760. uint8 retry_count = 5;
  761. while(retry_count--)
  762. {
  763. if(QL_I2C_SUCCESS == ql_I2cWrite(QL_CUR_IIC_CHANNEL, ES8311_I2C_SLAVE_ADDR, RegAddr, &RegData, 1))
  764. {
  765. return QL_AUDIO_SUCCESS;
  766. }
  767. }
  768. QL_EXT_CODEC_LOG("es311 write reg err 0x%x 0x%x",RegAddr, RegData);
  769. return QL_AUDIO_CODEC_WR_FAIL;
  770. }
  771. void ql_app_es8311_write_list(ql_codec_reg_t *regList, uint16_t len)
  772. {
  773. uint16_t regCount;
  774. for (regCount = 0; regCount < len; regCount++)
  775. {
  776. ql_app_es8311_write_reg(regList[regCount].addr, regList[regCount].data);
  777. }
  778. }
  779. int ql_app_es8311_cfg_cb(ql_codec_cb_param_t *param)
  780. {
  781. switch(param->stage)
  782. {
  783. case QL_EXT_CODEC_INIT:
  784. ql_pin_set_func(QL_CUR_IIC_CLK_PIN, 0);
  785. ql_pin_set_func(QL_CUR_IIC_SDA_PIN, 0);
  786. ql_I2cInit(QL_CUR_IIC_CHANNEL, STANDARD_MODE);
  787. ql_app_es8311_write_list(g_codecInitRegList, sizeof(g_codecInitRegList) / sizeof(ql_codec_reg_t));
  788. break;
  789. case QL_EXT_CODEC_REC:
  790. ql_app_es8311_write_list(g_codecrecRegList, sizeof(g_codecrecRegList) / sizeof(ql_codec_reg_t));
  791. break;
  792. case QL_EXT_CODEC_PLAY:
  793. ql_app_es8311_write_list(g_codecplayRegList, sizeof(g_codecplayRegList) / sizeof(ql_codec_reg_t));
  794. break;
  795. case QL_EXT_CODEC_DEINIT:
  796. ql_app_es8311_write_list(g_codecCloseRegList, sizeof(g_codecCloseRegList) / sizeof(ql_codec_reg_t));
  797. ql_I2cRelease(QL_CUR_IIC_CHANNEL);
  798. break;
  799. default:
  800. break;
  801. }
  802. return QL_AUDIO_SUCCESS;
  803. }
  804. void ql_ext_codec_cb_init(void)
  805. {
  806. ql_extcodec_info_t codec_cfg = {0};
  807. #if QL_USE_DAC_TM8211
  808. /*
  809. 使用TM8211时启用此demo;由于TM8211没有寄存器,所以不需要配置回调函数
  810. */
  811. codec_cfg.extcodec_enable = true;
  812. codec_cfg.callback = NULL;
  813. codec_cfg.protocal = QL_DATA_PROROCOL_IIS;
  814. codec_cfg.data_bits = QL_AUD_DATA_BIT_16;
  815. codec_cfg.rx_delay = QL_AUD_RXDELAY_0;
  816. codec_cfg.tx_delay = QL_AUD_TXDELAY_0;
  817. #elif QL_USE_DAC_ES7148
  818. /*
  819. 使用ES7148时启用此demo;由于ES7148没有寄存器,所以不需要配置回调函数
  820. */
  821. codec_cfg.extcodec_enable = true;
  822. codec_cfg.callback = ql_app_es8311_cfg_cb;
  823. codec_cfg.protocal = QL_DATA_PROROCOL_IIS;
  824. codec_cfg.data_bits = QL_AUD_DATA_BIT_32;
  825. codec_cfg.rx_delay = QL_AUD_RXDELAY_DEFAULT;
  826. codec_cfg.tx_delay = QL_AUD_RXDELAY_DEFAULT;
  827. #elif QL_USE_CODEC_ES8311
  828. /*
  829. 使用ES8311等需要配置寄存器的codec时,需要定义回调函数;
  830. 播放时,内核会按照 init -> play -> deinit的顺序调用
  831. 录音时,内核会按照 init -> rec -> deinit的顺序调用
  832. */
  833. codec_cfg.extcodec_enable = true;
  834. codec_cfg.callback = ql_app_es8311_cfg_cb;
  835. codec_cfg.protocal = QL_DATA_PROROCOL_IIS;
  836. codec_cfg.data_bits = QL_AUD_DATA_BIT_32;
  837. codec_cfg.rx_delay = QL_AUD_RXDELAY_DEFAULT;
  838. codec_cfg.tx_delay = QL_AUD_RXDELAY_DEFAULT;
  839. #endif
  840. ql_aud_ext_codec_cfg(&codec_cfg);
  841. }