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