duerapp_recorder.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. /**
  2. * Copyright (2017) Baidu Inc. All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /**
  17. * File: duerapp_recorder.c
  18. * Auth: Renhe Zhang (v_zhangrenhe@baidu.com)
  19. * Desc: Record module function implementation.
  20. */
  21. #include <arpa/inet.h>
  22. #include <errno.h>
  23. #include <fcntl.h>
  24. #include <netdb.h>
  25. #include <netinet/in.h>
  26. #ifdef ENABLE_TCP_NODELAY
  27. #include <netinet/tcp.h>
  28. #endif
  29. #include <pthread.h>
  30. #include <sys/select.h>
  31. #include <sys/socket.h>
  32. #include <sys/time.h>
  33. #include <sys/types.h>
  34. #include <unistd.h>
  35. #include <semaphore.h>
  36. #include "duerapp_recorder.h"
  37. #include "duerapp_config.h"
  38. #include "lightduer_voice.h"
  39. #include "lightduer_dcs_router.h"
  40. #include <alsa/asoundlib.h>
  41. #include "snowboy-detect-c-wrapper.h"
  42. #define ALSA_PCM_NEW_HW_PARAMS_API
  43. #define SAMPLE_RATE (16000)
  44. #define FRAMES_INIT (640*4)
  45. #define CHANNEL (2)
  46. #define FRAMES_SIZE ((16/8) *CHANNEL)// bytes / sample * channels
  47. //#define PCM_STREAM_CAPTURE_DEVICE "hw:1,0"
  48. #define PCM_STREAM_CAPTURE_DEVICE "default"
  49. //#define RECORD_DATA_TO_FILE
  50. static int s_duer_rec_snd_fd=-1;
  51. static int s_duer_rec_recv_fd=-1;
  52. struct sockaddr_in s_duer_rec_addr;
  53. static duer_rec_state_t s_duer_rec_state = RECORDER_STOP;
  54. static pthread_t s_rec_threadID;
  55. static sem_t s_rec_sem;
  56. static duer_rec_config_t *s_index = NULL;
  57. static bool s_is_suspend = false;
  58. static bool s_is_baidu_rec_start = false;
  59. static pthread_t s_rec_send_threadID;
  60. static char * s_kws_model_filename = NULL;
  61. const char *s_tone_url[3] = {"./resources/60.wav","./resources/61.wav","./resources/62.wav"};
  62. extern void event_record_start();
  63. int duer_set_kws_model_file(char *filename)
  64. {
  65. if(filename==NULL){
  66. return 0;
  67. }
  68. if(s_kws_model_filename==NULL){
  69. free(s_kws_model_filename);
  70. s_kws_model_filename=NULL;
  71. }
  72. s_kws_model_filename = strdup(filename);
  73. return 0;
  74. }
  75. typedef struct _pcm_header_t {
  76. char pcm_header[4];
  77. size_t pcm_length;
  78. char format[8];
  79. int bit_rate;
  80. short pcm;
  81. short channel;
  82. int sample_rate;
  83. int byte_rate;
  84. short block_align;
  85. short bits_per_sample;
  86. char fix_data[4];
  87. size_t data_length;
  88. } pcm_header_t;
  89. int g_recorder_channel = 0;
  90. static pcm_header_t s_pcm_header = {
  91. {'R', 'I', 'F', 'F'},
  92. (size_t)-1,
  93. {'W', 'A', 'V', 'E', 'f', 'm', 't', ' '},
  94. 0x10,
  95. 0x01,
  96. 0x01,
  97. #if 1 //def SAMPLE_RATE_16K
  98. 0x3E80,
  99. 0x7D00,
  100. #else //8k
  101. 0x1F40,
  102. 0x3E80,
  103. #endif // SAMPLE_RATE_16K
  104. 0x02,
  105. 0x10,
  106. {'d', 'a', 't', 'a'},
  107. (size_t)-1
  108. };
  109. static FILE *s_voice_file=NULL;
  110. int duer_store_voice_start(int name_id)
  111. {
  112. DUER_LOGD("start");
  113. if (s_voice_file) {
  114. fclose(s_voice_file);
  115. s_voice_file = NULL;
  116. }
  117. char _name[64];
  118. snprintf(_name, sizeof(_name), "./%d.wav", name_id);
  119. s_voice_file = fopen(_name, "wb");
  120. if (!s_voice_file) {
  121. DUER_LOGE("can't open file %s", _name);
  122. return -1;
  123. } else {
  124. DUER_LOGD("begin write to file:%s", _name);
  125. }
  126. fwrite(&s_pcm_header, 1, sizeof(s_pcm_header), s_voice_file);
  127. s_pcm_header.data_length = 0;
  128. s_pcm_header.pcm_length = sizeof(s_pcm_header) - 8;
  129. return 0;
  130. }
  131. int duer_store_voice_write(const void *data, uint32_t size)
  132. {
  133. DUER_LOGD("data");
  134. if (s_voice_file) {
  135. fwrite(data, 1, size, s_voice_file);
  136. s_pcm_header.data_length += size;
  137. }
  138. return 0;
  139. }
  140. int duer_store_voice_end()
  141. {
  142. if (s_voice_file) {
  143. s_pcm_header.pcm_length += s_pcm_header.data_length;
  144. fseek(s_voice_file, 0, SEEK_SET);
  145. fwrite(&s_pcm_header, 1, sizeof(s_pcm_header), s_voice_file);
  146. fclose(s_voice_file);
  147. s_voice_file = NULL;
  148. DUER_LOGD("finish the voice record");
  149. }
  150. return 0;
  151. }
  152. int stereo_to_mono(int16_t *in,int ilen,int16_t *out,int outlen)
  153. {
  154. int i=0;
  155. if(CHANNEL==1){
  156. memcpy(out,in,ilen<<1);
  157. return ilen;
  158. }else if(CHANNEL==2){
  159. for(i=0;i<ilen>>1;i++){
  160. if(duer_app_is_test_mode()!=1||(g_recorder_channel==0)){
  161. out[i] = (in[2*i]+in[2*i+1])>>1;
  162. //out[i] = in[2*i];
  163. }else if(g_recorder_channel==1){
  164. out[i] = in[2*i];
  165. }else if(g_recorder_channel==2){
  166. out[i] = in[2*i+1];
  167. }
  168. }
  169. return ilen>>1;
  170. }else if(CHANNEL==4){
  171. for(i=0;i<ilen>>2;i++){
  172. out[i] = (in[4*i]+in[4*i+1]+in[4*i+2]+in[4*i+3])>>2;
  173. //out[i] = in[4*i+2];
  174. }
  175. return ilen>>2;
  176. }
  177. return 0;
  178. }
  179. int duer_recorder_test_start(int channel)
  180. {
  181. g_recorder_channel = channel;
  182. if(duer_app_is_test_mode()){
  183. if(g_recorder_channel==1){
  184. duer_media_tone_play("./resources/left.wav",20000);
  185. }else if(g_recorder_channel==2){
  186. duer_media_tone_play("./resources/right.wav",20000);
  187. }
  188. duer_store_voice_end();
  189. duer_store_voice_start(g_recorder_channel);
  190. }
  191. return 0;
  192. }
  193. int duer_recorder_test_end(void)
  194. {
  195. char fn[32];
  196. sprintf(fn,"./%d.wav",g_recorder_channel);
  197. duer_store_voice_end();
  198. if(duer_app_is_test_mode()){
  199. duer_media_tone_play(fn,20000);
  200. }
  201. return 0;
  202. }
  203. static void recorder_thread()
  204. {
  205. fd_set fdwrite;
  206. int value=0;
  207. const char resource_filename[] = "resources/common.res";
  208. //const char model_filename[] = "snowboy/resources/models/snowboy.umdl";
  209. //const char model_filename[] = "resources/models/keywords.pmdl,resources/models/peppapig.pmdl";
  210. //const char sensitivity_str[] = "0.5,0.5";
  211. //const char model_filename[] = "resources/models/keywords.pmdl";
  212. char *model_filename=s_kws_model_filename;
  213. //const char sensitivity_str[] = "0.5,0.6,0.6";
  214. const char sensitivity_str[] = "0.5";
  215. float audio_gain = 1.1;
  216. bool apply_frontend = false;
  217. if(model_filename==NULL){
  218. model_filename = "resources/models/keywords.pmdl";
  219. }
  220. // Initializes Snowboy detector.
  221. SnowboyDetect* detector = SnowboyDetectConstructor(resource_filename,
  222. (const char*)model_filename);
  223. SnowboyDetectSetSensitivity(detector, sensitivity_str);
  224. SnowboyDetectSetAudioGain(detector, audio_gain);
  225. SnowboyDetectApplyFrontend(detector, apply_frontend);
  226. // Initializes PortAudio. You may use other tools to capture the audio.
  227. value = SnowboyDetectSampleRate(detector);
  228. DUER_LOGI("samplerate:%d\n",value);
  229. value = SnowboyDetectNumChannels(detector);
  230. DUER_LOGI("channels:%d\n",value);
  231. value = SnowboyDetectBitsPerSample(detector);
  232. DUER_LOGI("bits:%d\n",value);
  233. pthread_detach(pthread_self());
  234. snd_pcm_hw_params_get_period_size(s_index->params, &(s_index->frames), &(s_index->dir));
  235. if (s_index->frames < 0) {
  236. DUER_LOGE("Get period size failed!");
  237. return;
  238. }
  239. DUER_LOGI("frames %d dir %d\n",s_index->frames,s_index->dir);
  240. s_index->size = s_index->frames * FRAMES_SIZE;
  241. int16_t *buffer = NULL;
  242. int16_t *mono_buffer = NULL;
  243. int mono_data_size = 0;
  244. if (buffer) {
  245. free(buffer);
  246. buffer = NULL;
  247. }
  248. buffer = (int16_t *)malloc(s_index->size);
  249. if (!buffer) {
  250. DUER_LOGE("malloc buffer failed!\n");
  251. } else {
  252. memset(buffer, 0, s_index->size);
  253. }
  254. mono_buffer = (int16_t *)malloc(s_index->size);
  255. if (!mono_buffer) {
  256. DUER_LOGE("malloc buffer failed!\n");
  257. } else {
  258. memset(mono_buffer, 0, s_index->size);
  259. }
  260. while (1)
  261. {
  262. int ret = snd_pcm_readi(s_index->handle, buffer, s_index->frames);
  263. if (ret == -EPIPE) {
  264. DUER_LOGE("an overrun occurred!");
  265. snd_pcm_prepare(s_index->handle);
  266. continue;
  267. } else if (ret < 0) {
  268. DUER_LOGE("read: %s", snd_strerror(ret));
  269. continue;
  270. } else if (ret != (int)s_index->frames) {
  271. DUER_LOGE("read %d frames!", ret);
  272. continue;
  273. } else {
  274. // do nothing
  275. //printf("ret=%d\n",ret);
  276. }
  277. mono_data_size = stereo_to_mono(buffer,s_index->size>>1,mono_buffer,s_index->size>>1);
  278. #if 1
  279. int result = SnowboyDetectRunDetection(detector,
  280. mono_buffer, mono_data_size, false);
  281. if (result > 0) {
  282. DUER_LOGI("Hotword %d detected!\n", result);
  283. duer_dcs_dialog_cancel();
  284. duer_media_tone_play(s_tone_url[rand()%3],5000);
  285. event_record_start();
  286. #ifdef RECORD_DATA_TO_FILE
  287. duer_store_voice_end();
  288. duer_store_voice_start(time(NULL));
  289. #else
  290. if(duer_app_is_test_mode()){
  291. duer_store_voice_end();
  292. duer_store_voice_start(g_recorder_channel);
  293. }
  294. #endif
  295. }
  296. #endif
  297. if((RECORDER_START == s_duer_rec_state)&&s_is_baidu_rec_start){
  298. struct timeval time = {0, 0};
  299. FD_ZERO(&fdwrite);
  300. FD_SET(s_duer_rec_snd_fd, &fdwrite);
  301. if(select(s_duer_rec_snd_fd + 1, NULL, &fdwrite, NULL, &time)>0){
  302. send(s_duer_rec_snd_fd,mono_buffer,mono_data_size<<1,0);
  303. #ifdef RECORD_DATA_TO_FILE
  304. duer_store_voice_write(mono_buffer,mono_data_size<<1);
  305. #else
  306. if(duer_app_is_test_mode()){
  307. DUER_LOGI("test mode\n");
  308. duer_store_voice_write(mono_buffer,mono_data_size<<1);
  309. }
  310. #endif
  311. }else{
  312. DUER_LOGI("overloap!!!!!!!!!\n");
  313. }
  314. }
  315. }
  316. if (buffer) {
  317. free(buffer);
  318. buffer = NULL;
  319. }
  320. if(mono_buffer){
  321. free(mono_buffer);
  322. mono_buffer=NULL;
  323. }
  324. snd_pcm_drain(s_index->handle);
  325. snd_pcm_close(s_index->handle);
  326. if(s_index) {
  327. free(s_index);
  328. s_index = NULL;
  329. }
  330. SnowboyDetectDestructor(detector);
  331. return;
  332. }
  333. static void recorder_data_send_thread()
  334. {
  335. char *buffer = NULL;
  336. int size = s_index->size;
  337. fd_set fdread;
  338. struct timeval time = {0, 0};
  339. int recvlen=0;
  340. pthread_detach(pthread_self());
  341. DUER_LOGI("recorder_data_send_thread start!\n");
  342. s_is_baidu_rec_start = false;
  343. while(1)
  344. {
  345. FD_ZERO(&fdread);
  346. FD_SET(s_duer_rec_recv_fd, &fdread);
  347. if(select(s_duer_rec_recv_fd + 1, &fdread, NULL, NULL, &time)>0){
  348. recv(s_duer_rec_recv_fd, buffer, size, 0);
  349. }else{
  350. break;
  351. }
  352. }
  353. DUER_LOGI("flush data end %d!\n",s_duer_rec_state);
  354. s_is_baidu_rec_start = true;
  355. duer_voice_start(16000);
  356. buffer = (char *)malloc(size);
  357. if (!buffer) {
  358. DUER_LOGE("malloc buffer failed!\n");
  359. } else {
  360. memset(buffer, 0, size);
  361. }
  362. while (RECORDER_START == s_duer_rec_state)
  363. {
  364. FD_ZERO(&fdread);
  365. time.tv_sec = 1;
  366. time.tv_usec = 0;
  367. FD_SET(s_duer_rec_recv_fd, &fdread);
  368. if(select(s_duer_rec_recv_fd + 1, &fdread, NULL, NULL, &time)>0){
  369. recvlen = recv(s_duer_rec_recv_fd, buffer, size, 0);
  370. if(recvlen>0){
  371. printf(".&.");
  372. duer_voice_send(buffer, recvlen);
  373. }else{
  374. DUER_LOGE("recv fail!\n");
  375. }
  376. }
  377. }
  378. s_is_baidu_rec_start = false;
  379. duer_voice_stop();
  380. if(s_is_suspend) {
  381. duer_voice_terminate();
  382. s_is_suspend = false;
  383. }
  384. if (buffer) {
  385. free(buffer);
  386. buffer = NULL;
  387. }
  388. if(sem_post(&s_rec_sem)) {
  389. DUER_LOGE("sem_post failed.");
  390. }
  391. return ;
  392. }
  393. static int duer_open_alsa_pcm()
  394. {
  395. int ret = DUER_OK;
  396. int result = (snd_pcm_open(&(s_index->handle), PCM_STREAM_CAPTURE_DEVICE, SND_PCM_STREAM_CAPTURE, 0));
  397. if (result < 0)
  398. {
  399. DUER_LOGE("\n\n****unable to open pcm device: %s*********\n\n", snd_strerror(ret));
  400. ret = DUER_ERR_FAILED;
  401. }
  402. return ret;
  403. }
  404. static int duer_set_pcm_params()
  405. {
  406. int ret = DUER_OK;
  407. snd_pcm_hw_params_alloca(&(s_index->params));
  408. snd_pcm_hw_params_any(s_index->handle, s_index->params);
  409. snd_pcm_hw_params_set_access(s_index->handle, s_index->params,
  410. SND_PCM_ACCESS_RW_INTERLEAVED);
  411. snd_pcm_hw_params_set_format(s_index->handle, s_index->params,
  412. SND_PCM_FORMAT_S16_LE);
  413. snd_pcm_hw_params_set_channels(s_index->handle, s_index->params,
  414. CHANNEL);
  415. snd_pcm_hw_params_set_rate_near(s_index->handle, s_index->params,
  416. &(s_index->val), &(s_index->dir));
  417. snd_pcm_hw_params_set_period_size_near(s_index->handle, s_index->params,
  418. &(s_index->frames), &(s_index->dir));
  419. int result = snd_pcm_hw_params(s_index->handle, s_index->params);
  420. if (result < 0) {
  421. DUER_LOGE("unable to set hw parameters: %s", snd_strerror(ret));
  422. ret = DUER_ERR_FAILED;
  423. }
  424. return ret;
  425. }
  426. int duer_recorder_start()
  427. {
  428. int ret = 0;
  429. DUER_LOGI("duer_recorder_start %d!",s_duer_rec_state);
  430. do {
  431. if(sem_wait(&s_rec_sem)) {
  432. DUER_LOGE("sem_wait failed.");
  433. break;
  434. }
  435. if (RECORDER_STOP == s_duer_rec_state) {
  436. s_duer_rec_state = RECORDER_START;
  437. ret = pthread_create(&s_rec_send_threadID, NULL, (void *)recorder_data_send_thread, NULL);
  438. if(ret != 0)
  439. {
  440. s_duer_rec_state = RECORDER_STOP;
  441. DUER_LOGE("Create recorder pthread error!");
  442. break;
  443. } else {
  444. pthread_setname_np(s_rec_send_threadID, "recorder");
  445. }
  446. }
  447. else{
  448. DUER_LOGI("Recorder Start failed! state:%d", s_duer_rec_state);
  449. }
  450. return DUER_OK;
  451. } while(0);
  452. return DUER_ERR_FAILED;
  453. }
  454. int duer_recorder_stop()
  455. {
  456. int ret = DUER_OK;
  457. DUER_LOGI("duer_recorder_stop! state:%d", s_duer_rec_state);
  458. if (RECORDER_START == s_duer_rec_state) {
  459. s_duer_rec_state = RECORDER_STOP;
  460. s_is_baidu_rec_start = false;
  461. } else {
  462. ret = DUER_ERR_FAILED;
  463. DUER_LOGI("Recorder Stop failed! state:%d", s_duer_rec_state);
  464. }
  465. return ret;
  466. }
  467. int duer_recorder_suspend()
  468. {
  469. int ret = duer_recorder_stop();
  470. if (DUER_OK == ret) {
  471. s_is_suspend = true;
  472. } else {
  473. DUER_LOGI("Recorder Stop failed! state:%d", s_duer_rec_state);
  474. }
  475. return ret;
  476. }
  477. duer_rec_state_t duer_get_recorder_state()
  478. {
  479. return s_duer_rec_state;
  480. }
  481. int duer_hotwords_detect_start(char *model_filename)
  482. {
  483. int ret=0;
  484. duer_set_kws_model_file(model_filename);
  485. s_duer_rec_addr.sin_family = AF_INET;
  486. s_duer_rec_addr.sin_port = htons(19290);
  487. s_duer_rec_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  488. if(sem_init(&s_rec_sem, 0, 1)) {
  489. DUER_LOGE("Init s_rec_sem failed.");
  490. return -1;
  491. }
  492. s_index = (duer_rec_config_t *)malloc(sizeof(duer_rec_config_t));
  493. if (!s_index) {
  494. DUER_LOGE("malloc fail");
  495. return -1;
  496. }
  497. memset(s_index, 0, sizeof(duer_rec_config_t));
  498. s_index->frames = FRAMES_INIT;
  499. s_index->val = SAMPLE_RATE; // pcm sample rate
  500. do{
  501. s_duer_rec_snd_fd = socket(AF_INET, SOCK_DGRAM,IPPROTO_UDP);
  502. if(s_duer_rec_snd_fd <0){
  503. DUER_LOGE("open send socket failed");
  504. break;
  505. }
  506. ret = connect(s_duer_rec_snd_fd, (struct sockaddr *)&s_duer_rec_addr, sizeof(s_duer_rec_addr));
  507. if(ret!=0){
  508. DUER_LOGE("socket connect failed");
  509. break;
  510. }
  511. s_duer_rec_recv_fd = socket(AF_INET, SOCK_DGRAM,IPPROTO_UDP);
  512. if(s_duer_rec_recv_fd <0){
  513. DUER_LOGE("open recv socket failed");
  514. break;
  515. }
  516. ret = bind(s_duer_rec_recv_fd, (struct sockaddr *) &s_duer_rec_addr, sizeof(s_duer_rec_addr));
  517. if(ret<0){
  518. DUER_LOGE("socket bind failed");
  519. break;
  520. }
  521. ret = duer_open_alsa_pcm();
  522. if (ret != DUER_OK) {
  523. DUER_LOGE("open pcm failed");
  524. break;
  525. }
  526. ret = duer_set_pcm_params();
  527. if (ret != DUER_OK) {
  528. DUER_LOGE("open pcm failed");
  529. break;
  530. }
  531. ret = pthread_create(&s_rec_threadID, NULL, (void *)recorder_thread, NULL);
  532. if(ret != 0){
  533. DUER_LOGE("Create recorder pthread error!");
  534. break;
  535. } else {
  536. pthread_setname_np(s_rec_threadID, "recorder");
  537. }
  538. }while(0);
  539. if(ret!=0){
  540. if(s_index) {
  541. free(s_index);
  542. s_index = NULL;
  543. }
  544. if(s_duer_rec_recv_fd>=0){
  545. close(s_duer_rec_recv_fd);
  546. s_duer_rec_recv_fd = -1;
  547. }
  548. if(s_duer_rec_snd_fd>=0){
  549. close(s_duer_rec_snd_fd);
  550. s_duer_rec_snd_fd = -1;
  551. }
  552. }
  553. return ret;
  554. }