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 1993-2003 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 #include <string.h> 30*7c478bd9Sstevel@tonic-gate #include <stdio.h> 31*7c478bd9Sstevel@tonic-gate #include <errno.h> 32*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 33*7c478bd9Sstevel@tonic-gate #include <stdio.h> 34*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 35*7c478bd9Sstevel@tonic-gate #include <memory.h> 36*7c478bd9Sstevel@tonic-gate #include <unistd.h> 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/file.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate #include <AudioDebug.h> 44*7c478bd9Sstevel@tonic-gate #include <AudioUnixfile.h> 45*7c478bd9Sstevel@tonic-gate #include <libaudio.h> 46*7c478bd9Sstevel@tonic-gate #include <audio_hdr.h> 47*7c478bd9Sstevel@tonic-gate #include <audio/au.h> 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate // class AudioUnixfile methods 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate // Constructor with pathname and mode arg 52*7c478bd9Sstevel@tonic-gate AudioUnixfile:: 53*7c478bd9Sstevel@tonic-gate AudioUnixfile( 54*7c478bd9Sstevel@tonic-gate const char *path, // pathname 55*7c478bd9Sstevel@tonic-gate const FileAccess acc): // access mode 56*7c478bd9Sstevel@tonic-gate AudioStream(path), fd(-1), block(TRUE), mode(acc), 57*7c478bd9Sstevel@tonic-gate infostring(new char[1]), infolength(1) 58*7c478bd9Sstevel@tonic-gate { 59*7c478bd9Sstevel@tonic-gate infostring[0] = '\0'; 60*7c478bd9Sstevel@tonic-gate } 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate // Destructor 63*7c478bd9Sstevel@tonic-gate AudioUnixfile:: 64*7c478bd9Sstevel@tonic-gate ~AudioUnixfile() 65*7c478bd9Sstevel@tonic-gate { 66*7c478bd9Sstevel@tonic-gate // If the file is open, close it 67*7c478bd9Sstevel@tonic-gate if (opened()) 68*7c478bd9Sstevel@tonic-gate (void) Close(); 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate // Deallocate the dynamic storage 71*7c478bd9Sstevel@tonic-gate delete infostring; 72*7c478bd9Sstevel@tonic-gate } 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate // Generic open with search path routine just calls default Open() 75*7c478bd9Sstevel@tonic-gate AudioError AudioUnixfile:: 76*7c478bd9Sstevel@tonic-gate OpenPath( 77*7c478bd9Sstevel@tonic-gate const char *) 78*7c478bd9Sstevel@tonic-gate { 79*7c478bd9Sstevel@tonic-gate return (Open()); 80*7c478bd9Sstevel@tonic-gate } 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate // Decode an audio file header 83*7c478bd9Sstevel@tonic-gate // This routine reads the audio file header and decodes it. 84*7c478bd9Sstevel@tonic-gate // 85*7c478bd9Sstevel@tonic-gate // This method should be specialized by subclasses that are not files, 86*7c478bd9Sstevel@tonic-gate // like devices for instance. 87*7c478bd9Sstevel@tonic-gate // 88*7c478bd9Sstevel@tonic-gate // XXX - this routine should be rewritten for C++ 89*7c478bd9Sstevel@tonic-gate AudioError AudioUnixfile:: 90*7c478bd9Sstevel@tonic-gate decode_filehdr() 91*7c478bd9Sstevel@tonic-gate { 92*7c478bd9Sstevel@tonic-gate Boolean saveblock; // saved state of the blocking i/o flag 93*7c478bd9Sstevel@tonic-gate AudioHdr hdr_local; // local copy of header 94*7c478bd9Sstevel@tonic-gate Audio_hdr ohdr; // XXX - old libaudio hdr 95*7c478bd9Sstevel@tonic-gate au_filehdr_t fhdr; 96*7c478bd9Sstevel@tonic-gate char *ibuf; 97*7c478bd9Sstevel@tonic-gate int file_type; 98*7c478bd9Sstevel@tonic-gate int infosize; 99*7c478bd9Sstevel@tonic-gate int cnt; 100*7c478bd9Sstevel@tonic-gate struct stat st; 101*7c478bd9Sstevel@tonic-gate AudioError err; 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate // If fd is not open, or file header already decoded, skip it 104*7c478bd9Sstevel@tonic-gate if (!isfdset() || opened()) 105*7c478bd9Sstevel@tonic-gate return (RaiseError(AUDIO_ERR_NOEFFECT, Warning)); 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate // Stat the file, to see if it is a regular file 108*7c478bd9Sstevel@tonic-gate if (fstat(getfd(), &st) < 0) 109*7c478bd9Sstevel@tonic-gate return (RaiseError(AUDIO_UNIXERROR)); 110*7c478bd9Sstevel@tonic-gate 111*7c478bd9Sstevel@tonic-gate // Make sure the file is not set for blocking i/o 112*7c478bd9Sstevel@tonic-gate saveblock = GetBlocking(); 113*7c478bd9Sstevel@tonic-gate if (!saveblock) 114*7c478bd9Sstevel@tonic-gate SetBlocking(TRUE); 115*7c478bd9Sstevel@tonic-gate 116*7c478bd9Sstevel@tonic-gate // Read the file header, but not the info field 117*7c478bd9Sstevel@tonic-gate // XXX - Should use C++ input method 118*7c478bd9Sstevel@tonic-gate cnt = read(getfd(), (char *)&fhdr, sizeof (fhdr)); 119*7c478bd9Sstevel@tonic-gate if (cnt != sizeof (fhdr)) { 120*7c478bd9Sstevel@tonic-gate return (RaiseError(AUDIO_UNIXERROR)); 121*7c478bd9Sstevel@tonic-gate } 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate // Check the validity of the header and get the size of the info field 124*7c478bd9Sstevel@tonic-gate err = (AudioError) audio_decode_filehdr(getfd(), (unsigned char *)&fhdr, 125*7c478bd9Sstevel@tonic-gate &file_type, &ohdr, &infosize); 126*7c478bd9Sstevel@tonic-gate if (err != AUDIO_SUCCESS) 127*7c478bd9Sstevel@tonic-gate return (RaiseError(err)); 128*7c478bd9Sstevel@tonic-gate 129*7c478bd9Sstevel@tonic-gate // Allocate and read in the info field 130*7c478bd9Sstevel@tonic-gate ibuf = new char[infosize]; 131*7c478bd9Sstevel@tonic-gate cnt = read(getfd(), ibuf, infosize); 132*7c478bd9Sstevel@tonic-gate if (cnt != infosize) { 133*7c478bd9Sstevel@tonic-gate delete ibuf; 134*7c478bd9Sstevel@tonic-gate return (RaiseError(AUDIO_UNIXERROR)); 135*7c478bd9Sstevel@tonic-gate } 136*7c478bd9Sstevel@tonic-gate SetBlocking(saveblock); // Restore the saved blocking i/o state 137*7c478bd9Sstevel@tonic-gate 138*7c478bd9Sstevel@tonic-gate // XXX - convert from libaudio header 139*7c478bd9Sstevel@tonic-gate hdr_local = GetHeader(); 140*7c478bd9Sstevel@tonic-gate hdr_local.sample_rate = ohdr.sample_rate; 141*7c478bd9Sstevel@tonic-gate hdr_local.samples_per_unit = ohdr.samples_per_unit; 142*7c478bd9Sstevel@tonic-gate hdr_local.bytes_per_unit = ohdr.bytes_per_unit; 143*7c478bd9Sstevel@tonic-gate hdr_local.channels = ohdr.channels; 144*7c478bd9Sstevel@tonic-gate hdr_local.encoding = (AudioEncoding) ohdr.encoding; 145*7c478bd9Sstevel@tonic-gate hdr_local.endian = BIG_ENDIAN; // Files are always written in 146*7c478bd9Sstevel@tonic-gate // big endian. 147*7c478bd9Sstevel@tonic-gate 148*7c478bd9Sstevel@tonic-gate err = SetHeader(hdr_local); 149*7c478bd9Sstevel@tonic-gate if (err != AUDIO_SUCCESS) { 150*7c478bd9Sstevel@tonic-gate delete ibuf; 151*7c478bd9Sstevel@tonic-gate return (RaiseError(err)); 152*7c478bd9Sstevel@tonic-gate } 153*7c478bd9Sstevel@tonic-gate SetInfostring(ibuf, infosize); 154*7c478bd9Sstevel@tonic-gate delete ibuf; 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate // Only trust the file size for regular files 157*7c478bd9Sstevel@tonic-gate if (S_ISREG(st.st_mode)) { 158*7c478bd9Sstevel@tonic-gate setlength(GetHeader().Bytes_to_Time( 159*7c478bd9Sstevel@tonic-gate st.st_size - infosize - sizeof (au_filehdr_t))); 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate // Sanity check 162*7c478bd9Sstevel@tonic-gate if ((ohdr.data_size != AUDIO_UNKNOWN_SIZE) && 163*7c478bd9Sstevel@tonic-gate (GetLength() != GetHeader().Bytes_to_Time(ohdr.data_size))) 164*7c478bd9Sstevel@tonic-gate PrintMsg(_MGET_( 165*7c478bd9Sstevel@tonic-gate "AudioUnixfile: header/file size mismatch")); 166*7c478bd9Sstevel@tonic-gate 167*7c478bd9Sstevel@tonic-gate // always consider it to be unknown if not reading a real file 168*7c478bd9Sstevel@tonic-gate // since there's no real way to verify if the header is 169*7c478bd9Sstevel@tonic-gate // correct. 170*7c478bd9Sstevel@tonic-gate } else { 171*7c478bd9Sstevel@tonic-gate setlength(AUDIO_UNKNOWN_TIME); 172*7c478bd9Sstevel@tonic-gate } 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate // set flag for opened() test 175*7c478bd9Sstevel@tonic-gate filehdrset = TRUE; 176*7c478bd9Sstevel@tonic-gate 177*7c478bd9Sstevel@tonic-gate return (AUDIO_SUCCESS); 178*7c478bd9Sstevel@tonic-gate } 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate // Write an audio file header 181*7c478bd9Sstevel@tonic-gate // This routine encodes the audio file header and writes it out. 182*7c478bd9Sstevel@tonic-gate // XXX - It assumes that the file pointer is set to the start of the file. 183*7c478bd9Sstevel@tonic-gate // 184*7c478bd9Sstevel@tonic-gate // This method should be specialized by subclasses that are not files, 185*7c478bd9Sstevel@tonic-gate // like devices for instance. 186*7c478bd9Sstevel@tonic-gate // 187*7c478bd9Sstevel@tonic-gate // XXX - this routine should be rewritten for C++ 188*7c478bd9Sstevel@tonic-gate AudioError AudioUnixfile:: 189*7c478bd9Sstevel@tonic-gate encode_filehdr() 190*7c478bd9Sstevel@tonic-gate { 191*7c478bd9Sstevel@tonic-gate Boolean saveblock; // saved state of the blocking i/o flag 192*7c478bd9Sstevel@tonic-gate AudioHdr hdr_local; // local copy of header 193*7c478bd9Sstevel@tonic-gate Audio_hdr ohdr; // XXX - old libaudio hdr 194*7c478bd9Sstevel@tonic-gate AudioError err; 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate // If fd is not open, or file header already written, skip it 197*7c478bd9Sstevel@tonic-gate if (!isfdset() || opened()) 198*7c478bd9Sstevel@tonic-gate return (RaiseError(AUDIO_ERR_NOEFFECT, Warning)); 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate // XXX - Set up the libaudio hdr 201*7c478bd9Sstevel@tonic-gate hdr_local = GetHeader(); 202*7c478bd9Sstevel@tonic-gate hdr_local.endian = BIG_ENDIAN; // Files are always written big endian. 203*7c478bd9Sstevel@tonic-gate err = SetHeader(hdr_local); 204*7c478bd9Sstevel@tonic-gate if (err != AUDIO_SUCCESS) { 205*7c478bd9Sstevel@tonic-gate return (RaiseError(err)); 206*7c478bd9Sstevel@tonic-gate } 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate ohdr.sample_rate = hdr_local.sample_rate; 209*7c478bd9Sstevel@tonic-gate ohdr.samples_per_unit = hdr_local.samples_per_unit; 210*7c478bd9Sstevel@tonic-gate ohdr.bytes_per_unit = hdr_local.bytes_per_unit; 211*7c478bd9Sstevel@tonic-gate ohdr.channels = hdr_local.channels; 212*7c478bd9Sstevel@tonic-gate ohdr.encoding = hdr_local.encoding; 213*7c478bd9Sstevel@tonic-gate if (Undefined(GetLength())) 214*7c478bd9Sstevel@tonic-gate ohdr.data_size = AUDIO_UNKNOWN_SIZE; 215*7c478bd9Sstevel@tonic-gate else 216*7c478bd9Sstevel@tonic-gate ohdr.data_size = (uint_t)GetHeader().Time_to_Bytes(GetLength()); 217*7c478bd9Sstevel@tonic-gate 218*7c478bd9Sstevel@tonic-gate /* Make sure the file is not set for blocking i/o */ 219*7c478bd9Sstevel@tonic-gate saveblock = GetBlocking(); 220*7c478bd9Sstevel@tonic-gate if (!saveblock) 221*7c478bd9Sstevel@tonic-gate SetBlocking(TRUE); 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate // XXX - Should use C++ output method 224*7c478bd9Sstevel@tonic-gate err = (AudioError) audio_write_filehdr(getfd(), &ohdr, FILE_AU, 225*7c478bd9Sstevel@tonic-gate infostring, infolength); 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate // set flag for opened() test 228*7c478bd9Sstevel@tonic-gate if (err == AUDIO_SUCCESS) 229*7c478bd9Sstevel@tonic-gate filehdrset = TRUE; 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate SetBlocking(saveblock); // Restore the saved blocking i/o state 232*7c478bd9Sstevel@tonic-gate return (RaiseError(err)); 233*7c478bd9Sstevel@tonic-gate } 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate // Set a file blocking/non-blocking 236*7c478bd9Sstevel@tonic-gate // This method should be subclassed by objects that always block (eg, files) 237*7c478bd9Sstevel@tonic-gate void AudioUnixfile:: 238*7c478bd9Sstevel@tonic-gate SetBlocking( 239*7c478bd9Sstevel@tonic-gate Boolean b) // FALSE to set non-blocking 240*7c478bd9Sstevel@tonic-gate { 241*7c478bd9Sstevel@tonic-gate int flag; 242*7c478bd9Sstevel@tonic-gate 243*7c478bd9Sstevel@tonic-gate // If the file is open, set blocking/non-blocking now 244*7c478bd9Sstevel@tonic-gate if (isfdset()) { 245*7c478bd9Sstevel@tonic-gate flag = fcntl(getfd(), F_GETFL, 0); 246*7c478bd9Sstevel@tonic-gate if ((flag < 0) && (errno == EOVERFLOW || errno == EINVAL)) { 247*7c478bd9Sstevel@tonic-gate RaiseError(AUDIO_UNIXERROR, Fatal, 248*7c478bd9Sstevel@tonic-gate (char *)"Large File"); 249*7c478bd9Sstevel@tonic-gate } else if (b) { 250*7c478bd9Sstevel@tonic-gate flag &= ~(O_NDELAY | O_NONBLOCK); // set blocking 251*7c478bd9Sstevel@tonic-gate } else { 252*7c478bd9Sstevel@tonic-gate flag |= O_NONBLOCK; // set non-blocking 253*7c478bd9Sstevel@tonic-gate } 254*7c478bd9Sstevel@tonic-gate if (fcntl(getfd(), F_SETFL, flag) < 0) { 255*7c478bd9Sstevel@tonic-gate RaiseError(AUDIO_UNIXERROR, Warning); 256*7c478bd9Sstevel@tonic-gate } 257*7c478bd9Sstevel@tonic-gate } 258*7c478bd9Sstevel@tonic-gate // Set the blocking flag (this may affect the Open() behavior) 259*7c478bd9Sstevel@tonic-gate block = b; 260*7c478bd9Sstevel@tonic-gate } 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate // Return a pointer to the info string 263*7c478bd9Sstevel@tonic-gate // XXX - returns a pointer to the string stored in the object 264*7c478bd9Sstevel@tonic-gate // XXX - assumes ASCII data 265*7c478bd9Sstevel@tonic-gate char *const AudioUnixfile:: 266*7c478bd9Sstevel@tonic-gate GetInfostring( 267*7c478bd9Sstevel@tonic-gate int& len) const // returned length of string 268*7c478bd9Sstevel@tonic-gate { 269*7c478bd9Sstevel@tonic-gate len = infolength; 270*7c478bd9Sstevel@tonic-gate return (infostring); 271*7c478bd9Sstevel@tonic-gate } 272*7c478bd9Sstevel@tonic-gate 273*7c478bd9Sstevel@tonic-gate // Set the info string 274*7c478bd9Sstevel@tonic-gate void AudioUnixfile:: 275*7c478bd9Sstevel@tonic-gate SetInfostring( 276*7c478bd9Sstevel@tonic-gate const char *str, // new info string 277*7c478bd9Sstevel@tonic-gate int len) // length of string 278*7c478bd9Sstevel@tonic-gate { 279*7c478bd9Sstevel@tonic-gate // If length defaulted, assume an ASCII string 280*7c478bd9Sstevel@tonic-gate if (len == -1) 281*7c478bd9Sstevel@tonic-gate len = strlen(str) + 1; 282*7c478bd9Sstevel@tonic-gate delete infostring; 283*7c478bd9Sstevel@tonic-gate infostring = new char[len]; 284*7c478bd9Sstevel@tonic-gate infolength = len; 285*7c478bd9Sstevel@tonic-gate (void) memcpy(infostring, str, len); 286*7c478bd9Sstevel@tonic-gate } 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate // Close file 289*7c478bd9Sstevel@tonic-gate AudioError AudioUnixfile:: 290*7c478bd9Sstevel@tonic-gate Close() 291*7c478bd9Sstevel@tonic-gate { 292*7c478bd9Sstevel@tonic-gate // If the file is open, close it 293*7c478bd9Sstevel@tonic-gate if (isfdset()) { 294*7c478bd9Sstevel@tonic-gate if (close(getfd()) < 0) 295*7c478bd9Sstevel@tonic-gate return (RaiseError(AUDIO_UNIXERROR)); 296*7c478bd9Sstevel@tonic-gate } else { 297*7c478bd9Sstevel@tonic-gate return (RaiseError(AUDIO_ERR_NOEFFECT, Warning)); 298*7c478bd9Sstevel@tonic-gate } 299*7c478bd9Sstevel@tonic-gate 300*7c478bd9Sstevel@tonic-gate // Init important values, in case the file is reopened 301*7c478bd9Sstevel@tonic-gate setfd(-1); 302*7c478bd9Sstevel@tonic-gate filehdrset = FALSE; 303*7c478bd9Sstevel@tonic-gate (void) SetReadPosition((Double)0., Absolute); 304*7c478bd9Sstevel@tonic-gate (void) SetWritePosition((Double)0., Absolute); 305*7c478bd9Sstevel@tonic-gate return (AUDIO_SUCCESS); 306*7c478bd9Sstevel@tonic-gate } 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate // Read data from underlying file into specified buffer. 309*7c478bd9Sstevel@tonic-gate // No data format translation takes place. 310*7c478bd9Sstevel@tonic-gate // The object's read position is not updated (subclasses can change this) 311*7c478bd9Sstevel@tonic-gate AudioError AudioUnixfile:: 312*7c478bd9Sstevel@tonic-gate ReadData( 313*7c478bd9Sstevel@tonic-gate void* buf, // destination buffer address 314*7c478bd9Sstevel@tonic-gate size_t& len, // buffer length (updated) 315*7c478bd9Sstevel@tonic-gate Double& pos) // start position (updated) 316*7c478bd9Sstevel@tonic-gate { 317*7c478bd9Sstevel@tonic-gate off_t offset; 318*7c478bd9Sstevel@tonic-gate off_t cnt; 319*7c478bd9Sstevel@tonic-gate AudioError err; 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate // Save buffer size and zero transfer count 322*7c478bd9Sstevel@tonic-gate cnt = (off_t)len; 323*7c478bd9Sstevel@tonic-gate len = 0; 324*7c478bd9Sstevel@tonic-gate 325*7c478bd9Sstevel@tonic-gate // Cannot read if file is not open 326*7c478bd9Sstevel@tonic-gate if (!opened() || !mode.Readable()) 327*7c478bd9Sstevel@tonic-gate return (RaiseError(AUDIO_ERR_NOEFFECT)); 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate // Position must be valid 330*7c478bd9Sstevel@tonic-gate if (Undefined(pos) || (pos < 0.) || (cnt < 0)) 331*7c478bd9Sstevel@tonic-gate return (RaiseError(AUDIO_ERR_BADARG)); 332*7c478bd9Sstevel@tonic-gate 333*7c478bd9Sstevel@tonic-gate // Position the file pointer to the right place 334*7c478bd9Sstevel@tonic-gate err = seekread(pos, offset); 335*7c478bd9Sstevel@tonic-gate if (err != AUDIO_SUCCESS) 336*7c478bd9Sstevel@tonic-gate return (err); 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate // Check for EOF 339*7c478bd9Sstevel@tonic-gate if (pos >= GetLength()) { 340*7c478bd9Sstevel@tonic-gate err = AUDIO_EOF; 341*7c478bd9Sstevel@tonic-gate err.sys = AUDIO_COPY_INPUT_EOF; 342*7c478bd9Sstevel@tonic-gate return (err); 343*7c478bd9Sstevel@tonic-gate } 344*7c478bd9Sstevel@tonic-gate 345*7c478bd9Sstevel@tonic-gate // Zero-length reads are finished 346*7c478bd9Sstevel@tonic-gate if (GetHeader().Bytes_to_Bytes(cnt) == 0) { 347*7c478bd9Sstevel@tonic-gate err = AUDIO_SUCCESS; 348*7c478bd9Sstevel@tonic-gate err.sys = AUDIO_COPY_ZERO_LIMIT; 349*7c478bd9Sstevel@tonic-gate return (err); 350*7c478bd9Sstevel@tonic-gate } 351*7c478bd9Sstevel@tonic-gate 352*7c478bd9Sstevel@tonic-gate // Read as much data as possible 353*7c478bd9Sstevel@tonic-gate cnt = read(fd, (char *)buf, (int)cnt); 354*7c478bd9Sstevel@tonic-gate if (cnt < 0) { 355*7c478bd9Sstevel@tonic-gate if (errno == EOVERFLOW) { 356*7c478bd9Sstevel@tonic-gate perror("read"); 357*7c478bd9Sstevel@tonic-gate exit(1); 358*7c478bd9Sstevel@tonic-gate } else if ((errno == EINTR) || 359*7c478bd9Sstevel@tonic-gate (((errno == EWOULDBLOCK) || (errno == EAGAIN)) && 360*7c478bd9Sstevel@tonic-gate !GetBlocking())) { 361*7c478bd9Sstevel@tonic-gate // Is this an interrupted or failed non-blocking request? 362*7c478bd9Sstevel@tonic-gate err = AUDIO_SUCCESS; 363*7c478bd9Sstevel@tonic-gate err.sys = AUDIO_COPY_SHORT_INPUT; 364*7c478bd9Sstevel@tonic-gate return (err); 365*7c478bd9Sstevel@tonic-gate } 366*7c478bd9Sstevel@tonic-gate return (RaiseError(AUDIO_UNIXERROR)); 367*7c478bd9Sstevel@tonic-gate } 368*7c478bd9Sstevel@tonic-gate 369*7c478bd9Sstevel@tonic-gate // End-of-file? 370*7c478bd9Sstevel@tonic-gate if ((cnt == 0) && GetBlocking()) { 371*7c478bd9Sstevel@tonic-gate if (isDevice() || isPipe()) { 372*7c478bd9Sstevel@tonic-gate AUDIO_DEBUG((1, 373*7c478bd9Sstevel@tonic-gate "Zero-length blocking device/pipe read?!\n")); 374*7c478bd9Sstevel@tonic-gate } 375*7c478bd9Sstevel@tonic-gate err = AUDIO_EOF; 376*7c478bd9Sstevel@tonic-gate err.sys = AUDIO_COPY_INPUT_EOF; 377*7c478bd9Sstevel@tonic-gate return (err); 378*7c478bd9Sstevel@tonic-gate } 379*7c478bd9Sstevel@tonic-gate err = AUDIO_SUCCESS; 380*7c478bd9Sstevel@tonic-gate if (cnt == 0) { 381*7c478bd9Sstevel@tonic-gate err.sys = AUDIO_COPY_SHORT_INPUT; 382*7c478bd9Sstevel@tonic-gate } 383*7c478bd9Sstevel@tonic-gate 384*7c478bd9Sstevel@tonic-gate // Return the updated byte count and position 385*7c478bd9Sstevel@tonic-gate len = (size_t)cnt; 386*7c478bd9Sstevel@tonic-gate if (GetHeader().Bytes_to_Bytes(cnt) != len) { 387*7c478bd9Sstevel@tonic-gate AUDIO_DEBUG((1, 388*7c478bd9Sstevel@tonic-gate "Read returned a partial sample frame?!\n")); 389*7c478bd9Sstevel@tonic-gate } 390*7c478bd9Sstevel@tonic-gate pos = GetHeader().Bytes_to_Time(offset + len); 391*7c478bd9Sstevel@tonic-gate 392*7c478bd9Sstevel@tonic-gate // Check to see if the endian is right. 393*7c478bd9Sstevel@tonic-gate coerceEndian((unsigned char *)buf, len, localByteOrder()); 394*7c478bd9Sstevel@tonic-gate 395*7c478bd9Sstevel@tonic-gate return (err); 396*7c478bd9Sstevel@tonic-gate } 397*7c478bd9Sstevel@tonic-gate 398*7c478bd9Sstevel@tonic-gate // Write data to underlying file from specified buffer. 399*7c478bd9Sstevel@tonic-gate // No data format translation takes place. 400*7c478bd9Sstevel@tonic-gate // The object's write position is not updated (subclasses can change this) 401*7c478bd9Sstevel@tonic-gate AudioError AudioUnixfile:: 402*7c478bd9Sstevel@tonic-gate WriteData( 403*7c478bd9Sstevel@tonic-gate void* buf, // source buffer address 404*7c478bd9Sstevel@tonic-gate size_t& len, // buffer length (updated) 405*7c478bd9Sstevel@tonic-gate Double& pos) // start position (updated) 406*7c478bd9Sstevel@tonic-gate { 407*7c478bd9Sstevel@tonic-gate off_t offset; 408*7c478bd9Sstevel@tonic-gate off_t cnt; 409*7c478bd9Sstevel@tonic-gate AudioError err; 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate // Save buffer size and zero transfer count 412*7c478bd9Sstevel@tonic-gate cnt = (off_t)len; 413*7c478bd9Sstevel@tonic-gate len = 0; 414*7c478bd9Sstevel@tonic-gate 415*7c478bd9Sstevel@tonic-gate // Cannot write if file is not open 416*7c478bd9Sstevel@tonic-gate if (!opened() || !mode.Writeable()) 417*7c478bd9Sstevel@tonic-gate return (RaiseError(AUDIO_ERR_NOEFFECT)); 418*7c478bd9Sstevel@tonic-gate 419*7c478bd9Sstevel@tonic-gate // Position must be valid 420*7c478bd9Sstevel@tonic-gate if (Undefined(pos) || (pos < 0.) || (cnt < 0)) 421*7c478bd9Sstevel@tonic-gate return (RaiseError(AUDIO_ERR_BADARG)); 422*7c478bd9Sstevel@tonic-gate 423*7c478bd9Sstevel@tonic-gate // Zero-length writes are easy 424*7c478bd9Sstevel@tonic-gate if (GetHeader().Bytes_to_Bytes(cnt) == 0) { 425*7c478bd9Sstevel@tonic-gate err = AUDIO_SUCCESS; 426*7c478bd9Sstevel@tonic-gate err.sys = AUDIO_COPY_ZERO_LIMIT; 427*7c478bd9Sstevel@tonic-gate return (err); 428*7c478bd9Sstevel@tonic-gate } 429*7c478bd9Sstevel@tonic-gate 430*7c478bd9Sstevel@tonic-gate // Position the file pointer to the right place 431*7c478bd9Sstevel@tonic-gate err = seekwrite(pos, offset); 432*7c478bd9Sstevel@tonic-gate if (err != AUDIO_SUCCESS) 433*7c478bd9Sstevel@tonic-gate return (err); 434*7c478bd9Sstevel@tonic-gate 435*7c478bd9Sstevel@tonic-gate // Make sure data is in target's endian format before writing. 436*7c478bd9Sstevel@tonic-gate // This conversion is done inplace so we need to change back. 437*7c478bd9Sstevel@tonic-gate // We assume that the data in buf is in localByteOrder. 438*7c478bd9Sstevel@tonic-gate // Only files should have order issues. 439*7c478bd9Sstevel@tonic-gate if (localByteOrder() != GetHeader().endian) 440*7c478bd9Sstevel@tonic-gate coerceEndian((unsigned char *)buf, (size_t)cnt, SWITCH_ENDIAN); 441*7c478bd9Sstevel@tonic-gate 442*7c478bd9Sstevel@tonic-gate // Write as much data as possible 443*7c478bd9Sstevel@tonic-gate err = AUDIO_SUCCESS; 444*7c478bd9Sstevel@tonic-gate cnt = write(fd, (char *)buf, (int)cnt); 445*7c478bd9Sstevel@tonic-gate if (cnt < 0) { 446*7c478bd9Sstevel@tonic-gate if (errno == EFBIG) { 447*7c478bd9Sstevel@tonic-gate perror("write"); 448*7c478bd9Sstevel@tonic-gate exit(1); 449*7c478bd9Sstevel@tonic-gate } else if ((errno == EWOULDBLOCK) || (errno == EAGAIN)) { 450*7c478bd9Sstevel@tonic-gate // Is this a failed non-blocking request? 451*7c478bd9Sstevel@tonic-gate err.sys = AUDIO_COPY_SHORT_OUTPUT; 452*7c478bd9Sstevel@tonic-gate return (err); 453*7c478bd9Sstevel@tonic-gate } 454*7c478bd9Sstevel@tonic-gate return (RaiseError(AUDIO_UNIXERROR)); 455*7c478bd9Sstevel@tonic-gate } 456*7c478bd9Sstevel@tonic-gate if (cnt == 0) 457*7c478bd9Sstevel@tonic-gate err.sys = AUDIO_COPY_SHORT_OUTPUT; 458*7c478bd9Sstevel@tonic-gate 459*7c478bd9Sstevel@tonic-gate // Switch the endian back if local order doesn't match target order. 460*7c478bd9Sstevel@tonic-gate if (localByteOrder() != GetHeader().endian) 461*7c478bd9Sstevel@tonic-gate coerceEndian((unsigned char *)buf, (size_t)cnt, SWITCH_ENDIAN); 462*7c478bd9Sstevel@tonic-gate 463*7c478bd9Sstevel@tonic-gate // Return the updated byte count and position 464*7c478bd9Sstevel@tonic-gate len = (size_t)cnt; 465*7c478bd9Sstevel@tonic-gate pos = GetHeader().Bytes_to_Time(offset + len); 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate // If the current position is beyond old EOF, update the size 468*7c478bd9Sstevel@tonic-gate if (!Undefined(GetLength()) && (pos > GetLength())) { 469*7c478bd9Sstevel@tonic-gate setlength(pos); 470*7c478bd9Sstevel@tonic-gate } 471*7c478bd9Sstevel@tonic-gate 472*7c478bd9Sstevel@tonic-gate return (AUDIO_SUCCESS); 473*7c478bd9Sstevel@tonic-gate } 474*7c478bd9Sstevel@tonic-gate 475*7c478bd9Sstevel@tonic-gate // Seek in input stream 476*7c478bd9Sstevel@tonic-gate // Ordinary streams (ie, pipes and devices) cannot be rewound. 477*7c478bd9Sstevel@tonic-gate // A forward seek in them consumes data by reading it. 478*7c478bd9Sstevel@tonic-gate // 479*7c478bd9Sstevel@tonic-gate // This method should be specialized by subclasses that can actually seek, 480*7c478bd9Sstevel@tonic-gate // like regular files for instance. 481*7c478bd9Sstevel@tonic-gate // 482*7c478bd9Sstevel@tonic-gate AudioError AudioUnixfile:: 483*7c478bd9Sstevel@tonic-gate seekread( 484*7c478bd9Sstevel@tonic-gate Double pos, // position to seek to 485*7c478bd9Sstevel@tonic-gate off_t& offset) // returned byte offset 486*7c478bd9Sstevel@tonic-gate { 487*7c478bd9Sstevel@tonic-gate char *bufp; // temporary input buffer 488*7c478bd9Sstevel@tonic-gate size_t bufl; // input buffer size 489*7c478bd9Sstevel@tonic-gate size_t cnt; // input byte count 490*7c478bd9Sstevel@tonic-gate long icnt; // read size 491*7c478bd9Sstevel@tonic-gate Boolean saveblock; // saved state of the blocking i/o flag 492*7c478bd9Sstevel@tonic-gate Double buflen; 493*7c478bd9Sstevel@tonic-gate AudioError err; 494*7c478bd9Sstevel@tonic-gate 495*7c478bd9Sstevel@tonic-gate offset = GetHeader().Time_to_Bytes(pos); 496*7c478bd9Sstevel@tonic-gate pos -= ReadPosition(); 497*7c478bd9Sstevel@tonic-gate 498*7c478bd9Sstevel@tonic-gate // If the seek is backwards, do nothing 499*7c478bd9Sstevel@tonic-gate if (pos < 0.) 500*7c478bd9Sstevel@tonic-gate return (RaiseError(AUDIO_ERR_NOEFFECT, Warning)); 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate // If the seek is to the current position, then do nothing. 503*7c478bd9Sstevel@tonic-gate icnt = GetHeader().Time_to_Bytes(pos); 504*7c478bd9Sstevel@tonic-gate if (icnt == 0) 505*7c478bd9Sstevel@tonic-gate return (AUDIO_SUCCESS); 506*7c478bd9Sstevel@tonic-gate 507*7c478bd9Sstevel@tonic-gate // The seek is determinate and forward. 508*7c478bd9Sstevel@tonic-gate // We'll have to consume data to get there. 509*7c478bd9Sstevel@tonic-gate // First allocate a buffer to stuff the data into. 510*7c478bd9Sstevel@tonic-gate // Then set the stream for blocking i/o (saving the old state). 511*7c478bd9Sstevel@tonic-gate buflen = max(pos, 1.); 512*7c478bd9Sstevel@tonic-gate bufl = (size_t)GetHeader().Time_to_Bytes(buflen); 513*7c478bd9Sstevel@tonic-gate bufp = new char[bufl]; 514*7c478bd9Sstevel@tonic-gate if (bufp == 0) { // allocation error, try a smaller buf 515*7c478bd9Sstevel@tonic-gate bufl = (size_t)sysconf(_SC_PAGESIZE); 516*7c478bd9Sstevel@tonic-gate bufp = new char[bufl]; 517*7c478bd9Sstevel@tonic-gate if (bufp == 0) 518*7c478bd9Sstevel@tonic-gate return (RaiseError(AUDIO_UNIXERROR)); 519*7c478bd9Sstevel@tonic-gate } 520*7c478bd9Sstevel@tonic-gate // XXX - May have to realign to partial frame count! 521*7c478bd9Sstevel@tonic-gate 522*7c478bd9Sstevel@tonic-gate saveblock = GetBlocking(); 523*7c478bd9Sstevel@tonic-gate if (!saveblock) 524*7c478bd9Sstevel@tonic-gate SetBlocking(TRUE); 525*7c478bd9Sstevel@tonic-gate 526*7c478bd9Sstevel@tonic-gate // Loop until the seek is satisfied (or an error occurs). 527*7c478bd9Sstevel@tonic-gate do { 528*7c478bd9Sstevel@tonic-gate // Limit the read to keep from going too far 529*7c478bd9Sstevel@tonic-gate cnt = (icnt >= (long)bufl) ? bufl : (size_t)icnt; 530*7c478bd9Sstevel@tonic-gate err = Read(bufp, cnt); 531*7c478bd9Sstevel@tonic-gate if (err != AUDIO_SUCCESS) 532*7c478bd9Sstevel@tonic-gate break; 533*7c478bd9Sstevel@tonic-gate icnt -= (long)cnt; 534*7c478bd9Sstevel@tonic-gate } while (icnt > 0); 535*7c478bd9Sstevel@tonic-gate 536*7c478bd9Sstevel@tonic-gate SetBlocking(saveblock); // Restore the saved blocking i/o state 537*7c478bd9Sstevel@tonic-gate delete bufp; // Free the temporary buffer 538*7c478bd9Sstevel@tonic-gate return (RaiseError(err)); 539*7c478bd9Sstevel@tonic-gate } 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate // Seek in output stream 542*7c478bd9Sstevel@tonic-gate // Ordinary streams (ie, pipes and devices) cannot be rewound. 543*7c478bd9Sstevel@tonic-gate // A forward seek in them writes NULL data. 544*7c478bd9Sstevel@tonic-gate // 545*7c478bd9Sstevel@tonic-gate // This method should be specialized by subclasses that can actually seek, 546*7c478bd9Sstevel@tonic-gate // like regular files for instance. 547*7c478bd9Sstevel@tonic-gate // 548*7c478bd9Sstevel@tonic-gate AudioError AudioUnixfile:: 549*7c478bd9Sstevel@tonic-gate seekwrite( 550*7c478bd9Sstevel@tonic-gate Double pos, // position to seek to 551*7c478bd9Sstevel@tonic-gate off_t& offset) // returned byte offset 552*7c478bd9Sstevel@tonic-gate { 553*7c478bd9Sstevel@tonic-gate char *bufp; // temporary output buffer 554*7c478bd9Sstevel@tonic-gate size_t bufl; // output buffer size 555*7c478bd9Sstevel@tonic-gate size_t cnt; // output byte count 556*7c478bd9Sstevel@tonic-gate long ocnt; // write size 557*7c478bd9Sstevel@tonic-gate Boolean saveblock; // saved state of the blocking i/o flag 558*7c478bd9Sstevel@tonic-gate Double buflen; 559*7c478bd9Sstevel@tonic-gate AudioError err; 560*7c478bd9Sstevel@tonic-gate 561*7c478bd9Sstevel@tonic-gate offset = GetHeader().Time_to_Bytes(pos); 562*7c478bd9Sstevel@tonic-gate pos -= WritePosition(); 563*7c478bd9Sstevel@tonic-gate 564*7c478bd9Sstevel@tonic-gate // If the seek is backwards, do nothing 565*7c478bd9Sstevel@tonic-gate if (pos < 0.) 566*7c478bd9Sstevel@tonic-gate return (RaiseError(AUDIO_ERR_NOEFFECT, Warning)); 567*7c478bd9Sstevel@tonic-gate 568*7c478bd9Sstevel@tonic-gate // If the seek is to the current position, then do nothing. 569*7c478bd9Sstevel@tonic-gate ocnt = GetHeader().Time_to_Bytes(pos); 570*7c478bd9Sstevel@tonic-gate if (ocnt == 0) 571*7c478bd9Sstevel@tonic-gate return (AUDIO_SUCCESS); 572*7c478bd9Sstevel@tonic-gate 573*7c478bd9Sstevel@tonic-gate // The seek is determinate and forward. 574*7c478bd9Sstevel@tonic-gate // We'll have to produce NULL data to get there. 575*7c478bd9Sstevel@tonic-gate // XXX - not implemented correctly yet 576*7c478bd9Sstevel@tonic-gate buflen = max(pos, 1.); 577*7c478bd9Sstevel@tonic-gate bufl = (size_t)GetHeader().Time_to_Bytes(buflen); 578*7c478bd9Sstevel@tonic-gate bufp = new char[bufl]; 579*7c478bd9Sstevel@tonic-gate if (bufp == 0) { // allocation error, try a smaller buf 580*7c478bd9Sstevel@tonic-gate bufl = (size_t)sysconf(_SC_PAGESIZE); 581*7c478bd9Sstevel@tonic-gate bufp = new char[bufl]; 582*7c478bd9Sstevel@tonic-gate if (bufp == 0) 583*7c478bd9Sstevel@tonic-gate return (RaiseError(AUDIO_UNIXERROR)); 584*7c478bd9Sstevel@tonic-gate } 585*7c478bd9Sstevel@tonic-gate 586*7c478bd9Sstevel@tonic-gate // XXX - May have to realign to partial frame count! 587*7c478bd9Sstevel@tonic-gate saveblock = GetBlocking(); 588*7c478bd9Sstevel@tonic-gate if (!saveblock) 589*7c478bd9Sstevel@tonic-gate SetBlocking(TRUE); 590*7c478bd9Sstevel@tonic-gate 591*7c478bd9Sstevel@tonic-gate // Loop until the seek is satisfied (or an error occurs). 592*7c478bd9Sstevel@tonic-gate do { 593*7c478bd9Sstevel@tonic-gate // Limit the write to keep from going too far 594*7c478bd9Sstevel@tonic-gate cnt = (ocnt >= (long)bufl) ? bufl : (size_t)ocnt; 595*7c478bd9Sstevel@tonic-gate err = Write(bufp, cnt); 596*7c478bd9Sstevel@tonic-gate if (err != AUDIO_SUCCESS) 597*7c478bd9Sstevel@tonic-gate break; 598*7c478bd9Sstevel@tonic-gate ocnt -= (long)cnt; 599*7c478bd9Sstevel@tonic-gate } while (ocnt > 0); 600*7c478bd9Sstevel@tonic-gate 601*7c478bd9Sstevel@tonic-gate SetBlocking(saveblock); // Restore the saved blocking i/o state 602*7c478bd9Sstevel@tonic-gate delete bufp; // Free the temporary buffer 603*7c478bd9Sstevel@tonic-gate return (RaiseError(err)); 604*7c478bd9Sstevel@tonic-gate } 605