xref: /titanic_50/usr/src/cmd/audio/utilities/Audio.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) 1993-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 <string.h>
30*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
31*7c478bd9Sstevel@tonic-gate #include <stdio.h>
32*7c478bd9Sstevel@tonic-gate #include <Audio.h>
33*7c478bd9Sstevel@tonic-gate #include <AudioDebug.h>
34*7c478bd9Sstevel@tonic-gate #include <AudioBuffer.h>
35*7c478bd9Sstevel@tonic-gate 
36*7c478bd9Sstevel@tonic-gate // class Audio methods
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate // Initialize monotonically increasing id counter
40*7c478bd9Sstevel@tonic-gate int
41*7c478bd9Sstevel@tonic-gate Audio::idctr = 0;
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate // Constructor
44*7c478bd9Sstevel@tonic-gate Audio::
Audio(const char * str)45*7c478bd9Sstevel@tonic-gate Audio(
46*7c478bd9Sstevel@tonic-gate 	const char	*str):				// name
47*7c478bd9Sstevel@tonic-gate 	id(++idctr), refcnt(0), readpos(0.), writepos(0.), errorfunc(0)
48*7c478bd9Sstevel@tonic-gate {
49*7c478bd9Sstevel@tonic-gate 	char		*s;
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate 	s = (char *)((str == NULL) ? "" : str);
52*7c478bd9Sstevel@tonic-gate 	name = new char[strlen(s) + 1];
53*7c478bd9Sstevel@tonic-gate 	(void) strcpy(name, s);
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate #ifndef DEBUG
56*7c478bd9Sstevel@tonic-gate 	// errorfunc is always set if compiling DEBUG;
57*7c478bd9Sstevel@tonic-gate 	// otherwise, only if requested
58*7c478bd9Sstevel@tonic-gate 	if (GetDebug() > 0)
59*7c478bd9Sstevel@tonic-gate #endif
60*7c478bd9Sstevel@tonic-gate 		errorfunc = AudioStderrMsg;
61*7c478bd9Sstevel@tonic-gate 	PrintMsg(_MGET_("Audio object create"), InitMessage);
62*7c478bd9Sstevel@tonic-gate }
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate // Destructor
65*7c478bd9Sstevel@tonic-gate Audio::
~Audio()66*7c478bd9Sstevel@tonic-gate ~Audio()
67*7c478bd9Sstevel@tonic-gate {
68*7c478bd9Sstevel@tonic-gate 	// If there are outstanding references, there is a programming error
69*7c478bd9Sstevel@tonic-gate 	if (refcnt < 0) {
70*7c478bd9Sstevel@tonic-gate 		PrintMsg(_MGET_("Audio object multiple destroy"), InitFatal);
71*7c478bd9Sstevel@tonic-gate 	} else if (refcnt > 0) {
72*7c478bd9Sstevel@tonic-gate 		PrintMsg(_MGET_("Referenced Audio object destroyed"),
73*7c478bd9Sstevel@tonic-gate 		    InitFatal);
74*7c478bd9Sstevel@tonic-gate 	} else {
75*7c478bd9Sstevel@tonic-gate 		refcnt = -1;
76*7c478bd9Sstevel@tonic-gate 		PrintMsg(_MGET_("Audio object destroy"), InitMessage);
77*7c478bd9Sstevel@tonic-gate 	}
78*7c478bd9Sstevel@tonic-gate 	delete name;
79*7c478bd9Sstevel@tonic-gate }
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate // Raise error code
82*7c478bd9Sstevel@tonic-gate AudioError Audio::
RaiseError(AudioError code,AudioSeverity sev,char * msg) const83*7c478bd9Sstevel@tonic-gate RaiseError(
84*7c478bd9Sstevel@tonic-gate 	AudioError	code,			// error code
85*7c478bd9Sstevel@tonic-gate 	AudioSeverity	sev,			// error severity
86*7c478bd9Sstevel@tonic-gate 	char		*msg) const		// additional message
87*7c478bd9Sstevel@tonic-gate {
88*7c478bd9Sstevel@tonic-gate 	if (code == AUDIO_SUCCESS)
89*7c478bd9Sstevel@tonic-gate 		return (code);
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate 	if (errorfunc != 0) {
92*7c478bd9Sstevel@tonic-gate 		// XXX - Userfunc return value ignored for now
93*7c478bd9Sstevel@tonic-gate 		(void) (*errorfunc)(this, code, sev, msg);
94*7c478bd9Sstevel@tonic-gate 	}
95*7c478bd9Sstevel@tonic-gate 	if ((sev == Fatal) || (sev == InitFatal))
96*7c478bd9Sstevel@tonic-gate 		abort();
97*7c478bd9Sstevel@tonic-gate 	return (code);
98*7c478bd9Sstevel@tonic-gate }
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate // Print out messages
101*7c478bd9Sstevel@tonic-gate void Audio::
PrintMsg(char * msg,AudioSeverity sev) const102*7c478bd9Sstevel@tonic-gate PrintMsg(
103*7c478bd9Sstevel@tonic-gate 	char		*msg,			// error message
104*7c478bd9Sstevel@tonic-gate 	AudioSeverity	sev) const		// error severity
105*7c478bd9Sstevel@tonic-gate {
106*7c478bd9Sstevel@tonic-gate 	if (errorfunc != 0) {
107*7c478bd9Sstevel@tonic-gate 		// XXX - Userfunc return value ignored for now
108*7c478bd9Sstevel@tonic-gate 		(void) (*errorfunc)(this, AUDIO_NOERROR, sev, msg);
109*7c478bd9Sstevel@tonic-gate 	}
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate 	if ((sev == Fatal) || (sev == InitFatal)) {
112*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, _MGET_("** Fatal Error: %s\n"), msg);
113*7c478bd9Sstevel@tonic-gate 		abort();
114*7c478bd9Sstevel@tonic-gate 	}
115*7c478bd9Sstevel@tonic-gate }
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate // Increment reference count
118*7c478bd9Sstevel@tonic-gate void Audio::
Reference()119*7c478bd9Sstevel@tonic-gate Reference()
120*7c478bd9Sstevel@tonic-gate {
121*7c478bd9Sstevel@tonic-gate 	if (refcnt < 0) {
122*7c478bd9Sstevel@tonic-gate 		PrintMsg(_MGET_("Reference to destroyed Audio object"), Fatal);
123*7c478bd9Sstevel@tonic-gate 	} else {
124*7c478bd9Sstevel@tonic-gate 		refcnt++;
125*7c478bd9Sstevel@tonic-gate 	}
126*7c478bd9Sstevel@tonic-gate }
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate // Decrement reference count
129*7c478bd9Sstevel@tonic-gate void Audio::
Dereference()130*7c478bd9Sstevel@tonic-gate Dereference()
131*7c478bd9Sstevel@tonic-gate {
132*7c478bd9Sstevel@tonic-gate 	if (refcnt < 0) {
133*7c478bd9Sstevel@tonic-gate 		PrintMsg(_MGET_("Dereference of destroyed Audio object"),
134*7c478bd9Sstevel@tonic-gate 		    Fatal);
135*7c478bd9Sstevel@tonic-gate 	} else if (refcnt == 0) {
136*7c478bd9Sstevel@tonic-gate 		PrintMsg(_MGET_("Audio object dereference underflow"), Fatal);
137*7c478bd9Sstevel@tonic-gate 	} else if (--refcnt == 0) {	// If this was the last reference,
138*7c478bd9Sstevel@tonic-gate 		delete this;		//  blow the object away
139*7c478bd9Sstevel@tonic-gate 	}
140*7c478bd9Sstevel@tonic-gate }
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate // Reset the stored name
143*7c478bd9Sstevel@tonic-gate void Audio::
SetName(const char * str)144*7c478bd9Sstevel@tonic-gate SetName(
145*7c478bd9Sstevel@tonic-gate 	const char	*str)		// new name string
146*7c478bd9Sstevel@tonic-gate {
147*7c478bd9Sstevel@tonic-gate 	delete name;
148*7c478bd9Sstevel@tonic-gate 	name = new char[strlen(str) + 1];
149*7c478bd9Sstevel@tonic-gate 	(void) strcpy(name, str);
150*7c478bd9Sstevel@tonic-gate }
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate // Set the current read/write position pointer
154*7c478bd9Sstevel@tonic-gate Double Audio::
setpos(Double & pos,Double newpos,Whence w)155*7c478bd9Sstevel@tonic-gate setpos(
156*7c478bd9Sstevel@tonic-gate 	Double&	pos,			// field to update
157*7c478bd9Sstevel@tonic-gate 	Double	newpos,			// new position
158*7c478bd9Sstevel@tonic-gate 	Whence	w)			// Absolute || Relative || Relative_eof
159*7c478bd9Sstevel@tonic-gate {
160*7c478bd9Sstevel@tonic-gate 	if (w == Relative)			// offset from current position
161*7c478bd9Sstevel@tonic-gate 		newpos += pos;
162*7c478bd9Sstevel@tonic-gate 	else if (w == Relative_eof) {		// offset from end-of-file
163*7c478bd9Sstevel@tonic-gate 		if (!Undefined(GetLength()))
164*7c478bd9Sstevel@tonic-gate 			newpos += GetLength();
165*7c478bd9Sstevel@tonic-gate 		else
166*7c478bd9Sstevel@tonic-gate 			return (AUDIO_UNKNOWN_TIME);
167*7c478bd9Sstevel@tonic-gate 	}
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 	// If seek before start of file, set to start of file
170*7c478bd9Sstevel@tonic-gate 	if (newpos < 0.)
171*7c478bd9Sstevel@tonic-gate 		newpos = 0.;
172*7c478bd9Sstevel@tonic-gate 	pos = newpos;
173*7c478bd9Sstevel@tonic-gate 	return (pos);
174*7c478bd9Sstevel@tonic-gate }
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate // Set a new read position
177*7c478bd9Sstevel@tonic-gate Double Audio::
SetReadPosition(Double pos,Whence w)178*7c478bd9Sstevel@tonic-gate SetReadPosition(
179*7c478bd9Sstevel@tonic-gate 	Double		pos,		// new position or offset
180*7c478bd9Sstevel@tonic-gate 	Whence		w)		// Absolute | Relative
181*7c478bd9Sstevel@tonic-gate {
182*7c478bd9Sstevel@tonic-gate 	return (setpos(readpos, pos, w));
183*7c478bd9Sstevel@tonic-gate }
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate // Set a new write position
186*7c478bd9Sstevel@tonic-gate Double Audio::
SetWritePosition(Double pos,Whence w)187*7c478bd9Sstevel@tonic-gate SetWritePosition(
188*7c478bd9Sstevel@tonic-gate 	Double		pos,		// new position or offset
189*7c478bd9Sstevel@tonic-gate 	Whence		w)		// Absolute | Relative
190*7c478bd9Sstevel@tonic-gate {
191*7c478bd9Sstevel@tonic-gate 	return (setpos(writepos, pos, w));
192*7c478bd9Sstevel@tonic-gate }
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate // Default read routine reads from the current position
195*7c478bd9Sstevel@tonic-gate AudioError Audio::
Read(void * buf,size_t & len)196*7c478bd9Sstevel@tonic-gate Read(
197*7c478bd9Sstevel@tonic-gate 	void*		buf,			// buffer address
198*7c478bd9Sstevel@tonic-gate 	size_t&		len)			// buffer length (updated)
199*7c478bd9Sstevel@tonic-gate {
200*7c478bd9Sstevel@tonic-gate 	// ReadData updates the position argument
201*7c478bd9Sstevel@tonic-gate 	return (ReadData(buf, len, readpos));
202*7c478bd9Sstevel@tonic-gate }
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate // Default write routine writes to the current position
205*7c478bd9Sstevel@tonic-gate AudioError Audio::
Write(void * buf,size_t & len)206*7c478bd9Sstevel@tonic-gate Write(
207*7c478bd9Sstevel@tonic-gate 	void*		buf,			// buffer address
208*7c478bd9Sstevel@tonic-gate 	size_t&		len)			// buffer length (updated)
209*7c478bd9Sstevel@tonic-gate {
210*7c478bd9Sstevel@tonic-gate 	// WriteData updates the position argument
211*7c478bd9Sstevel@tonic-gate 	return (WriteData(buf, len, writepos));
212*7c478bd9Sstevel@tonic-gate }
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate // Default append routine should be specialized, if the object is fixed-length
215*7c478bd9Sstevel@tonic-gate AudioError Audio::
AppendData(void * buf,size_t & len,Double & pos)216*7c478bd9Sstevel@tonic-gate AppendData(
217*7c478bd9Sstevel@tonic-gate 	void*		buf,			// buffer address
218*7c478bd9Sstevel@tonic-gate 	size_t&		len,			// buffer length (updated)
219*7c478bd9Sstevel@tonic-gate 	Double&		pos)			// write position (updated)
220*7c478bd9Sstevel@tonic-gate {
221*7c478bd9Sstevel@tonic-gate 	// The default action is just to write the data.
222*7c478bd9Sstevel@tonic-gate 	// Subclasses, like AudioBuffer, should specialize this method
223*7c478bd9Sstevel@tonic-gate 	// to extend the object, if necessary.
224*7c478bd9Sstevel@tonic-gate 	return (WriteData(buf, len, pos));
225*7c478bd9Sstevel@tonic-gate }
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate // Copy out to the specified audio object.
228*7c478bd9Sstevel@tonic-gate // Input and output positions default to the 'current' positions.
229*7c478bd9Sstevel@tonic-gate AudioError Audio::
Copy(Audio * to)230*7c478bd9Sstevel@tonic-gate Copy(
231*7c478bd9Sstevel@tonic-gate 	Audio*		to)			// audio object to copy to
232*7c478bd9Sstevel@tonic-gate {
233*7c478bd9Sstevel@tonic-gate 	Double		frompos = AUDIO_UNKNOWN_TIME;
234*7c478bd9Sstevel@tonic-gate 	Double		topos = AUDIO_UNKNOWN_TIME;
235*7c478bd9Sstevel@tonic-gate 	Double		limit = AUDIO_UNKNOWN_TIME;
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate 	return (Copy(to, frompos, topos, limit));
238*7c478bd9Sstevel@tonic-gate }
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate // Default Copy out routine. Specify the destination audio object,
241*7c478bd9Sstevel@tonic-gate // and src/dest start offsets.  limit is either the time to copy or
242*7c478bd9Sstevel@tonic-gate // AUDIO_UNKNOWN_TIME to copy to eof or error.
243*7c478bd9Sstevel@tonic-gate // frompos and topos are updated with the final positions.
244*7c478bd9Sstevel@tonic-gate // limit is updated with the amount of data actually copied.
245*7c478bd9Sstevel@tonic-gate AudioError Audio::
Copy(Audio * to,Double & frompos,Double & topos,Double & limit)246*7c478bd9Sstevel@tonic-gate Copy(
247*7c478bd9Sstevel@tonic-gate 	Audio*		to,			// audio object to copy to
248*7c478bd9Sstevel@tonic-gate 	Double&		frompos,
249*7c478bd9Sstevel@tonic-gate 	Double&		topos,
250*7c478bd9Sstevel@tonic-gate 	Double&		limit)
251*7c478bd9Sstevel@tonic-gate {
252*7c478bd9Sstevel@tonic-gate 	Double		len;
253*7c478bd9Sstevel@tonic-gate 	Double		svpos;
254*7c478bd9Sstevel@tonic-gate 	AudioError	err;
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 	// If positions are Undefined, try to set them properly
257*7c478bd9Sstevel@tonic-gate 	if (Undefined(frompos))
258*7c478bd9Sstevel@tonic-gate 		frompos = ReadPosition();
259*7c478bd9Sstevel@tonic-gate 	if (Undefined(topos))
260*7c478bd9Sstevel@tonic-gate 		topos = to->WritePosition();
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate 	svpos = frompos;
263*7c478bd9Sstevel@tonic-gate 	do {
264*7c478bd9Sstevel@tonic-gate 		// Calculate remaining copy size
265*7c478bd9Sstevel@tonic-gate 		if (Undefined(limit)) {
266*7c478bd9Sstevel@tonic-gate 			len = limit;
267*7c478bd9Sstevel@tonic-gate 		} else {
268*7c478bd9Sstevel@tonic-gate 			len = limit - (frompos - svpos);
269*7c478bd9Sstevel@tonic-gate 			if (len < 0.)
270*7c478bd9Sstevel@tonic-gate 				len = 0.;
271*7c478bd9Sstevel@tonic-gate 		}
272*7c478bd9Sstevel@tonic-gate 		// Copy one segment
273*7c478bd9Sstevel@tonic-gate 		err = AsyncCopy(to, frompos, topos, len);
274*7c478bd9Sstevel@tonic-gate 		if (!err) {
275*7c478bd9Sstevel@tonic-gate 			switch (err.sys) {
276*7c478bd9Sstevel@tonic-gate 			default:
277*7c478bd9Sstevel@tonic-gate 			case 0:
278*7c478bd9Sstevel@tonic-gate 				break;
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 			// XXX - What do we do with short writes?
281*7c478bd9Sstevel@tonic-gate 			//	 This routine is meant to block until all the
282*7c478bd9Sstevel@tonic-gate 			//	 data has been copied.  So copies to a pipe or
283*7c478bd9Sstevel@tonic-gate 			//	 device should continue.  However, copies to a
284*7c478bd9Sstevel@tonic-gate 			//	 buffer (or extent or list?) will never go any
285*7c478bd9Sstevel@tonic-gate 			//	further.
286*7c478bd9Sstevel@tonic-gate 			// For now, punt and return immediately.
287*7c478bd9Sstevel@tonic-gate 			case AUDIO_COPY_SHORT_OUTPUT:
288*7c478bd9Sstevel@tonic-gate 				goto outofloop;
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 			// If a zero-length transfer was requested, we're done
291*7c478bd9Sstevel@tonic-gate 			case AUDIO_COPY_ZERO_LIMIT:
292*7c478bd9Sstevel@tonic-gate 				goto outofloop;
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 			// If the input would block, we're done
295*7c478bd9Sstevel@tonic-gate 			case AUDIO_COPY_SHORT_INPUT:
296*7c478bd9Sstevel@tonic-gate 				goto outofloop;
297*7c478bd9Sstevel@tonic-gate 			}
298*7c478bd9Sstevel@tonic-gate 		}
299*7c478bd9Sstevel@tonic-gate 	} while (err == AUDIO_SUCCESS);
300*7c478bd9Sstevel@tonic-gate outofloop:
301*7c478bd9Sstevel@tonic-gate 	// Calculate total transfer count
302*7c478bd9Sstevel@tonic-gate 	limit = frompos - svpos;
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate 	// Declare victory if anything was copied
305*7c478bd9Sstevel@tonic-gate 	if (limit > 0.)
306*7c478bd9Sstevel@tonic-gate 		return (AUDIO_SUCCESS);
307*7c478bd9Sstevel@tonic-gate 	return (err);
308*7c478bd9Sstevel@tonic-gate }
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate // Default Data Copy out routine. Like Copy(), but only does one segment.
311*7c478bd9Sstevel@tonic-gate // If either src or dest are set non-blocking, a partial transfer may occur.
312*7c478bd9Sstevel@tonic-gate // Returns AUDIO_SUCCESS on normal completion, regardless of how much data
313*7c478bd9Sstevel@tonic-gate // was actually transferred (err.sys: AUDIO_COPY_SHORT_INPUT if input would
314*7c478bd9Sstevel@tonic-gate // block;  AUDIO_COPY_ZERO_LIMIT if a zero-length copy was requested).
315*7c478bd9Sstevel@tonic-gate // Returns AUDIO_SUCCESS (err.sys: AUDIO_COPY_SHORT_OUTPUT) if more data was
316*7c478bd9Sstevel@tonic-gate // read than could be copied out (eg, if there was a short write to a
317*7c478bd9Sstevel@tonic-gate // non-blocking output).  Short writes result in the input pointer being
318*7c478bd9Sstevel@tonic-gate // backed up to the right place in the input stream.
319*7c478bd9Sstevel@tonic-gate // Returns AUDIO_EOF if input or output position beyond end-of-file.
320*7c478bd9Sstevel@tonic-gate //
321*7c478bd9Sstevel@tonic-gate // XXX - If the input cannot seek backwards, this routine will spin trying
322*7c478bd9Sstevel@tonic-gate //	 to finish writing all input data to the output.  We need to keep
323*7c478bd9Sstevel@tonic-gate //	 partial data in a state structure.
324*7c478bd9Sstevel@tonic-gate AudioError Audio::
AsyncCopy(Audio * to,Double & frompos,Double & topos,Double & limit)325*7c478bd9Sstevel@tonic-gate AsyncCopy(
326*7c478bd9Sstevel@tonic-gate 	Audio*		to,			// audio object to copy to
327*7c478bd9Sstevel@tonic-gate 	Double&		frompos,
328*7c478bd9Sstevel@tonic-gate 	Double&		topos,
329*7c478bd9Sstevel@tonic-gate 	Double&		limit)
330*7c478bd9Sstevel@tonic-gate {
331*7c478bd9Sstevel@tonic-gate 	caddr_t		bptr;
332*7c478bd9Sstevel@tonic-gate 	size_t		bufsiz;
333*7c478bd9Sstevel@tonic-gate 	size_t		lim;
334*7c478bd9Sstevel@tonic-gate 	Double		svfrom;
335*7c478bd9Sstevel@tonic-gate 	Double		svto;
336*7c478bd9Sstevel@tonic-gate 	AudioBuffer*	tob;
337*7c478bd9Sstevel@tonic-gate 	AudioHdr	tohdr;
338*7c478bd9Sstevel@tonic-gate 	AudioError	err;
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate 	// Validate basic arguments and state
341*7c478bd9Sstevel@tonic-gate 	tohdr = to->GetHeader();
342*7c478bd9Sstevel@tonic-gate 	if (err = tohdr.Validate())
343*7c478bd9Sstevel@tonic-gate 		return (err);
344*7c478bd9Sstevel@tonic-gate 	if (limit < 0.)
345*7c478bd9Sstevel@tonic-gate 		return (RaiseError(AUDIO_ERR_BADARG));
346*7c478bd9Sstevel@tonic-gate 	lim = (size_t)tohdr.Time_to_Bytes(limit);
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 	// If the destination is an AudioBuffer, we can copy more directly
349*7c478bd9Sstevel@tonic-gate 	if (to->isBuffer()) {
350*7c478bd9Sstevel@tonic-gate 		tob = (AudioBuffer*) to;
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 		// Get the buffer address at the starting offset
353*7c478bd9Sstevel@tonic-gate 		bptr = (caddr_t)tob->GetAddress(topos);
354*7c478bd9Sstevel@tonic-gate 		bufsiz = bptr - (caddr_t)tob->GetAddress();
355*7c478bd9Sstevel@tonic-gate 		if ((bptr == NULL) || (tob->GetByteCount() <= bufsiz)) {
356*7c478bd9Sstevel@tonic-gate 			limit = 0.;
357*7c478bd9Sstevel@tonic-gate 			err = AUDIO_EOF;
358*7c478bd9Sstevel@tonic-gate 			err.sys = AUDIO_COPY_OUTPUT_EOF;
359*7c478bd9Sstevel@tonic-gate 			return (err);
360*7c478bd9Sstevel@tonic-gate 		}
361*7c478bd9Sstevel@tonic-gate 		bufsiz = tob->GetByteCount() - bufsiz;
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate 		// Limit the data transfer by the limit argument
364*7c478bd9Sstevel@tonic-gate 		if (!Undefined(limit) && (lim < bufsiz))
365*7c478bd9Sstevel@tonic-gate 			bufsiz = lim;
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate 		// Read the data directly into buffer
368*7c478bd9Sstevel@tonic-gate 		(void) tohdr.Bytes_to_Bytes(bufsiz);
369*7c478bd9Sstevel@tonic-gate 		err = ReadData((void*) bptr, bufsiz, frompos);
370*7c478bd9Sstevel@tonic-gate 		limit = tohdr.Bytes_to_Time(bufsiz);
371*7c478bd9Sstevel@tonic-gate 		topos += limit;
372*7c478bd9Sstevel@tonic-gate 		tob->SetLength(topos);
373*7c478bd9Sstevel@tonic-gate 		return (err);
374*7c478bd9Sstevel@tonic-gate 	}
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate 	// XXX - temporary bogus implementation
377*7c478bd9Sstevel@tonic-gate 	// XXX - max transfer buf will be 2 seconds of data (1 sec for stereo)
378*7c478bd9Sstevel@tonic-gate 	if (tohdr.channels < 2) {
379*7c478bd9Sstevel@tonic-gate 		bufsiz = (size_t)tohdr.Time_to_Bytes(2.0);
380*7c478bd9Sstevel@tonic-gate 	} else {
381*7c478bd9Sstevel@tonic-gate 		bufsiz = (size_t)tohdr.Time_to_Bytes(1.0);
382*7c478bd9Sstevel@tonic-gate 	}
383*7c478bd9Sstevel@tonic-gate 	if (!Undefined(limit) && (lim < bufsiz))
384*7c478bd9Sstevel@tonic-gate 		bufsiz = lim;
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 	limit = 0.;
387*7c478bd9Sstevel@tonic-gate 	if ((bptr = new char[bufsiz]) == NULL)
388*7c478bd9Sstevel@tonic-gate 		return (AUDIO_UNIXERROR);
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate 	svfrom = frompos;
391*7c478bd9Sstevel@tonic-gate 	err = ReadData((void*)bptr, bufsiz, frompos);
392*7c478bd9Sstevel@tonic-gate 	if (!err) {
393*7c478bd9Sstevel@tonic-gate 		svto = topos;
394*7c478bd9Sstevel@tonic-gate 		lim = bufsiz;
395*7c478bd9Sstevel@tonic-gate 		if (tohdr.Bytes_to_Bytes(bufsiz) != lim) {
396*7c478bd9Sstevel@tonic-gate 			AUDIO_DEBUG((1,
397*7c478bd9Sstevel@tonic-gate 			    "Read returned a fraction of a sample frame?!\n"));
398*7c478bd9Sstevel@tonic-gate 			lim = bufsiz;
399*7c478bd9Sstevel@tonic-gate 		}
400*7c478bd9Sstevel@tonic-gate 		if (bufsiz > 0) {
401*7c478bd9Sstevel@tonic-gate 			err = to->WriteData(bptr, bufsiz, topos);
402*7c478bd9Sstevel@tonic-gate 			limit = topos - svto;
403*7c478bd9Sstevel@tonic-gate 
404*7c478bd9Sstevel@tonic-gate 			// If the write was short, back up the input pointer
405*7c478bd9Sstevel@tonic-gate 			if (bufsiz < lim) {
406*7c478bd9Sstevel@tonic-gate 				lim = bufsiz;
407*7c478bd9Sstevel@tonic-gate 				if (tohdr.Bytes_to_Bytes(bufsiz) != lim) {
408*7c478bd9Sstevel@tonic-gate 					AUDIO_DEBUG((1,
409*7c478bd9Sstevel@tonic-gate 		    "Write returned a fraction of a sample frame?!\n"));
410*7c478bd9Sstevel@tonic-gate 				}
411*7c478bd9Sstevel@tonic-gate 				frompos = svfrom + limit;
412*7c478bd9Sstevel@tonic-gate 				if (!err)
413*7c478bd9Sstevel@tonic-gate 					err.sys = AUDIO_COPY_SHORT_OUTPUT;
414*7c478bd9Sstevel@tonic-gate 			}
415*7c478bd9Sstevel@tonic-gate 		}
416*7c478bd9Sstevel@tonic-gate 	}
417*7c478bd9Sstevel@tonic-gate 	delete bptr;
418*7c478bd9Sstevel@tonic-gate 	return (err);
419*7c478bd9Sstevel@tonic-gate }
420