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 	int			encoding;
905 	uint16_t		tmp_ushort;
906 
907 	/* the only encoding we support for .aiff is signed linear PCM */
908 	if (hdrp->encoding != AUDIO_ENCODING_LINEAR) {
909 		return (AUDIO_ERR_ENCODING);
910 	}
911 
912 	/* build the header chunk */
913 	tmp_uint = AUDIO_AIFF_HDR_CHUNK_ID;
914 	AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &hdr_chunk.aiff_hdr_ID);
915 	/* needs to be fixed when closed */
916 	tmp_uint = AUDIO_AIFF_UNKNOWN_SIZE;
917 	AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &hdr_chunk.aiff_hdr_size);
918 	tmp_uint = AUDIO_AIFF_HDR_FORM_AIFF;
919 	AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &hdr_chunk.aiff_hdr_data_type);
920 	(void) memcpy(&buf[buf_size], &hdr_chunk, sizeof (hdr_chunk));
921 	buf_size += sizeof (hdr_chunk);
922 
923 	/* build the COMM chunk */
924 	tmp_uint = AUDIO_AIFF_COMM_ID;
925 	AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &comm_chunk.aiff_comm_ID);
926 	tmp_uint = AUDIO_AIFF_COMM_SIZE;
927 	AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &comm_chunk.aiff_comm_size);
928 	tmp_ushort = hdrp->channels;
929 	AUDIO_AIFF_HOST2FILE_SHORT(&tmp_ushort, &comm_chunk.aiff_comm_channels);
930 	/* needs to be fixed when closed */
931 	tmp_uint = AUDIO_AIFF_UNKNOWN_SIZE;
932 	AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &tmp_uint2);
933 	AUDIO_AIFF_COMM_INT2FRAMES(comm_chunk.aiff_comm_frames, tmp_uint2);
934 	tmp_ushort = hdrp->bytes_per_unit * 8;
935 	AUDIO_AIFF_HOST2FILE_SHORT(&tmp_ushort,
936 	    &comm_chunk.aiff_comm_sample_size);
937 	convert_to_ieee_extended((double)hdrp->sample_rate,
938 	    comm_chunk.aiff_comm_sample_rate);
939 	(void) memcpy(&buf[buf_size], &comm_chunk, AUDIO_AIFF_COMM_CHUNK_SIZE);
940 	buf_size += AUDIO_AIFF_COMM_CHUNK_SIZE;
941 
942 	/* build the SSND chunk */
943 	tmp_uint = AUDIO_AIFF_SSND_ID;
944 	AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &ssnd_chunk.aiff_ssnd_ID);
945 	/* needs to be fixed when closed */
946 	tmp_uint = AUDIO_AIFF_UNKNOWN_SIZE;
947 	AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &ssnd_chunk.aiff_ssnd_size);
948 	ssnd_chunk.aiff_ssnd_offset = 0;
949 	ssnd_chunk.aiff_ssnd_block_size = 0;
950 	(void) memcpy(&buf[buf_size], &ssnd_chunk, sizeof (ssnd_chunk));
951 	buf_size += sizeof (ssnd_chunk);
952 
953 	*blen = buf_size;
954 
955 	return (AUDIO_SUCCESS);
956 
957 }	/* audio_encode_aiff() */
958 
959 /*
960  * Encode a .au file header from the supplied Audio_hdr structure and
961  * store in the supplied char* buffer. blen is the size of the buffer to
962  * store the header in. If 'infop' is not NULL, it is the address of a
963  * buffer containing 'info' data. 'ilen' specifies the size of this buffer.
964  * The entire file header will be zero-padded to a double-word boundary.
965  *
966  * NOTE: .au doesn't support unsigned 8-bit linear PCM.
967  */
968 static int
audio_encode_au(Audio_hdr * hdrp,char * infop,unsigned int ilen,unsigned char * buf,unsigned int * blen)969 audio_encode_au(Audio_hdr *hdrp, char *infop, unsigned int ilen,
970 	unsigned char *buf, unsigned int *blen)
971 					/* audio header */
972 					/* info buffer pointer */
973 					/* info buffer size */
974 					/* output buffer */
975 					/* output buffer size */
976 {
977 	au_filehdr_t	fhdr;
978 	int		encoding;
979 	int		hdrsize;
980 	int		magic;
981 	int		offset;
982 
983 	/*
984 	 * Set the size of the real header (hdr size + info size).
985 	 * If no supplied info, make sure a minimum size is accounted for.
986 	 * Also, round the whole thing up to double-word alignment.
987 	 */
988 	if ((infop == NULL) || (ilen == 0)) {
989 		infop = NULL;
990 		ilen = 4;
991 	}
992 	hdrsize = sizeof (fhdr) + ilen;
993 	offset = ROUND_DBL(hdrsize);
994 
995 	/* Check the data encoding. */
996 	switch (hdrp->encoding) {
997 	case AUDIO_ENCODING_LINEAR8:
998 		return (AUDIO_ERR_ENCODING);	/* we don't support ulinear */
999 	case AUDIO_ENCODING_ULAW:
1000 		if (hdrp->samples_per_unit != 1)
1001 			return (AUDIO_ERR_BADHDR);
1002 
1003 		switch (hdrp->bytes_per_unit) {
1004 		case 1:
1005 			encoding = AUDIO_AU_ENCODING_ULAW;
1006 			break;
1007 		default:
1008 			return (AUDIO_ERR_BADHDR);
1009 		}
1010 		break;
1011 	case AUDIO_ENCODING_ALAW:
1012 		if (hdrp->samples_per_unit != 1)
1013 			return (AUDIO_ERR_BADHDR);
1014 
1015 		switch (hdrp->bytes_per_unit) {
1016 		case 1:
1017 			encoding = AUDIO_AU_ENCODING_ALAW;
1018 			break;
1019 		default:
1020 			return (AUDIO_ERR_BADHDR);
1021 		}
1022 		break;
1023 	case AUDIO_ENCODING_LINEAR:
1024 		if (hdrp->samples_per_unit != 1)
1025 			return (AUDIO_ERR_BADHDR);
1026 
1027 		switch (hdrp->bytes_per_unit) {
1028 		case 1:
1029 			encoding = AUDIO_AU_ENCODING_LINEAR_8;
1030 			break;
1031 		case 2:
1032 			encoding = AUDIO_AU_ENCODING_LINEAR_16;
1033 			break;
1034 		case 3:
1035 			encoding = AUDIO_AU_ENCODING_LINEAR_24;
1036 			break;
1037 		case 4:
1038 			encoding = AUDIO_AU_ENCODING_LINEAR_32;
1039 			break;
1040 		default:
1041 			return (AUDIO_ERR_BADHDR);
1042 		}
1043 		break;
1044 	case AUDIO_ENCODING_FLOAT:
1045 		if (hdrp->samples_per_unit != 1)
1046 			return (AUDIO_ERR_BADHDR);
1047 
1048 		switch (hdrp->bytes_per_unit) {
1049 		case 4:
1050 			encoding = AUDIO_AU_ENCODING_FLOAT;
1051 			break;
1052 		case 8:
1053 			encoding = AUDIO_AU_ENCODING_DOUBLE;
1054 			break;
1055 		default:
1056 			return (AUDIO_ERR_BADHDR);
1057 		}
1058 		break;
1059 	case AUDIO_ENCODING_G721:
1060 		if (hdrp->bytes_per_unit != 1)
1061 			return (AUDIO_ERR_BADHDR);
1062 		else if (hdrp->samples_per_unit != 2)
1063 			return (AUDIO_ERR_BADHDR);
1064 		else
1065 			encoding = AUDIO_AU_ENCODING_ADPCM_G721;
1066 		break;
1067 	case AUDIO_ENCODING_G723:
1068 		if (hdrp->samples_per_unit != 8)
1069 			return (AUDIO_ERR_BADHDR);
1070 		else if (hdrp->bytes_per_unit == 3)
1071 			encoding = AUDIO_AU_ENCODING_ADPCM_G723_3;
1072 		else if (hdrp->bytes_per_unit == 5)
1073 			encoding = AUDIO_AU_ENCODING_ADPCM_G723_5;
1074 		else
1075 			return (AUDIO_ERR_BADHDR);
1076 		break;
1077 	default:
1078 		return (AUDIO_ERR_BADHDR);
1079 	}
1080 
1081 	/* copy the fhdr into the supplied buffer - make sure it'll fit */
1082 	if (*blen < offset) {
1083 		/* XXX - is this apropriate? */
1084 		return (AUDIO_EOF);
1085 	}
1086 
1087 	/* reset blen to actual size of hdr data */
1088 	*blen = (unsigned)offset;
1089 
1090 	magic = AUDIO_AU_FILE_MAGIC;	/* set the magic number */
1091 
1092 	/* Encode the audio header structure. */
1093 	AUDIO_AU_HOST2FILE(&magic, &fhdr.au_magic);
1094 	AUDIO_AU_HOST2FILE(&offset, &fhdr.au_offset);
1095 	AUDIO_AU_HOST2FILE(&hdrp->data_size, &fhdr.au_data_size);
1096 	AUDIO_AU_HOST2FILE(&encoding, &fhdr.au_encoding);
1097 	AUDIO_AU_HOST2FILE(&hdrp->sample_rate, &fhdr.au_sample_rate);
1098 	AUDIO_AU_HOST2FILE(&hdrp->channels, &fhdr.au_channels);
1099 
1100 	/* Copy to the buffer */
1101 	(void) memcpy(buf, &fhdr, sizeof (fhdr));
1102 
1103 	/* Copy the info data, if present */
1104 	if (infop != NULL) {
1105 		(void) memcpy(&buf[sizeof (fhdr)], infop, (int)ilen);
1106 		buf += ilen;
1107 	}
1108 
1109 	if (offset > hdrsize) {
1110 		(void) memset(&buf[hdrsize], '\0', (size_t)(offset - hdrsize));
1111 	}
1112 
1113 	/* buf now has the data, just return ... */
1114 
1115 	return (AUDIO_SUCCESS);
1116 
1117 }	/* audio_encode_au() */
1118 
1119 /*
1120  * Encode a .wav file header from the supplied Audio_hdr structure and
1121  * store in the supplied char* buffer. blen is the size of the buffer to
1122  * store the header in. .wav doesn't support an information string like
1123  * .au does.
1124  *
1125  * NOTE: .wav only supports a few encoding methods.
1126  */
1127 static int
audio_encode_wav(Audio_hdr * hdrp,unsigned char * buf,unsigned int * blen)1128 audio_encode_wav(Audio_hdr *hdrp, unsigned char *buf, unsigned int *blen)
1129 					/* audio header */
1130 					/* output buffer */
1131 					/* output buffer size */
1132 {
1133 	wav_filehdr_t	fhdr;
1134 	int		bytes_per_second;
1135 	int		bytes_per_sample;
1136 	int		bits_per_sample;
1137 	int		id;
1138 	int		length;
1139 	int		type;
1140 	short		encoding;
1141 
1142 	/* make sure we've got valid encoding and precision settings for .wav */
1143 	switch (hdrp->encoding) {
1144 	case AUDIO_ENCODING_LINEAR8:
1145 		if (hdrp->bytes_per_unit != 1) {
1146 			return (AUDIO_ERR_ENCODING);
1147 		}
1148 		encoding = AUDIO_WAV_FMT_ENCODING_PCM;
1149 		break;
1150 	case AUDIO_ENCODING_ULAW:
1151 		if (hdrp->bytes_per_unit != 1) {
1152 			return (AUDIO_ERR_ENCODING);
1153 		}
1154 		encoding = AUDIO_WAV_FMT_ENCODING_MULAW;
1155 		break;
1156 	case AUDIO_ENCODING_ALAW:
1157 		if (hdrp->bytes_per_unit != 1) {
1158 			return (AUDIO_ERR_ENCODING);
1159 		}
1160 		encoding = AUDIO_WAV_FMT_ENCODING_ALAW;
1161 		break;
1162 	case AUDIO_ENCODING_LINEAR:
1163 		if (hdrp->bytes_per_unit != 2) {
1164 			return (AUDIO_ERR_ENCODING);
1165 		}
1166 		encoding = AUDIO_WAV_FMT_ENCODING_PCM;
1167 		break;
1168 	default:
1169 		return (AUDIO_ERR_ENCODING);
1170 	}
1171 
1172 	/* fill in the riff chunk */
1173 	id = AUDIO_WAV_RIFF_ID;
1174 	length = AUDIO_WAV_UNKNOWN_SIZE;
1175 	AUDIO_WAV_HOST2FILE_INT(&id, &fhdr.wav_riff_ID);
1176 	AUDIO_WAV_HOST2FILE_INT(&length, &fhdr.wav_riff_size);
1177 
1178 	/* fill in the type chunk */
1179 	type = AUDIO_WAV_TYPE_ID;
1180 	AUDIO_WAV_HOST2FILE_INT(&type, &fhdr.wav_type_ID);
1181 
1182 
1183 	/* fill in the format chunk */
1184 	id = AUDIO_WAV_FORMAT_ID;
1185 	length = AUDIO_WAV_FORMAT_SIZE;
1186 	bytes_per_second = hdrp->sample_rate * hdrp->channels *
1187 	    hdrp->bytes_per_unit;
1188 	bytes_per_sample = hdrp->channels * hdrp->bytes_per_unit;
1189 	bits_per_sample = hdrp->bytes_per_unit * 8;
1190 
1191 	AUDIO_WAV_HOST2FILE_INT(&id, &fhdr.wav_fmt_ID);
1192 	AUDIO_WAV_HOST2FILE_INT(&length, &fhdr.wav_fmt_size);
1193 	AUDIO_WAV_HOST2FILE_SHORT(&encoding, &fhdr.wav_fmt_encoding);
1194 	AUDIO_WAV_HOST2FILE_SHORT(&hdrp->channels, &fhdr.wav_fmt_channels);
1195 	AUDIO_WAV_HOST2FILE_INT(&hdrp->sample_rate, &fhdr.wav_fmt_sample_rate);
1196 	AUDIO_WAV_HOST2FILE_INT(&bytes_per_second,
1197 	    &fhdr.wav_fmt_bytes_per_second);
1198 	AUDIO_WAV_HOST2FILE_SHORT(&bytes_per_sample,
1199 	    &fhdr.wav_fmt_bytes_per_sample);
1200 	AUDIO_WAV_HOST2FILE_SHORT(&bits_per_sample,
1201 	    &fhdr.wav_fmt_bits_per_sample);
1202 
1203 	/* fill in the data chunk */
1204 	id = AUDIO_WAV_DATA_ID_LC;
1205 	length = AUDIO_WAV_UNKNOWN_SIZE;
1206 	AUDIO_WAV_HOST2FILE_INT(&id, &fhdr.wav_data_ID);
1207 	AUDIO_WAV_HOST2FILE_INT(&length, &fhdr.wav_data_size);
1208 
1209 	*blen = sizeof (fhdr);
1210 
1211 	/* copy to the buffer */
1212 	(void) memcpy(buf, &fhdr, sizeof (fhdr));
1213 
1214 	return (AUDIO_SUCCESS);
1215 
1216 }	/* audio_encode_wav() */
1217 
1218 /*
1219  * Utility routine used to convert 10 byte IEEE extended float into
1220  * a regular double. Raw data arrives in an unsigned char array. Because
1221  * this is for sample rate, which is always positive, we don't worry
1222  * about the sign.
1223  */
1224 static double
convert_from_ieee_extended(unsigned char * data)1225 convert_from_ieee_extended(unsigned char *data)
1226 {
1227 	double		value = 0.0;
1228 	unsigned long	high_mantissa;
1229 	unsigned long	low_mantissa;
1230 	int		exponent;
1231 
1232 	/* first 2 bytes are the exponent */
1233 	exponent = ((data[0] & 0x7f) << 8) | data[1];
1234 
1235 	high_mantissa = ((unsigned long)data[2] << 24) |
1236 	    ((unsigned long)data[3] << 16) |
1237 	    ((unsigned long)data[4] << 8) |
1238 	    (unsigned long)data[5];
1239 	low_mantissa = ((unsigned long)data[6] << 24) |
1240 	    ((unsigned long)data[7] << 16) |
1241 	    ((unsigned long)data[8] << 8) |
1242 	    (unsigned long)data[9];
1243 
1244 	/* convert exponent and mantissas into a real double */
1245 	if (exponent == 0 && high_mantissa == 0 && low_mantissa == 0) {
1246 		/* everything is 0, so we're done */
1247 		value = 0.0;
1248 	} else {
1249 		if (exponent == 0x7fff) {	/* infinity */
1250 			value = MAXFLOAT;
1251 		} else {
1252 			/* convert exponent from being unsigned to signed */
1253 			exponent -= 0x3fff;
1254 
1255 			exponent -= 31;
1256 			value = ldexp((double)high_mantissa, exponent);
1257 
1258 			exponent -= 32;
1259 			value += ldexp((double)low_mantissa, exponent);
1260 		}
1261 	}
1262 
1263 	return (value);
1264 
1265 }
1266 
1267 /*
1268  * Utility routine to convert a double into 10 byte IEEE extended floating
1269  * point. The new number is placed into the unsigned char array. This is a
1270  * very brain dead convesion routine. It only supports integers, but then
1271  * that should be all we need for sample rate.
1272  */
1273 static void
convert_to_ieee_extended(double value,unsigned char * data)1274 convert_to_ieee_extended(double value, unsigned char *data)
1275 {
1276 	double		fmantissa;
1277 	int		exponent;
1278 	int		mantissa;
1279 
1280 	exponent = 16398;
1281 	fmantissa = value;
1282 
1283 	while (fmantissa < 44000) {
1284 		fmantissa *= 2;
1285 		exponent--;
1286 	}
1287 
1288 	mantissa = (int)fmantissa << 16;
1289 
1290 	data[0] = exponent >> 8;
1291 	data[1] = exponent;
1292 	data[2] = mantissa >> 24;
1293 	data[3] = mantissa >> 16;
1294 	data[4] = mantissa >> 8;
1295 	data[5] = mantissa;
1296 	data[6] = 0;
1297 	data[7] = 0;
1298 	data[8] = 0;
1299 	data[9] = 0;
1300 
1301 }
1302