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
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.
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]
23 * Copyright (c) 1992-2001 by Sun Microsystems, Inc.
24 * All rights reserved.
27 #pragma ident "%Z%%M% %I% %E% SMI"
31 #include "../include/AudioDebug.h"
32 #include "../include/AudioBuffer.h"
33 #include "../include/zmalloc.h"
35 // class AudioBuffer methods
37 // Constructor with optional hdr, size, and name arguments
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)
50 (void) SetSize(0.); // deallocate the buffer
53 // XXX - the following functions are good candidates for inlining
55 // Return TRUE if the stream is 'open'
59 // A buffer is open if it is allocated and has a valid header
60 return (hdrset() && (GetAddress() != 0));
63 #define MIN_ZBUFFER (8192 * 10) // only for large buffers
65 // Allocate buffer. Size and header must be set.
66 AudioError
AudioBuffer::
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());
78 // this is actual current size, in bytes, of the allocated
79 // buffer (the bufsize field).
82 AUDIO_DEBUG((5, "%d: AudioBuffer::alloc - change from %d to %d bytes\n",
88 // Zero size deletes the buffer
92 "%d: AudioBuffer::alloc - zfree mmapped buffer\n",
94 (void) zfree((char *)bufaddr
);
97 "%d: AudioBuffer::alloc - free malloc'd buffer\n",
99 (void) free((char *)bufaddr
);
105 } else if (size
< 0) {
107 AUDIO_DEBUG((5, "%d: AudioBuffer::alloc - bad size\n",
109 return (RaiseError(AUDIO_ERR_BADARG
));
111 } else if (bufaddr
== 0) {
112 // Allocate a new buffer
113 if (size
> MIN_ZBUFFER
) {
115 "%d: AudioBuffer::alloc - zmalloc new buffer\n",
117 bufaddr
= (void*) zmalloc((unsigned int)size
);
121 "%d: AudioBuffer::alloc - malloc new buffer\n",
123 bufaddr
= (void*) malloc((unsigned int)size
);
128 "%d: AudioBuffer::alloc - buffer alloc failed\n",
130 return (RaiseError(AUDIO_UNIXERROR
));
133 // A buffer was already allocated.
134 // Change its size, preserving as much data as possible.
135 if ((cnt
<= MIN_ZBUFFER
) && (size
<= MIN_ZBUFFER
) &&
138 "%d: AudioBuffer::alloc - realloc to change size\n",
141 realloc((char *)bufaddr
, (unsigned int)size
);
144 "%d: AudioBuffer::alloc - zmalloc new buffer\n",
147 bufaddr
= (void*) zmalloc((unsigned int)size
);
149 // copy over as much of the old data as will fit
151 ncpy
= (cnt
< size
) ? (unsigned int)cnt
:
155 "%d: AudioBuffer::alloc - trasnfer %d bytes\n",
157 (void) memcpy(bufaddr
, tmpbuf
, ncpy
);
159 if ((cnt
> MIN_ZBUFFER
) && (zflag
!= 0)) {
161 "%d: AudioBuffer::alloc - zfree old buffer\n",
163 (void) zfree((char *)tmpbuf
);
166 "%d: AudioBuffer::alloc - free old buffer\n",
168 (void) free((char *)tmpbuf
);
173 return (RaiseError(AUDIO_UNIXERROR
));
176 bufsize
= (size_t)size
;
177 return (AUDIO_SUCCESS
);
181 // Return the buffer address
185 return (GetAddress(0.));
188 // Return the buffer address at a given time offset
189 // Returns NULL if no buffer, or the position is not within the buffer.
196 AudioHdr(AudioBuffer::*hfunc
)()const;
198 addr
= (char *)bufaddr
;
199 if ((addr
== 0) || (pos
< 0.) || (pos
>= buflen
))
202 // If no offset, it's ok if the header hasn't been set yet
204 return ((void*) addr
);
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())
212 addr
+= hdr_local
.Time_to_Bytes(pos
);
214 // One more validation, to be paranoid before handing out this address
215 if (addr
>= ((char *)bufaddr
+ bufsize
))
217 return ((void*) addr
);
220 // Return the buffer size, in bytes
221 // (as opposed to 'length' which indicates how much data is in the buffer)
228 // Return the buffer size, in seconds
229 // (as opposed to 'length' which indicates how much data is in the buffer)
236 // Set the buffer size, allocating the buffer as necessary
237 AudioError
AudioBuffer::
239 Double len
) // new size, in seconds
241 // If no change in size, do nothing
243 return (AUDIO_SUCCESS
);
245 // If header not set, store the size for later
248 return (AUDIO_SUCCESS
);
251 // If shrinking buffer, note this
252 if (buflen
< GetLength())
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::
262 const AudioHdr
& h
) // header to copy
266 // Validate, then update the header
269 return (RaiseError(err
));
270 (void) AudioStream::updateheader(h
);
272 // If no size set, done for now
274 return (AUDIO_SUCCESS
);
276 // If no buffer allocated, allocate one now
277 if (GetAddress() == 0)
280 // If buffer allocated, change size to match new header
281 buflen
= h
.Bytes_to_Time(GetByteCount());
282 return (AUDIO_SUCCESS
);
285 // Set the buffer length (ie, the amount of data written to the buffer)
288 Double len
) // new length
290 if (!hdrset() || (len
< 0.)) // no-op if not ready
292 if (!opened() && (len
> 0.))
295 if (Undefined(len
) || (len
> GetSize())) {
296 // Limit to the size of the buffer
297 setlength(GetSize());
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::
308 void* buf
, // destination buffer address
309 size_t& len
, // buffer length (updated)
310 Double
& pos
) // start position (updated)
317 // Copy length, zero return value
321 // Cannot read if buffer or header not valid
323 return (RaiseError(AUDIO_ERR_NOEFFECT
));
325 // Position must be valid
326 if ((pos
< 0.) || (cnt
< 0))
327 return (RaiseError(AUDIO_ERR_BADARG
));
329 // If the starting offset is at or beyond EOF, return eof flag
330 if (pos
>= GetLength()) {
332 err
.sys
= AUDIO_COPY_INPUT_EOF
;
336 // Limit transfer to remaining room in buffer
337 offset
= GetHeader().Time_to_Bytes(pos
);
338 resid
= GetHeader().Time_to_Bytes(GetLength()) - offset
;
341 err
.sys
= AUDIO_COPY_INPUT_EOF
;
347 // Fix the alignment to make sure we're not splitting frames
349 if (GetHeader().Bytes_to_Bytes(cnt
) > 0) {
350 // Copy as much data as possible
351 memcpy((char *)buf
, (char *)((off_t
)GetAddress() + offset
),
354 err
.sys
= AUDIO_COPY_ZERO_LIMIT
;
357 // Return the updated transfer size and position
359 pos
= GetHeader().Bytes_to_Time(offset
+ cnt
);
362 // Check to see if the endian is right.
363 coerceEndian((unsigned char *)buf
, len
, localByteOrder());
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::
373 void* buf
, // source buffer address
374 size_t& len
, // buffer length (updated)
375 Double
& pos
) // start position (updated)
382 // Copy length, zero return value
386 // Cannot write if buffer or header not valid
388 return (RaiseError(AUDIO_ERR_NOEFFECT
));
390 // Position must be valid
391 if ((pos
< 0.) || (cnt
< 0))
392 return (RaiseError(AUDIO_ERR_BADARG
));
394 // If the starting offset beyond end of buffer, return short write flag
395 if (pos
>= GetSize()) {
397 err
.sys
= AUDIO_COPY_OUTPUT_EOF
;
401 // Limit transfer to remaining room in buffer
402 offset
= GetHeader().Time_to_Bytes(pos
);
403 resid
= (off_t
)bufsize
- offset
;
406 err
.sys
= AUDIO_COPY_OUTPUT_EOF
;
412 // Fix the alignment to make sure we're not splitting frames
414 if (GetHeader().Bytes_to_Bytes(cnt
) > 0) {
415 // Copy as much data as possible
416 memcpy((char *)((off_t
)GetAddress() + offset
), (char *)buf
,
419 err
.sys
= AUDIO_COPY_ZERO_LIMIT
;
422 // Return the updated transfer size and position
424 pos
= GetHeader().Bytes_to_Time(offset
+ cnt
);
426 // The end of a write to a buffer always becomes the buffer EOF
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::
436 void* buf
, // source buffer address
437 size_t& len
, // buffer length (updated)
438 Double
& pos
) // start position (updated)
443 // Cannot write if header not valid
445 return (RaiseError(AUDIO_ERR_NOEFFECT
));
447 // Position must be valid
449 return (RaiseError(AUDIO_ERR_BADARG
));
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
))
457 return (WriteData(buf
, len
, pos
));
460 // Copy routine to copy direct to destination
461 AudioError
AudioBuffer::
463 Audio
* to
, // audio object to copy to
477 // Cannot write if buffer or header not valid
479 return (RaiseError(AUDIO_ERR_NOEFFECT
));
481 tohdr
= to
->GetHeader();
483 return (RaiseError(AUDIO_ERR_BADARG
));
485 // Get maximum possible copy length
486 svfrom
= GetLength();
487 if (frompos
>= svfrom
) {
490 err
.sys
= AUDIO_COPY_INPUT_EOF
;
493 lim
= svfrom
- frompos
;
494 if (!Undefined(limit
) && (limit
< lim
))
499 bptr
= (caddr_t
)GetAddress(frompos
);
502 err
.sys
= AUDIO_COPY_INPUT_EOF
;
505 cnt
= (size_t)GetHeader().Time_to_Bytes(lim
);
508 err
.sys
= AUDIO_COPY_ZERO_LIMIT
;
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
);
518 if (GetHeader().Bytes_to_Bytes(cnt
) == 0) {
520 err
.sys
= AUDIO_COPY_INPUT_EOF
;
524 // Write the data to the destination and update pointers/ctrs
528 err
= to
->WriteData(bptr
, cnt
, topos
);
529 limit
= topos
- svto
;
530 frompos
= svfrom
+ limit
;
532 // Report short writes
533 if (!err
&& (cnt
< svcnt
)) {
534 err
.sys
= AUDIO_COPY_SHORT_OUTPUT
;