17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright (c) 1993-2001 by Sun Microsystems, Inc.
247c478bd9Sstevel@tonic-gate  * All rights reserved.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <string.h>
287c478bd9Sstevel@tonic-gate #include <stdlib.h>
297c478bd9Sstevel@tonic-gate #include <stdio.h>
307c478bd9Sstevel@tonic-gate #include <Audio.h>
317c478bd9Sstevel@tonic-gate #include <AudioDebug.h>
327c478bd9Sstevel@tonic-gate #include <AudioBuffer.h>
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate // class Audio methods
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate // Initialize monotonically increasing id counter
387c478bd9Sstevel@tonic-gate int
397c478bd9Sstevel@tonic-gate Audio::idctr = 0;
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate // Constructor
427c478bd9Sstevel@tonic-gate Audio::
Audio(const char * str)437c478bd9Sstevel@tonic-gate Audio(
447c478bd9Sstevel@tonic-gate 	const char	*str):				// name
457c478bd9Sstevel@tonic-gate 	id(++idctr), refcnt(0), readpos(0.), writepos(0.), errorfunc(0)
467c478bd9Sstevel@tonic-gate {
477c478bd9Sstevel@tonic-gate 	char		*s;
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate 	s = (char *)((str == NULL) ? "" : str);
507c478bd9Sstevel@tonic-gate 	name = new char[strlen(s) + 1];
517c478bd9Sstevel@tonic-gate 	(void) strcpy(name, s);
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate #ifndef DEBUG
547c478bd9Sstevel@tonic-gate 	// errorfunc is always set if compiling DEBUG;
557c478bd9Sstevel@tonic-gate 	// otherwise, only if requested
567c478bd9Sstevel@tonic-gate 	if (GetDebug() > 0)
577c478bd9Sstevel@tonic-gate #endif
587c478bd9Sstevel@tonic-gate 		errorfunc = AudioStderrMsg;
597c478bd9Sstevel@tonic-gate 	PrintMsg(_MGET_("Audio object create"), InitMessage);
607c478bd9Sstevel@tonic-gate }
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate // Destructor
637c478bd9Sstevel@tonic-gate Audio::
~Audio()647c478bd9Sstevel@tonic-gate ~Audio()
657c478bd9Sstevel@tonic-gate {
667c478bd9Sstevel@tonic-gate 	// If there are outstanding references, there is a programming error
677c478bd9Sstevel@tonic-gate 	if (refcnt < 0) {
687c478bd9Sstevel@tonic-gate 		PrintMsg(_MGET_("Audio object multiple destroy"), InitFatal);
697c478bd9Sstevel@tonic-gate 	} else if (refcnt > 0) {
707c478bd9Sstevel@tonic-gate 		PrintMsg(_MGET_("Referenced Audio object destroyed"),
717c478bd9Sstevel@tonic-gate 		    InitFatal);
727c478bd9Sstevel@tonic-gate 	} else {
737c478bd9Sstevel@tonic-gate 		refcnt = -1;
747c478bd9Sstevel@tonic-gate 		PrintMsg(_MGET_("Audio object destroy"), InitMessage);
757c478bd9Sstevel@tonic-gate 	}
767c478bd9Sstevel@tonic-gate 	delete name;
777c478bd9Sstevel@tonic-gate }
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate // Raise error code
807c478bd9Sstevel@tonic-gate AudioError Audio::
RaiseError(AudioError code,AudioSeverity sev,const char * msg) const817c478bd9Sstevel@tonic-gate RaiseError(
827c478bd9Sstevel@tonic-gate 	AudioError	code,			// error code
837c478bd9Sstevel@tonic-gate 	AudioSeverity	sev,			// error severity
84779d9599SToomas Soome 	const char	*msg) const		// additional message
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate 	if (code == AUDIO_SUCCESS)
877c478bd9Sstevel@tonic-gate 		return (code);
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	if (errorfunc != 0) {
907c478bd9Sstevel@tonic-gate 		// XXX - Userfunc return value ignored for now
917c478bd9Sstevel@tonic-gate 		(void) (*errorfunc)(this, code, sev, msg);
927c478bd9Sstevel@tonic-gate 	}
937c478bd9Sstevel@tonic-gate 	if ((sev == Fatal) || (sev == InitFatal))
947c478bd9Sstevel@tonic-gate 		abort();
957c478bd9Sstevel@tonic-gate 	return (code);
967c478bd9Sstevel@tonic-gate }
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate // Print out messages
997c478bd9Sstevel@tonic-gate void Audio::
PrintMsg(char * msg,AudioSeverity sev) const1007c478bd9Sstevel@tonic-gate PrintMsg(
1017c478bd9Sstevel@tonic-gate 	char		*msg,			// error message
1027c478bd9Sstevel@tonic-gate 	AudioSeverity	sev) const		// error severity
1037c478bd9Sstevel@tonic-gate {
1047c478bd9Sstevel@tonic-gate 	if (errorfunc != 0) {
1057c478bd9Sstevel@tonic-gate 		// XXX - Userfunc return value ignored for now
1067c478bd9Sstevel@tonic-gate 		(void) (*errorfunc)(this, AUDIO_NOERROR, sev, msg);
1077c478bd9Sstevel@tonic-gate 	}
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 	if ((sev == Fatal) || (sev == InitFatal)) {
1107c478bd9Sstevel@tonic-gate 		fprintf(stderr, _MGET_("** Fatal Error: %s\n"), msg);
1117c478bd9Sstevel@tonic-gate 		abort();
1127c478bd9Sstevel@tonic-gate 	}
1137c478bd9Sstevel@tonic-gate }
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate // Increment reference count
1167c478bd9Sstevel@tonic-gate void Audio::
Reference()1177c478bd9Sstevel@tonic-gate Reference()
1187c478bd9Sstevel@tonic-gate {
1197c478bd9Sstevel@tonic-gate 	if (refcnt < 0) {
1207c478bd9Sstevel@tonic-gate 		PrintMsg(_MGET_("Reference to destroyed Audio object"), Fatal);
1217c478bd9Sstevel@tonic-gate 	} else {
1227c478bd9Sstevel@tonic-gate 		refcnt++;
1237c478bd9Sstevel@tonic-gate 	}
1247c478bd9Sstevel@tonic-gate }
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate // Decrement reference count
1277c478bd9Sstevel@tonic-gate void Audio::
Dereference()1287c478bd9Sstevel@tonic-gate Dereference()
1297c478bd9Sstevel@tonic-gate {
1307c478bd9Sstevel@tonic-gate 	if (refcnt < 0) {
1317c478bd9Sstevel@tonic-gate 		PrintMsg(_MGET_("Dereference of destroyed Audio object"),
1327c478bd9Sstevel@tonic-gate 		    Fatal);
1337c478bd9Sstevel@tonic-gate 	} else if (refcnt == 0) {
1347c478bd9Sstevel@tonic-gate 		PrintMsg(_MGET_("Audio object dereference underflow"), Fatal);
1357c478bd9Sstevel@tonic-gate 	} else if (--refcnt == 0) {	// If this was the last reference,
1367c478bd9Sstevel@tonic-gate 		delete this;		//  blow the object away
1377c478bd9Sstevel@tonic-gate 	}
1387c478bd9Sstevel@tonic-gate }
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate // Reset the stored name
1417c478bd9Sstevel@tonic-gate void Audio::
SetName(const char * str)1427c478bd9Sstevel@tonic-gate SetName(
1437c478bd9Sstevel@tonic-gate 	const char	*str)		// new name string
1447c478bd9Sstevel@tonic-gate {
1457c478bd9Sstevel@tonic-gate 	delete name;
1467c478bd9Sstevel@tonic-gate 	name = new char[strlen(str) + 1];
1477c478bd9Sstevel@tonic-gate 	(void) strcpy(name, str);
1487c478bd9Sstevel@tonic-gate }
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate // Set the current read/write position pointer
1527c478bd9Sstevel@tonic-gate Double Audio::
setpos(Double & pos,Double newpos,Whence w)1537c478bd9Sstevel@tonic-gate setpos(
1547c478bd9Sstevel@tonic-gate 	Double&	pos,			// field to update
1557c478bd9Sstevel@tonic-gate 	Double	newpos,			// new position
1567c478bd9Sstevel@tonic-gate 	Whence	w)			// Absolute || Relative || Relative_eof
1577c478bd9Sstevel@tonic-gate {
1587c478bd9Sstevel@tonic-gate 	if (w == Relative)			// offset from current position
1597c478bd9Sstevel@tonic-gate 		newpos += pos;
1607c478bd9Sstevel@tonic-gate 	else if (w == Relative_eof) {		// offset from end-of-file
1617c478bd9Sstevel@tonic-gate 		if (!Undefined(GetLength()))
1627c478bd9Sstevel@tonic-gate 			newpos += GetLength();
1637c478bd9Sstevel@tonic-gate 		else
1647c478bd9Sstevel@tonic-gate 			return (AUDIO_UNKNOWN_TIME);
1657c478bd9Sstevel@tonic-gate 	}
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	// If seek before start of file, set to start of file
1687c478bd9Sstevel@tonic-gate 	if (newpos < 0.)
1697c478bd9Sstevel@tonic-gate 		newpos = 0.;
1707c478bd9Sstevel@tonic-gate 	pos = newpos;
1717c478bd9Sstevel@tonic-gate 	return (pos);
1727c478bd9Sstevel@tonic-gate }
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate // Set a new read position
1757c478bd9Sstevel@tonic-gate Double Audio::
SetReadPosition(Double pos,Whence w)1767c478bd9Sstevel@tonic-gate SetReadPosition(
1777c478bd9Sstevel@tonic-gate 	Double		pos,		// new position or offset
1787c478bd9Sstevel@tonic-gate 	Whence		w)		// Absolute | Relative
1797c478bd9Sstevel@tonic-gate {
1807c478bd9Sstevel@tonic-gate 	return (setpos(readpos, pos, w));
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate // Set a new write position
1847c478bd9Sstevel@tonic-gate Double Audio::
SetWritePosition(Double pos,Whence w)1857c478bd9Sstevel@tonic-gate SetWritePosition(
1867c478bd9Sstevel@tonic-gate 	Double		pos,		// new position or offset
1877c478bd9Sstevel@tonic-gate 	Whence		w)		// Absolute | Relative
1887c478bd9Sstevel@tonic-gate {
1897c478bd9Sstevel@tonic-gate 	return (setpos(writepos, pos, w));
1907c478bd9Sstevel@tonic-gate }
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate // Default read routine reads from the current position
1937c478bd9Sstevel@tonic-gate AudioError Audio::
Read(void * buf,size_t & len)1947c478bd9Sstevel@tonic-gate Read(
1957c478bd9Sstevel@tonic-gate 	void*		buf,			// buffer address
1967c478bd9Sstevel@tonic-gate 	size_t&		len)			// buffer length (updated)
1977c478bd9Sstevel@tonic-gate {
1987c478bd9Sstevel@tonic-gate 	// ReadData updates the position argument
1997c478bd9Sstevel@tonic-gate 	return (ReadData(buf, len, readpos));
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate // Default write routine writes to the current position
2037c478bd9Sstevel@tonic-gate AudioError Audio::
Write(void * buf,size_t & len)2047c478bd9Sstevel@tonic-gate Write(
2057c478bd9Sstevel@tonic-gate 	void*		buf,			// buffer address
2067c478bd9Sstevel@tonic-gate 	size_t&		len)			// buffer length (updated)
2077c478bd9Sstevel@tonic-gate {
2087c478bd9Sstevel@tonic-gate 	// WriteData updates the position argument
2097c478bd9Sstevel@tonic-gate 	return (WriteData(buf, len, writepos));
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate // Default append routine should be specialized, if the object is fixed-length
2137c478bd9Sstevel@tonic-gate AudioError Audio::
AppendData(void * buf,size_t & len,Double & pos)2147c478bd9Sstevel@tonic-gate AppendData(
2157c478bd9Sstevel@tonic-gate 	void*		buf,			// buffer address
2167c478bd9Sstevel@tonic-gate 	size_t&		len,			// buffer length (updated)
2177c478bd9Sstevel@tonic-gate 	Double&		pos)			// write position (updated)
2187c478bd9Sstevel@tonic-gate {
2197c478bd9Sstevel@tonic-gate 	// The default action is just to write the data.
2207c478bd9Sstevel@tonic-gate 	// Subclasses, like AudioBuffer, should specialize this method
2217c478bd9Sstevel@tonic-gate 	// to extend the object, if necessary.
2227c478bd9Sstevel@tonic-gate 	return (WriteData(buf, len, pos));
2237c478bd9Sstevel@tonic-gate }
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate // Copy out to the specified audio object.
2267c478bd9Sstevel@tonic-gate // Input and output positions default to the 'current' positions.
2277c478bd9Sstevel@tonic-gate AudioError Audio::
Copy(Audio * to)2287c478bd9Sstevel@tonic-gate Copy(
2297c478bd9Sstevel@tonic-gate 	Audio*		to)			// audio object to copy to
2307c478bd9Sstevel@tonic-gate {
2317c478bd9Sstevel@tonic-gate 	Double		frompos = AUDIO_UNKNOWN_TIME;
2327c478bd9Sstevel@tonic-gate 	Double		topos = AUDIO_UNKNOWN_TIME;
2337c478bd9Sstevel@tonic-gate 	Double		limit = AUDIO_UNKNOWN_TIME;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	return (Copy(to, frompos, topos, limit));
2367c478bd9Sstevel@tonic-gate }
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate // Default Copy out routine. Specify the destination audio object,
2397c478bd9Sstevel@tonic-gate // and src/dest start offsets.  limit is either the time to copy or
2407c478bd9Sstevel@tonic-gate // AUDIO_UNKNOWN_TIME to copy to eof or error.
2417c478bd9Sstevel@tonic-gate // frompos and topos are updated with the final positions.
2427c478bd9Sstevel@tonic-gate // limit is updated with the amount of data actually copied.
2437c478bd9Sstevel@tonic-gate AudioError Audio::
Copy(Audio * to,Double & frompos,Double & topos,Double & limit)2447c478bd9Sstevel@tonic-gate Copy(
2457c478bd9Sstevel@tonic-gate 	Audio*		to,			// audio object to copy to
2467c478bd9Sstevel@tonic-gate 	Double&		frompos,
2477c478bd9Sstevel@tonic-gate 	Double&		topos,
2487c478bd9Sstevel@tonic-gate 	Double&		limit)
2497c478bd9Sstevel@tonic-gate {
2507c478bd9Sstevel@tonic-gate 	Double		len;
2517c478bd9Sstevel@tonic-gate 	Double		svpos;
2527c478bd9Sstevel@tonic-gate 	AudioError	err;
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	// If positions are Undefined, try to set them properly
2557c478bd9Sstevel@tonic-gate 	if (Undefined(frompos))
2567c478bd9Sstevel@tonic-gate 		frompos = ReadPosition();
2577c478bd9Sstevel@tonic-gate 	if (Undefined(topos))
2587c478bd9Sstevel@tonic-gate 		topos = to->WritePosition();
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	svpos = frompos;
2617c478bd9Sstevel@tonic-gate 	do {
2627c478bd9Sstevel@tonic-gate 		// Calculate remaining copy size
2637c478bd9Sstevel@tonic-gate 		if (Undefined(limit)) {
2647c478bd9Sstevel@tonic-gate 			len = limit;
2657c478bd9Sstevel@tonic-gate 		} else {
2667c478bd9Sstevel@tonic-gate 			len = limit - (frompos - svpos);
2677c478bd9Sstevel@tonic-gate 			if (len < 0.)
2687c478bd9Sstevel@tonic-gate 				len = 0.;
2697c478bd9Sstevel@tonic-gate 		}
2707c478bd9Sstevel@tonic-gate 		// Copy one segment
2717c478bd9Sstevel@tonic-gate 		err = AsyncCopy(to, frompos, topos, len);
2727c478bd9Sstevel@tonic-gate 		if (!err) {
2737c478bd9Sstevel@tonic-gate 			switch (err.sys) {
2747c478bd9Sstevel@tonic-gate 			default:
2757c478bd9Sstevel@tonic-gate 			case 0:
2767c478bd9Sstevel@tonic-gate 				break;
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 			// XXX - What do we do with short writes?
2797c478bd9Sstevel@tonic-gate 			//	 This routine is meant to block until all the
2807c478bd9Sstevel@tonic-gate 			//	 data has been copied.  So copies to a pipe or
2817c478bd9Sstevel@tonic-gate 			//	 device should continue.  However, copies to a
2827c478bd9Sstevel@tonic-gate 			//	 buffer (or extent or list?) will never go any
2837c478bd9Sstevel@tonic-gate 			//	further.
2847c478bd9Sstevel@tonic-gate 			// For now, punt and return immediately.
2857c478bd9Sstevel@tonic-gate 			case AUDIO_COPY_SHORT_OUTPUT:
2867c478bd9Sstevel@tonic-gate 				goto outofloop;
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 			// If a zero-length transfer was requested, we're done
2897c478bd9Sstevel@tonic-gate 			case AUDIO_COPY_ZERO_LIMIT:
2907c478bd9Sstevel@tonic-gate 				goto outofloop;
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 			// If the input would block, we're done
2937c478bd9Sstevel@tonic-gate 			case AUDIO_COPY_SHORT_INPUT:
2947c478bd9Sstevel@tonic-gate 				goto outofloop;
2957c478bd9Sstevel@tonic-gate 			}
2967c478bd9Sstevel@tonic-gate 		}
2977c478bd9Sstevel@tonic-gate 	} while (err == AUDIO_SUCCESS);
2987c478bd9Sstevel@tonic-gate outofloop:
2997c478bd9Sstevel@tonic-gate 	// Calculate total transfer count
3007c478bd9Sstevel@tonic-gate 	limit = frompos - svpos;
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	// Declare victory if anything was copied
3037c478bd9Sstevel@tonic-gate 	if (limit > 0.)
3047c478bd9Sstevel@tonic-gate 		return (AUDIO_SUCCESS);
3057c478bd9Sstevel@tonic-gate 	return (err);
3067c478bd9Sstevel@tonic-gate }
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate // Default Data Copy out routine. Like Copy(), but only does one segment.
3097c478bd9Sstevel@tonic-gate // If either src or dest are set non-blocking, a partial transfer may occur.
3107c478bd9Sstevel@tonic-gate // Returns AUDIO_SUCCESS on normal completion, regardless of how much data
3117c478bd9Sstevel@tonic-gate // was actually transferred (err.sys: AUDIO_COPY_SHORT_INPUT if input would
3127c478bd9Sstevel@tonic-gate // block;  AUDIO_COPY_ZERO_LIMIT if a zero-length copy was requested).
3137c478bd9Sstevel@tonic-gate // Returns AUDIO_SUCCESS (err.sys: AUDIO_COPY_SHORT_OUTPUT) if more data was
3147c478bd9Sstevel@tonic-gate // read than could be copied out (eg, if there was a short write to a
3157c478bd9Sstevel@tonic-gate // non-blocking output).  Short writes result in the input pointer being
3167c478bd9Sstevel@tonic-gate // backed up to the right place in the input stream.
3177c478bd9Sstevel@tonic-gate // Returns AUDIO_EOF if input or output position beyond end-of-file.
3187c478bd9Sstevel@tonic-gate //
3197c478bd9Sstevel@tonic-gate // XXX - If the input cannot seek backwards, this routine will spin trying
3207c478bd9Sstevel@tonic-gate //	 to finish writing all input data to the output.  We need to keep
3217c478bd9Sstevel@tonic-gate //	 partial data in a state structure.
3227c478bd9Sstevel@tonic-gate AudioError Audio::
AsyncCopy(Audio * to,Double & frompos,Double & topos,Double & limit)3237c478bd9Sstevel@tonic-gate AsyncCopy(
3247c478bd9Sstevel@tonic-gate 	Audio*		to,			// audio object to copy to
3257c478bd9Sstevel@tonic-gate 	Double&		frompos,
3267c478bd9Sstevel@tonic-gate 	Double&		topos,
3277c478bd9Sstevel@tonic-gate 	Double&		limit)
3287c478bd9Sstevel@tonic-gate {
3297c478bd9Sstevel@tonic-gate 	caddr_t		bptr;
3307c478bd9Sstevel@tonic-gate 	size_t		bufsiz;
3317c478bd9Sstevel@tonic-gate 	size_t		lim;
3327c478bd9Sstevel@tonic-gate 	Double		svfrom;
3337c478bd9Sstevel@tonic-gate 	Double		svto;
3347c478bd9Sstevel@tonic-gate 	AudioBuffer*	tob;
3357c478bd9Sstevel@tonic-gate 	AudioHdr	tohdr;
3367c478bd9Sstevel@tonic-gate 	AudioError	err;
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	// Validate basic arguments and state
3397c478bd9Sstevel@tonic-gate 	tohdr = to->GetHeader();
3407c478bd9Sstevel@tonic-gate 	if (err = tohdr.Validate())
3417c478bd9Sstevel@tonic-gate 		return (err);
3427c478bd9Sstevel@tonic-gate 	if (limit < 0.)
3437c478bd9Sstevel@tonic-gate 		return (RaiseError(AUDIO_ERR_BADARG));
3447c478bd9Sstevel@tonic-gate 	lim = (size_t)tohdr.Time_to_Bytes(limit);
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	// If the destination is an AudioBuffer, we can copy more directly
3477c478bd9Sstevel@tonic-gate 	if (to->isBuffer()) {
3487c478bd9Sstevel@tonic-gate 		tob = (AudioBuffer*) to;
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 		// Get the buffer address at the starting offset
3517c478bd9Sstevel@tonic-gate 		bptr = (caddr_t)tob->GetAddress(topos);
3527c478bd9Sstevel@tonic-gate 		bufsiz = bptr - (caddr_t)tob->GetAddress();
3537c478bd9Sstevel@tonic-gate 		if ((bptr == NULL) || (tob->GetByteCount() <= bufsiz)) {
3547c478bd9Sstevel@tonic-gate 			limit = 0.;
3557c478bd9Sstevel@tonic-gate 			err = AUDIO_EOF;
3567c478bd9Sstevel@tonic-gate 			err.sys = AUDIO_COPY_OUTPUT_EOF;
3577c478bd9Sstevel@tonic-gate 			return (err);
3587c478bd9Sstevel@tonic-gate 		}
3597c478bd9Sstevel@tonic-gate 		bufsiz = tob->GetByteCount() - bufsiz;
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 		// Limit the data transfer by the limit argument
3627c478bd9Sstevel@tonic-gate 		if (!Undefined(limit) && (lim < bufsiz))
3637c478bd9Sstevel@tonic-gate 			bufsiz = lim;
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 		// Read the data directly into buffer
3667c478bd9Sstevel@tonic-gate 		(void) tohdr.Bytes_to_Bytes(bufsiz);
3677c478bd9Sstevel@tonic-gate 		err = ReadData((void*) bptr, bufsiz, frompos);
3687c478bd9Sstevel@tonic-gate 		limit = tohdr.Bytes_to_Time(bufsiz);
3697c478bd9Sstevel@tonic-gate 		topos += limit;
3707c478bd9Sstevel@tonic-gate 		tob->SetLength(topos);
3717c478bd9Sstevel@tonic-gate 		return (err);
3727c478bd9Sstevel@tonic-gate 	}
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	// XXX - temporary bogus implementation
3757c478bd9Sstevel@tonic-gate 	// XXX - max transfer buf will be 2 seconds of data (1 sec for stereo)
3767c478bd9Sstevel@tonic-gate 	if (tohdr.channels < 2) {
3777c478bd9Sstevel@tonic-gate 		bufsiz = (size_t)tohdr.Time_to_Bytes(2.0);
3787c478bd9Sstevel@tonic-gate 	} else {
3797c478bd9Sstevel@tonic-gate 		bufsiz = (size_t)tohdr.Time_to_Bytes(1.0);
3807c478bd9Sstevel@tonic-gate 	}
3817c478bd9Sstevel@tonic-gate 	if (!Undefined(limit) && (lim < bufsiz))
3827c478bd9Sstevel@tonic-gate 		bufsiz = lim;
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	limit = 0.;
3857c478bd9Sstevel@tonic-gate 	if ((bptr = new char[bufsiz]) == NULL)
3867c478bd9Sstevel@tonic-gate 		return (AUDIO_UNIXERROR);
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	svfrom = frompos;
3897c478bd9Sstevel@tonic-gate 	err = ReadData((void*)bptr, bufsiz, frompos);
3907c478bd9Sstevel@tonic-gate 	if (!err) {
3917c478bd9Sstevel@tonic-gate 		svto = topos;
3927c478bd9Sstevel@tonic-gate 		lim = bufsiz;
3937c478bd9Sstevel@tonic-gate 		if (tohdr.Bytes_to_Bytes(bufsiz) != lim) {
3947c478bd9Sstevel@tonic-gate 			AUDIO_DEBUG((1,
3957c478bd9Sstevel@tonic-gate 			    "Read returned a fraction of a sample frame?!\n"));
3967c478bd9Sstevel@tonic-gate 			lim = bufsiz;
3977c478bd9Sstevel@tonic-gate 		}
3987c478bd9Sstevel@tonic-gate 		if (bufsiz > 0) {
3997c478bd9Sstevel@tonic-gate 			err = to->WriteData(bptr, bufsiz, topos);
4007c478bd9Sstevel@tonic-gate 			limit = topos - svto;
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 			// If the write was short, back up the input pointer
4037c478bd9Sstevel@tonic-gate 			if (bufsiz < lim) {
4047c478bd9Sstevel@tonic-gate 				lim = bufsiz;
4057c478bd9Sstevel@tonic-gate 				if (tohdr.Bytes_to_Bytes(bufsiz) != lim) {
4067c478bd9Sstevel@tonic-gate 					AUDIO_DEBUG((1,
4077c478bd9Sstevel@tonic-gate 		    "Write returned a fraction of a sample frame?!\n"));
4087c478bd9Sstevel@tonic-gate 				}
4097c478bd9Sstevel@tonic-gate 				frompos = svfrom + limit;
4107c478bd9Sstevel@tonic-gate 				if (!err)
4117c478bd9Sstevel@tonic-gate 					err.sys = AUDIO_COPY_SHORT_OUTPUT;
4127c478bd9Sstevel@tonic-gate 			}
4137c478bd9Sstevel@tonic-gate 		}
4147c478bd9Sstevel@tonic-gate 	}
415*7cad4b84SToomas Soome 	delete[] bptr;
4167c478bd9Sstevel@tonic-gate 	return (err);
4177c478bd9Sstevel@tonic-gate }
418