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