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