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