blob: a941545c9c0a379c82579cecebf9e6887fb4d425 [file] [log] [blame]
Iliyan Malchev4765c432012-06-11 14:36:16 -07001/*
2** Copyright 2010, The Android Open-Source Project
Duy Truongeb337332013-01-17 10:33:22 -08003** Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
Iliyan Malchev4765c432012-06-11 14:36:16 -07004**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <fcntl.h>
21#include <unistd.h>
22#include <stdint.h>
23#include <string.h>
24#include <signal.h>
25#include <errno.h>
26#include <sys/poll.h>
27#include <sys/ioctl.h>
28#include <getopt.h>
29#include <limits.h>
30
Mingming Yinbbd94ad2012-11-29 20:04:36 -080031#include <sound/asound.h>
dhacker2994db5552013-04-26 21:32:42 -050032#ifdef QCOM_COMPRESSED_AUDIO_ENABLED
Mingming Yinbbd94ad2012-11-29 20:04:36 -080033#include <sound/compress_params.h>
34#include <sound/compress_offload.h>
dhacker2994db5552013-04-26 21:32:42 -050035#endif
Mingming Yinbbd94ad2012-11-29 20:04:36 -080036
Iliyan Malchev4765c432012-06-11 14:36:16 -070037#include "alsa_audio.h"
38
39#define ID_RIFF 0x46464952
40#define ID_WAVE 0x45564157
41#define ID_FMT 0x20746d66
42#define ID_DATA 0x61746164
43
44#define FORMAT_PCM 1
45
46#ifndef ANDROID
47#define strlcat g_strlcat
48#define strlcpy g_strlcpy
49#endif
50
Mingming Yinbbd94ad2012-11-29 20:04:36 -080051#define COMPR_META_DATA_SIZE 64
Iliyan Malchev4765c432012-06-11 14:36:16 -070052static struct wav_header hdr;
53static int fd;
54static struct pcm *pcm;
Mingming Yinbbd94ad2012-11-29 20:04:36 -080055static debug = 0;
56static pcm_flag = 1;
57static duration = 0;
Iliyan Malchev4765c432012-06-11 14:36:16 -070058static char *filename;
59static char *data;
60static int format = SNDRV_PCM_FORMAT_S16_LE;
61static int period = 0;
62static int piped = 0;
Mingming Yinbbd94ad2012-11-29 20:04:36 -080063static int compressed = 0;
64static char *compr_codec;
Iliyan Malchev4765c432012-06-11 14:36:16 -070065
66static struct option long_options[] =
67{
68 {"pcm", 0, 0, 'P'},
69 {"debug", 0, 0, 'V'},
70 {"Mmap", 0, 0, 'M'},
71 {"HW", 1, 0, 'D'},
72 {"Rate", 1, 0, 'R'},
73 {"channel", 1, 0, 'C'},
74 {"duration", 1, 0, 'T'},
75 {"format", 1, 0, 'F'},
76 {"period", 1, 0, 'B'},
Mingming Yinbbd94ad2012-11-29 20:04:36 -080077 {"compressed", 1, 0, 'K'},
Iliyan Malchev4765c432012-06-11 14:36:16 -070078 {0, 0, 0, 0}
79};
80
81struct wav_header {
82 uint32_t riff_id;
83 uint32_t riff_sz;
84 uint32_t riff_fmt;
85 uint32_t fmt_id;
86 uint32_t fmt_sz;
87 uint16_t audio_format;
88 uint16_t num_channels;
89 uint32_t sample_rate;
90 uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */
91 uint16_t block_align; /* num_channels * bps / 8 */
92 uint16_t bits_per_sample;
93 uint32_t data_id;
94 uint32_t data_sz;
95};
96
97static int set_params(struct pcm *pcm)
98{
99 struct snd_pcm_hw_params *params;
100 struct snd_pcm_sw_params *sparams;
101
102 unsigned long periodSize, bufferSize, reqBuffSize;
103 unsigned int periodTime, bufferTime;
104 unsigned int requestedRate = pcm->rate;
105
106 params = (struct snd_pcm_hw_params*) calloc(1, sizeof(struct snd_pcm_hw_params));
107 if (!params) {
108 fprintf(stderr, "Arec:Failed to allocate ALSA hardware parameters!");
109 return -ENOMEM;
110 }
111
112 param_init(params);
113
114 param_set_mask(params, SNDRV_PCM_HW_PARAM_ACCESS,
115 (pcm->flags & PCM_MMAP)? SNDRV_PCM_ACCESS_MMAP_INTERLEAVED : SNDRV_PCM_ACCESS_RW_INTERLEAVED);
116 param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, pcm->format);
117 param_set_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT,
118 SNDRV_PCM_SUBFORMAT_STD);
119 if (period)
120 param_set_min(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, period);
121 else
122 param_set_min(params, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 10);
123 param_set_int(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 16);
124 param_set_int(params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
125 pcm->channels * 16);
126 param_set_int(params, SNDRV_PCM_HW_PARAM_CHANNELS,
127 pcm->channels);
128 param_set_int(params, SNDRV_PCM_HW_PARAM_RATE, pcm->rate);
129
130 param_set_hw_refine(pcm, params);
131
132 if (param_set_hw_params(pcm, params)) {
133 fprintf(stderr, "Arec:cannot set hw params");
134 return -errno;
135 }
136 if (debug)
137 param_dump(params);
138
139 pcm->buffer_size = pcm_buffer_size(params);
140 pcm->period_size = pcm_period_size(params);
141 pcm->period_cnt = pcm->buffer_size/pcm->period_size;
142 if (debug) {
143 fprintf (stderr,"period_size (%d)", pcm->period_size);
144 fprintf (stderr," buffer_size (%d)", pcm->buffer_size);
145 fprintf (stderr," period_cnt (%d)\n", pcm->period_cnt);
146 }
147 sparams = (struct snd_pcm_sw_params*) calloc(1, sizeof(struct snd_pcm_sw_params));
148 if (!sparams) {
149 fprintf(stderr, "Arec:Failed to allocate ALSA software parameters!\n");
150 return -ENOMEM;
151 }
152 sparams->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
153 sparams->period_step = 1;
154
155 if (pcm->flags & PCM_MONO) {
156 sparams->avail_min = pcm->period_size/2;
157 sparams->xfer_align = pcm->period_size/2;
158 } else if (pcm->flags & PCM_QUAD) {
159 sparams->avail_min = pcm->period_size/8;
160 sparams->xfer_align = pcm->period_size/8;
161 } else if (pcm->flags & PCM_5POINT1) {
162 sparams->avail_min = pcm->period_size/12;
163 sparams->xfer_align = pcm->period_size/12;
164 } else {
165 sparams->avail_min = pcm->period_size/4;
166 sparams->xfer_align = pcm->period_size/4;
167 }
168
169 sparams->start_threshold = 1;
170 sparams->stop_threshold = INT_MAX;
171 sparams->silence_size = 0;
172 sparams->silence_threshold = 0;
173
174 if (param_set_sw_params(pcm, sparams)) {
175 fprintf(stderr, "Arec:cannot set sw params");
176 return -errno;
177 }
178 if (debug) {
179 fprintf (stderr,"avail_min (%lu)\n", sparams->avail_min);
180 fprintf (stderr,"start_threshold (%lu)\n", sparams->start_threshold);
181 fprintf (stderr,"stop_threshold (%lu)\n", sparams->stop_threshold);
182 fprintf (stderr,"xfer_align (%lu)\n", sparams->xfer_align);
183 }
184 return 0;
185
186}
187
188int record_file(unsigned rate, unsigned channels, int fd, unsigned count, unsigned flags, const char *device)
189{
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800190 unsigned xfer, bufsize, framesize;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700191 int r, avail;
192 int nfds = 1;
193 static int start = 0;
194 struct snd_xferi x;
195 long frames;
196 unsigned offset = 0;
197 int err;
198 struct pollfd pfd[1];
199 int rec_size = 0;
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800200 framesize = 0;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700201 flags |= PCM_IN;
202
203 if (channels == 1)
204 flags |= PCM_MONO;
205 else if (channels == 4)
206 flags |= PCM_QUAD;
207 else if (channels == 6)
208 flags |= PCM_5POINT1;
209 else
210 flags |= PCM_STEREO;
211
212 pcm = pcm_open(flags, device);
213 if (!pcm_ready(pcm)) {
214 pcm_close(pcm);
215 goto fail;
216 }
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800217
218 if (compressed) {
219 struct snd_compr_caps compr_cap;
220 struct snd_compr_params compr_params;
221 printf("SNDRV_COMPRESS_GET_CAPS= 0x%X\n", SNDRV_COMPRESS_GET_CAPS);
222 if (ioctl(pcm->fd, SNDRV_COMPRESS_GET_CAPS, &compr_cap)) {
223 fprintf(stderr, "AREC: SNDRV_COMPRESS_GET_CAPS, failed Error no %d \n", errno);
224 pcm_close(pcm);
225 return -errno;
226 }
227 if (!period)
228 period = compr_cap.min_fragment_size;
229 switch (get_compressed_format(compr_codec)) {
230 case SND_AUDIOCODEC_MP3:
231 compr_params.codec.id = SND_AUDIOCODEC_MP3;
232 break;
233 case SND_AUDIOCODEC_AC3_PASS_THROUGH:
234 compr_params.codec.id = SND_AUDIOCODEC_AC3_PASS_THROUGH;
235 printf("codec -d = %x\n", compr_params.codec.id);
236 break;
237 case SND_AUDIOCODEC_AMRWB:
238 compr_params.codec.id = SND_AUDIOCODEC_AMRWB;
239 compr_params.codec.options.generic.reserved[0] = 8; /*band mode - 23.85 kbps*/
240 compr_params.codec.options.generic.reserved[1] = 0; /*dtx mode - disable*/
241 printf("codec -d = %x\n", compr_params.codec.id);
242 break;
243 default:
244 break;
245 }
246 if (ioctl(pcm->fd, SNDRV_COMPRESS_SET_PARAMS, &compr_params)) {
247 fprintf(stderr, "AREC: SNDRV_COMPRESS_SET_PARAMS,failed Error no %d \n", errno);
248 pcm_close(pcm);
249 return -errno;
250 }
251 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700252 pcm->channels = channels;
253 pcm->rate = rate;
254 pcm->flags = flags;
255 pcm->format = format;
256 if (set_params(pcm)) {
257 fprintf(stderr, "Arec:params setting failed\n");
258 pcm_close(pcm);
259 return -EINVAL;
260 }
261
262 if (!pcm_flag) {
263 if (pcm_prepare(pcm)) {
264 fprintf(stderr, "Arec:Failed in pcm_prepare\n");
265 pcm_close(pcm);
266 return -errno;
267 }
268 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START)) {
269 fprintf(stderr, "Arec: Hostless IOCTL_START Error no %d \n", errno);
270 pcm_close(pcm);
271 return -errno;
272 }
273 while(1);
274 }
275
276 if (flags & PCM_MMAP) {
277 u_int8_t *dst_addr = NULL;
278 struct snd_pcm_sync_ptr *sync_ptr1 = pcm->sync_ptr;
279 unsigned int tmp;
280
281 if (mmap_buffer(pcm)) {
282 fprintf(stderr, "Arec:params setting failed\n");
283 pcm_close(pcm);
284 return -EINVAL;
285 }
286 if (debug)
287 fprintf(stderr, "Arec:mmap_buffer done\n");
288
289 if (pcm_prepare(pcm)) {
290 fprintf(stderr, "Arec:Failed in pcm_prepare\n");
291 pcm_close(pcm);
292 return -errno;
293 }
294
295 bufsize = pcm->period_size;
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800296
Iliyan Malchev4765c432012-06-11 14:36:16 -0700297 if (debug)
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800298 fprintf(stderr, "Arec:bufsize = %d\n", bufsize);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700299 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START)) {
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800300 if (errno == EPIPE) {
Iliyan Malchev4765c432012-06-11 14:36:16 -0700301 fprintf(stderr, "Arec:Failed in SNDRV_PCM_IOCTL_START\n");
302 /* we failed to make our window -- try to restart */
303 pcm->running = 0;
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800304 } else {
305 fprintf(stderr, "Arec:Error no %d \n", errno);
306 return -errno;
307 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700308 }
309
310 pfd[0].fd = pcm->fd;
311 pfd[0].events = POLLIN;
312
313 hdr.data_sz = 0;
314 if (pcm->flags & PCM_MONO) {
315 frames = bufsize / 2;
316 } else if (pcm->flags & PCM_QUAD) {
317 frames = bufsize / 8;
318 } else if (pcm->flags & PCM_5POINT1) {
319 frames = bufsize / 12;
320 } else{
321 frames = bufsize / 4;
322 }
323 x.frames = frames;
324 for(;;) {
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800325 if (!pcm->running) {
326 if (pcm_prepare(pcm))
327 return --errno;
328 start = 0;
329 }
330 /* Sync the current Application pointer from the kernel */
331 pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;/*SNDRV_PCM_SYNC_PTR_HWSYNC;*/
332 err = sync_ptr(pcm);
333 if (err == EPIPE) {
334 fprintf(stderr, "Arec:Failed in sync_ptr \n");
335 /* we failed to make our window -- try to restart */
336 //pcm->overruns++;
337 pcm->running = 0;
338 continue;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700339 }
340 /*
341 * Check for the available data in driver. If available data is
342 * less than avail_min we need to wait
343 */
344 avail = pcm_avail(pcm);
345 if (debug)
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800346 fprintf(stderr, "Arec:avail 1 = %d frames = %ld, avail_min = %d,"
347 "x.frames = %d, bufsize = %d, dst_addr = %p\n",avail, frames,
348 (int)pcm->sw_p->avail_min, (int)x.frames, bufsize, dst_addr);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700349 if (avail < 0)
350 return avail;
351 if (avail < pcm->sw_p->avail_min) {
352 poll(pfd, nfds, TIMEOUT_INFINITE);
353 continue;
354 }
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800355 if (x.frames > avail)
Iliyan Malchev4765c432012-06-11 14:36:16 -0700356 frames = avail;
357 /*
358 * Now that we have data size greater than avail_min available to
359 * to be read we need to calcutate the buffer offset where we can
360 * start reading from.
361 */
362 dst_addr = dst_address(pcm);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800363 if (compressed) {
364 framesize = (unsigned)(dst_addr[3] << 24) + (unsigned)(dst_addr[2] << 16) +
365 (unsigned) (dst_addr[1] << 8) + (unsigned)dst_addr[0];
366 if (debug)
367 fprintf(stderr, "Arec:dst_addr[0] = %d, dst_addr[1] = %d,"
368 "dst_addr[2] = %d, dst_addr[3] = %d, dst_addr[4] = %d,"
369 "dst_addr[5] = %d, dst_addr = %p, bufsize = %d, framesize = %d\n",
370 dst_addr[0], dst_addr[1], dst_addr[2], dst_addr[3], dst_addr[4],
371 dst_addr[5],dst_addr, bufsize, framesize);
372 dst_addr += COMPR_META_DATA_SIZE;
373 } else {
374 framesize = bufsize;
375 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700376
377 /*
378 * Write to the file at the destination address from kernel mmaped buffer
379 * This reduces a extra copy of intermediate buffer.
380 */
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800381 if (write(fd, dst_addr, framesize) != framesize) {
382 fprintf(stderr, "Arec:could not write %d bytes\n", framesize);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700383 return -errno;
384 }
385 x.frames -= frames;
386 pcm->sync_ptr->c.control.appl_ptr += frames;
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800387 pcm->sync_ptr->flags = 0;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700388 err = sync_ptr(pcm);
389 if (err == EPIPE) {
390 fprintf(stderr, "Arec:Failed in sync_ptr \n");
391 /* we failed to make our window -- try to restart */
392 pcm->running = 0;
393 continue;
394 }
395 rec_size += bufsize;
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800396 if (!compressed) {
397 hdr.data_sz += bufsize;
398 hdr.riff_sz = hdr.data_sz + 44 - 8;
399 if (!piped) {
400 lseek(fd, 0, SEEK_SET);
401 write(fd, &hdr, sizeof(hdr));
402 lseek(fd, 0, SEEK_END);
403 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700404 }
405 if (rec_size >= count)
406 break;
407 }
408 } else {
409 bufsize = pcm->period_size;
410 if (pcm_prepare(pcm)) {
411 fprintf(stderr, "Arec:Failed in pcm_prepare\n");
412 pcm_close(pcm);
413 return -errno;
414 }
415
416 data = calloc(1, bufsize);
417 if (!data) {
418 fprintf(stderr, "Arec:could not allocate %d bytes\n", bufsize);
419 return -ENOMEM;
420 }
421
422 while (!pcm_read(pcm, data, bufsize)) {
423 if (write(fd, data, bufsize) != bufsize) {
424 fprintf(stderr, "Arec:could not write %d bytes\n", bufsize);
425 break;
426 }
427 rec_size += bufsize;
428 hdr.data_sz += bufsize;
429 hdr.riff_sz = hdr.data_sz + 44 - 8;
430 if (!piped) {
431 lseek(fd, 0, SEEK_SET);
432 write(fd, &hdr, sizeof(hdr));
433 lseek(fd, 0, SEEK_END);
434 }
435 if (rec_size >= count)
436 break;
437 }
438 }
439 fprintf(stderr, " rec_size =%d count =%d\n", rec_size, count);
440 close(fd);
441 free(data);
442 pcm_close(pcm);
443 return hdr.data_sz;
444
445fail:
446 fprintf(stderr, "Arec:pcm error: %s\n", pcm_error(pcm));
447 return -errno;
448}
449
450int rec_raw(const char *fg, const char *device, int rate, int ch,
451 const char *fn)
452{
453 unsigned flag = 0;
454 uint32_t rec_max_sz = 2147483648LL;
455 uint32_t count;
456 int i = 0;
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800457 printf("rec_raw-> pcm_flag = %d\n", pcm_flag);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700458 if (!fn) {
459 fd = fileno(stdout);
460 piped = 1;
461 } else {
462 fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);
463 if (fd < 0) {
464 fprintf(stderr, "Arec:arec: cannot open '%s'\n", fn);
465 return -EBADFD;
466 }
467 }
468 if (duration == 0) {
469 count = rec_max_sz;
470 } else {
471 count = rate * ch * 2;
472 count *= (uint32_t)duration;
473 }
474 count = count < rec_max_sz ? count : rec_max_sz;
475 if (debug)
476 fprintf(stderr, "arec: %d ch, %d hz, %d bit, format %x\n",
477 ch, rate, 16, format);
478
479 if (!strncmp(fg, "M", sizeof("M"))) {
480 flag = PCM_MMAP;
481 } else if (!strncmp(fg, "N", sizeof("N"))) {
482 flag = PCM_NMMAP;
483 }
484 return record_file(rate, ch, fd, count, flag, device);
485}
486
487int rec_wav(const char *fg, const char *device, int rate, int ch, const char *fn)
488{
489 unsigned flag = 0;
490 uint32_t rec_max_sz = 2147483648LL;
491 uint32_t count = 0;
492 int i = 0;
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800493 printf("rec_wav-> pcm_flag = %d\n", pcm_flag);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700494 if (pcm_flag) {
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800495 if (!fn) {
496 fd = fileno(stdout);
497 piped = 1;
498 } else {
499 fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);
500 if (fd < 0) {
501 fprintf(stderr, "Arec:arec: cannot open '%s'\n", fn);
502 return -EBADFD;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700503 }
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800504 }
505 if (compressed) {
Iliyan Malchev4765c432012-06-11 14:36:16 -0700506
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800507 printf("rec_wav-> compressed = %d\n", compressed);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700508 hdr.sample_rate = rate;
509 hdr.num_channels = ch;
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800510 goto ignore_header;
511 }
512 memset(&hdr, 0, sizeof(struct wav_header));
513 hdr.riff_id = ID_RIFF;
514 hdr.riff_fmt = ID_WAVE;
515 hdr.fmt_id = ID_FMT;
516 hdr.fmt_sz = 16;
517 hdr.audio_format = FORMAT_PCM;
518 hdr.num_channels = ch;
519 hdr.sample_rate = rate;
520 hdr.bits_per_sample = 16;
521 hdr.byte_rate = (rate * ch * hdr.bits_per_sample) / 8;
522 hdr.block_align = ( hdr.bits_per_sample * ch ) / 8;
523 hdr.data_id = ID_DATA;
524 hdr.data_sz = 0;
525 hdr.riff_sz = hdr.data_sz + 44 - 8;
526 if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
527 if (debug)
528 fprintf(stderr, "arec: cannot write header\n");
529 return -errno;
530 }
531 if (debug)
532 fprintf(stderr, "arec: %d ch, %d hz, %d bit, %s\n",
533 hdr.num_channels, hdr.sample_rate, hdr.bits_per_sample,
534 hdr.audio_format == FORMAT_PCM ? "PCM" : "unknown");
535 } else {
536 hdr.sample_rate = rate;
537 hdr.num_channels = ch;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700538 }
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800539ignore_header:
Iliyan Malchev4765c432012-06-11 14:36:16 -0700540
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800541 if (duration == 0) {
542 count = rec_max_sz;
543 } else {
544 count = rate * ch * 2;
545 count *= (uint32_t)duration;
546 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700547 if (!strncmp(fg, "M", sizeof("M"))) {
548 flag = PCM_MMAP;
549 } else if (!strncmp(fg, "N", sizeof("N"))) {
550 flag = PCM_NMMAP;
551 }
552 return record_file(hdr.sample_rate, hdr.num_channels, fd, count, flag, device);
553}
554
555static void signal_handler(int sig)
556{
557 long file_size;
558 FILE *fp;
559
560 fprintf(stderr, "Arec:Aborted by signal %s...\n", strsignal(sig));
561 fprintf(stderr, "Arec:lseeked to %d", (int) lseek(fd, 0, SEEK_SET));
562 hdr.riff_sz = hdr.data_sz + 44 - 8;
563 fprintf(stderr, "Arec: hdr.data_sz =%d\n", hdr.data_sz);
564 fprintf(stderr, "Arec: hdr.riff_sz =%d\n", hdr.riff_sz);
565 if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
566 if (debug)
567 fprintf(stderr, "Arec:arec: cannot write header\n");
568 } else
569 fd = -1;
570
571 if (fd > 1) {
572 close(fd);
573 fd = -1;
574 }
575 free(filename);
576 free(data);
577 pcm = NULL;
578 raise(sig);
579}
580
581int main(int argc, char **argv)
582{
583 int rate = 48000;
584 int ch = 1;
585 int i = 0;
586 int option_index = 0;
587 int c;
588 char *mmap = "N";
589 char *device = "hw:0,0";
590 struct sigaction sa;
591 int rc = 0;
592
593 if (argc < 2) {
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800594 printf("\nUsage: arec [options] <file>\n"
595 "options:\n"
596 "-D <hw:C,D> -- Alsa PCM by name\n"
597 "-M -- Mmap stream\n"
598 "-P -- Hostless steam[No PCM]\n"
599 "-V -- verbose\n"
600 "-C -- Channels\n"
601 "-R -- Rate\n"
602 "-T -- Time in seconds for recording\n"
603 "-F -- Format\n"
604 "-B -- Period\n"
605 "-K <AC3,DTS,etc> -- compressed\n"
606 "<file> \n");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700607 for (i = 0; i < SNDRV_PCM_FORMAT_LAST; ++i)
608 if (get_format_name(i))
609 fprintf(stderr, "%s ", get_format_name(i));
610 fprintf(stderr, "\nSome of these may not be available on selected hardware\n");
611 return 0;
612 }
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800613 while ((c = getopt_long(argc, argv, "PVMD:R:C:T:F:B:K:", long_options, &option_index)) != -1) {
Iliyan Malchev4765c432012-06-11 14:36:16 -0700614 switch (c) {
615 case 'P':
616 pcm_flag = 0;
617 break;
618 case 'V':
619 debug = 1;
620 break;
621 case 'M':
622 mmap = "M";
623 break;
624 case 'D':
625 device = optarg;
626 break;
627 case 'R':
628 rate = (int)strtol(optarg, NULL, 0);
629 break;
630 case 'C':
631 ch = (int)strtol(optarg, NULL, 0);
632 break;
633 case 'T':
634 duration = (int)strtol(optarg, NULL, 0);
635 break;
636 case 'F':
637 format = (int)get_format(optarg);
638 break;
639 case 'B':
640 period = (int)strtol(optarg, NULL, 0);
641 break;
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800642 case 'K':
643 compressed = 1;
644 printf("compressed codec type requested = %s\n", optarg);
645 compr_codec = optarg;
646 break;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700647 default:
648 printf("\nUsage: arec [options] <file>\n"
649 "options:\n"
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800650 "-D <hw:C,D> -- Alsa PCM by name\n"
651 "-M -- Mmap stream\n"
652 "-P -- Hostless steam[No PCM]\n"
653 "-V -- verbose\n"
654 "-C -- Channels\n"
655 "-R -- Rate\n"
656 "-T -- Time in seconds for recording\n"
657 "-F -- Format\n"
658 "-B -- Period\n"
659 "-K <AC3,DTS,etc> -- compressed\n"
Iliyan Malchev4765c432012-06-11 14:36:16 -0700660 "<file> \n");
661 for (i = 0; i < SNDRV_PCM_FORMAT_LAST; ++i)
662 if (get_format_name(i))
663 fprintf(stderr, "%s ", get_format_name(i));
664 fprintf(stderr, "\nSome of these may not be available on selected hardware\n");
665 return -EINVAL;
666 }
667 }
668 filename = (char*) calloc(1, 30);
669 if (!filename) {
670 fprintf(stderr, "Arec:Failed to allocate filename!");
671 return -ENOMEM;
672 }
673 if (optind > argc - 1) {
674 free(filename);
675 filename = NULL;
676 } else {
677 strlcpy(filename, argv[optind++], 30);
678 }
679
680 memset(&sa, 0, sizeof(sa));
681 sa.sa_handler = &signal_handler;
682 sigaction(SIGABRT, &sa, NULL);
683
684 if (pcm_flag) {
685 if (format == SNDRV_PCM_FORMAT_S16_LE)
686 rc = rec_wav(mmap, device, rate, ch, filename);
687 else
688 rc = rec_raw(mmap, device, rate, ch, filename);
689 } else {
690 rc = rec_wav(mmap, device, rate, ch, "dummy");
691 }
692 if (filename)
693 free(filename);
694
695 return rc;
696}
697