Home | History | Annotate | Line # | Download | only in record
record.c revision 1.48
      1  1.48       mrg /*	$NetBSD: record.c,v 1.48 2010/12/29 13:09:03 mrg 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.48       mrg __RCSID("$NetBSD: record.c,v 1.48 2010/12/29 13:09:03 mrg 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.1       mrg audio_info_t info, oinfo;
     59   1.1       mrg ssize_t	total_size = -1;
     60  1.21       mrg const char *device;
     61  1.27       mrg int	format = AUDIO_FORMAT_DEFAULT;
     62   1.1       mrg char	*header_info;
     63   1.1       mrg char	default_info[8] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' };
     64  1.23  jdolecek int	audiofd, outfd;
     65   1.1       mrg int	qflag, aflag, fflag;
     66   1.1       mrg int	verbose;
     67  1.17       mrg int	monitor_gain, omonitor_gain;
     68  1.17       mrg int	gain;
     69   1.1       mrg int	balance;
     70   1.1       mrg int	port;
     71   1.1       mrg int	encoding;
     72   1.1       mrg char	*encoding_str;
     73   1.1       mrg int	precision;
     74   1.1       mrg int	sample_rate;
     75   1.1       mrg int	channels;
     76   1.1       mrg struct timeval record_time;
     77  1.32       mrg struct timeval start_time;
     78   1.1       mrg 
     79  1.37   mycroft void (*conv_func) (u_char *, int);
     80  1.18       mrg 
     81  1.12       mrg void usage (void);
     82  1.12       mrg int main (int, char *[]);
     83  1.12       mrg int timeleft (struct timeval *, struct timeval *);
     84  1.45     perry void cleanup (int) __dead;
     85  1.17       mrg int write_header_sun (void **, size_t *, int *);
     86  1.17       mrg int write_header_wav (void **, size_t *, int *);
     87  1.12       mrg void write_header (void);
     88  1.12       mrg void rewrite_header (void);
     89   1.1       mrg 
     90   1.1       mrg int
     91   1.1       mrg main(argc, argv)
     92   1.1       mrg 	int argc;
     93   1.1       mrg 	char *argv[];
     94   1.1       mrg {
     95  1.43       mrg 	u_char	*buffer;
     96  1.48       mrg 	size_t	len, bufsize = 0;
     97   1.8       mrg 	int	ch, no_time_limit = 1;
     98  1.24  augustss 	const char *defdevice = _PATH_SOUND;
     99   1.1       mrg 
    100  1.48       mrg 	while ((ch = getopt(argc, argv, "ab:B:C:F:c:d:e:fhi:m:P:p:qt:s:Vv:")) != -1) {
    101   1.1       mrg 		switch (ch) {
    102   1.1       mrg 		case 'a':
    103   1.1       mrg 			aflag++;
    104   1.1       mrg 			break;
    105   1.1       mrg 		case 'b':
    106   1.1       mrg 			decode_int(optarg, &balance);
    107   1.1       mrg 			if (balance < 0 || balance > 63)
    108  1.30     grant 				errx(1, "balance must be between 0 and 63");
    109   1.1       mrg 			break;
    110  1.48       mrg 		case 'B':
    111  1.48       mrg 			bufsize = strsuftoll("read buffer size", optarg,
    112  1.48       mrg 					     1, UINT_MAX);
    113  1.48       mrg 			break;
    114   1.1       mrg 		case 'C':
    115  1.23  jdolecek 			/* Ignore, compatibility */
    116   1.1       mrg 			break;
    117  1.17       mrg 		case 'F':
    118  1.17       mrg 			format = audio_format_from_str(optarg);
    119  1.17       mrg 			if (format < 0)
    120  1.27       mrg 				errx(1, "Unknown audio format; supported "
    121  1.27       mrg 				    "formats: \"sun\", \"wav\", and \"none\"");
    122  1.17       mrg 			break;
    123   1.1       mrg 		case 'c':
    124   1.1       mrg 			decode_int(optarg, &channels);
    125   1.1       mrg 			if (channels < 0 || channels > 16)
    126  1.30     grant 				errx(1, "channels must be between 0 and 16");
    127   1.1       mrg 			break;
    128   1.1       mrg 		case 'd':
    129   1.1       mrg 			device = optarg;
    130   1.1       mrg 			break;
    131   1.1       mrg 		case 'e':
    132   1.1       mrg 			encoding_str = optarg;
    133   1.1       mrg 			break;
    134   1.1       mrg 		case 'f':
    135   1.1       mrg 			fflag++;
    136   1.1       mrg 			break;
    137   1.1       mrg 		case 'i':
    138   1.1       mrg 			header_info = optarg;
    139   1.1       mrg 			break;
    140   1.1       mrg 		case 'm':
    141  1.17       mrg 			decode_int(optarg, &monitor_gain);
    142  1.17       mrg 			if (monitor_gain < 0 || monitor_gain > 255)
    143  1.30     grant 				errx(1, "monitor volume must be between 0 and 255");
    144   1.1       mrg 			break;
    145   1.1       mrg 		case 'P':
    146   1.1       mrg 			decode_int(optarg, &precision);
    147  1.15   minoura 			if (precision != 4 && precision != 8 &&
    148  1.15   minoura 			    precision != 16 && precision != 24 &&
    149  1.15   minoura 			    precision != 32)
    150  1.15   minoura 				errx(1, "precision must be between 4, 8, 16, 24 or 32");
    151   1.1       mrg 			break;
    152   1.1       mrg 		case 'p':
    153   1.1       mrg 			len = strlen(optarg);
    154   1.1       mrg 
    155   1.1       mrg 			if (strncmp(optarg, "mic", len) == 0)
    156   1.1       mrg 				port |= AUDIO_MICROPHONE;
    157   1.1       mrg 			else if (strncmp(optarg, "cd", len) == 0 ||
    158   1.1       mrg 			           strncmp(optarg, "internal-cd", len) == 0)
    159   1.1       mrg 				port |= AUDIO_CD;
    160   1.1       mrg 			else if (strncmp(optarg, "line", len) == 0)
    161   1.1       mrg 				port |= AUDIO_LINE_IN;
    162   1.1       mrg 			else
    163   1.1       mrg 				errx(1,
    164   1.1       mrg 			    "port must be `cd', `internal-cd', `mic', or `line'");
    165   1.1       mrg 			break;
    166   1.1       mrg 		case 'q':
    167   1.1       mrg 			qflag++;
    168   1.1       mrg 			break;
    169   1.1       mrg 		case 's':
    170   1.1       mrg 			decode_int(optarg, &sample_rate);
    171   1.1       mrg 			if (sample_rate < 0 || sample_rate > 48000 * 2)	/* XXX */
    172  1.30     grant 				errx(1, "sample rate must be between 0 and 96000");
    173   1.1       mrg 			break;
    174   1.1       mrg 		case 't':
    175   1.8       mrg 			no_time_limit = 0;
    176   1.1       mrg 			decode_time(optarg, &record_time);
    177   1.1       mrg 			break;
    178   1.1       mrg 		case 'V':
    179   1.1       mrg 			verbose++;
    180   1.1       mrg 			break;
    181   1.1       mrg 		case 'v':
    182  1.17       mrg 			decode_int(optarg, &gain);
    183  1.17       mrg 			if (gain < 0 || gain > 255)
    184  1.30     grant 				errx(1, "volume must be between 0 and 255");
    185   1.1       mrg 			break;
    186   1.1       mrg 		/* case 'h': */
    187   1.1       mrg 		default:
    188   1.1       mrg 			usage();
    189   1.1       mrg 			/* NOTREACHED */
    190   1.1       mrg 		}
    191   1.1       mrg 	}
    192   1.1       mrg 	argc -= optind;
    193   1.1       mrg 	argv += optind;
    194   1.1       mrg 
    195  1.39       mrg 	if (argc != 1)
    196  1.39       mrg 		usage();
    197  1.39       mrg 
    198   1.1       mrg 	/*
    199  1.40       mrg 	 * convert the encoding string into a value.
    200  1.40       mrg 	 */
    201  1.40       mrg 	if (encoding_str) {
    202  1.40       mrg 		encoding = audio_enc_to_val(encoding_str);
    203  1.40       mrg 		if (encoding == -1)
    204  1.40       mrg 			errx(1, "unknown encoding, bailing...");
    205  1.40       mrg 	}
    206  1.40       mrg 
    207  1.40       mrg 	/*
    208  1.40       mrg 	 * open the output file
    209  1.40       mrg 	 */
    210  1.42      gson 	if (argv[0][0] != '-' || argv[0][1] != '\0') {
    211  1.40       mrg 		/* intuit the file type from the name */
    212  1.40       mrg 		if (format == AUDIO_FORMAT_DEFAULT)
    213  1.40       mrg 		{
    214  1.40       mrg 			size_t flen = strlen(*argv);
    215  1.40       mrg 			const char *arg = *argv;
    216  1.40       mrg 
    217  1.40       mrg 			if (strcasecmp(arg + flen - 3, ".au") == 0)
    218  1.40       mrg 				format = AUDIO_FORMAT_SUN;
    219  1.40       mrg 			else if (strcasecmp(arg + flen - 4, ".wav") == 0)
    220  1.40       mrg 				format = AUDIO_FORMAT_WAV;
    221  1.40       mrg 		}
    222  1.40       mrg 		outfd = open(*argv, O_CREAT|(aflag ? O_APPEND : O_TRUNC)|O_WRONLY, 0666);
    223  1.40       mrg 		if (outfd < 0)
    224  1.40       mrg 			err(1, "could not open %s", *argv);
    225  1.40       mrg 	} else
    226  1.40       mrg 		outfd = STDOUT_FILENO;
    227  1.40       mrg 
    228  1.40       mrg 	/*
    229  1.34       mrg 	 * open the audio device
    230   1.1       mrg 	 */
    231   1.6    kleink 	if (device == NULL && (device = getenv("AUDIODEVICE")) == NULL &&
    232   1.6    kleink 	    (device = getenv("AUDIODEV")) == NULL) /* Sun compatibility */
    233  1.24  augustss 		device = defdevice;
    234   1.1       mrg 
    235   1.1       mrg 	audiofd = open(device, O_RDONLY);
    236  1.24  augustss 	if (audiofd < 0 && device == defdevice) {
    237  1.22  augustss 		device = _PATH_SOUND0;
    238  1.28       uwe 		audiofd = open(device, O_RDONLY);
    239  1.22  augustss 	}
    240   1.1       mrg 	if (audiofd < 0)
    241   1.1       mrg 		err(1, "failed to open %s", device);
    242   1.1       mrg 
    243   1.1       mrg 	/*
    244   1.1       mrg 	 * work out the buffer size to use, and allocate it.  also work out
    245   1.1       mrg 	 * what the old monitor gain value is, so that we can reset it later.
    246   1.1       mrg 	 */
    247  1.23  jdolecek 	if (ioctl(audiofd, AUDIO_GETINFO, &oinfo) < 0)
    248   1.1       mrg 		err(1, "failed to get audio info");
    249  1.48       mrg 	if (bufsize == 0)
    250  1.48       mrg 		bufsize = oinfo.record.buffer_size;
    251   1.1       mrg 	if (bufsize < 32 * 1024)
    252   1.1       mrg 		bufsize = 32 * 1024;
    253  1.17       mrg 	omonitor_gain = oinfo.monitor_gain;
    254   1.1       mrg 
    255   1.1       mrg 	buffer = malloc(bufsize);
    256   1.1       mrg 	if (buffer == NULL)
    257   1.1       mrg 		err(1, "couldn't malloc buffer of %d size", (int)bufsize);
    258   1.1       mrg 
    259   1.1       mrg 	/*
    260  1.17       mrg 	 * set up audio device for recording with the speified parameters
    261  1.17       mrg 	 */
    262  1.17       mrg 	AUDIO_INITINFO(&info);
    263  1.17       mrg 
    264  1.17       mrg 	/*
    265  1.17       mrg 	 * for these, get the current values for stuffing into the header
    266  1.17       mrg 	 */
    267  1.40       mrg #define SETINFO(x)	if (x) \
    268  1.40       mrg 				info.record.x = x; \
    269  1.40       mrg 			else \
    270  1.40       mrg 				info.record.x = x = oinfo.record.x;
    271  1.40       mrg 	SETINFO (sample_rate)
    272  1.40       mrg 	SETINFO (channels)
    273  1.40       mrg 	SETINFO (precision)
    274  1.40       mrg 	SETINFO (encoding)
    275  1.40       mrg 	SETINFO (gain)
    276  1.40       mrg 	SETINFO (port)
    277  1.40       mrg 	SETINFO (balance)
    278  1.17       mrg #undef SETINFO
    279  1.17       mrg 
    280  1.17       mrg 	if (monitor_gain)
    281  1.17       mrg 		info.monitor_gain = monitor_gain;
    282  1.17       mrg 	else
    283  1.17       mrg 		monitor_gain = oinfo.monitor_gain;
    284   1.1       mrg 
    285   1.1       mrg 	info.mode = AUMODE_RECORD;
    286  1.23  jdolecek 	if (ioctl(audiofd, AUDIO_SETINFO, &info) < 0)
    287  1.29       mrg 		err(1, "failed to set audio info");
    288   1.1       mrg 
    289   1.1       mrg 	signal(SIGINT, cleanup);
    290   1.1       mrg 	write_header();
    291   1.1       mrg 	total_size = 0;
    292   1.1       mrg 
    293  1.27       mrg 	if (verbose && conv_func) {
    294  1.27       mrg 		const char *s = NULL;
    295  1.27       mrg 
    296  1.27       mrg 		if (conv_func == swap_bytes)
    297  1.27       mrg 			s = "swap bytes (16 bit)";
    298  1.27       mrg 		else if (conv_func == swap_bytes32)
    299  1.27       mrg 			s = "swap bytes (32 bit)";
    300  1.27       mrg 		else if (conv_func == change_sign16_be)
    301  1.27       mrg 			s = "change sign (big-endian, 16 bit)";
    302  1.27       mrg 		else if (conv_func == change_sign16_le)
    303  1.27       mrg 			s = "change sign (little-endian, 16 bit)";
    304  1.27       mrg 		else if (conv_func == change_sign32_be)
    305  1.27       mrg 			s = "change sign (big-endian, 32 bit)";
    306  1.27       mrg 		else if (conv_func == change_sign32_le)
    307  1.27       mrg 			s = "change sign (little-endian, 32 bit)";
    308  1.27       mrg 		else if (conv_func == change_sign16_swap_bytes_be)
    309  1.27       mrg 			s = "change sign & swap bytes (big-endian, 16 bit)";
    310  1.27       mrg 		else if (conv_func == change_sign16_swap_bytes_le)
    311  1.27       mrg 			s = "change sign & swap bytes (little-endian, 16 bit)";
    312  1.27       mrg 		else if (conv_func == change_sign32_swap_bytes_be)
    313  1.27       mrg 			s = "change sign (big-endian, 32 bit)";
    314  1.27       mrg 		else if (conv_func == change_sign32_swap_bytes_le)
    315  1.27       mrg 			s = "change sign & swap bytes (little-endian, 32 bit)";
    316  1.27       mrg 
    317  1.27       mrg 		if (s)
    318  1.27       mrg 			fprintf(stderr, "%s: converting, using function: %s\n",
    319  1.27       mrg 			    getprogname(), s);
    320  1.27       mrg 		else
    321  1.27       mrg 			fprintf(stderr, "%s: using unnamed conversion "
    322  1.27       mrg 					"function\n", getprogname());
    323  1.27       mrg 	}
    324  1.27       mrg 
    325  1.27       mrg 	if (verbose)
    326  1.27       mrg 		fprintf(stderr,
    327  1.27       mrg 		   "sample_rate=%d channels=%d precision=%d encoding=%s\n",
    328  1.27       mrg 		   info.record.sample_rate, info.record.channels,
    329  1.27       mrg 		   info.record.precision,
    330  1.27       mrg 		   audio_enc_from_val(info.record.encoding));
    331  1.32       mrg 
    332  1.32       mrg 	if (!no_time_limit && verbose)
    333  1.32       mrg 		fprintf(stderr, "recording for %lu seconds, %lu microseconds\n",
    334  1.32       mrg 		    (u_long)record_time.tv_sec, (u_long)record_time.tv_usec);
    335  1.27       mrg 
    336   1.1       mrg 	(void)gettimeofday(&start_time, NULL);
    337   1.8       mrg 	while (no_time_limit || timeleft(&start_time, &record_time)) {
    338  1.47     lukem 		if ((size_t)read(audiofd, buffer, bufsize) != bufsize)
    339   1.1       mrg 			err(1, "read failed");
    340  1.18       mrg 		if (conv_func)
    341  1.19       mrg 			(*conv_func)(buffer, bufsize);
    342  1.47     lukem 		if ((size_t)write(outfd, buffer, bufsize) != bufsize)
    343   1.1       mrg 			err(1, "write failed");
    344   1.1       mrg 		total_size += bufsize;
    345   1.1       mrg 	}
    346   1.1       mrg 	cleanup(0);
    347   1.1       mrg }
    348   1.1       mrg 
    349   1.1       mrg int
    350   1.1       mrg timeleft(start_tvp, record_tvp)
    351   1.1       mrg 	struct timeval *start_tvp;
    352   1.1       mrg 	struct timeval *record_tvp;
    353   1.1       mrg {
    354   1.1       mrg 	struct timeval now, diff;
    355   1.1       mrg 
    356   1.1       mrg 	(void)gettimeofday(&now, NULL);
    357   1.7  dmcmahil 	timersub(&now, start_tvp, &diff);
    358   1.7  dmcmahil 	timersub(record_tvp, &diff, &now);
    359   1.1       mrg 
    360   1.1       mrg 	return (now.tv_sec > 0 || (now.tv_sec == 0 && now.tv_usec > 0));
    361   1.1       mrg }
    362   1.1       mrg 
    363   1.1       mrg void
    364   1.1       mrg cleanup(signo)
    365   1.1       mrg 	int signo;
    366   1.1       mrg {
    367   1.1       mrg 
    368   1.1       mrg 	rewrite_header();
    369   1.1       mrg 	close(outfd);
    370  1.17       mrg 	if (omonitor_gain) {
    371   1.1       mrg 		AUDIO_INITINFO(&info);
    372  1.17       mrg 		info.monitor_gain = omonitor_gain;
    373  1.23  jdolecek 		if (ioctl(audiofd, AUDIO_SETINFO, &info) < 0)
    374   1.1       mrg 			err(1, "failed to reset audio info");
    375   1.1       mrg 	}
    376  1.23  jdolecek 	close(audiofd);
    377  1.44     lukem 	if (signo != 0) {
    378  1.44     lukem 		(void)raise_default_signal(signo);
    379  1.44     lukem 	}
    380   1.1       mrg 	exit(0);
    381   1.1       mrg }
    382   1.1       mrg 
    383  1.17       mrg int
    384  1.17       mrg write_header_sun(hdrp, lenp, leftp)
    385  1.17       mrg 	void **hdrp;
    386  1.17       mrg 	size_t *lenp;
    387  1.17       mrg 	int *leftp;
    388   1.1       mrg {
    389  1.16       mrg 	static int warned = 0;
    390  1.17       mrg 	static sun_audioheader auh;
    391  1.19       mrg 	int sunenc, oencoding = encoding;
    392  1.11       mrg 
    393  1.27       mrg 	/* only perform conversions if we don't specify the encoding */
    394  1.25       mrg 	switch (encoding) {
    395  1.25       mrg 	case AUDIO_ENCODING_ULINEAR_LE:
    396  1.25       mrg #if BYTE_ORDER == LITTLE_ENDIAN
    397  1.25       mrg 	case AUDIO_ENCODING_ULINEAR:
    398  1.25       mrg #endif
    399  1.19       mrg 		if (precision == 16)
    400  1.27       mrg 			conv_func = change_sign16_swap_bytes_le;
    401  1.19       mrg 		else if (precision == 32)
    402  1.27       mrg 			conv_func = change_sign32_swap_bytes_le;
    403  1.21       mrg 		if (conv_func)
    404  1.21       mrg 			encoding = AUDIO_ENCODING_SLINEAR_BE;
    405  1.25       mrg 		break;
    406  1.25       mrg 
    407  1.25       mrg 	case AUDIO_ENCODING_ULINEAR_BE:
    408  1.25       mrg #if BYTE_ORDER == BIG_ENDIAN
    409  1.25       mrg 	case AUDIO_ENCODING_ULINEAR:
    410  1.25       mrg #endif
    411  1.19       mrg 		if (precision == 16)
    412  1.19       mrg 			conv_func = change_sign16_be;
    413  1.19       mrg 		else if (precision == 32)
    414  1.19       mrg 			conv_func = change_sign32_be;
    415  1.21       mrg 		if (conv_func)
    416  1.21       mrg 			encoding = AUDIO_ENCODING_SLINEAR_BE;
    417  1.25       mrg 		break;
    418  1.25       mrg 
    419  1.25       mrg 	case AUDIO_ENCODING_SLINEAR_LE:
    420  1.25       mrg #if BYTE_ORDER == LITTLE_ENDIAN
    421  1.25       mrg 	case AUDIO_ENCODING_SLINEAR:
    422  1.25       mrg #endif
    423  1.19       mrg 		if (precision == 16)
    424  1.27       mrg 			conv_func = swap_bytes;
    425  1.19       mrg 		else if (precision == 32)
    426  1.27       mrg 			conv_func = swap_bytes32;
    427  1.21       mrg 		if (conv_func)
    428  1.21       mrg 			encoding = AUDIO_ENCODING_SLINEAR_BE;
    429  1.25       mrg 		break;
    430  1.25       mrg 
    431  1.25       mrg #if BYTE_ORDER == BIG_ENDIAN
    432  1.25       mrg 	case AUDIO_ENCODING_SLINEAR:
    433  1.25       mrg 		encoding = AUDIO_ENCODING_SLINEAR_BE;
    434  1.25       mrg 		break;
    435  1.25       mrg #endif
    436  1.19       mrg 	}
    437  1.19       mrg 
    438  1.11       mrg 	/* if we can't express this as a Sun header, don't write any */
    439  1.11       mrg 	if (audio_encoding_to_sun(encoding, precision, &sunenc) != 0) {
    440  1.25       mrg 		if (!qflag && !warned) {
    441  1.25       mrg 			const char *s = audio_enc_from_val(oencoding);
    442  1.25       mrg 
    443  1.25       mrg 			if (s == NULL)
    444  1.25       mrg 				s = "(unknown)";
    445  1.25       mrg 			warnx("failed to convert to sun encoding from %s "
    446  1.25       mrg 			      "(precision %d);\nSun audio header not written",
    447  1.25       mrg 			      s, precision);
    448  1.25       mrg 		}
    449  1.27       mrg 		format = AUDIO_FORMAT_NONE;
    450  1.19       mrg 		conv_func = 0;
    451  1.16       mrg 		warned = 1;
    452  1.17       mrg 		return -1;
    453  1.11       mrg 	}
    454   1.1       mrg 
    455   1.1       mrg 	auh.magic = htonl(AUDIO_FILE_MAGIC);
    456   1.1       mrg 	if (outfd == STDOUT_FILENO)
    457   1.1       mrg 		auh.data_size = htonl(AUDIO_UNKNOWN_SIZE);
    458  1.41       mrg 	else if (total_size != -1)
    459  1.41       mrg 		auh.data_size = htonl(total_size);
    460   1.1       mrg 	else
    461  1.41       mrg 		auh.data_size = 0;
    462  1.11       mrg 	auh.encoding = htonl(sunenc);
    463   1.1       mrg 	auh.sample_rate = htonl(sample_rate);
    464   1.1       mrg 	auh.channels = htonl(channels);
    465   1.1       mrg 	if (header_info) {
    466   1.1       mrg 		int 	len, infolen;
    467   1.1       mrg 
    468   1.1       mrg 		infolen = ((len = strlen(header_info)) + 7) & 0xfffffff8;
    469  1.17       mrg 		*leftp = infolen - len;
    470   1.1       mrg 		auh.hdr_size = htonl(sizeof(auh) + infolen);
    471   1.1       mrg 	} else {
    472  1.17       mrg 		*leftp = sizeof(default_info);
    473  1.17       mrg 		auh.hdr_size = htonl(sizeof(auh) + *leftp);
    474   1.1       mrg 	}
    475  1.17       mrg 	*(sun_audioheader **)hdrp = &auh;
    476  1.17       mrg 	*lenp = sizeof auh;
    477  1.17       mrg 	return 0;
    478  1.17       mrg }
    479   1.1       mrg 
    480  1.17       mrg int
    481  1.17       mrg write_header_wav(hdrp, lenp, leftp)
    482  1.17       mrg 	void **hdrp;
    483  1.17       mrg 	size_t *lenp;
    484  1.17       mrg 	int *leftp;
    485  1.17       mrg {
    486  1.17       mrg 	/*
    487  1.17       mrg 	 * WAV header we write looks like this:
    488  1.17       mrg 	 *
    489  1.17       mrg 	 *      bytes   purpose
    490  1.17       mrg 	 *      0-3     "RIFF"
    491  1.17       mrg 	 *      4-7     file length (minus 8)
    492  1.17       mrg 	 *      8-15    "WAVEfmt "
    493  1.17       mrg 	 *      16-19   format size
    494  1.17       mrg 	 *      20-21   format tag
    495  1.17       mrg 	 *      22-23   number of channels
    496  1.17       mrg 	 *      24-27   sample rate
    497  1.17       mrg 	 *      28-31   average bytes per second
    498  1.17       mrg 	 *      32-33   block alignment
    499  1.17       mrg 	 *      34-35   bits per sample
    500  1.17       mrg 	 *
    501  1.17       mrg 	 * then for ULAW and ALAW outputs, we have an extended chunk size
    502  1.17       mrg 	 * and a WAV "fact" to add:
    503  1.17       mrg 	 *
    504  1.17       mrg 	 *      36-37   length of extension (== 0)
    505  1.17       mrg 	 *      38-41   "fact"
    506  1.17       mrg 	 *      42-45   fact size
    507  1.17       mrg 	 *      46-49   number of samples written
    508  1.17       mrg 	 *      50-53   "data"
    509  1.17       mrg 	 *      54-57   data length
    510  1.17       mrg 	 *      58-     raw audio data
    511  1.17       mrg 	 *
    512  1.17       mrg 	 * for PCM outputs we have just the data remaining:
    513  1.17       mrg 	 *
    514  1.17       mrg 	 *      36-39   "data"
    515  1.17       mrg 	 *      40-43   data length
    516  1.17       mrg 	 *      44-     raw audio data
    517  1.17       mrg 	 *
    518  1.17       mrg 	 *	RIFF\^@^C^@WAVEfmt ^P^@^@^@^A^@^B^@D<AC>^@^@^P<B1>^B^@^D^@^P^@data^@^@^C^@^@^@^@^@^@^@^@^@^@
    519  1.17       mrg 	 */
    520  1.17       mrg 	char	wavheaderbuf[64], *p = wavheaderbuf;
    521  1.21       mrg 	const char *riff = "RIFF",
    522  1.21       mrg 	    *wavefmt = "WAVEfmt ",
    523  1.21       mrg 	    *fact = "fact",
    524  1.21       mrg 	    *data = "data";
    525  1.17       mrg 	u_int32_t filelen, fmtsz, sps, abps, factsz = 4, nsample, datalen;
    526  1.17       mrg 	u_int16_t fmttag, nchan, align, bps, extln = 0;
    527  1.17       mrg 
    528  1.17       mrg 	if (header_info)
    529  1.17       mrg 		warnx("header information not supported for WAV");
    530  1.36      fvdl 	*leftp = 0;
    531  1.17       mrg 
    532  1.17       mrg 	switch (precision) {
    533  1.17       mrg 	case 8:
    534  1.17       mrg 		bps = 8;
    535  1.17       mrg 		break;
    536  1.17       mrg 	case 16:
    537  1.17       mrg 		bps = 16;
    538  1.17       mrg 		break;
    539  1.17       mrg 	case 32:
    540  1.17       mrg 		bps = 32;
    541  1.17       mrg 		break;
    542  1.17       mrg 	default:
    543  1.18       mrg 		{
    544  1.18       mrg 			static int warned = 0;
    545  1.18       mrg 
    546  1.18       mrg 			if (warned == 0) {
    547  1.30     grant 				warnx("can not support precision of %d", precision);
    548  1.18       mrg 				warned = 1;
    549  1.18       mrg 			}
    550  1.17       mrg 		}
    551  1.17       mrg 		return (-1);
    552  1.17       mrg 	}
    553  1.17       mrg 
    554  1.17       mrg 	switch (encoding) {
    555  1.17       mrg 	case AUDIO_ENCODING_ULAW:
    556  1.17       mrg 		fmttag = WAVE_FORMAT_MULAW;
    557  1.17       mrg 		fmtsz = 18;
    558  1.17       mrg 		align = channels;
    559  1.17       mrg 		break;
    560  1.26       mrg 
    561  1.17       mrg 	case AUDIO_ENCODING_ALAW:
    562  1.17       mrg 		fmttag = WAVE_FORMAT_ALAW;
    563  1.17       mrg 		fmtsz = 18;
    564  1.17       mrg 		align = channels;
    565  1.17       mrg 		break;
    566  1.26       mrg 
    567  1.18       mrg 	/*
    568  1.18       mrg 	 * we could try to support RIFX but it seems to be more portable
    569  1.18       mrg 	 * to output little-endian data for WAV files.
    570  1.18       mrg 	 */
    571  1.18       mrg 	case AUDIO_ENCODING_ULINEAR_BE:
    572  1.26       mrg #if BYTE_ORDER == BIG_ENDIAN
    573  1.26       mrg 	case AUDIO_ENCODING_ULINEAR:
    574  1.26       mrg #endif
    575  1.20       mrg 		if (bps == 16)
    576  1.20       mrg 			conv_func = change_sign16_swap_bytes_be;
    577  1.20       mrg 		else if (bps == 32)
    578  1.20       mrg 			conv_func = change_sign32_swap_bytes_be;
    579  1.20       mrg 		goto fmt_pcm;
    580  1.26       mrg 
    581  1.18       mrg 	case AUDIO_ENCODING_SLINEAR_BE:
    582  1.26       mrg #if BYTE_ORDER == BIG_ENDIAN
    583  1.26       mrg 	case AUDIO_ENCODING_SLINEAR:
    584  1.26       mrg #endif
    585  1.38   mycroft 		if (bps == 8)
    586  1.38   mycroft 			conv_func = change_sign8;
    587  1.38   mycroft 		else if (bps == 16)
    588  1.19       mrg 			conv_func = swap_bytes;
    589  1.18       mrg 		else if (bps == 32)
    590  1.19       mrg 			conv_func = swap_bytes32;
    591  1.20       mrg 		goto fmt_pcm;
    592  1.26       mrg 
    593  1.20       mrg 	case AUDIO_ENCODING_ULINEAR_LE:
    594  1.26       mrg #if BYTE_ORDER == LITTLE_ENDIAN
    595  1.26       mrg 	case AUDIO_ENCODING_ULINEAR:
    596  1.26       mrg #endif
    597  1.20       mrg 		if (bps == 16)
    598  1.20       mrg 			conv_func = change_sign16_le;
    599  1.20       mrg 		else if (bps == 32)
    600  1.20       mrg 			conv_func = change_sign32_le;
    601  1.18       mrg 		/* FALLTHROUGH */
    602  1.26       mrg 
    603  1.20       mrg 	case AUDIO_ENCODING_SLINEAR_LE:
    604  1.17       mrg 	case AUDIO_ENCODING_PCM16:
    605  1.26       mrg #if BYTE_ORDER == LITTLE_ENDIAN
    606  1.26       mrg 	case AUDIO_ENCODING_SLINEAR:
    607  1.26       mrg #endif
    608  1.38   mycroft 		if (bps == 8)
    609  1.38   mycroft 			conv_func = change_sign8;
    610  1.20       mrg fmt_pcm:
    611  1.17       mrg 		fmttag = WAVE_FORMAT_PCM;
    612  1.17       mrg 		fmtsz = 16;
    613  1.17       mrg 		align = channels * (bps / 8);
    614  1.17       mrg 		break;
    615  1.26       mrg 
    616  1.17       mrg 	default:
    617  1.18       mrg 		{
    618  1.18       mrg 			static int warned = 0;
    619  1.18       mrg 
    620  1.18       mrg 			if (warned == 0) {
    621  1.26       mrg 				const char *s = wav_enc_from_val(encoding);
    622  1.26       mrg 
    623  1.26       mrg 				if (s == NULL)
    624  1.30     grant 					warnx("can not support encoding of %s", s);
    625  1.26       mrg 				else
    626  1.30     grant 					warnx("can not support encoding of %d", encoding);
    627  1.18       mrg 				warned = 1;
    628  1.18       mrg 			}
    629  1.17       mrg 		}
    630  1.27       mrg 		format = AUDIO_FORMAT_NONE;
    631  1.17       mrg 		return (-1);
    632  1.17       mrg 	}
    633  1.17       mrg 
    634  1.17       mrg 	nchan = channels;
    635  1.17       mrg 	sps = sample_rate;
    636  1.17       mrg 
    637  1.17       mrg 	/* data length */
    638  1.17       mrg 	if (outfd == STDOUT_FILENO)
    639  1.17       mrg 		datalen = 0;
    640  1.41       mrg 	else if (total_size != -1)
    641  1.41       mrg 		datalen = total_size;
    642  1.17       mrg 	else
    643  1.41       mrg 		datalen = 0;
    644  1.17       mrg 
    645  1.17       mrg 	/* file length */
    646  1.17       mrg 	filelen = 4 + (8 + fmtsz) + (8 + datalen);
    647  1.17       mrg 	if (fmttag != WAVE_FORMAT_PCM)
    648  1.17       mrg 		filelen += 8 + factsz;
    649  1.17       mrg 
    650  1.17       mrg 	abps = (double)align*sample_rate / (double)1 + 0.5;
    651  1.17       mrg 
    652  1.17       mrg 	nsample = (datalen / bps) / sample_rate;
    653  1.17       mrg 
    654  1.17       mrg 	/*
    655  1.17       mrg 	 * now we've calculated the info, write it out!
    656  1.17       mrg 	 */
    657  1.17       mrg #define put32(x) do { \
    658  1.17       mrg 	u_int32_t _f; \
    659  1.17       mrg 	putle32(_f, (x)); \
    660  1.17       mrg 	memcpy(p, &_f, 4); \
    661  1.17       mrg } while (0)
    662  1.17       mrg #define put16(x) do { \
    663  1.17       mrg 	u_int16_t _f; \
    664  1.17       mrg 	putle16(_f, (x)); \
    665  1.17       mrg 	memcpy(p, &_f, 2); \
    666  1.17       mrg } while (0)
    667  1.17       mrg 	memcpy(p, riff, 4);
    668  1.17       mrg 	p += 4;				/* 4 */
    669  1.17       mrg 	put32(filelen);
    670  1.17       mrg 	p += 4;				/* 8 */
    671  1.17       mrg 	memcpy(p, wavefmt, 8);
    672  1.17       mrg 	p += 8;				/* 16 */
    673  1.17       mrg 	put32(fmtsz);
    674  1.17       mrg 	p += 4;				/* 20 */
    675  1.17       mrg 	put16(fmttag);
    676  1.17       mrg 	p += 2;				/* 22 */
    677  1.17       mrg 	put16(nchan);
    678  1.17       mrg 	p += 2;				/* 24 */
    679  1.17       mrg 	put32(sps);
    680  1.17       mrg 	p += 4;				/* 28 */
    681  1.17       mrg 	put32(abps);
    682  1.17       mrg 	p += 4;				/* 32 */
    683  1.17       mrg 	put16(align);
    684  1.17       mrg 	p += 2;				/* 34 */
    685  1.17       mrg 	put16(bps);
    686  1.17       mrg 	p += 2;				/* 36 */
    687  1.17       mrg 	/* NON PCM formats have an extended chunk; write it */
    688  1.17       mrg 	if (fmttag != WAVE_FORMAT_PCM) {
    689  1.17       mrg 		put16(extln);
    690  1.17       mrg 		p += 2;			/* 38 */
    691  1.17       mrg 		memcpy(p, fact, 4);
    692  1.17       mrg 		p += 4;			/* 42 */
    693  1.17       mrg 		put32(factsz);
    694  1.17       mrg 		p += 4;			/* 46 */
    695  1.17       mrg 		put32(nsample);
    696  1.17       mrg 		p += 4;			/* 50 */
    697  1.17       mrg 	}
    698  1.17       mrg 	memcpy(p, data, 4);
    699  1.17       mrg 	p += 4;				/* 40/54 */
    700  1.17       mrg 	put32(datalen);
    701  1.17       mrg 	p += 4;				/* 44/58 */
    702  1.17       mrg #undef put32
    703  1.17       mrg #undef put16
    704  1.17       mrg 
    705  1.17       mrg 	*hdrp = wavheaderbuf;
    706  1.17       mrg 	*lenp = (p - wavheaderbuf);
    707  1.17       mrg 
    708  1.17       mrg 	return 0;
    709  1.17       mrg }
    710  1.17       mrg 
    711  1.17       mrg void
    712  1.17       mrg write_header()
    713  1.17       mrg {
    714  1.17       mrg 	struct iovec iv[3];
    715  1.17       mrg 	int veclen, left, tlen;
    716  1.17       mrg 	void *hdr;
    717  1.17       mrg 	size_t hdrlen;
    718  1.17       mrg 
    719  1.17       mrg 	switch (format) {
    720  1.27       mrg 	case AUDIO_FORMAT_DEFAULT:
    721  1.17       mrg 	case AUDIO_FORMAT_SUN:
    722  1.17       mrg 		if (write_header_sun(&hdr, &hdrlen, &left) != 0)
    723  1.17       mrg 			return;
    724  1.17       mrg 		break;
    725  1.17       mrg 	case AUDIO_FORMAT_WAV:
    726  1.17       mrg 		if (write_header_wav(&hdr, &hdrlen, &left) != 0)
    727  1.17       mrg 			return;
    728  1.17       mrg 		break;
    729  1.17       mrg 	case AUDIO_FORMAT_NONE:
    730  1.17       mrg 		return;
    731  1.17       mrg 	default:
    732  1.17       mrg 		errx(1, "unknown audio format");
    733  1.17       mrg 	}
    734  1.17       mrg 
    735  1.17       mrg 	veclen = 0;
    736  1.17       mrg 	tlen = 0;
    737  1.17       mrg 
    738  1.17       mrg 	if (hdrlen != 0) {
    739  1.17       mrg 		iv[veclen].iov_base = hdr;
    740  1.17       mrg 		iv[veclen].iov_len = hdrlen;
    741  1.17       mrg 		tlen += iv[veclen++].iov_len;
    742  1.17       mrg 	}
    743   1.1       mrg 	if (header_info) {
    744   1.1       mrg 		iv[veclen].iov_base = header_info;
    745  1.17       mrg 		iv[veclen].iov_len = (int)strlen(header_info) + 1;
    746   1.1       mrg 		tlen += iv[veclen++].iov_len;
    747   1.1       mrg 	}
    748   1.1       mrg 	if (left) {
    749   1.1       mrg 		iv[veclen].iov_base = default_info;
    750   1.1       mrg 		iv[veclen].iov_len = left;
    751   1.1       mrg 		tlen += iv[veclen++].iov_len;
    752   1.1       mrg 	}
    753   1.1       mrg 
    754  1.17       mrg 	if (tlen == 0)
    755  1.17       mrg 		return;
    756  1.17       mrg 
    757   1.1       mrg 	if (writev(outfd, iv, veclen) != tlen)
    758   1.1       mrg 		err(1, "could not write audio header");
    759   1.1       mrg }
    760   1.1       mrg 
    761   1.1       mrg void
    762   1.1       mrg rewrite_header()
    763   1.1       mrg {
    764   1.1       mrg 
    765   1.1       mrg 	/* can't do this here! */
    766   1.1       mrg 	if (outfd == STDOUT_FILENO)
    767   1.1       mrg 		return;
    768   1.1       mrg 
    769   1.1       mrg 	if (lseek(outfd, SEEK_SET, 0) < 0)
    770   1.1       mrg 		err(1, "could not seek to start of file for header rewrite");
    771   1.1       mrg 	write_header();
    772   1.1       mrg }
    773   1.1       mrg 
    774   1.1       mrg void
    775   1.1       mrg usage()
    776   1.1       mrg {
    777  1.14       cgd 
    778  1.14       cgd 	fprintf(stderr, "Usage: %s [-afhqV] [options] {files ...|-}\n",
    779  1.14       cgd 	    getprogname());
    780   1.4       mrg 	fprintf(stderr, "Options:\n\t"
    781   1.4       mrg 	    "-b balance (0-63)\n\t"
    782  1.48       mrg 	    "-B buffer size\n\t"
    783   1.4       mrg 	    "-c channels\n\t"
    784   1.4       mrg 	    "-d audio device\n\t"
    785   1.4       mrg 	    "-e encoding\n\t"
    786  1.35       wiz 	    "-F format\n\t"
    787   1.4       mrg 	    "-i header information\n\t"
    788   1.4       mrg 	    "-m monitor volume\n\t"
    789  1.35       wiz 	    "-P precision (4, 8, 16, 24, or 32 bits)\n\t"
    790   1.4       mrg 	    "-p input port\n\t"
    791   1.4       mrg 	    "-s sample rate\n\t"
    792   1.4       mrg 	    "-t recording time\n\t"
    793   1.4       mrg 	    "-v volume\n");
    794   1.9    kleink 	exit(EXIT_FAILURE);
    795   1.1       mrg }
    796