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