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