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