xref: /illumos-gate/usr/src/cmd/audio/utilities/filehdr.c (revision d8048045f75b60d97deaf376b39d437b027becd1)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * This file contains a set of Very Paranoid routines to convert
29  * audio file headers to in-core audio headers and vice versa.
30  *
31  * They are robust enough to handle any random file input without
32  * crashing miserably.  Of course, bad audio headers coming from
33  * the calling program can cause significant problems.
34  */
35 
36 #include <stdlib.h>
37 #include <memory.h>
38 #include <fcntl.h>
39 #include <errno.h>	/* needed for large file error checking */
40 #include <stdio.h>
41 #include <sys/types.h>
42 #include <sys/file.h>
43 #include <sys/stat.h>
44 #include <libintl.h>
45 #include <math.h>
46 
47 #include <libaudio_impl.h>	/* include other audio hdr's */
48 
49 /* Round up to a double boundary */
50 #define	ROUND_DBL(x)	(((x) + 7) & ~7)
51 
52 #define	HEADER_BUFFER		100
53 
54 #define	_MGET_(str)	(char *)dgettext(TEXT_DOMAIN, str)
55 
56 static int audio_encode_aiff(Audio_hdr *, unsigned char *, unsigned int *);
57 static int audio_encode_au(Audio_hdr *, char *, unsigned int,
58 	unsigned char *, unsigned int *);
59 static int audio_encode_wav(Audio_hdr *, unsigned char *, unsigned int *);
60 static double convert_from_ieee_extended(unsigned char *);
61 static void convert_to_ieee_extended(double, unsigned char *);
62 
63 /*
64  * Write an audio file header to an output stream.
65  *
66  * The file header is encoded from the supplied Audio_hdr structure.
67  * If 'infop' is not NULL, it is the address of a buffer containing 'info'
68  * data.  'ilen' specifies the size of this buffer.
69  * The entire file header will be zero-padded to a double-word boundary.
70  *
71  * Note that the file header is stored on-disk in big-endian format,
72  * regardless of the machine type.
73  *
74  * Note also that the output file descriptor must not have been set up
75  * non-blocking i/o.  If non-blocking behavior is desired, set this
76  * flag after writing the file header.
77  */
78 int
audio_write_filehdr(int fd,Audio_hdr * hdrp,int file_type,char * infop,unsigned int ilen)79 audio_write_filehdr(int fd, Audio_hdr *hdrp, int file_type, char *infop,
80 	unsigned int ilen)
81 					/* file descriptor */
82 					/* audio header */
83 					/* audio header type */
84 					/* info buffer pointer */
85 					/* buffer size */
86 {
87 	int		err;
88 	unsigned	blen;
89 	unsigned char	*buf;		/* temporary buffer */
90 
91 	/* create tmp buf for the encoding routines to work with */
92 	blen = HEADER_BUFFER + (infop ? ilen : 0) + 4;
93 	blen = ROUND_DBL(blen);
94 
95 	if (!(buf = (unsigned char *)calloc(1, blen))) {
96 		return (AUDIO_UNIXERROR);
97 	}
98 
99 	switch (file_type) {
100 	case FILE_AU:
101 		err = audio_encode_au(hdrp, infop, ilen, buf, &blen);
102 		break;
103 	case FILE_WAV:
104 		err = audio_encode_wav(hdrp, buf, &blen);
105 		break;
106 	case FILE_AIFF:
107 		err = audio_encode_aiff(hdrp, buf, &blen);
108 		break;
109 	default:
110 		return (AUDIO_ERR_BADFILETYPE);
111 	}
112 
113 	if (err != AUDIO_SUCCESS) {
114 		return (err);
115 	}
116 
117 	/* Write and free the holding buffer */
118 	err = write(fd, (char *)buf, (int)blen);
119 	(void) free((char *)buf);
120 
121 	if (err != blen)
122 		return ((err < 0) ? AUDIO_UNIXERROR : AUDIO_ERR_BADFILEHDR);
123 
124 	return (AUDIO_SUCCESS);
125 
126 }
127 
128 /*
129  * Rewrite the aiff header chunk length and the data chunk length fields.
130  */
131 static int
audio_rewrite_aiff_filesize(int fd,unsigned int size,unsigned int channels,unsigned int bytes_per_sample)132 audio_rewrite_aiff_filesize(int fd, unsigned int size, unsigned int channels,
133 	unsigned int bytes_per_sample)
134 {
135 	unsigned int	offset;
136 	unsigned int	tmp_uint;
137 	unsigned int	tmp_uint2;
138 	unsigned int	total_size;
139 
140 	/* first fix aiff_hdr_size */
141 	total_size = size + sizeof (aiff_hdr_chunk_t) +
142 	    AUDIO_AIFF_COMM_CHUNK_SIZE + sizeof (aiff_ssnd_chunk_t);
143 	tmp_uint = total_size - (2 * sizeof (int));
144 	AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &tmp_uint2);
145 	offset = sizeof (int);
146 	if (lseek(fd, offset, SEEK_SET) < 0) {
147 		return (AUDIO_ERR_NOEFFECT);
148 	}
149 	if (write(fd, &tmp_uint2, sizeof (tmp_uint2)) != sizeof (tmp_uint2)) {
150 		return (AUDIO_ERR_NOEFFECT);
151 	}
152 
153 	/* fix the frame count */
154 	tmp_uint = size / channels / bytes_per_sample;
155 	AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &tmp_uint2);
156 	offset = sizeof (aiff_hdr_chunk_t) + (2 * sizeof (int)) +
157 	    sizeof (short);
158 	if (lseek(fd, offset, SEEK_SET) < 0) {
159 		return (AUDIO_ERR_NOEFFECT);
160 	}
161 	if (write(fd, &tmp_uint2, sizeof (tmp_uint2)) != sizeof (tmp_uint2)) {
162 		return (AUDIO_ERR_NOEFFECT);
163 	}
164 
165 	/* fix the data size */
166 	tmp_uint = size + sizeof (aiff_ssnd_chunk_t) - (2 * sizeof (int));
167 	AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &tmp_uint2);
168 	offset = sizeof (aiff_hdr_chunk_t) + AUDIO_AIFF_COMM_CHUNK_SIZE +
169 	    sizeof (int);
170 	if (lseek(fd, offset, SEEK_SET) < 0) {
171 		return (AUDIO_ERR_NOEFFECT);
172 	}
173 	if (write(fd, &tmp_uint2, sizeof (tmp_uint2)) != sizeof (tmp_uint2)) {
174 		return (AUDIO_ERR_NOEFFECT);
175 	}
176 
177 	return (AUDIO_SUCCESS);
178 
179 }
180 
181 /*
182  * Rewrite the data size field for the .au file format. Rewrite the audio
183  * file header au_data_size field with the supplied value. Otherwise,
184  * return AUDIO_ERR_NOEFFECT.
185  */
186 static int
audio_rewrite_au_filesize(int fd,unsigned int size)187 audio_rewrite_au_filesize(int fd, unsigned int size)
188 {
189 	au_filehdr_t	fhdr;
190 	int		err;
191 	int		data;
192 	int		offset;
193 
194 	/* seek to the position of the au_data_size member */
195 	offset = (char *)&fhdr.au_data_size - (char *)&fhdr;
196 	if (lseek(fd, offset, SEEK_SET) < 0) {
197 		return (AUDIO_ERR_NOEFFECT);
198 	}
199 
200 	/* Encode the 32-bit integer header field */
201 	AUDIO_AU_HOST2FILE(&size, &data);
202 
203 	/* Write the data */
204 	err = write(fd, (char *)&data, sizeof (fhdr.au_data_size));
205 	if (err != sizeof (fhdr.au_data_size))
206 		return ((err < 0) ? AUDIO_UNIXERROR : AUDIO_ERR_BADFILEHDR);
207 
208 	return (AUDIO_SUCCESS);
209 
210 }
211 
212 /*
213  * Rewrite the riff header chunk length and the data chunk length fields.
214  */
215 static int
audio_rewrite_wav_filesize(int fd,unsigned int size)216 audio_rewrite_wav_filesize(int fd, unsigned int size)
217 {
218 	wav_filehdr_t	fhdr;
219 	int		calc_size;
220 	int		err;
221 	int		data;
222 	int		offset;
223 
224 	/* seek to the position of the riff header chunk length */
225 	calc_size = size + sizeof (fhdr) - sizeof (fhdr.wav_riff_ID) -
226 	    sizeof (fhdr.wav_riff_size);
227 	AUDIO_WAV_HOST2FILE_INT(&calc_size, &data);
228 	offset = (char *)&fhdr.wav_riff_size - (char *)&fhdr;
229 	if (lseek(fd, offset, SEEK_SET) < 0) {
230 		return (AUDIO_ERR_NOEFFECT);
231 	}
232 
233 	/* Write the data */
234 	err = write(fd, (char *)&data, sizeof (fhdr.wav_riff_size));
235 	if (err != sizeof (fhdr.wav_riff_size))
236 		return ((err < 0) ? AUDIO_UNIXERROR : AUDIO_ERR_BADFILEHDR);
237 
238 	/* now seek to the position of the data chunk length */
239 	AUDIO_WAV_HOST2FILE_INT(&size, &data);
240 	offset = (char *)&fhdr.wav_data_size - (char *)&fhdr;
241 	if (lseek(fd, offset, SEEK_SET) < 0) {
242 		return (AUDIO_ERR_NOEFFECT);
243 	}
244 
245 	/* Write the data */
246 	err = write(fd, (char *)&data, sizeof (fhdr.wav_data_size));
247 	if (err != sizeof (fhdr.wav_data_size))
248 		return ((err < 0) ? AUDIO_UNIXERROR : AUDIO_ERR_BADFILEHDR);
249 
250 	return (AUDIO_SUCCESS);
251 
252 }
253 
254 /*
255  * Rewrite the data size field of an audio header to the output stream if
256  * the output file is capable of seeking.
257  */
258 int
audio_rewrite_filesize(int fd,int file_type,unsigned int size,unsigned int channels,unsigned int bytes_per_sample)259 audio_rewrite_filesize(int fd, int file_type, unsigned int size,
260 	unsigned int channels, unsigned int bytes_per_sample)
261 					/* file descriptor */
262 					/* audio file type */
263 					/* new data size */
264 					/* number of channels */
265 					/* number of bytes per sample */
266 {
267 	int		fcntl_err;
268 
269 	/* Can we seek back in this file and write without appending? */
270 	fcntl_err = fcntl(fd, F_GETFL, 0);
271 	if ((fcntl_err < 0) && ((errno == EOVERFLOW) || (errno == EINVAL))) {
272 		/* Large file encountered (probably) */
273 		perror("fcntl");
274 		exit(1);
275 	} else if ((lseek(fd, (off_t)0, SEEK_SET) < 0) ||
276 		    (fcntl_err & FAPPEND)) {
277 		return (AUDIO_ERR_NOEFFECT);
278 	}
279 
280 	switch (file_type) {
281 	case FILE_AU:
282 		return (audio_rewrite_au_filesize(fd, size));
283 	case FILE_WAV:
284 		return (audio_rewrite_wav_filesize(fd, size));
285 	case FILE_AIFF:
286 		return (audio_rewrite_aiff_filesize(fd, size, channels,
287 		    bytes_per_sample));
288 	default:
289 		return (AUDIO_ERR_BADFILETYPE);
290 	}
291 }
292 
293 
294 /*
295  * Decode an audio file header from an input stream.
296  *
297  * The file header is decoded into the supplied Audio_hdr structure, regardless
298  * of the file format. Thus .wav and .aiff files look like .au files once the
299  * header is decoded.
300  *
301  * If 'infop' is not NULL, it is the address of a buffer to which the
302  * 'info' portion of the file header will be copied.  'ilen' specifies
303  * the maximum number of bytes to copy.  The buffer will be NULL-terminated,
304  * even if it means over-writing the last byte.
305  *
306  * Note that the .au file header is stored on-disk in big-endian format,
307  * regardless of the machine type.  This may not have been true if
308  * the file was written on a non-Sun machine.  For now, such
309  * files will appear invalid.
310  *
311  * Note also that the input file descriptor must not have been set up
312  * non-blocking i/o.  If non-blocking behavior is desired, set this
313  * flag after reading the file header.
314  */
315 int
audio_read_filehdr(int fd,Audio_hdr * hdrp,int * file_type,char * infop,unsigned int ilen)316 audio_read_filehdr(int fd, Audio_hdr *hdrp, int *file_type, char *infop,
317 	unsigned int ilen)
318 					/* input file descriptor */
319 					/* output audio header */
320 					/* audio file type */
321 					/* info buffer pointer */
322 					/* buffer size */
323 {
324 	int		err;
325 	int		dsize;
326 	int		isize;
327 	unsigned	resid;
328 	unsigned char	buf[HEADER_BUFFER];
329 	struct stat	st;
330 
331 	/* decode the file header and fill in the hdrp structure */
332 	if ((err = audio_decode_filehdr(fd, buf, file_type, hdrp, &isize)) !=
333 	    AUDIO_SUCCESS) {
334 		goto checkerror;
335 	}
336 
337 	/* Stat the file, to determine if it is a regular file. */
338 	err = fstat(fd, &st);
339 	if (err < 0) {
340 		return (AUDIO_UNIXERROR);
341 	}
342 
343 	/*
344 	 * If au_data_size is not indeterminate (i.e., this isn't a pipe),
345 	 * try to validate the au_offset and au_data_size.
346 	 */
347 	if (*file_type == FILE_AU && hdrp->data_size != AUDIO_UNKNOWN_SIZE) {
348 		/* Only trust the size for regular files */
349 		if (S_ISREG(st.st_mode)) {
350 			dsize = isize + hdrp->data_size + sizeof (au_filehdr_t);
351 			if (st.st_size < dsize) {
352 				(void) fprintf(stderr,
353 				    _MGET_("Warning: More audio data "
354 				    "than the file header specifies\n"));
355 			} else if (st.st_size > dsize) {
356 				(void) fprintf(stderr,
357 				    _MGET_("Warning: Less audio data "
358 				    "than the file header specifies\n"));
359 			}
360 		}
361 	}
362 
363 	resid = isize;
364 	/*
365 	 * Deal with extra header data.
366 	 */
367 	if ((infop != NULL) && (ilen != 0)) {
368 		/*
369 		 * If infop is non-NULL, try to read in the info data
370 		 */
371 		if (isize > ilen)
372 			isize = ilen;
373 		err = read(fd, infop, (int)isize);
374 		if (err != isize)
375 			goto checkerror;
376 
377 		/* Zero any residual bytes in the text buffer */
378 		if (isize < ilen)
379 			(void) memset(&infop[isize], '\0',
380 				    (int)(ilen - isize));
381 		else
382 			infop[ilen - 1] = '\0';	/* zero-terminate */
383 
384 		resid -= err;		/* subtract the amount read */
385 	}
386 
387 	/*
388 	 * If we truncated the info, seek or read data until info size
389 	 * is satisfied.  If regular file, seek nearly to end and check
390 	 * for eof.
391 	 */
392 	if (resid != 0) {
393 		if (S_ISREG(st.st_mode)) {
394 			err = lseek(fd, (off_t)(resid - 1), SEEK_CUR);
395 			if ((err < 0) ||
396 			    ((err = read(fd, (char *)buf, 1)) != 1))
397 				goto checkerror;
398 		} else while (resid != 0) {
399 			char	junk[8192];	/* temporary buffer */
400 
401 			isize = (resid > sizeof (junk)) ?
402 			    sizeof (junk) : resid;
403 			err = read(fd, junk, isize);
404 			if (err != isize)
405 				goto checkerror;
406 			resid -= err;
407 		}
408 	}
409 
410 	return (AUDIO_SUCCESS);
411 
412 checkerror:
413 	if ((err < 0) && (errno == EOVERFLOW)) {
414 		perror("read");
415 		exit(1);
416 	} else {
417 		return ((err < 0) ? AUDIO_UNIXERROR : AUDIO_ERR_BADFILEHDR);
418 	}
419 	return (AUDIO_SUCCESS);
420 }
421 
422 /*
423  * Return TRUE if the named file is an audio file.  Else, return FALSE.
424  */
425 int
audio_isaudiofile(char * name)426 audio_isaudiofile(char *name)
427 {
428 	int		fd;
429 	int		err;
430 	int		file_type;	/* ignored */
431 	int		isize;
432 	Audio_hdr	hdr;
433 	unsigned char	buf[sizeof (au_filehdr_t)];
434 
435 	/* Open the file (set O_NONBLOCK in case the name refers to a device) */
436 	fd = open(name, O_RDONLY | O_NONBLOCK);
437 	if (fd < 0) {
438 		if (errno == EOVERFLOW) {
439 			perror("open");
440 			exit(1);
441 		} else {
442 			return (FALSE);
443 		}
444 	}
445 
446 	/* Read the header (but not the text info). */
447 	err = read(fd, (char *)buf, sizeof (buf));
448 	if (err < 0) {
449 		if (errno == EOVERFLOW) {
450 			perror("open");
451 			exit(1);
452 		} else {
453 			return (FALSE);
454 		}
455 	}
456 	(void) close(fd);
457 
458 	if ((err == sizeof (buf)) &&
459 	    (audio_decode_filehdr(fd, buf, &file_type, &hdr, &isize) ==
460 	    AUDIO_SUCCESS)) {
461 		return (hdr.encoding);
462 	} else {
463 		return (FALSE);
464 	}
465 }
466 
467 /*
468  * audio_endian()
469  *
470  * This routine tests the magic number at the head of a buffer
471  * containing the file header.  The first thing in the header
472  * should be the magic number.
473  */
474 static int
audio_endian(unsigned char * buf,int * file_type)475 audio_endian(unsigned char *buf, int *file_type)
476 {
477 	unsigned int	magic1;
478 	unsigned int	magic2;
479 
480 	/* put the buffer into an int that is aligned properly */
481 	(void) memcpy(&magic1, buf, sizeof (magic1));
482 
483 	magic2 = magic1;
484 	SWABI(magic2);
485 
486 	if (magic1 == AUDIO_AU_FILE_MAGIC || magic2 == AUDIO_AU_FILE_MAGIC) {
487 		*file_type = FILE_AU;
488 		return (AUDIO_ENDIAN_BIG);
489 	} else if (magic1 == AUDIO_WAV_RIFF_ID || magic2 == AUDIO_WAV_RIFF_ID) {
490 		*file_type = FILE_WAV;
491 		return (AUDIO_ENDIAN_SMALL);
492 	} else if (magic1 == AUDIO_AIFF_HDR_CHUNK_ID ||
493 	    magic2 == AUDIO_AIFF_HDR_CHUNK_ID) {
494 		*file_type = FILE_AIFF;
495 		return (AUDIO_ENDIAN_BIG);
496 	}
497 
498 	return (AUDIO_ENDIAN_UNKNOWN);
499 }
500 
501 /*
502  * Decode an aiff file header. Unlike .au and .wav, we have to process
503  * by chunk.
504  */
505 static int
decode_aiff(int fd,unsigned char * buf,Audio_hdr * hdrp,int * isize)506 decode_aiff(int fd, unsigned char *buf, Audio_hdr *hdrp, int *isize)
507 {
508 	aiff_hdr_chunk_t	hdr_chunk;
509 	aiff_comm_chunk_t	comm_chunk;
510 	aiff_ssnd_chunk_t	ssnd_chunk;
511 	uint32_t		ID;
512 	uint32_t		size;
513 	uint32_t		tmp;
514 	int			data_type;
515 	int			hdr_sizes;
516 	int			sr;
517 	short			bits_per_sample;
518 	short			channels;
519 
520 	/* we've read in 4 bytes, read in the rest of the wav header */
521 	size = sizeof (hdr_chunk) - sizeof (hdr_chunk.aiff_hdr_ID);
522 
523 	/* read in the rest of the header */
524 	if (read(fd, &hdr_chunk.aiff_hdr_size, size) != size) {
525 		return (AUDIO_UNIXERROR);
526 	}
527 
528 	/* see which kind of audio file we have */
529 	AUDIO_AIFF_FILE2HOST_INT(&hdr_chunk.aiff_hdr_data_type, &data_type);
530 	if (data_type != AUDIO_AIFF_HDR_FORM_AIFF) {
531 		/* we can't play this version of a .aiff file */
532 		return (AUDIO_ERR_BADFILEHDR);
533 	}
534 
535 	hdr_sizes = sizeof (hdr_chunk);
536 
537 	/*
538 	 * We don't know what the chunk order will be, so read each, getting
539 	 * the data we need from each. Eventually we'll get to the end of
540 	 * the file, in which case we should have all of the info on the
541 	 * file that we need. We then lseek() back to the data to play.
542 	 *
543 	 * We start each loop by reading the chunk ID.
544 	 */
545 	while (read(fd, &tmp, sizeof (tmp)) == sizeof (tmp)) {
546 		AUDIO_AIFF_FILE2HOST_INT(&tmp, &ID);
547 		switch (ID) {
548 		case AUDIO_AIFF_COMM_ID:
549 			/* read in the rest of the COMM chunk */
550 			size = AUDIO_AIFF_COMM_CHUNK_SIZE -
551 			    sizeof (comm_chunk.aiff_comm_ID);
552 			if (read(fd, &comm_chunk.aiff_comm_size, size) !=
553 			    size) {
554 				return (AUDIO_UNIXERROR);
555 			}
556 
557 			sr = convert_from_ieee_extended(
558 			    comm_chunk.aiff_comm_sample_rate);
559 
560 			hdr_sizes += AUDIO_AIFF_COMM_CHUNK_SIZE;
561 
562 			break;
563 		case AUDIO_AIFF_SSND_ID:
564 			/* read in the rest of the INST chunk */
565 			size = sizeof (ssnd_chunk) -
566 			    sizeof (ssnd_chunk.aiff_ssnd_ID);
567 			if (read(fd, &ssnd_chunk.aiff_ssnd_size, size) !=
568 			    size) {
569 				return (AUDIO_UNIXERROR);
570 			}
571 
572 			/*
573 			 * This has to be the last chunk because the audio data
574 			 * follows. So we should have all we need to tell the
575 			 * app the format information.
576 			 */
577 			hdrp->sample_rate = sr;
578 
579 			AUDIO_AIFF_FILE2HOST_SHORT(
580 			    &comm_chunk.aiff_comm_channels,
581 			    &channels);
582 			/* use channels to convert from short to int */
583 			hdrp->channels = channels;
584 
585 			AUDIO_AIFF_FILE2HOST_SHORT(
586 			    &comm_chunk.aiff_comm_sample_size,
587 			    &bits_per_sample);
588 			switch (bits_per_sample) {
589 			case AUDIO_AIFF_COMM_8_BIT_SAMPLE_SIZE:
590 				hdrp->encoding = AUDIO_AU_ENCODING_LINEAR_8;
591 				break;
592 			case AUDIO_AIFF_COMM_16_BIT_SAMPLE_SIZE:
593 				hdrp->encoding = AUDIO_AU_ENCODING_LINEAR_16;
594 				break;
595 			default:
596 				return (AUDIO_ERR_BADFILEHDR);
597 			}
598 
599 			AUDIO_AIFF_FILE2HOST_INT(&ssnd_chunk.aiff_ssnd_size,
600 			    &size);
601 			size -= sizeof (ssnd_chunk.aiff_ssnd_offset) +
602 			    sizeof (ssnd_chunk.aiff_ssnd_block_size);
603 			hdrp->data_size = size;
604 
605 			hdr_sizes += sizeof (ssnd_chunk);
606 
607 			*isize = hdr_sizes - sizeof (au_filehdr_t);
608 
609 			return (AUDIO_SUCCESS);
610 		default:
611 			/*
612 			 * Unknown chunk. Read the size, which is right after
613 			 * the ID. Then seek past it to get to the next chunk.
614 			 */
615 			if (read(fd, &size, sizeof (size)) != sizeof (size)) {
616 				return (AUDIO_UNIXERROR);
617 			}
618 
619 			if (lseek(fd, size, SEEK_CUR) < 0) {
620 				return (AUDIO_UNIXERROR);
621 			}
622 			break;
623 		}
624 	}
625 
626 	return (AUDIO_SUCCESS);
627 
628 }	/* decode_aiff() */
629 
630 /*
631  * Decode an au file header.
632  */
633 static int
decode_au(int fd,unsigned char * buf,Audio_hdr * hdrp,int * isize,boolean_t read_info)634 decode_au(int fd, unsigned char *buf, Audio_hdr *hdrp, int *isize,
635     boolean_t read_info)
636 {
637 	au_filehdr_t	fhdr;
638 	int		offset;
639 	int		size;
640 
641 	if (read_info) {
642 		/* read in the rest of the au header */
643 		size = sizeof (fhdr) - sizeof (int);
644 		(void) lseek(fd, (off_t)4, SEEK_SET);
645 		if (read(fd, &buf[sizeof (int)], size) != size) {
646 
647 			return (AUDIO_UNIXERROR);
648 		}
649 	}
650 
651 	/* put the buffer into a structure that is aligned properly */
652 	(void) memcpy(&fhdr, buf, sizeof (fhdr));
653 
654 	/* Decode the 32-bit integer header fields. */
655 	AUDIO_AU_FILE2HOST(&fhdr.au_offset, &offset);
656 	AUDIO_AU_FILE2HOST(&fhdr.au_data_size, &hdrp->data_size);
657 	AUDIO_AU_FILE2HOST(&fhdr.au_encoding, &hdrp->encoding);
658 	AUDIO_AU_FILE2HOST(&fhdr.au_sample_rate, &hdrp->sample_rate);
659 	AUDIO_AU_FILE2HOST(&fhdr.au_channels, &hdrp->channels);
660 
661 	/* Set the info field size (ie, number of bytes left before data). */
662 	*isize = offset - sizeof (au_filehdr_t);
663 
664 	return (AUDIO_SUCCESS);
665 
666 }	/* decode_au() */
667 
668 /*
669  * Decode a wav file header.
670  *
671  * .wav files are stored on-disk in little-endian format.
672  */
673 static int
decode_wav(int fd,unsigned char * buf,Audio_hdr * hdrp,int * isize)674 decode_wav(int fd, unsigned char *buf, Audio_hdr *hdrp, int *isize)
675 {
676 	wav_filehdr_t	fhdr;
677 	uint32_t	ID;
678 	uint32_t	size;
679 	short		bits_per_sample;
680 	short		encoding;
681 
682 	/* we've read in 4 bytes, read in the rest of the wav header */
683 	size = sizeof (fhdr) - sizeof (int);
684 
685 	/* read in the rest of the header */
686 	if (read(fd, &buf[sizeof (int)], size) != size) {
687 		return (AUDIO_UNIXERROR);
688 	}
689 
690 	/* put the buffer into a structure that is aligned properly */
691 	(void) memcpy(&fhdr, buf, sizeof (fhdr));
692 
693 	/* make sure we have the correct RIFF type */
694 	AUDIO_WAV_FILE2HOST_INT(&fhdr.wav_type_ID, &ID);
695 	if (ID != AUDIO_WAV_TYPE_ID) {
696 		/* not a wave file */
697 		return (AUDIO_ERR_BADFILEHDR);
698 	}
699 
700 	/* decode the fields */
701 	AUDIO_WAV_FILE2HOST_INT(&fhdr.wav_fmt_ID, &ID);
702 	if (ID != AUDIO_WAV_FORMAT_ID) {
703 		/* mangled format */
704 		return (AUDIO_ERR_BADFILEHDR);
705 	}
706 
707 	AUDIO_WAV_FILE2HOST_SHORT(&fhdr.wav_fmt_encoding, &encoding);
708 	AUDIO_WAV_FILE2HOST_SHORT(&fhdr.wav_fmt_channels, &hdrp->channels);
709 	AUDIO_WAV_FILE2HOST_INT(&fhdr.wav_fmt_sample_rate, &hdrp->sample_rate);
710 	AUDIO_WAV_FILE2HOST_SHORT(&fhdr.wav_fmt_bits_per_sample,
711 	    &bits_per_sample);
712 
713 	/* convert .wav encodings to .au encodings */
714 	switch (encoding) {
715 	case AUDIO_WAV_FMT_ENCODING_PCM:
716 		switch (bits_per_sample) {
717 		case AUDIO_WAV_FMT_BITS_PER_SAMPLE_8_BITS:
718 			hdrp->encoding = AUDIO_AU_ENCODING_LINEAR_8;
719 			break;
720 		case AUDIO_WAV_FMT_BITS_PER_SAMPLE_16_BITS:
721 			hdrp->encoding = AUDIO_AU_ENCODING_LINEAR_16;
722 			break;
723 		default:
724 			return (AUDIO_ERR_BADFILEHDR);
725 		}
726 		break;
727 	case AUDIO_WAV_FMT_ENCODING_ALAW:
728 		hdrp->encoding = AUDIO_AU_ENCODING_ALAW;
729 		break;
730 	case AUDIO_WAV_FMT_ENCODING_MULAW:
731 		hdrp->encoding = AUDIO_AU_ENCODING_ULAW;
732 		break;
733 	default:
734 		return (AUDIO_ERR_BADFILEHDR);
735 	}
736 
737 	AUDIO_WAV_FILE2HOST_INT(&fhdr.wav_data_size, &hdrp->data_size);
738 
739 	*isize = sizeof (wav_filehdr_t) - sizeof (au_filehdr_t);
740 
741 	return (AUDIO_SUCCESS);
742 
743 }	/* decode_wav() */
744 
745 /*
746  * Try to decode buffer containing an audio file header into an audio header.
747  */
748 int
audio_decode_filehdr(int fd,unsigned char * buf,int * file_type,Audio_hdr * hdrp,int * isize)749 audio_decode_filehdr(int fd, unsigned char *buf, int *file_type,
750 	Audio_hdr *hdrp, int *isize)
751 					/* file descriptor */
752 					/* buffer address */
753 					/* audio file type */
754 					/* output audio header */
755 					/* output size of info */
756 {
757 	int		err;
758 	struct stat	fd_stat;
759 	boolean_t	read_info;
760 
761 	/* Test for .au first */
762 	hdrp->endian = audio_endian(buf, file_type);
763 
764 	/*
765 	 * When cat'ing a file, audioconvert will read the whole header
766 	 * trying to figure out the file. audioplay however, does not.
767 	 * Hence we check if this is a pipe and do not attempt to read
768 	 * any more header info if the file type is already known.
769 	 * Otherwise we overwrite the header data already in the buffer.
770 	 */
771 	if (fstat(fd, &fd_stat) < 0) {
772 		return (AUDIO_ERR_BADFILEHDR);
773 	}
774 	if (S_ISFIFO(fd_stat.st_mode) && (*file_type == FILE_AU)) {
775 		read_info = B_FALSE;
776 	} else {
777 		/*
778 		 * Not an au file, or file type unknown. Reread the header's
779 		 * magic number. Fortunately this is always an int.
780 		 */
781 		(void) lseek(fd, (off_t)0, SEEK_SET);
782 		err = read(fd, (char *)buf, sizeof (int));
783 		read_info = B_TRUE;
784 
785 		/* test the magic number to determine the endian */
786 		if ((hdrp->endian = audio_endian(buf, file_type)) ==
787 		    AUDIO_ENDIAN_UNKNOWN) {
788 
789 			return (AUDIO_ERR_BADFILEHDR);
790 		}
791 	}
792 
793 	/* decode the different file types, putting the data into hdrp */
794 	switch (*file_type) {
795 	case FILE_AU:
796 		if ((err = decode_au(fd, buf, hdrp, isize, read_info)) !=
797 		    AUDIO_SUCCESS) {
798 			return (err);
799 		}
800 		break;
801 	case FILE_WAV:
802 		if ((err = decode_wav(fd, buf, hdrp, isize)) != AUDIO_SUCCESS) {
803 			return (err);
804 		}
805 		break;
806 	case FILE_AIFF:
807 		if ((err = decode_aiff(fd, buf, hdrp, isize)) !=
808 		    AUDIO_SUCCESS) {
809 			return (err);
810 		}
811 		break;
812 	default:
813 		return (AUDIO_ERR_BADFILEHDR);
814 	}
815 
816 	/* Convert from file format info to audio format info */
817 	switch (hdrp->encoding) {
818 	case AUDIO_AU_ENCODING_ULAW:
819 		hdrp->encoding = AUDIO_ENCODING_ULAW;
820 		hdrp->bytes_per_unit = 1;
821 		hdrp->samples_per_unit = 1;
822 		break;
823 	case AUDIO_AU_ENCODING_ALAW:
824 		hdrp->encoding = AUDIO_ENCODING_ALAW;
825 		hdrp->bytes_per_unit = 1;
826 		hdrp->samples_per_unit = 1;
827 		break;
828 	case AUDIO_AU_ENCODING_LINEAR_8:
829 		if (*file_type == FILE_WAV) {
830 			hdrp->encoding = AUDIO_ENCODING_LINEAR8;
831 		} else {
832 			hdrp->encoding = AUDIO_ENCODING_LINEAR;
833 		}
834 		hdrp->bytes_per_unit = 1;
835 		hdrp->samples_per_unit = 1;
836 		break;
837 	case AUDIO_AU_ENCODING_LINEAR_16:
838 		hdrp->encoding = AUDIO_ENCODING_LINEAR;
839 		hdrp->bytes_per_unit = 2;
840 		hdrp->samples_per_unit = 1;
841 		break;
842 	case AUDIO_AU_ENCODING_LINEAR_24:
843 		hdrp->encoding = AUDIO_ENCODING_LINEAR;
844 		hdrp->bytes_per_unit = 3;
845 		hdrp->samples_per_unit = 1;
846 		break;
847 	case AUDIO_AU_ENCODING_LINEAR_32:
848 		hdrp->encoding = AUDIO_ENCODING_LINEAR;
849 		hdrp->bytes_per_unit = 4;
850 		hdrp->samples_per_unit = 1;
851 		break;
852 	case AUDIO_AU_ENCODING_FLOAT:
853 		hdrp->encoding = AUDIO_ENCODING_FLOAT;
854 		hdrp->bytes_per_unit = 4;
855 		hdrp->samples_per_unit = 1;
856 		break;
857 	case AUDIO_AU_ENCODING_DOUBLE:
858 		hdrp->encoding = AUDIO_ENCODING_FLOAT;
859 		hdrp->bytes_per_unit = 8;
860 		hdrp->samples_per_unit = 1;
861 		break;
862 	case AUDIO_AU_ENCODING_ADPCM_G721:
863 		hdrp->encoding = AUDIO_ENCODING_G721;
864 		hdrp->bytes_per_unit = 1;
865 		hdrp->samples_per_unit = 2;
866 		break;
867 	case AUDIO_AU_ENCODING_ADPCM_G723_3:
868 		hdrp->encoding = AUDIO_ENCODING_G723;
869 		hdrp->bytes_per_unit = 3;
870 		hdrp->samples_per_unit = 8;
871 		break;
872 	case AUDIO_AU_ENCODING_ADPCM_G723_5:
873 		hdrp->encoding = AUDIO_ENCODING_G723;
874 		hdrp->bytes_per_unit = 5;
875 		hdrp->samples_per_unit = 8;
876 		break;
877 
878 	default:
879 		return (AUDIO_ERR_BADFILEHDR);
880 	}
881 	return (AUDIO_SUCCESS);
882 }
883 
884 /*
885  * Encode a .aiff file header from the supplied Audio_hdr structure and
886  * store in the supplied char* buffer. blen is the size of the buffer to
887  * store the header in. Unlike .au and .wav we can't cast to a data structure.
888  * We have to build it one chunk at a time.
889  *
890  * NOTE: .aiff doesn't support unsigned 8-bit linear PCM.
891  */
892 static int
audio_encode_aiff(Audio_hdr * hdrp,unsigned char * buf,unsigned int * blen)893 audio_encode_aiff(Audio_hdr *hdrp, unsigned char *buf, unsigned int *blen)
894 					/* audio header */
895 					/* output buffer */
896 					/* output buffer size */
897 {
898 	aiff_comm_chunk_t	comm_chunk;
899 	aiff_hdr_chunk_t	hdr_chunk;
900 	aiff_ssnd_chunk_t	ssnd_chunk;
901 	uint32_t		tmp_uint;
902 	uint32_t		tmp_uint2;
903 	int			buf_size = 0;
904 	uint16_t		tmp_ushort;
905 
906 	/* the only encoding we support for .aiff is signed linear PCM */
907 	if (hdrp->encoding != AUDIO_ENCODING_LINEAR) {
908 		return (AUDIO_ERR_ENCODING);
909 	}
910 
911 	/* build the header chunk */
912 	tmp_uint = AUDIO_AIFF_HDR_CHUNK_ID;
913 	AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &hdr_chunk.aiff_hdr_ID);
914 	/* needs to be fixed when closed */
915 	tmp_uint = AUDIO_AIFF_UNKNOWN_SIZE;
916 	AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &hdr_chunk.aiff_hdr_size);
917 	tmp_uint = AUDIO_AIFF_HDR_FORM_AIFF;
918 	AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &hdr_chunk.aiff_hdr_data_type);
919 	(void) memcpy(&buf[buf_size], &hdr_chunk, sizeof (hdr_chunk));
920 	buf_size += sizeof (hdr_chunk);
921 
922 	/* build the COMM chunk */
923 	tmp_uint = AUDIO_AIFF_COMM_ID;
924 	AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &comm_chunk.aiff_comm_ID);
925 	tmp_uint = AUDIO_AIFF_COMM_SIZE;
926 	AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &comm_chunk.aiff_comm_size);
927 	tmp_ushort = hdrp->channels;
928 	AUDIO_AIFF_HOST2FILE_SHORT(&tmp_ushort, &comm_chunk.aiff_comm_channels);
929 	/* needs to be fixed when closed */
930 	tmp_uint = AUDIO_AIFF_UNKNOWN_SIZE;
931 	AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &tmp_uint2);
932 	AUDIO_AIFF_COMM_INT2FRAMES(comm_chunk.aiff_comm_frames, tmp_uint2);
933 	tmp_ushort = hdrp->bytes_per_unit * 8;
934 	AUDIO_AIFF_HOST2FILE_SHORT(&tmp_ushort,
935 	    &comm_chunk.aiff_comm_sample_size);
936 	convert_to_ieee_extended((double)hdrp->sample_rate,
937 	    comm_chunk.aiff_comm_sample_rate);
938 	(void) memcpy(&buf[buf_size], &comm_chunk, AUDIO_AIFF_COMM_CHUNK_SIZE);
939 	buf_size += AUDIO_AIFF_COMM_CHUNK_SIZE;
940 
941 	/* build the SSND chunk */
942 	tmp_uint = AUDIO_AIFF_SSND_ID;
943 	AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &ssnd_chunk.aiff_ssnd_ID);
944 	/* needs to be fixed when closed */
945 	tmp_uint = AUDIO_AIFF_UNKNOWN_SIZE;
946 	AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &ssnd_chunk.aiff_ssnd_size);
947 	ssnd_chunk.aiff_ssnd_offset = 0;
948 	ssnd_chunk.aiff_ssnd_block_size = 0;
949 	(void) memcpy(&buf[buf_size], &ssnd_chunk, sizeof (ssnd_chunk));
950 	buf_size += sizeof (ssnd_chunk);
951 
952 	*blen = buf_size;
953 
954 	return (AUDIO_SUCCESS);
955 
956 }	/* audio_encode_aiff() */
957 
958 /*
959  * Encode a .au file header from the supplied Audio_hdr structure and
960  * store in the supplied char* buffer. blen is the size of the buffer to
961  * store the header in. If 'infop' is not NULL, it is the address of a
962  * buffer containing 'info' data. 'ilen' specifies the size of this buffer.
963  * The entire file header will be zero-padded to a double-word boundary.
964  *
965  * NOTE: .au doesn't support unsigned 8-bit linear PCM.
966  */
967 static int
audio_encode_au(Audio_hdr * hdrp,char * infop,unsigned int ilen,unsigned char * buf,unsigned int * blen)968 audio_encode_au(Audio_hdr *hdrp, char *infop, unsigned int ilen,
969 	unsigned char *buf, unsigned int *blen)
970 					/* audio header */
971 					/* info buffer pointer */
972 					/* info buffer size */
973 					/* output buffer */
974 					/* output buffer size */
975 {
976 	au_filehdr_t	fhdr;
977 	int		encoding;
978 	int		hdrsize;
979 	int		magic;
980 	int		offset;
981 
982 	/*
983 	 * Set the size of the real header (hdr size + info size).
984 	 * If no supplied info, make sure a minimum size is accounted for.
985 	 * Also, round the whole thing up to double-word alignment.
986 	 */
987 	if ((infop == NULL) || (ilen == 0)) {
988 		infop = NULL;
989 		ilen = 4;
990 	}
991 	hdrsize = sizeof (fhdr) + ilen;
992 	offset = ROUND_DBL(hdrsize);
993 
994 	/* Check the data encoding. */
995 	switch (hdrp->encoding) {
996 	case AUDIO_ENCODING_LINEAR8:
997 		return (AUDIO_ERR_ENCODING);	/* we don't support ulinear */
998 	case AUDIO_ENCODING_ULAW:
999 		if (hdrp->samples_per_unit != 1)
1000 			return (AUDIO_ERR_BADHDR);
1001 
1002 		switch (hdrp->bytes_per_unit) {
1003 		case 1:
1004 			encoding = AUDIO_AU_ENCODING_ULAW;
1005 			break;
1006 		default:
1007 			return (AUDIO_ERR_BADHDR);
1008 		}
1009 		break;
1010 	case AUDIO_ENCODING_ALAW:
1011 		if (hdrp->samples_per_unit != 1)
1012 			return (AUDIO_ERR_BADHDR);
1013 
1014 		switch (hdrp->bytes_per_unit) {
1015 		case 1:
1016 			encoding = AUDIO_AU_ENCODING_ALAW;
1017 			break;
1018 		default:
1019 			return (AUDIO_ERR_BADHDR);
1020 		}
1021 		break;
1022 	case AUDIO_ENCODING_LINEAR:
1023 		if (hdrp->samples_per_unit != 1)
1024 			return (AUDIO_ERR_BADHDR);
1025 
1026 		switch (hdrp->bytes_per_unit) {
1027 		case 1:
1028 			encoding = AUDIO_AU_ENCODING_LINEAR_8;
1029 			break;
1030 		case 2:
1031 			encoding = AUDIO_AU_ENCODING_LINEAR_16;
1032 			break;
1033 		case 3:
1034 			encoding = AUDIO_AU_ENCODING_LINEAR_24;
1035 			break;
1036 		case 4:
1037 			encoding = AUDIO_AU_ENCODING_LINEAR_32;
1038 			break;
1039 		default:
1040 			return (AUDIO_ERR_BADHDR);
1041 		}
1042 		break;
1043 	case AUDIO_ENCODING_FLOAT:
1044 		if (hdrp->samples_per_unit != 1)
1045 			return (AUDIO_ERR_BADHDR);
1046 
1047 		switch (hdrp->bytes_per_unit) {
1048 		case 4:
1049 			encoding = AUDIO_AU_ENCODING_FLOAT;
1050 			break;
1051 		case 8:
1052 			encoding = AUDIO_AU_ENCODING_DOUBLE;
1053 			break;
1054 		default:
1055 			return (AUDIO_ERR_BADHDR);
1056 		}
1057 		break;
1058 	case AUDIO_ENCODING_G721:
1059 		if (hdrp->bytes_per_unit != 1)
1060 			return (AUDIO_ERR_BADHDR);
1061 		else if (hdrp->samples_per_unit != 2)
1062 			return (AUDIO_ERR_BADHDR);
1063 		else
1064 			encoding = AUDIO_AU_ENCODING_ADPCM_G721;
1065 		break;
1066 	case AUDIO_ENCODING_G723:
1067 		if (hdrp->samples_per_unit != 8)
1068 			return (AUDIO_ERR_BADHDR);
1069 		else if (hdrp->bytes_per_unit == 3)
1070 			encoding = AUDIO_AU_ENCODING_ADPCM_G723_3;
1071 		else if (hdrp->bytes_per_unit == 5)
1072 			encoding = AUDIO_AU_ENCODING_ADPCM_G723_5;
1073 		else
1074 			return (AUDIO_ERR_BADHDR);
1075 		break;
1076 	default:
1077 		return (AUDIO_ERR_BADHDR);
1078 	}
1079 
1080 	/* copy the fhdr into the supplied buffer - make sure it'll fit */
1081 	if (*blen < offset) {
1082 		/* XXX - is this apropriate? */
1083 		return (AUDIO_EOF);
1084 	}
1085 
1086 	/* reset blen to actual size of hdr data */
1087 	*blen = (unsigned)offset;
1088 
1089 	magic = AUDIO_AU_FILE_MAGIC;	/* set the magic number */
1090 
1091 	/* Encode the audio header structure. */
1092 	AUDIO_AU_HOST2FILE(&magic, &fhdr.au_magic);
1093 	AUDIO_AU_HOST2FILE(&offset, &fhdr.au_offset);
1094 	AUDIO_AU_HOST2FILE(&hdrp->data_size, &fhdr.au_data_size);
1095 	AUDIO_AU_HOST2FILE(&encoding, &fhdr.au_encoding);
1096 	AUDIO_AU_HOST2FILE(&hdrp->sample_rate, &fhdr.au_sample_rate);
1097 	AUDIO_AU_HOST2FILE(&hdrp->channels, &fhdr.au_channels);
1098 
1099 	/* Copy to the buffer */
1100 	(void) memcpy(buf, &fhdr, sizeof (fhdr));
1101 
1102 	/* Copy the info data, if present */
1103 	if (infop != NULL) {
1104 		(void) memcpy(&buf[sizeof (fhdr)], infop, (int)ilen);
1105 		buf += ilen;
1106 	}
1107 
1108 	if (offset > hdrsize) {
1109 		(void) memset(&buf[hdrsize], '\0', (size_t)(offset - hdrsize));
1110 	}
1111 
1112 	/* buf now has the data, just return ... */
1113 
1114 	return (AUDIO_SUCCESS);
1115 
1116 }	/* audio_encode_au() */
1117 
1118 /*
1119  * Encode a .wav file header from the supplied Audio_hdr structure and
1120  * store in the supplied char* buffer. blen is the size of the buffer to
1121  * store the header in. .wav doesn't support an information string like
1122  * .au does.
1123  *
1124  * NOTE: .wav only supports a few encoding methods.
1125  */
1126 static int
audio_encode_wav(Audio_hdr * hdrp,unsigned char * buf,unsigned int * blen)1127 audio_encode_wav(Audio_hdr *hdrp, unsigned char *buf, unsigned int *blen)
1128 					/* audio header */
1129 					/* output buffer */
1130 					/* output buffer size */
1131 {
1132 	wav_filehdr_t	fhdr;
1133 	int		bytes_per_second;
1134 	int		bytes_per_sample;
1135 	int		bits_per_sample;
1136 	int		id;
1137 	int		length;
1138 	int		type;
1139 	short		encoding;
1140 
1141 	/* make sure we've got valid encoding and precision settings for .wav */
1142 	switch (hdrp->encoding) {
1143 	case AUDIO_ENCODING_LINEAR8:
1144 		if (hdrp->bytes_per_unit != 1) {
1145 			return (AUDIO_ERR_ENCODING);
1146 		}
1147 		encoding = AUDIO_WAV_FMT_ENCODING_PCM;
1148 		break;
1149 	case AUDIO_ENCODING_ULAW:
1150 		if (hdrp->bytes_per_unit != 1) {
1151 			return (AUDIO_ERR_ENCODING);
1152 		}
1153 		encoding = AUDIO_WAV_FMT_ENCODING_MULAW;
1154 		break;
1155 	case AUDIO_ENCODING_ALAW:
1156 		if (hdrp->bytes_per_unit != 1) {
1157 			return (AUDIO_ERR_ENCODING);
1158 		}
1159 		encoding = AUDIO_WAV_FMT_ENCODING_ALAW;
1160 		break;
1161 	case AUDIO_ENCODING_LINEAR:
1162 		if (hdrp->bytes_per_unit != 2) {
1163 			return (AUDIO_ERR_ENCODING);
1164 		}
1165 		encoding = AUDIO_WAV_FMT_ENCODING_PCM;
1166 		break;
1167 	default:
1168 		return (AUDIO_ERR_ENCODING);
1169 	}
1170 
1171 	/* fill in the riff chunk */
1172 	id = AUDIO_WAV_RIFF_ID;
1173 	length = AUDIO_WAV_UNKNOWN_SIZE;
1174 	AUDIO_WAV_HOST2FILE_INT(&id, &fhdr.wav_riff_ID);
1175 	AUDIO_WAV_HOST2FILE_INT(&length, &fhdr.wav_riff_size);
1176 
1177 	/* fill in the type chunk */
1178 	type = AUDIO_WAV_TYPE_ID;
1179 	AUDIO_WAV_HOST2FILE_INT(&type, &fhdr.wav_type_ID);
1180 
1181 
1182 	/* fill in the format chunk */
1183 	id = AUDIO_WAV_FORMAT_ID;
1184 	length = AUDIO_WAV_FORMAT_SIZE;
1185 	bytes_per_second = hdrp->sample_rate * hdrp->channels *
1186 	    hdrp->bytes_per_unit;
1187 	bytes_per_sample = hdrp->channels * hdrp->bytes_per_unit;
1188 	bits_per_sample = hdrp->bytes_per_unit * 8;
1189 
1190 	AUDIO_WAV_HOST2FILE_INT(&id, &fhdr.wav_fmt_ID);
1191 	AUDIO_WAV_HOST2FILE_INT(&length, &fhdr.wav_fmt_size);
1192 	AUDIO_WAV_HOST2FILE_SHORT(&encoding, &fhdr.wav_fmt_encoding);
1193 	AUDIO_WAV_HOST2FILE_SHORT(&hdrp->channels, &fhdr.wav_fmt_channels);
1194 	AUDIO_WAV_HOST2FILE_INT(&hdrp->sample_rate, &fhdr.wav_fmt_sample_rate);
1195 	AUDIO_WAV_HOST2FILE_INT(&bytes_per_second,
1196 	    &fhdr.wav_fmt_bytes_per_second);
1197 	AUDIO_WAV_HOST2FILE_SHORT(&bytes_per_sample,
1198 	    &fhdr.wav_fmt_bytes_per_sample);
1199 	AUDIO_WAV_HOST2FILE_SHORT(&bits_per_sample,
1200 	    &fhdr.wav_fmt_bits_per_sample);
1201 
1202 	/* fill in the data chunk */
1203 	id = AUDIO_WAV_DATA_ID_LC;
1204 	length = AUDIO_WAV_UNKNOWN_SIZE;
1205 	AUDIO_WAV_HOST2FILE_INT(&id, &fhdr.wav_data_ID);
1206 	AUDIO_WAV_HOST2FILE_INT(&length, &fhdr.wav_data_size);
1207 
1208 	*blen = sizeof (fhdr);
1209 
1210 	/* copy to the buffer */
1211 	(void) memcpy(buf, &fhdr, sizeof (fhdr));
1212 
1213 	return (AUDIO_SUCCESS);
1214 
1215 }	/* audio_encode_wav() */
1216 
1217 /*
1218  * Utility routine used to convert 10 byte IEEE extended float into
1219  * a regular double. Raw data arrives in an unsigned char array. Because
1220  * this is for sample rate, which is always positive, we don't worry
1221  * about the sign.
1222  */
1223 static double
convert_from_ieee_extended(unsigned char * data)1224 convert_from_ieee_extended(unsigned char *data)
1225 {
1226 	double		value = 0.0;
1227 	unsigned long	high_mantissa;
1228 	unsigned long	low_mantissa;
1229 	int		exponent;
1230 
1231 	/* first 2 bytes are the exponent */
1232 	exponent = ((data[0] & 0x7f) << 8) | data[1];
1233 
1234 	high_mantissa = ((unsigned long)data[2] << 24) |
1235 	    ((unsigned long)data[3] << 16) |
1236 	    ((unsigned long)data[4] << 8) |
1237 	    (unsigned long)data[5];
1238 	low_mantissa = ((unsigned long)data[6] << 24) |
1239 	    ((unsigned long)data[7] << 16) |
1240 	    ((unsigned long)data[8] << 8) |
1241 	    (unsigned long)data[9];
1242 
1243 	/* convert exponent and mantissas into a real double */
1244 	if (exponent == 0 && high_mantissa == 0 && low_mantissa == 0) {
1245 		/* everything is 0, so we're done */
1246 		value = 0.0;
1247 	} else {
1248 		if (exponent == 0x7fff) {	/* infinity */
1249 			value = MAXFLOAT;
1250 		} else {
1251 			/* convert exponent from being unsigned to signed */
1252 			exponent -= 0x3fff;
1253 
1254 			exponent -= 31;
1255 			value = ldexp((double)high_mantissa, exponent);
1256 
1257 			exponent -= 32;
1258 			value += ldexp((double)low_mantissa, exponent);
1259 		}
1260 	}
1261 
1262 	return (value);
1263 
1264 }
1265 
1266 /*
1267  * Utility routine to convert a double into 10 byte IEEE extended floating
1268  * point. The new number is placed into the unsigned char array. This is a
1269  * very brain dead convesion routine. It only supports integers, but then
1270  * that should be all we need for sample rate.
1271  */
1272 static void
convert_to_ieee_extended(double value,unsigned char * data)1273 convert_to_ieee_extended(double value, unsigned char *data)
1274 {
1275 	double		fmantissa;
1276 	int		exponent;
1277 	int		mantissa;
1278 
1279 	exponent = 16398;
1280 	fmantissa = value;
1281 
1282 	while (fmantissa < 44000) {
1283 		fmantissa *= 2;
1284 		exponent--;
1285 	}
1286 
1287 	mantissa = (int)fmantissa << 16;
1288 
1289 	data[0] = exponent >> 8;
1290 	data[1] = exponent;
1291 	data[2] = mantissa >> 24;
1292 	data[3] = mantissa >> 16;
1293 	data[4] = mantissa >> 8;
1294 	data[5] = mantissa;
1295 	data[6] = 0;
1296 	data[7] = 0;
1297 	data[8] = 0;
1298 	data[9] = 0;
1299 
1300 }
1301