Home | History | Annotate | Line # | Download | only in common
audio.c revision 1.1
      1  1.1  mrg #include <sys/types.h>
      2  1.1  mrg #include <sys/audioio.h>
      3  1.1  mrg #include <sys/ioctl.h>
      4  1.1  mrg #include <sys/time.h>
      5  1.1  mrg 
      6  1.1  mrg #include <ctype.h>
      7  1.1  mrg #include <err.h>
      8  1.1  mrg #include <stdio.h>
      9  1.1  mrg #include <stdlib.h>
     10  1.1  mrg #include <string.h>
     11  1.1  mrg 
     12  1.1  mrg #include "libaudio.h"
     13  1.1  mrg 
     14  1.1  mrg /* back and forth between encodings */
     15  1.1  mrg struct {
     16  1.1  mrg 	char *ename;
     17  1.1  mrg 	int eno;
     18  1.1  mrg } encs[] = {
     19  1.1  mrg 	{ AudioEmulaw,		AUDIO_ENCODING_ULAW },
     20  1.1  mrg 	{ "ulaw",		AUDIO_ENCODING_ULAW },
     21  1.1  mrg 	{ AudioEalaw, 		AUDIO_ENCODING_ALAW },
     22  1.1  mrg 	{ AudioEslinear,	AUDIO_ENCODING_SLINEAR },
     23  1.1  mrg 	{ "linear",		AUDIO_ENCODING_SLINEAR },
     24  1.1  mrg 	{ AudioEulinear,	AUDIO_ENCODING_ULINEAR },
     25  1.1  mrg 	{ AudioEadpcm,		AUDIO_ENCODING_ADPCM },
     26  1.1  mrg 	{ "ADPCM",		AUDIO_ENCODING_ADPCM },
     27  1.1  mrg 	{ AudioEslinear_le,	AUDIO_ENCODING_SLINEAR_LE },
     28  1.1  mrg 	{ "linear_le",		AUDIO_ENCODING_SLINEAR_LE },
     29  1.1  mrg 	{ AudioEulinear_le,	AUDIO_ENCODING_ULINEAR_LE },
     30  1.1  mrg 	{ AudioEslinear_be,	AUDIO_ENCODING_SLINEAR_BE },
     31  1.1  mrg 	{ "linear_be",		AUDIO_ENCODING_SLINEAR_BE },
     32  1.1  mrg 	{ AudioEulinear_be,	AUDIO_ENCODING_ULINEAR_BE },
     33  1.1  mrg 	{ AudioEmpeg_l1_stream,	AUDIO_ENCODING_MPEG_L1_STREAM },
     34  1.1  mrg 	{ AudioEmpeg_l1_packets,AUDIO_ENCODING_MPEG_L1_PACKETS },
     35  1.1  mrg 	{ AudioEmpeg_l1_system,	AUDIO_ENCODING_MPEG_L1_SYSTEM },
     36  1.1  mrg 	{ AudioEmpeg_l2_stream,	AUDIO_ENCODING_MPEG_L2_STREAM },
     37  1.1  mrg 	{ AudioEmpeg_l2_packets,AUDIO_ENCODING_MPEG_L2_PACKETS },
     38  1.1  mrg 	{ AudioEmpeg_l2_system,	AUDIO_ENCODING_MPEG_L2_SYSTEM },
     39  1.1  mrg 	{ 0, -1 }
     40  1.1  mrg };
     41  1.1  mrg 
     42  1.1  mrg 
     43  1.1  mrg char *
     44  1.1  mrg audio_enc_from_val(val)
     45  1.1  mrg 	int	val;
     46  1.1  mrg {
     47  1.1  mrg 	int	i;
     48  1.1  mrg 
     49  1.1  mrg 	for (i = 0; encs[i].ename; i++)
     50  1.1  mrg 		if (encs[i].eno == val)
     51  1.1  mrg 			break;
     52  1.1  mrg 	return (encs[i].ename);
     53  1.1  mrg }
     54  1.1  mrg 
     55  1.1  mrg int
     56  1.1  mrg audio_enc_to_val(enc)
     57  1.1  mrg 	const	char *enc;
     58  1.1  mrg {
     59  1.1  mrg 	int	i;
     60  1.1  mrg 
     61  1.1  mrg 	for (i = 0; encs[i].ename; i++)
     62  1.1  mrg 		if (strcmp(encs[i].ename, enc) == 0)
     63  1.1  mrg 			break;
     64  1.1  mrg 	if (encs[i].ename)
     65  1.1  mrg 		return (encs[i].eno);
     66  1.1  mrg 	else
     67  1.1  mrg 		return (-1);
     68  1.1  mrg }
     69  1.1  mrg 
     70  1.1  mrg int
     71  1.1  mrg audio_parse_encoding(encoding_str, fd, encp, precp)
     72  1.1  mrg 	char	*encoding_str;
     73  1.1  mrg 	int	fd;
     74  1.1  mrg 	int	*encp;
     75  1.1  mrg 	int	*precp;
     76  1.1  mrg {
     77  1.1  mrg 	int	i, prec = 0;
     78  1.1  mrg 	char	*colon, *star;
     79  1.1  mrg 
     80  1.1  mrg 	colon = strchr(encoding_str, ':');
     81  1.1  mrg 	if (colon) {
     82  1.1  mrg 		*colon++ = '\0';
     83  1.1  mrg 		if (*colon)
     84  1.1  mrg 			prec = atoi(colon);
     85  1.1  mrg 	}
     86  1.1  mrg 	star = strrchr(encoding_str, '*');
     87  1.1  mrg 	if (star)
     88  1.1  mrg 		*star = '\0';
     89  1.1  mrg 	for (i = 0; ; i++) {
     90  1.1  mrg 		audio_encoding_t enc;
     91  1.1  mrg 
     92  1.1  mrg 		enc.index = i;
     93  1.1  mrg 		if (ioctl(fd, AUDIO_GETENC, &enc) < 0)
     94  1.1  mrg 			break;
     95  1.1  mrg 
     96  1.1  mrg 		if (strcasecmp(enc.name, encoding_str) == 0 &&
     97  1.1  mrg 		   (prec == 0 || prec == enc.precision)) {
     98  1.1  mrg 			*encp = enc.encoding;
     99  1.1  mrg 			*precp = enc.precision;
    100  1.1  mrg 			return (0);
    101  1.1  mrg 		}
    102  1.1  mrg 
    103  1.1  mrg 	}
    104  1.1  mrg 	return (1);
    105  1.1  mrg }
    106  1.1  mrg 
    107  1.1  mrg /*
    108  1.1  mrg  * SunOS/NeXT .au format helpers
    109  1.1  mrg  */
    110  1.1  mrg struct {
    111  1.1  mrg 	int	file_encoding;
    112  1.1  mrg 	int	encoding;
    113  1.1  mrg 	int	precision;
    114  1.1  mrg } file2sw_encodings[] = {
    115  1.1  mrg 	{ AUDIO_FILE_ENCODING_MULAW_8,		AUDIO_ENCODING_ULAW,	8 },
    116  1.1  mrg 	{ AUDIO_FILE_ENCODING_LINEAR_8,		AUDIO_ENCODING_ULINEAR_BE, 8 },
    117  1.1  mrg 	{ AUDIO_FILE_ENCODING_LINEAR_16,	AUDIO_ENCODING_ULINEAR_BE, 16 },
    118  1.1  mrg 	{ AUDIO_FILE_ENCODING_LINEAR_24,	AUDIO_ENCODING_ULINEAR_BE, 24 },
    119  1.1  mrg 	{ AUDIO_FILE_ENCODING_LINEAR_32,	AUDIO_ENCODING_ULINEAR_BE, 32 },
    120  1.1  mrg #if 0
    121  1.1  mrg 	{ AUDIO_FILE_ENCODING_FLOAT,		AUDIO_ENCODING_ULAW,	32 },
    122  1.1  mrg 	{ AUDIO_FILE_ENCODING_DOUBLE,		AUDIO_ENCODING_ULAW,	64 },
    123  1.1  mrg 	{ AUDIO_FILE_ENCODING_ADPCM_G721,	AUDIO_ENCODING_ULAW,	4 },
    124  1.1  mrg 	{ AUDIO_FILE_ENCODING_ADPCM_G722,	AUDIO_ENCODING_ULAW,	0 },
    125  1.1  mrg 	{ AUDIO_FILE_ENCODING_ADPCM_G723_3,	AUDIO_ENCODING_ULAW,	3 },
    126  1.1  mrg 	{ AUDIO_FILE_ENCODING_ADPCM_G723_5,	AUDIO_ENCODING_ULAW,	5 },
    127  1.1  mrg #endif
    128  1.1  mrg 	{ AUDIO_FILE_ENCODING_ALAW_8,		AUDIO_ENCODING_ALAW,	8 },
    129  1.1  mrg 	{ -1, -1 }
    130  1.1  mrg };
    131  1.1  mrg 
    132  1.1  mrg int
    133  1.1  mrg audio_get_sun_encoding(sun_encoding, encp, precp)
    134  1.1  mrg 	int	sun_encoding;
    135  1.1  mrg 	int	*encp;
    136  1.1  mrg 	int	*precp;
    137  1.1  mrg {
    138  1.1  mrg 	int i;
    139  1.1  mrg 
    140  1.1  mrg 	for (i = 0; file2sw_encodings[i].file_encoding != -1; i++)
    141  1.1  mrg 		if (file2sw_encodings[i].file_encoding == sun_encoding) {
    142  1.1  mrg 			*precp = file2sw_encodings[i].precision;
    143  1.1  mrg 			*encp = file2sw_encodings[i].encoding;
    144  1.1  mrg 			return (0);
    145  1.1  mrg 		}
    146  1.1  mrg 	return (1);
    147  1.1  mrg }
    148  1.1  mrg 
    149  1.1  mrg /*
    150  1.1  mrg  * sample header is:
    151  1.1  mrg  *
    152  1.1  mrg  *   RIFF\^@^C^@WAVEfmt ^P^@^@^@^A^@^B^@D<AC>^@^@^P<B1>^B^@^D^@^P^@data^@^@^C^@^@^@^@^@^@^@^@^@^@
    153  1.1  mrg  *
    154  1.1  mrg  */
    155  1.1  mrg /*
    156  1.1  mrg  * WAV format helpers
    157  1.1  mrg  */
    158  1.1  mrg /*
    159  1.1  mrg  * find a .wav header, etc. returns header length on success
    160  1.1  mrg  */
    161  1.1  mrg size_t
    162  1.1  mrg audio_parse_wav_hdr(hdr, sz, enc, prec, sample, channels)
    163  1.1  mrg 	void	*hdr;
    164  1.1  mrg 	size_t	sz;
    165  1.1  mrg 	int	*enc;
    166  1.1  mrg 	int	*prec;
    167  1.1  mrg 	int	*sample;
    168  1.1  mrg 	int	*channels;
    169  1.1  mrg {
    170  1.1  mrg 	char	*where = hdr;
    171  1.1  mrg 	wav_audioheaderpart *part;
    172  1.1  mrg 	wav_audioheaderfmt *fmt;
    173  1.1  mrg 	char	*end = (((char *)hdr) + sz);
    174  1.1  mrg 	int	newenc, newprec;
    175  1.1  mrg 
    176  1.1  mrg 	if (sz < 32)
    177  1.1  mrg 		return (AUDIO_ENOENT);
    178  1.1  mrg 
    179  1.1  mrg 	if (strncmp(where, "RIFF", 4))
    180  1.1  mrg 		return (AUDIO_ENOENT);
    181  1.1  mrg 	where += 8;
    182  1.1  mrg 	if (strncmp(where,  "WAVE", 4))
    183  1.1  mrg 		return (AUDIO_ENOENT);
    184  1.1  mrg 	where += 4;
    185  1.1  mrg 
    186  1.1  mrg 	do {
    187  1.1  mrg 		part = (wav_audioheaderpart *)where;
    188  1.1  mrg 		where += getle32(part->len) + 8;
    189  1.1  mrg 	} while (where < end && strncmp(part->name, "fmt ", 4));
    190  1.1  mrg 
    191  1.1  mrg 	/* too short ? */
    192  1.1  mrg 	if (where + 16 > end)
    193  1.1  mrg 		return (AUDIO_ESHORTHDR);
    194  1.1  mrg 
    195  1.1  mrg 	fmt = (wav_audioheaderfmt *)(part + 1);
    196  1.1  mrg 
    197  1.1  mrg #if 0
    198  1.1  mrg printf("fmt header is:\n\t%d\ttag\n\t%d\tchannels\n\t%d\tsample rate\n\t%d\tavg_bps\n\t%d\talignment\n\t%d\tbits per sample\n", getle16(fmt->tag), getle16(fmt->channels), getle32(fmt->sample_rate), getle32(fmt->avg_bps), getle16(fmt->alignment), getle16(fmt->bits_per_sample));
    199  1.1  mrg #endif
    200  1.1  mrg 
    201  1.1  mrg 	switch (getle16(fmt->tag)) {
    202  1.1  mrg 	case WAVE_FORMAT_UNKNOWN:
    203  1.1  mrg 	case WAVE_FORMAT_ADPCM:
    204  1.1  mrg 	case WAVE_FORMAT_OKI_ADPCM:
    205  1.1  mrg 	case WAVE_FORMAT_DIGISTD:
    206  1.1  mrg 	case WAVE_FORMAT_DIGIFIX:
    207  1.1  mrg 	case IBM_FORMAT_MULAW:
    208  1.1  mrg 	case IBM_FORMAT_ALAW:
    209  1.1  mrg 	case IBM_FORMAT_ADPCM:
    210  1.1  mrg 	default:
    211  1.1  mrg 		return (AUDIO_EWAVUNSUPP);
    212  1.1  mrg 
    213  1.1  mrg 	case WAVE_FORMAT_PCM:
    214  1.1  mrg 		switch (getle16(fmt->bits_per_sample)) {
    215  1.1  mrg 		case 8:
    216  1.1  mrg 			newprec = 8;
    217  1.1  mrg 			break;
    218  1.1  mrg 		case 16:
    219  1.1  mrg 			newprec = 16;
    220  1.1  mrg 			break;
    221  1.1  mrg 		case 24:
    222  1.1  mrg 			newprec = 24;
    223  1.1  mrg 			break;
    224  1.1  mrg 		case 32:
    225  1.1  mrg 			newprec = 32;
    226  1.1  mrg 			break;
    227  1.1  mrg 		default:
    228  1.1  mrg 			return (AUDIO_EWAVBADPCM);
    229  1.1  mrg 		}
    230  1.1  mrg 		newenc = AUDIO_ENCODING_ULINEAR;;
    231  1.1  mrg 		break;
    232  1.1  mrg 	case WAVE_FORMAT_ALAW:
    233  1.1  mrg 		newenc = AUDIO_ENCODING_ALAW;
    234  1.1  mrg 		newprec = 8;
    235  1.1  mrg 		break;
    236  1.1  mrg 	case WAVE_FORMAT_MULAW:
    237  1.1  mrg 		newenc = AUDIO_ENCODING_ULAW;
    238  1.1  mrg 		newprec = 8;
    239  1.1  mrg 		break;
    240  1.1  mrg 	}
    241  1.1  mrg 
    242  1.1  mrg 	do {
    243  1.1  mrg 		part = (wav_audioheaderpart *)where;
    244  1.1  mrg 		where += (getle32(part->len) + 8);
    245  1.1  mrg 	} while ((char *)where < end && strncmp(part->name, "data", 4));
    246  1.1  mrg 
    247  1.1  mrg 	if (where <= end) {
    248  1.1  mrg 		*channels = getle16(fmt->channels);
    249  1.1  mrg 		*sample = getle32(fmt->sample_rate);
    250  1.1  mrg 		*enc = newenc;
    251  1.1  mrg 		*prec = newprec;
    252  1.1  mrg 		part++;
    253  1.1  mrg 		return ((char *)part - (char *)hdr);
    254  1.1  mrg 	}
    255  1.1  mrg 	return (AUDIO_EWAVNODATA);
    256  1.1  mrg }
    257  1.1  mrg 
    258  1.1  mrg /*
    259  1.1  mrg  * these belong elsewhere??
    260  1.1  mrg  */
    261  1.1  mrg void
    262  1.1  mrg decode_int(arg, intp)
    263  1.1  mrg 	const char *arg;
    264  1.1  mrg 	int *intp;
    265  1.1  mrg {
    266  1.1  mrg 	char	*ep;
    267  1.1  mrg 	int	ret;
    268  1.1  mrg 
    269  1.1  mrg 	ret = strtoul(arg, &ep, 0);
    270  1.1  mrg 
    271  1.1  mrg 	if (ep[0] == '\0') {
    272  1.1  mrg 		*intp = ret;
    273  1.1  mrg 		return;
    274  1.1  mrg 	}
    275  1.1  mrg 	errx(1, "argument `%s' not a valid integer", arg);
    276  1.1  mrg }
    277  1.1  mrg 
    278  1.1  mrg #include <stdio.h>
    279  1.1  mrg void
    280  1.1  mrg decode_time(arg, tvp)
    281  1.1  mrg 	const char *arg;
    282  1.1  mrg 	struct timeval *tvp;
    283  1.1  mrg {
    284  1.1  mrg 	char	*s, *colon, *dot;
    285  1.1  mrg 	char	*copy = strdup(arg);
    286  1.1  mrg 	int	first;
    287  1.1  mrg 
    288  1.1  mrg 	if (copy == NULL)
    289  1.1  mrg 		err(1, "could not allocate a copy of %s", arg);
    290  1.1  mrg 
    291  1.1  mrg 	tvp->tv_sec = tvp->tv_usec = 0;
    292  1.1  mrg 	s = copy;
    293  1.1  mrg 
    294  1.1  mrg 	/* handle [hh:]mm:ss.dd */
    295  1.1  mrg 	if ((colon = strchr(s, ':'))) {
    296  1.1  mrg 		*colon++ = '\0';
    297  1.1  mrg 		decode_int(s, &first);
    298  1.1  mrg 		tvp->tv_sec = first * 60;	/* minutes */
    299  1.1  mrg 		s = colon;
    300  1.1  mrg 
    301  1.1  mrg 		if ((colon = strchr(s, ':'))) {
    302  1.1  mrg 			*colon++ = '\0';
    303  1.1  mrg 			decode_int(s, &first);
    304  1.1  mrg 			tvp->tv_sec += first;
    305  1.1  mrg 			tvp->tv_sec *= 60;	/* minutes and hours */
    306  1.1  mrg 			s = colon;
    307  1.1  mrg 		}
    308  1.1  mrg 	}
    309  1.1  mrg 	if ((dot = strchr(s, '.'))) {
    310  1.1  mrg 		int 	i, base = 100000;
    311  1.1  mrg 
    312  1.1  mrg 		*dot++ = '\0';
    313  1.1  mrg 
    314  1.1  mrg 		for (i = 0; i < 6; i++, base /= 10) {
    315  1.1  mrg 			if (!dot[i])
    316  1.1  mrg 				break;
    317  1.1  mrg 			if (!isdigit(dot[i]))
    318  1.1  mrg 				errx(1, "argument `%s' is not a value time specification", arg);
    319  1.1  mrg 			tvp->tv_usec += base * (dot[i] - '0');
    320  1.1  mrg 		}
    321  1.1  mrg 	}
    322  1.1  mrg 	decode_int(s, &first);
    323  1.1  mrg 	tvp->tv_sec += first;
    324  1.1  mrg #if 0
    325  1.1  mrg printf("tvp->tv_sec = %ld, tvp->tv_usec = %ld\n", tvp->tv_sec, tvp->tv_usec);
    326  1.1  mrg #endif
    327  1.1  mrg 
    328  1.1  mrg 	free(copy);
    329  1.1  mrg }
    330  1.1  mrg 
    331  1.1  mrg /*
    332  1.1  mrg  * decode a string into an encoding value.
    333  1.1  mrg  */
    334  1.1  mrg void
    335  1.1  mrg decode_encoding(arg, encp)
    336  1.1  mrg 	const char *arg;
    337  1.1  mrg 	int *encp;
    338  1.1  mrg {
    339  1.1  mrg 	size_t	len;
    340  1.1  mrg 	int i;
    341  1.1  mrg 
    342  1.1  mrg 	len = strlen(arg);
    343  1.1  mrg 	for (i = 0; encs[i].ename; i++)
    344  1.1  mrg 		if (strncmp(encs[i].ename, arg, len) == 0) {
    345  1.1  mrg 			*encp = encs[i].eno;
    346  1.1  mrg 			return;
    347  1.1  mrg 		}
    348  1.1  mrg 	errx(1, "unknown encoding `%s'", arg);
    349  1.1  mrg }
    350  1.1  mrg 
    351  1.1  mrg const char *const audio_errlist[] = {
    352  1.1  mrg 	"no audio entry",
    353  1.1  mrg 	"short header",
    354  1.1  mrg 	"unsupported WAV format",
    355  1.1  mrg 	"bad (unsupported) WAV PCM format",
    356  1.1  mrg 	"no WAV audio data",
    357  1.1  mrg };
    358  1.1  mrg 
    359  1.1  mrg const char *
    360  1.1  mrg audio_errstring(errval)
    361  1.1  mrg 	int	errval;
    362  1.1  mrg {
    363  1.1  mrg 
    364  1.1  mrg 	errval = -errval;
    365  1.1  mrg 	if (errval < 1 || errval > AUDIO_MAXERRNO)
    366  1.1  mrg 		return "Invalid error";
    367  1.1  mrg 	return audio_errlist[errval];
    368  1.1  mrg }
    369