record.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. #include <arpa/inet.h>
  2. #include <errno.h>
  3. #include <fcntl.h>
  4. #include <netdb.h>
  5. #include <pthread.h>
  6. #include <sys/select.h>
  7. #include <sys/socket.h>
  8. #include <sys/time.h>
  9. #include <sys/types.h>
  10. #include <unistd.h>
  11. #include <alsa/asoundlib.h>
  12. #include <semaphore.h>
  13. #include <sys/wait.h>
  14. #include <sys/types.h>
  15. #define ALSA_PCM_NEW_HW_PARAMS_API
  16. #define SAMPLE_RATE (16000)
  17. #define FRAMES_INIT (640*4)
  18. #define CHANNEL (4)
  19. #define FRAMES_SIZE ((16/8) *CHANNEL)
  20. #define PCM_STREAM_CAPTURE_DEVICE "hw:2,0"
  21. //#define PCM_STREAM_CAPTURE_DEVICE "default"
  22. typedef struct{
  23. int dir;
  24. int size;
  25. unsigned int val;
  26. snd_pcm_t *handle;
  27. snd_pcm_uframes_t frames;
  28. snd_pcm_hw_params_t *params;
  29. }rec_config_t;
  30. static rec_config_t *s_index = NULL;
  31. typedef struct _pcm_header_t {
  32. char pcm_header[4];
  33. size_t pcm_length;
  34. char format[8];
  35. int bit_rate;
  36. short pcm;
  37. short channel;
  38. int sample_rate;
  39. int byte_rate;
  40. short block_align;
  41. short bits_per_sample;
  42. char fix_data[4];
  43. size_t data_length;
  44. } pcm_header_t;
  45. static pcm_header_t s_pcm_header = {
  46. {'R', 'I', 'F', 'F'},
  47. (size_t)-1,
  48. {'W', 'A', 'V', 'E', 'f', 'm', 't', ' '},
  49. 0x10,
  50. 0x01,
  51. 0x01,
  52. #if 1 //def SAMPLE_RATE_16K
  53. 0x3E80,
  54. 0x7D00,
  55. #else //8k
  56. 0x1F40,
  57. 0x3E80,
  58. #endif // SAMPLE_RATE_16K
  59. 0x02,
  60. 0x10,
  61. {'d', 'a', 't', 'a'},
  62. (size_t)-1
  63. };
  64. typedef struct _REC_FILE{
  65. FILE *_file;
  66. pcm_header_t _hdr;
  67. }REC_FILE;
  68. REC_FILE *s_rec_files[CHANNEL+1];
  69. REC_FILE * duer_store_voice_start(int channel_id)
  70. {
  71. REC_FILE *file=NULL;
  72. printf("start");
  73. file = (REC_FILE*)malloc(sizeof(REC_FILE));
  74. if(file==NULL){
  75. return NULL;
  76. }
  77. char _name[64];
  78. snprintf(_name, sizeof(_name), "./channel-%d.wav", channel_id);
  79. file->_file = fopen(_name, "wb");
  80. if (!file->_file ) {
  81. printf("can't open file %s", _name);
  82. return NULL;
  83. } else {
  84. printf("begin write to file:%s", _name);
  85. }
  86. memcpy(&file->_hdr,&s_pcm_header,sizeof(s_pcm_header));
  87. fwrite(&s_pcm_header, 1, sizeof(s_pcm_header), file->_file);
  88. file->_hdr.data_length = 0;
  89. file->_hdr.pcm_length = sizeof(s_pcm_header) - 8;
  90. return file;
  91. }
  92. int duer_store_voice_write(REC_FILE *file,const void *data, uint32_t size)
  93. {
  94. if (file&&file->_file) {
  95. fwrite(data, 1, size, file->_file);
  96. file->_hdr.data_length += size;
  97. }
  98. return 0;
  99. }
  100. int duer_store_voice_end(REC_FILE *file)
  101. {
  102. if (file&&file->_file) {
  103. file->_hdr.pcm_length += s_pcm_header.data_length;
  104. fseek(file->_file, 0, SEEK_SET);
  105. fwrite(&file->_hdr, 1, sizeof(file->_hdr), file->_file);
  106. fclose(file->_file);
  107. file->_file = NULL;
  108. }
  109. return 0;
  110. }
  111. int read_pcm_mono_data(int16_t *in,int ilen,int16_t *out,int channel_cnt)
  112. {
  113. int i=0;
  114. if((ilen%channel_cnt)){
  115. printf("invalid pcm data lenght!\n");
  116. return -1;
  117. }
  118. for(i=0;i<ilen/channel_cnt;i++){
  119. uint16_t mono_data = 0;
  120. int j=0;
  121. for(j=0;j<channel_cnt;j++){
  122. out[i] += in[channel_cnt*i+j];
  123. }
  124. out[i] /= channel_cnt;
  125. }
  126. return ilen/channel_cnt;
  127. }
  128. int read_pcm_channel_data(int16_t *in,int ilen,int16_t *out,int channel_id,int channel_cnt)
  129. {
  130. int i=0;
  131. if((ilen%channel_cnt)){
  132. printf("invalid pcm data lenght!\n");
  133. return -1;
  134. }
  135. if(channel_id<0||channel_id>=channel_cnt){
  136. printf("please input invalid channel id \n");
  137. return -1;
  138. }
  139. for(i=0;i<ilen/channel_cnt;i++){
  140. out[i] = in[i*channel_cnt+channel_id];
  141. }
  142. return ilen/channel_cnt;
  143. }
  144. static void recording_pcm_data()
  145. {
  146. int16_t *buffer = NULL;
  147. int16_t *mono_buffer = NULL;
  148. int mono_data_size = 0;
  149. snd_pcm_hw_params_get_period_size(s_index->params, &(s_index->frames), &(s_index->dir));
  150. if (s_index->frames < 0) {
  151. printf("Get period size failed!");
  152. return;
  153. }
  154. printf("frames %d dir %d\n",s_index->frames,s_index->dir);
  155. s_index->size = s_index->frames * FRAMES_SIZE;
  156. if (buffer) {
  157. free(buffer);
  158. buffer = NULL;
  159. }
  160. buffer = (int16_t *)malloc(s_index->size);
  161. if (!buffer) {
  162. printf("malloc buffer failed!\n");
  163. } else {
  164. memset(buffer, 0, s_index->size);
  165. }
  166. mono_buffer = (int16_t *)malloc(s_index->size);
  167. if (!mono_buffer) {
  168. printf("malloc buffer failed!\n");
  169. } else {
  170. memset(mono_buffer, 0, s_index->size);
  171. }
  172. while (1)
  173. {
  174. int i=0;
  175. int ret = snd_pcm_readi(s_index->handle, buffer, s_index->frames);
  176. if (ret == -EPIPE) {
  177. printf("an overrun occurred!\n");
  178. snd_pcm_prepare(s_index->handle);
  179. continue;
  180. } else if (ret < 0) {
  181. printf("read: %s\n", snd_strerror(ret));
  182. continue;
  183. } else if (ret != (int)s_index->frames) {
  184. printf("read %d frames!\n", ret);
  185. continue;
  186. } else {
  187. // do nothing
  188. printf("ret=%d %d\n",ret,s_index->size);
  189. }
  190. for(i=0;i<CHANNEL+1;i++){
  191. if(i==CHANNEL){
  192. mono_data_size = read_pcm_mono_data(buffer,s_index->size>>1,mono_buffer,CHANNEL);
  193. }else{
  194. mono_data_size = read_pcm_channel_data(buffer,s_index->size>>1,mono_buffer,i,CHANNEL);
  195. }
  196. duer_store_voice_write(s_rec_files[i],mono_buffer,mono_data_size<<1);
  197. }
  198. }
  199. if (buffer) {
  200. free(buffer);
  201. buffer = NULL;
  202. }
  203. if(mono_buffer){
  204. free(mono_buffer);
  205. mono_buffer=NULL;
  206. }
  207. snd_pcm_drain(s_index->handle);
  208. snd_pcm_close(s_index->handle);
  209. if(s_index) {
  210. free(s_index);
  211. s_index = NULL;
  212. }
  213. return;
  214. }
  215. static int duer_open_alsa_pcm()
  216. {
  217. int ret = 0;
  218. s_index = (rec_config_t *)malloc(sizeof(rec_config_t));
  219. if (!s_index) {
  220. printf("malloc fail\n");
  221. return -1;
  222. }
  223. memset(s_index, 0, sizeof(rec_config_t));
  224. s_index->frames = FRAMES_INIT;
  225. s_index->val = SAMPLE_RATE; // pcm sample rate
  226. int result = (snd_pcm_open(&(s_index->handle), PCM_STREAM_CAPTURE_DEVICE, SND_PCM_STREAM_CAPTURE, 0));
  227. if (result < 0){
  228. printf("\n\n****unable to open pcm device: %s*********\n\n", snd_strerror(ret));
  229. ret = -1;
  230. }
  231. return ret;
  232. }
  233. static int duer_set_pcm_params()
  234. {
  235. int ret = 0;
  236. snd_pcm_hw_params_alloca(&(s_index->params));
  237. snd_pcm_hw_params_any(s_index->handle, s_index->params);
  238. snd_pcm_hw_params_set_access(s_index->handle, s_index->params,
  239. SND_PCM_ACCESS_RW_INTERLEAVED);
  240. snd_pcm_hw_params_set_format(s_index->handle, s_index->params,
  241. SND_PCM_FORMAT_S16_LE);
  242. snd_pcm_hw_params_set_channels(s_index->handle, s_index->params,
  243. CHANNEL);
  244. snd_pcm_hw_params_set_rate_near(s_index->handle, s_index->params,
  245. &(s_index->val), &(s_index->dir));
  246. snd_pcm_hw_params_set_period_size_near(s_index->handle, s_index->params,
  247. &(s_index->frames), &(s_index->dir));
  248. int result = snd_pcm_hw_params(s_index->handle, s_index->params);
  249. if (result < 0) {
  250. printf("unable to set hw parameters: %s\n", snd_strerror(result));
  251. ret = -1;
  252. }
  253. return ret;
  254. }
  255. void record_stop(int signo)
  256. {
  257. int i=0;
  258. printf("oops! stop!!!\n");
  259. for(i=0;i<CHANNEL+1;i++){
  260. if(s_rec_files[i] != NULL){
  261. duer_store_voice_end(s_rec_files[i]);
  262. }
  263. }
  264. _exit(0);
  265. }
  266. int main(int argc, char *argv[])
  267. {
  268. int ret=0;
  269. int i;
  270. for(i=0;i<CHANNEL+1;i++){
  271. s_rec_files[i] = NULL;
  272. s_rec_files[i] = duer_store_voice_start(i);
  273. }
  274. signal(SIGINT, record_stop);
  275. printf("%s %d\n",__FUNCTION__,__LINE__);
  276. ret = duer_open_alsa_pcm();
  277. if (ret != 0) {
  278. printf("open pcm failed\n");
  279. return -1;
  280. }
  281. printf("%s %d\n",__FUNCTION__,__LINE__);
  282. ret = duer_set_pcm_params();
  283. if (ret != 0) {
  284. printf("duer_set_pcm_params failed\n");
  285. return -1;
  286. }
  287. printf("%s %d\n",__FUNCTION__,__LINE__);
  288. recording_pcm_data();
  289. return 0;
  290. }