1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1992-2001 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #include <stdlib.h> 28 #include <memory.h> 29 #include "../include/AudioDebug.h" 30 #include "../include/AudioBuffer.h" 31 #include "../include/zmalloc.h" 32 33 // class AudioBuffer methods 34 35 // Constructor with optional hdr, size, and name arguments 36 AudioBuffer:: 37 AudioBuffer( 38 double len, // buffer length, in seconds 39 const char *local_name): // name 40 AudioStream(local_name), buflen(len), bufaddr(0), zflag(0), bufsize(0) 41 { 42 } 43 44 // Destructor 45 AudioBuffer:: 46 ~AudioBuffer() 47 { 48 (void) SetSize(0.); // deallocate the buffer 49 } 50 51 // XXX - the following functions are good candidates for inlining 52 53 // Return TRUE if the stream is 'open' 54 Boolean AudioBuffer:: 55 opened() const 56 { 57 // A buffer is open if it is allocated and has a valid header 58 return (hdrset() && (GetAddress() != 0)); 59 } 60 61 #define MIN_ZBUFFER (8192 * 10) // only for large buffers 62 63 // Allocate buffer. Size and header must be set. 64 AudioError AudioBuffer:: 65 alloc() 66 { 67 long size; 68 size_t cnt; 69 unsigned int ncpy; 70 void* tmpbuf; 71 72 // this is going to be the size we're setting the buffer 73 // to (buflen field). it's set by calling SetSize(). 74 size = GetHeader().Time_to_Bytes(GetSize()); 75 76 // this is actual current size, in bytes, of the allocated 77 // buffer (the bufsize field). 78 cnt = GetByteCount(); 79 80 AUDIO_DEBUG((5, "%d: AudioBuffer::alloc - change from %d to %d bytes\n", 81 getid(), cnt, size)); 82 83 bufsize = 0; 84 85 if (size == 0) { 86 // Zero size deletes the buffer 87 if (bufaddr != 0) { 88 if (zflag != 0) { 89 AUDIO_DEBUG((5, 90 "%d: AudioBuffer::alloc - zfree mmapped buffer\n", 91 getid())); 92 (void) zfree((char *)bufaddr); 93 } else { 94 AUDIO_DEBUG((5, 95 "%d: AudioBuffer::alloc - free malloc'd buffer\n", 96 getid())); 97 (void) free((char *)bufaddr); 98 } 99 zflag = 0; 100 } 101 bufaddr = 0; 102 103 } else if (size < 0) { 104 // Ridiculous size 105 AUDIO_DEBUG((5, "%d: AudioBuffer::alloc - bad size\n", 106 getid())); 107 return (RaiseError(AUDIO_ERR_BADARG)); 108 109 } else if (bufaddr == 0) { 110 // Allocate a new buffer 111 if (size > MIN_ZBUFFER) { 112 AUDIO_DEBUG((5, 113 "%d: AudioBuffer::alloc - zmalloc new buffer\n", 114 getid())); 115 bufaddr = (void*) zmalloc((unsigned int)size); 116 zflag = 1; 117 } else { 118 AUDIO_DEBUG((5, 119 "%d: AudioBuffer::alloc - malloc new buffer\n", 120 getid())); 121 bufaddr = (void*) malloc((unsigned int)size); 122 zflag = 0; 123 } 124 if (bufaddr == 0) { 125 AUDIO_DEBUG((5, 126 "%d: AudioBuffer::alloc - buffer alloc failed\n", 127 getid())); 128 return (RaiseError(AUDIO_UNIXERROR)); 129 } 130 } else { 131 // A buffer was already allocated. 132 // Change its size, preserving as much data as possible. 133 if ((cnt <= MIN_ZBUFFER) && (size <= MIN_ZBUFFER) && 134 (zflag == 0)) { 135 AUDIO_DEBUG((5, 136 "%d: AudioBuffer::alloc - realloc to change size\n", 137 getid())); 138 bufaddr = (void*) 139 realloc((char *)bufaddr, (unsigned int)size); 140 } else { 141 AUDIO_DEBUG((5, 142 "%d: AudioBuffer::alloc - zmalloc new buffer\n", 143 getid())); 144 tmpbuf = bufaddr; 145 bufaddr = (void*) zmalloc((unsigned int)size); 146 147 // copy over as much of the old data as will fit 148 if (bufaddr != 0) { 149 ncpy = (cnt < size) ? (unsigned int)cnt : 150 (unsigned int)size; 151 152 AUDIO_DEBUG((5, 153 "%d: AudioBuffer::alloc - trasnfer %d bytes\n", 154 getid(), ncpy)); 155 (void) memcpy(bufaddr, tmpbuf, ncpy); 156 } 157 if ((cnt > MIN_ZBUFFER) && (zflag != 0)) { 158 AUDIO_DEBUG((5, 159 "%d: AudioBuffer::alloc - zfree old buffer\n", 160 getid())); 161 (void) zfree((char *)tmpbuf); 162 } else { 163 AUDIO_DEBUG((5, 164 "%d: AudioBuffer::alloc - free old buffer\n", 165 getid())); 166 (void) free((char *)tmpbuf); 167 } 168 zflag = 1; 169 } 170 if (bufaddr == 0) { 171 return (RaiseError(AUDIO_UNIXERROR)); 172 } 173 } 174 bufsize = (size_t)size; 175 return (AUDIO_SUCCESS); 176 } 177 178 179 // Return the buffer address 180 void* AudioBuffer:: 181 GetAddress() const 182 { 183 return (GetAddress(0.)); 184 } 185 186 // Return the buffer address at a given time offset 187 // Returns NULL if no buffer, or the position is not within the buffer. 188 void* AudioBuffer:: 189 GetAddress( 190 Double pos) const 191 { 192 char *addr; 193 AudioHdr hdr_local; 194 AudioHdr(AudioBuffer::*hfunc)()const; 195 196 addr = (char *)bufaddr; 197 if ((addr == 0) || (pos < 0.) || (pos >= buflen)) 198 return (NULL); 199 200 // If no offset, it's ok if the header hasn't been set yet 201 if (pos == 0.) 202 return ((void*) addr); 203 204 // Get the header and make sure it's valid 205 // This convoluted hfunc works around non-const function problems 206 hfunc = (AudioHdr(AudioBuffer::*)() const)&AudioBuffer::GetHeader; 207 hdr_local = (this->*hfunc)(); 208 if (hdr_local.Validate()) 209 return (NULL); 210 addr += hdr_local.Time_to_Bytes(pos); 211 212 // One more validation, to be paranoid before handing out this address 213 if (addr >= ((char *)bufaddr + bufsize)) 214 return (NULL); 215 return ((void*) addr); 216 } 217 218 // Return the buffer size, in bytes 219 // (as opposed to 'length' which indicates how much data is in the buffer) 220 size_t AudioBuffer:: 221 GetByteCount() const 222 { 223 return (bufsize); 224 } 225 226 // Return the buffer size, in seconds 227 // (as opposed to 'length' which indicates how much data is in the buffer) 228 Double AudioBuffer:: 229 GetSize() const 230 { 231 return (buflen); 232 } 233 234 // Set the buffer size, allocating the buffer as necessary 235 AudioError AudioBuffer:: 236 SetSize( 237 Double len) // new size, in seconds 238 { 239 // If no change in size, do nothing 240 if (len == buflen) 241 return (AUDIO_SUCCESS); 242 243 // If header not set, store the size for later 244 buflen = len; 245 if (!hdrset()) { 246 return (AUDIO_SUCCESS); 247 } 248 249 // If shrinking buffer, note this 250 if (buflen < GetLength()) 251 SetLength(buflen); 252 return (alloc()); 253 } 254 255 // Set the data header 256 // If no buffer allocated, allocate one now (if size is set). 257 // If buffer allocated, fiddle the sizes to account for new header type. 258 AudioError AudioBuffer:: 259 SetHeader( 260 const AudioHdr& h) // header to copy 261 { 262 AudioError err; 263 264 // Validate, then update the header 265 err = h.Validate(); 266 if (err) 267 return (RaiseError(err)); 268 (void) AudioStream::updateheader(h); 269 270 // If no size set, done for now 271 if (buflen == 0.) 272 return (AUDIO_SUCCESS); 273 274 // If no buffer allocated, allocate one now 275 if (GetAddress() == 0) 276 return (alloc()); 277 278 // If buffer allocated, change size to match new header 279 buflen = h.Bytes_to_Time(GetByteCount()); 280 return (AUDIO_SUCCESS); 281 } 282 283 // Set the buffer length (ie, the amount of data written to the buffer) 284 void AudioBuffer:: 285 SetLength( 286 Double len) // new length 287 { 288 if (!hdrset() || (len < 0.)) // no-op if not ready 289 return; 290 if (!opened() && (len > 0.)) 291 return; 292 293 if (Undefined(len) || (len > GetSize())) { 294 // Limit to the size of the buffer 295 setlength(GetSize()); 296 } else { 297 setlength(len); 298 } 299 } 300 301 // Copy data from local buffer into specified buffer. 302 // No data format translation takes place. 303 // The object's read position is not updated. 304 AudioError AudioBuffer:: 305 ReadData( 306 void* buf, // destination buffer address 307 size_t& len, // buffer length (updated) 308 Double& pos) // start position (updated) 309 { 310 off_t resid; 311 off_t cnt; 312 off_t offset; 313 AudioError err; 314 315 // Copy length, zero return value 316 cnt = (off_t)len; 317 len = 0; 318 319 // Cannot read if buffer or header not valid 320 if (!opened()) 321 return (RaiseError(AUDIO_ERR_NOEFFECT)); 322 323 // Position must be valid 324 if ((pos < 0.) || (cnt < 0)) 325 return (RaiseError(AUDIO_ERR_BADARG)); 326 327 // If the starting offset is at or beyond EOF, return eof flag 328 if (pos >= GetLength()) { 329 err = AUDIO_EOF; 330 err.sys = AUDIO_COPY_INPUT_EOF; 331 return (err); 332 } 333 334 // Limit transfer to remaining room in buffer 335 offset = GetHeader().Time_to_Bytes(pos); 336 resid = GetHeader().Time_to_Bytes(GetLength()) - offset; 337 if (resid <= 0) { 338 err = AUDIO_EOF; 339 err.sys = AUDIO_COPY_INPUT_EOF; 340 return (err); 341 } 342 if (cnt > resid) 343 cnt = resid; 344 345 // Fix the alignment to make sure we're not splitting frames 346 err = AUDIO_SUCCESS; 347 if (GetHeader().Bytes_to_Bytes(cnt) > 0) { 348 // Copy as much data as possible 349 memcpy((char *)buf, (char *)((off_t)GetAddress() + offset), 350 (int)cnt); 351 } else { 352 err.sys = AUDIO_COPY_ZERO_LIMIT; 353 } 354 355 // Return the updated transfer size and position 356 len = (size_t)cnt; 357 pos = GetHeader().Bytes_to_Time(offset + cnt); 358 359 360 // Check to see if the endian is right. 361 coerceEndian((unsigned char *)buf, len, localByteOrder()); 362 363 return (err); 364 } 365 366 // Copy data to local buffer from specified buffer. 367 // No data format translation takes place. 368 // The object's write position is not updated. 369 AudioError AudioBuffer:: 370 WriteData( 371 void* buf, // source buffer address 372 size_t& len, // buffer length (updated) 373 Double& pos) // start position (updated) 374 { 375 off_t resid; 376 off_t cnt; 377 off_t offset; 378 AudioError err; 379 380 // Copy length, zero return value 381 cnt = (off_t)len; 382 len = 0; 383 384 // Cannot write if buffer or header not valid 385 if (!opened()) 386 return (RaiseError(AUDIO_ERR_NOEFFECT)); 387 388 // Position must be valid 389 if ((pos < 0.) || (cnt < 0)) 390 return (RaiseError(AUDIO_ERR_BADARG)); 391 392 // If the starting offset beyond end of buffer, return short write flag 393 if (pos >= GetSize()) { 394 err = AUDIO_EOF; 395 err.sys = AUDIO_COPY_OUTPUT_EOF; 396 return (err); 397 } 398 399 // Limit transfer to remaining room in buffer 400 offset = GetHeader().Time_to_Bytes(pos); 401 resid = (off_t)bufsize - offset; 402 if (resid <= 0) { 403 err = AUDIO_EOF; 404 err.sys = AUDIO_COPY_OUTPUT_EOF; 405 return (err); 406 } 407 if (cnt > resid) 408 cnt = resid; 409 410 // Fix the alignment to make sure we're not splitting frames 411 err = AUDIO_SUCCESS; 412 if (GetHeader().Bytes_to_Bytes(cnt) > 0) { 413 // Copy as much data as possible 414 memcpy((char *)((off_t)GetAddress() + offset), (char *)buf, 415 (int)cnt); 416 } else { 417 err.sys = AUDIO_COPY_ZERO_LIMIT; 418 } 419 420 // Return the updated transfer size and position 421 len = (size_t)cnt; 422 pos = GetHeader().Bytes_to_Time(offset + cnt); 423 424 // The end of a write to a buffer always becomes the buffer EOF 425 setlength(pos); 426 return (err); 427 } 428 429 // AppendData is just like WriteData, except that it guarantees to extend 430 // the buffer if it is not big enough. 431 // The object's write position is not updated. 432 AudioError AudioBuffer:: 433 AppendData( 434 void* buf, // source buffer address 435 size_t& len, // buffer length (updated) 436 Double& pos) // start position (updated) 437 { 438 Double local_length; 439 AudioError err; 440 441 // Cannot write if header not valid 442 if (!hdrset()) 443 return (RaiseError(AUDIO_ERR_NOEFFECT)); 444 445 // Position must be valid 446 if (pos < 0.) 447 return (RaiseError(AUDIO_ERR_BADARG)); 448 449 // If the ending offset is beyond end of buffer, extend it 450 local_length = pos + GetHeader().Bytes_to_Time(len); 451 if (local_length > GetSize()) { 452 if (err = SetSize(local_length)) 453 return (err); 454 } 455 return (WriteData(buf, len, pos)); 456 } 457 458 // Copy routine to copy direct to destination 459 AudioError AudioBuffer:: 460 AsyncCopy( 461 Audio* to, // audio object to copy to 462 Double& frompos, 463 Double& topos, 464 Double& limit) 465 { 466 caddr_t bptr; 467 size_t cnt; 468 size_t svcnt; 469 Double svfrom; 470 Double svto; 471 Double lim; 472 AudioHdr tohdr; 473 AudioError err; 474 475 // Cannot write if buffer or header not valid 476 if (!opened()) 477 return (RaiseError(AUDIO_ERR_NOEFFECT)); 478 479 tohdr = to->GetHeader(); 480 if (limit < 0.) 481 return (RaiseError(AUDIO_ERR_BADARG)); 482 483 // Get maximum possible copy length 484 svfrom = GetLength(); 485 if (frompos >= svfrom) { 486 limit = 0.; 487 err = AUDIO_EOF; 488 err.sys = AUDIO_COPY_INPUT_EOF; 489 return (err); 490 } 491 lim = svfrom - frompos; 492 if (!Undefined(limit) && (limit < lim)) 493 lim = limit; 494 495 limit = 0.; 496 497 bptr = (caddr_t)GetAddress(frompos); 498 if (bptr == 0) { 499 err = AUDIO_EOF; 500 err.sys = AUDIO_COPY_INPUT_EOF; 501 return (err); 502 } 503 cnt = (size_t)GetHeader().Time_to_Bytes(lim); 504 if (cnt == 0) { 505 err = AUDIO_SUCCESS; 506 err.sys = AUDIO_COPY_ZERO_LIMIT; 507 return (err); 508 } 509 510 // Add a bunch of paranoid checks 511 svcnt = (size_t)GetAddress() + (size_t)GetByteCount(); 512 if ((bptr + cnt) > (caddr_t)svcnt) { 513 // re-adjust cnt so it reads up to the end of file 514 cnt = (size_t)((caddr_t)svcnt - bptr); 515 } 516 if (GetHeader().Bytes_to_Bytes(cnt) == 0) { 517 err = AUDIO_EOF; 518 err.sys = AUDIO_COPY_INPUT_EOF; 519 return (err); 520 } 521 522 // Write the data to the destination and update pointers/ctrs 523 svfrom = frompos; 524 svto = topos; 525 svcnt = cnt; 526 err = to->WriteData(bptr, cnt, topos); 527 limit = topos - svto; 528 frompos = svfrom + limit; 529 530 // Report short writes 531 if (!err && (cnt < svcnt)) { 532 err.sys = AUDIO_COPY_SHORT_OUTPUT; 533 } 534 return (err); 535 } 536