Home | History | Annotate | Line # | Download | only in record
record.c revision 1.56
      1  1.56   mlelstv /*	$NetBSD: record.c,v 1.56 2022/01/09 06:33:13 mlelstv Exp $	*/
      2   1.2       mrg 
      3   1.2       mrg /*
      4  1.48       mrg  * Copyright (c) 1999, 2002, 2003, 2005, 2010 Matthew R. Green
      5   1.2       mrg  * All rights reserved.
      6   1.2       mrg  *
      7   1.2       mrg  * Redistribution and use in source and binary forms, with or without
      8   1.2       mrg  * modification, are permitted provided that the following conditions
      9   1.2       mrg  * are met:
     10   1.2       mrg  * 1. Redistributions of source code must retain the above copyright
     11   1.2       mrg  *    notice, this list of conditions and the following disclaimer.
     12   1.2       mrg  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.2       mrg  *    notice, this list of conditions and the following disclaimer in the
     14   1.2       mrg  *    documentation and/or other materials provided with the distribution.
     15   1.2       mrg  *
     16   1.2       mrg  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17   1.2       mrg  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18   1.2       mrg  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19   1.2       mrg  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20   1.2       mrg  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21   1.2       mrg  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22   1.2       mrg  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23   1.2       mrg  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24   1.2       mrg  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25   1.2       mrg  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26   1.2       mrg  * SUCH DAMAGE.
     27   1.2       mrg  */
     28   1.2       mrg 
     29   1.1       mrg /*
     30   1.1       mrg  * SunOS compatible audiorecord(1)
     31   1.1       mrg  */
     32  1.33       agc #include <sys/cdefs.h>
     33  1.33       agc 
     34  1.33       agc #ifndef lint
     35  1.56   mlelstv __RCSID("$NetBSD: record.c,v 1.56 2022/01/09 06:33:13 mlelstv Exp $");
     36  1.33       agc #endif
     37  1.33       agc 
     38   1.1       mrg 
     39  1.48       mrg #include <sys/param.h>
     40   1.1       mrg #include <sys/audioio.h>
     41   1.1       mrg #include <sys/ioctl.h>
     42   1.1       mrg #include <sys/time.h>
     43   1.1       mrg #include <sys/uio.h>
     44   1.1       mrg 
     45   1.1       mrg #include <err.h>
     46   1.1       mrg #include <fcntl.h>
     47   1.1       mrg #include <paths.h>
     48   1.1       mrg #include <signal.h>
     49   1.1       mrg #include <stdio.h>
     50   1.1       mrg #include <stdlib.h>
     51   1.1       mrg #include <string.h>
     52   1.1       mrg #include <unistd.h>
     53  1.44     lukem #include <util.h>
     54   1.1       mrg 
     55   1.1       mrg #include "libaudio.h"
     56  1.19       mrg #include "auconv.h"
     57   1.1       mrg 
     58  1.51     joerg static audio_info_t info, oinfo;
     59  1.51     joerg static const char *device;
     60  1.53       mrg static int	audiofd;
     61  1.53       mrg static int	aflag, fflag;
     62   1.1       mrg int	verbose;
     63  1.51     joerg static int	monitor_gain, omonitor_gain;
     64  1.51     joerg static int	gain;
     65  1.51     joerg static int	balance;
     66  1.51     joerg static int	port;
     67  1.51     joerg static char	*encoding_str;
     68  1.54       mrg static struct track_info ti;
     69  1.51     joerg static struct timeval record_time;
     70  1.51     joerg static struct timeval start_time;
     71  1.56   mlelstv static int no_time_limit = 1;
     72  1.51     joerg 
     73  1.51     joerg static void (*conv_func) (u_char *, int);
     74  1.51     joerg 
     75  1.51     joerg static void usage (void) __dead;
     76  1.51     joerg static int timeleft (struct timeval *, struct timeval *);
     77  1.51     joerg static void cleanup (int) __dead;
     78  1.51     joerg static void rewrite_header (void);
     79  1.56   mlelstv static void stop (int);
     80  1.56   mlelstv 
     81  1.56   mlelstv static void stop (int sig)
     82  1.56   mlelstv {
     83  1.56   mlelstv 	no_time_limit = 0;
     84  1.56   mlelstv 	timerclear(&record_time);
     85  1.56   mlelstv }
     86   1.1       mrg 
     87   1.1       mrg int
     88  1.51     joerg main(int argc, char *argv[])
     89   1.1       mrg {
     90  1.43       mrg 	u_char	*buffer;
     91  1.48       mrg 	size_t	len, bufsize = 0;
     92  1.55  riastrad 	ssize_t	nread;
     93  1.56   mlelstv 	int	ch;
     94  1.24  augustss 	const char *defdevice = _PATH_SOUND;
     95   1.1       mrg 
     96  1.53       mrg 	/*
     97  1.54       mrg 	 * Initialise the track_info.
     98  1.53       mrg 	 */
     99  1.54       mrg 	ti.format = AUDIO_FORMAT_DEFAULT;
    100  1.54       mrg 	ti.total_size = -1;
    101  1.53       mrg 
    102  1.48       mrg 	while ((ch = getopt(argc, argv, "ab:B:C:F:c:d:e:fhi:m:P:p:qt:s:Vv:")) != -1) {
    103   1.1       mrg 		switch (ch) {
    104   1.1       mrg 		case 'a':
    105   1.1       mrg 			aflag++;
    106   1.1       mrg 			break;
    107   1.1       mrg 		case 'b':
    108   1.1       mrg 			decode_int(optarg, &balance);
    109   1.1       mrg 			if (balance < 0 || balance > 63)
    110  1.30     grant 				errx(1, "balance must be between 0 and 63");
    111   1.1       mrg 			break;
    112  1.48       mrg 		case 'B':
    113  1.48       mrg 			bufsize = strsuftoll("read buffer size", optarg,
    114  1.48       mrg 					     1, UINT_MAX);
    115  1.48       mrg 			break;
    116   1.1       mrg 		case 'C':
    117  1.23  jdolecek 			/* Ignore, compatibility */
    118   1.1       mrg 			break;
    119  1.17       mrg 		case 'F':
    120  1.54       mrg 			ti.format = audio_format_from_str(optarg);
    121  1.54       mrg 			if (ti.format < 0)
    122  1.27       mrg 				errx(1, "Unknown audio format; supported "
    123  1.27       mrg 				    "formats: \"sun\", \"wav\", and \"none\"");
    124  1.17       mrg 			break;
    125   1.1       mrg 		case 'c':
    126  1.54       mrg 			decode_int(optarg, &ti.channels);
    127  1.54       mrg 			if (ti.channels < 0 || ti.channels > 16)
    128  1.30     grant 				errx(1, "channels must be between 0 and 16");
    129   1.1       mrg 			break;
    130   1.1       mrg 		case 'd':
    131   1.1       mrg 			device = optarg;
    132   1.1       mrg 			break;
    133   1.1       mrg 		case 'e':
    134   1.1       mrg 			encoding_str = optarg;
    135   1.1       mrg 			break;
    136   1.1       mrg 		case 'f':
    137   1.1       mrg 			fflag++;
    138   1.1       mrg 			break;
    139   1.1       mrg 		case 'i':
    140  1.54       mrg 			ti.header_info = optarg;
    141   1.1       mrg 			break;
    142   1.1       mrg 		case 'm':
    143  1.17       mrg 			decode_int(optarg, &monitor_gain);
    144  1.17       mrg 			if (monitor_gain < 0 || monitor_gain > 255)
    145  1.30     grant 				errx(1, "monitor volume must be between 0 and 255");
    146   1.1       mrg 			break;
    147   1.1       mrg 		case 'P':
    148  1.54       mrg 			decode_int(optarg, &ti.precision);
    149  1.54       mrg 			if (ti.precision != 4 && ti.precision != 8 &&
    150  1.54       mrg 			    ti.precision != 16 && ti.precision != 24 &&
    151  1.54       mrg 			    ti.precision != 32)
    152  1.15   minoura 				errx(1, "precision must be between 4, 8, 16, 24 or 32");
    153   1.1       mrg 			break;
    154   1.1       mrg 		case 'p':
    155   1.1       mrg 			len = strlen(optarg);
    156   1.1       mrg 
    157   1.1       mrg 			if (strncmp(optarg, "mic", len) == 0)
    158   1.1       mrg 				port |= AUDIO_MICROPHONE;
    159   1.1       mrg 			else if (strncmp(optarg, "cd", len) == 0 ||
    160   1.1       mrg 			           strncmp(optarg, "internal-cd", len) == 0)
    161   1.1       mrg 				port |= AUDIO_CD;
    162   1.1       mrg 			else if (strncmp(optarg, "line", len) == 0)
    163   1.1       mrg 				port |= AUDIO_LINE_IN;
    164   1.1       mrg 			else
    165   1.1       mrg 				errx(1,
    166   1.1       mrg 			    "port must be `cd', `internal-cd', `mic', or `line'");
    167   1.1       mrg 			break;
    168   1.1       mrg 		case 'q':
    169  1.54       mrg 			ti.qflag++;
    170   1.1       mrg 			break;
    171   1.1       mrg 		case 's':
    172  1.54       mrg 			decode_int(optarg, &ti.sample_rate);
    173  1.54       mrg 			if (ti.sample_rate < 0 || ti.sample_rate > 48000 * 2)	/* XXX */
    174  1.30     grant 				errx(1, "sample rate must be between 0 and 96000");
    175   1.1       mrg 			break;
    176   1.1       mrg 		case 't':
    177   1.8       mrg 			no_time_limit = 0;
    178   1.1       mrg 			decode_time(optarg, &record_time);
    179   1.1       mrg 			break;
    180   1.1       mrg 		case 'V':
    181   1.1       mrg 			verbose++;
    182   1.1       mrg 			break;
    183   1.1       mrg 		case 'v':
    184  1.17       mrg 			decode_int(optarg, &gain);
    185  1.17       mrg 			if (gain < 0 || gain > 255)
    186  1.30     grant 				errx(1, "volume must be between 0 and 255");
    187   1.1       mrg 			break;
    188   1.1       mrg 		/* case 'h': */
    189   1.1       mrg 		default:
    190   1.1       mrg 			usage();
    191   1.1       mrg 			/* NOTREACHED */
    192   1.1       mrg 		}
    193   1.1       mrg 	}
    194   1.1       mrg 	argc -= optind;
    195   1.1       mrg 	argv += optind;
    196   1.1       mrg 
    197  1.39       mrg 	if (argc != 1)
    198  1.39       mrg 		usage();
    199  1.39       mrg 
    200   1.1       mrg 	/*
    201  1.40       mrg 	 * convert the encoding string into a value.
    202  1.40       mrg 	 */
    203  1.40       mrg 	if (encoding_str) {
    204  1.54       mrg 		ti.encoding = audio_enc_to_val(encoding_str);
    205  1.54       mrg 		if (ti.encoding == -1)
    206  1.40       mrg 			errx(1, "unknown encoding, bailing...");
    207  1.40       mrg 	}
    208  1.40       mrg 
    209  1.40       mrg 	/*
    210  1.40       mrg 	 * open the output file
    211  1.40       mrg 	 */
    212  1.42      gson 	if (argv[0][0] != '-' || argv[0][1] != '\0') {
    213  1.40       mrg 		/* intuit the file type from the name */
    214  1.54       mrg 		if (ti.format == AUDIO_FORMAT_DEFAULT)
    215  1.40       mrg 		{
    216  1.40       mrg 			size_t flen = strlen(*argv);
    217  1.40       mrg 			const char *arg = *argv;
    218  1.40       mrg 
    219  1.40       mrg 			if (strcasecmp(arg + flen - 3, ".au") == 0)
    220  1.54       mrg 				ti.format = AUDIO_FORMAT_SUN;
    221  1.40       mrg 			else if (strcasecmp(arg + flen - 4, ".wav") == 0)
    222  1.54       mrg 				ti.format = AUDIO_FORMAT_WAV;
    223  1.40       mrg 		}
    224  1.54       mrg 		ti.outfd = open(*argv, O_CREAT|(aflag ? O_APPEND : O_TRUNC)|O_WRONLY, 0666);
    225  1.54       mrg 		if (ti.outfd < 0)
    226  1.40       mrg 			err(1, "could not open %s", *argv);
    227  1.40       mrg 	} else
    228  1.54       mrg 		ti.outfd = STDOUT_FILENO;
    229  1.40       mrg 
    230  1.40       mrg 	/*
    231  1.34       mrg 	 * open the audio device
    232   1.1       mrg 	 */
    233   1.6    kleink 	if (device == NULL && (device = getenv("AUDIODEVICE")) == NULL &&
    234   1.6    kleink 	    (device = getenv("AUDIODEV")) == NULL) /* Sun compatibility */
    235  1.24  augustss 		device = defdevice;
    236   1.1       mrg 
    237   1.1       mrg 	audiofd = open(device, O_RDONLY);
    238  1.24  augustss 	if (audiofd < 0 && device == defdevice) {
    239  1.22  augustss 		device = _PATH_SOUND0;
    240  1.28       uwe 		audiofd = open(device, O_RDONLY);
    241  1.22  augustss 	}
    242   1.1       mrg 	if (audiofd < 0)
    243   1.1       mrg 		err(1, "failed to open %s", device);
    244   1.1       mrg 
    245   1.1       mrg 	/*
    246   1.1       mrg 	 * work out the buffer size to use, and allocate it.  also work out
    247   1.1       mrg 	 * what the old monitor gain value is, so that we can reset it later.
    248   1.1       mrg 	 */
    249  1.23  jdolecek 	if (ioctl(audiofd, AUDIO_GETINFO, &oinfo) < 0)
    250   1.1       mrg 		err(1, "failed to get audio info");
    251  1.49  jmcneill 	if (bufsize == 0) {
    252  1.48       mrg 		bufsize = oinfo.record.buffer_size;
    253  1.49  jmcneill 		if (bufsize < 32 * 1024)
    254  1.49  jmcneill 			bufsize = 32 * 1024;
    255  1.49  jmcneill 	}
    256  1.17       mrg 	omonitor_gain = oinfo.monitor_gain;
    257   1.1       mrg 
    258   1.1       mrg 	buffer = malloc(bufsize);
    259   1.1       mrg 	if (buffer == NULL)
    260   1.1       mrg 		err(1, "couldn't malloc buffer of %d size", (int)bufsize);
    261   1.1       mrg 
    262   1.1       mrg 	/*
    263  1.17       mrg 	 * set up audio device for recording with the speified parameters
    264  1.17       mrg 	 */
    265  1.17       mrg 	AUDIO_INITINFO(&info);
    266  1.17       mrg 
    267  1.17       mrg 	/*
    268  1.17       mrg 	 * for these, get the current values for stuffing into the header
    269  1.17       mrg 	 */
    270  1.53       mrg #define SETINFO2(x, y)	if (x) \
    271  1.53       mrg 				info.record.y = x; \
    272  1.40       mrg 			else \
    273  1.53       mrg 				info.record.y = x = oinfo.record.y;
    274  1.54       mrg #define SETINFO(x)	SETINFO2(ti.x, x)
    275  1.53       mrg 
    276  1.40       mrg 	SETINFO (sample_rate)
    277  1.40       mrg 	SETINFO (channels)
    278  1.40       mrg 	SETINFO (precision)
    279  1.40       mrg 	SETINFO (encoding)
    280  1.53       mrg 	SETINFO2 (gain, gain)
    281  1.53       mrg 	SETINFO2 (port, port)
    282  1.53       mrg 	SETINFO2 (balance, balance)
    283  1.17       mrg #undef SETINFO
    284  1.53       mrg #undef SETINFO2
    285  1.17       mrg 
    286  1.17       mrg 	if (monitor_gain)
    287  1.17       mrg 		info.monitor_gain = monitor_gain;
    288  1.17       mrg 	else
    289  1.17       mrg 		monitor_gain = oinfo.monitor_gain;
    290   1.1       mrg 
    291   1.1       mrg 	info.mode = AUMODE_RECORD;
    292  1.23  jdolecek 	if (ioctl(audiofd, AUDIO_SETINFO, &info) < 0)
    293  1.29       mrg 		err(1, "failed to set audio info");
    294   1.1       mrg 
    295  1.56   mlelstv 	signal(SIGINT, stop);
    296  1.53       mrg 
    297  1.54       mrg 	ti.total_size = 0;
    298  1.53       mrg 
    299  1.54       mrg 	write_header(&ti);
    300  1.54       mrg 	if (ti.format == AUDIO_FORMAT_NONE)
    301  1.53       mrg 		errx(1, "unable to determine audio format");
    302  1.54       mrg 	conv_func = write_get_conv_func(&ti);
    303   1.1       mrg 
    304  1.27       mrg 	if (verbose && conv_func) {
    305  1.27       mrg 		const char *s = NULL;
    306  1.27       mrg 
    307  1.27       mrg 		if (conv_func == swap_bytes)
    308  1.27       mrg 			s = "swap bytes (16 bit)";
    309  1.27       mrg 		else if (conv_func == swap_bytes32)
    310  1.27       mrg 			s = "swap bytes (32 bit)";
    311  1.27       mrg 		else if (conv_func == change_sign16_be)
    312  1.27       mrg 			s = "change sign (big-endian, 16 bit)";
    313  1.27       mrg 		else if (conv_func == change_sign16_le)
    314  1.27       mrg 			s = "change sign (little-endian, 16 bit)";
    315  1.27       mrg 		else if (conv_func == change_sign32_be)
    316  1.27       mrg 			s = "change sign (big-endian, 32 bit)";
    317  1.27       mrg 		else if (conv_func == change_sign32_le)
    318  1.27       mrg 			s = "change sign (little-endian, 32 bit)";
    319  1.27       mrg 		else if (conv_func == change_sign16_swap_bytes_be)
    320  1.27       mrg 			s = "change sign & swap bytes (big-endian, 16 bit)";
    321  1.27       mrg 		else if (conv_func == change_sign16_swap_bytes_le)
    322  1.27       mrg 			s = "change sign & swap bytes (little-endian, 16 bit)";
    323  1.27       mrg 		else if (conv_func == change_sign32_swap_bytes_be)
    324  1.27       mrg 			s = "change sign (big-endian, 32 bit)";
    325  1.27       mrg 		else if (conv_func == change_sign32_swap_bytes_le)
    326  1.27       mrg 			s = "change sign & swap bytes (little-endian, 32 bit)";
    327  1.27       mrg 
    328  1.27       mrg 		if (s)
    329  1.27       mrg 			fprintf(stderr, "%s: converting, using function: %s\n",
    330  1.27       mrg 			    getprogname(), s);
    331  1.27       mrg 		else
    332  1.27       mrg 			fprintf(stderr, "%s: using unnamed conversion "
    333  1.27       mrg 					"function\n", getprogname());
    334  1.27       mrg 	}
    335  1.27       mrg 
    336  1.27       mrg 	if (verbose)
    337  1.27       mrg 		fprintf(stderr,
    338  1.27       mrg 		   "sample_rate=%d channels=%d precision=%d encoding=%s\n",
    339  1.27       mrg 		   info.record.sample_rate, info.record.channels,
    340  1.27       mrg 		   info.record.precision,
    341  1.27       mrg 		   audio_enc_from_val(info.record.encoding));
    342  1.32       mrg 
    343  1.32       mrg 	if (!no_time_limit && verbose)
    344  1.32       mrg 		fprintf(stderr, "recording for %lu seconds, %lu microseconds\n",
    345  1.32       mrg 		    (u_long)record_time.tv_sec, (u_long)record_time.tv_usec);
    346  1.27       mrg 
    347   1.1       mrg 	(void)gettimeofday(&start_time, NULL);
    348   1.8       mrg 	while (no_time_limit || timeleft(&start_time, &record_time)) {
    349  1.55  riastrad 		if ((nread = read(audiofd, buffer, bufsize)) == -1)
    350   1.1       mrg 			err(1, "read failed");
    351  1.55  riastrad 		if (nread == 0)
    352  1.56   mlelstv 			break;
    353  1.18       mrg 		if (conv_func)
    354  1.56   mlelstv 			(*conv_func)(buffer, nread);
    355  1.56   mlelstv 		if (write(ti.outfd, buffer, nread) != nread)
    356   1.1       mrg 			err(1, "write failed");
    357  1.56   mlelstv 		ti.total_size += nread;
    358   1.1       mrg 	}
    359   1.1       mrg 	cleanup(0);
    360   1.1       mrg }
    361   1.1       mrg 
    362   1.1       mrg int
    363  1.51     joerg timeleft(struct timeval *start_tvp, struct timeval *record_tvp)
    364   1.1       mrg {
    365   1.1       mrg 	struct timeval now, diff;
    366   1.1       mrg 
    367   1.1       mrg 	(void)gettimeofday(&now, NULL);
    368   1.7  dmcmahil 	timersub(&now, start_tvp, &diff);
    369   1.7  dmcmahil 	timersub(record_tvp, &diff, &now);
    370   1.1       mrg 
    371   1.1       mrg 	return (now.tv_sec > 0 || (now.tv_sec == 0 && now.tv_usec > 0));
    372   1.1       mrg }
    373   1.1       mrg 
    374   1.1       mrg void
    375  1.51     joerg cleanup(int signo)
    376   1.1       mrg {
    377   1.1       mrg 
    378   1.1       mrg 	rewrite_header();
    379  1.54       mrg 	close(ti.outfd);
    380  1.17       mrg 	if (omonitor_gain) {
    381   1.1       mrg 		AUDIO_INITINFO(&info);
    382  1.17       mrg 		info.monitor_gain = omonitor_gain;
    383  1.23  jdolecek 		if (ioctl(audiofd, AUDIO_SETINFO, &info) < 0)
    384   1.1       mrg 			err(1, "failed to reset audio info");
    385   1.1       mrg 	}
    386  1.23  jdolecek 	close(audiofd);
    387  1.44     lukem 	if (signo != 0) {
    388  1.44     lukem 		(void)raise_default_signal(signo);
    389  1.44     lukem 	}
    390   1.1       mrg 	exit(0);
    391   1.1       mrg }
    392   1.1       mrg 
    393  1.51     joerg static void
    394  1.51     joerg rewrite_header(void)
    395   1.1       mrg {
    396   1.1       mrg 
    397   1.1       mrg 	/* can't do this here! */
    398  1.54       mrg 	if (ti.outfd == STDOUT_FILENO)
    399   1.1       mrg 		return;
    400  1.54       mrg 	if (lseek(ti.outfd, (off_t)0, SEEK_SET) == (off_t)-1)
    401   1.1       mrg 		err(1, "could not seek to start of file for header rewrite");
    402  1.54       mrg 	write_header(&ti);
    403   1.1       mrg }
    404   1.1       mrg 
    405  1.51     joerg static void
    406  1.51     joerg usage(void)
    407   1.1       mrg {
    408  1.14       cgd 
    409  1.14       cgd 	fprintf(stderr, "Usage: %s [-afhqV] [options] {files ...|-}\n",
    410  1.14       cgd 	    getprogname());
    411   1.4       mrg 	fprintf(stderr, "Options:\n\t"
    412  1.50       wiz 	    "-B buffer size\n\t"
    413   1.4       mrg 	    "-b balance (0-63)\n\t"
    414   1.4       mrg 	    "-c channels\n\t"
    415   1.4       mrg 	    "-d audio device\n\t"
    416   1.4       mrg 	    "-e encoding\n\t"
    417  1.35       wiz 	    "-F format\n\t"
    418   1.4       mrg 	    "-i header information\n\t"
    419   1.4       mrg 	    "-m monitor volume\n\t"
    420  1.35       wiz 	    "-P precision (4, 8, 16, 24, or 32 bits)\n\t"
    421   1.4       mrg 	    "-p input port\n\t"
    422   1.4       mrg 	    "-s sample rate\n\t"
    423   1.4       mrg 	    "-t recording time\n\t"
    424   1.4       mrg 	    "-v volume\n");
    425   1.9    kleink 	exit(EXIT_FAILURE);
    426   1.1       mrg }
    427