4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1993-2001 by Sun Microsystems, Inc.
24 * All rights reserved.
27 #pragma ident "%Z%%M% %I% %E% SMI"
33 #include <AudioDebug.h>
34 #include <AudioBuffer.h>
36 // class Audio methods
39 // Initialize monotonically increasing id counter
46 const char *str
): // name
47 id(++idctr
), refcnt(0), readpos(0.), writepos(0.), errorfunc(0)
51 s
= (char *)((str
== NULL
) ? "" : str
);
52 name
= new char[strlen(s
) + 1];
53 (void) strcpy(name
, s
);
56 // errorfunc is always set if compiling DEBUG;
57 // otherwise, only if requested
60 errorfunc
= AudioStderrMsg
;
61 PrintMsg(_MGET_("Audio object create"), InitMessage
);
68 // If there are outstanding references, there is a programming error
70 PrintMsg(_MGET_("Audio object multiple destroy"), InitFatal
);
71 } else if (refcnt
> 0) {
72 PrintMsg(_MGET_("Referenced Audio object destroyed"),
76 PrintMsg(_MGET_("Audio object destroy"), InitMessage
);
84 AudioError code
, // error code
85 AudioSeverity sev
, // error severity
86 char *msg
) const // additional message
88 if (code
== AUDIO_SUCCESS
)
92 // XXX - Userfunc return value ignored for now
93 (void) (*errorfunc
)(this, code
, sev
, msg
);
95 if ((sev
== Fatal
) || (sev
== InitFatal
))
100 // Print out messages
103 char *msg
, // error message
104 AudioSeverity sev
) const // error severity
106 if (errorfunc
!= 0) {
107 // XXX - Userfunc return value ignored for now
108 (void) (*errorfunc
)(this, AUDIO_NOERROR
, sev
, msg
);
111 if ((sev
== Fatal
) || (sev
== InitFatal
)) {
112 fprintf(stderr
, _MGET_("** Fatal Error: %s\n"), msg
);
117 // Increment reference count
122 PrintMsg(_MGET_("Reference to destroyed Audio object"), Fatal
);
128 // Decrement reference count
133 PrintMsg(_MGET_("Dereference of destroyed Audio object"),
135 } else if (refcnt
== 0) {
136 PrintMsg(_MGET_("Audio object dereference underflow"), Fatal
);
137 } else if (--refcnt
== 0) { // If this was the last reference,
138 delete this; // blow the object away
142 // Reset the stored name
145 const char *str
) // new name string
148 name
= new char[strlen(str
) + 1];
149 (void) strcpy(name
, str
);
153 // Set the current read/write position pointer
156 Double
& pos
, // field to update
157 Double newpos
, // new position
158 Whence w
) // Absolute || Relative || Relative_eof
160 if (w
== Relative
) // offset from current position
162 else if (w
== Relative_eof
) { // offset from end-of-file
163 if (!Undefined(GetLength()))
164 newpos
+= GetLength();
166 return (AUDIO_UNKNOWN_TIME
);
169 // If seek before start of file, set to start of file
176 // Set a new read position
179 Double pos
, // new position or offset
180 Whence w
) // Absolute | Relative
182 return (setpos(readpos
, pos
, w
));
185 // Set a new write position
188 Double pos
, // new position or offset
189 Whence w
) // Absolute | Relative
191 return (setpos(writepos
, pos
, w
));
194 // Default read routine reads from the current position
197 void* buf
, // buffer address
198 size_t& len
) // buffer length (updated)
200 // ReadData updates the position argument
201 return (ReadData(buf
, len
, readpos
));
204 // Default write routine writes to the current position
207 void* buf
, // buffer address
208 size_t& len
) // buffer length (updated)
210 // WriteData updates the position argument
211 return (WriteData(buf
, len
, writepos
));
214 // Default append routine should be specialized, if the object is fixed-length
217 void* buf
, // buffer address
218 size_t& len
, // buffer length (updated)
219 Double
& pos
) // write position (updated)
221 // The default action is just to write the data.
222 // Subclasses, like AudioBuffer, should specialize this method
223 // to extend the object, if necessary.
224 return (WriteData(buf
, len
, pos
));
227 // Copy out to the specified audio object.
228 // Input and output positions default to the 'current' positions.
231 Audio
* to
) // audio object to copy to
233 Double frompos
= AUDIO_UNKNOWN_TIME
;
234 Double topos
= AUDIO_UNKNOWN_TIME
;
235 Double limit
= AUDIO_UNKNOWN_TIME
;
237 return (Copy(to
, frompos
, topos
, limit
));
240 // Default Copy out routine. Specify the destination audio object,
241 // and src/dest start offsets. limit is either the time to copy or
242 // AUDIO_UNKNOWN_TIME to copy to eof or error.
243 // frompos and topos are updated with the final positions.
244 // limit is updated with the amount of data actually copied.
247 Audio
* to
, // audio object to copy to
256 // If positions are Undefined, try to set them properly
257 if (Undefined(frompos
))
258 frompos
= ReadPosition();
259 if (Undefined(topos
))
260 topos
= to
->WritePosition();
264 // Calculate remaining copy size
265 if (Undefined(limit
)) {
268 len
= limit
- (frompos
- svpos
);
273 err
= AsyncCopy(to
, frompos
, topos
, len
);
280 // XXX - What do we do with short writes?
281 // This routine is meant to block until all the
282 // data has been copied. So copies to a pipe or
283 // device should continue. However, copies to a
284 // buffer (or extent or list?) will never go any
286 // For now, punt and return immediately.
287 case AUDIO_COPY_SHORT_OUTPUT
:
290 // If a zero-length transfer was requested, we're done
291 case AUDIO_COPY_ZERO_LIMIT
:
294 // If the input would block, we're done
295 case AUDIO_COPY_SHORT_INPUT
:
299 } while (err
== AUDIO_SUCCESS
);
301 // Calculate total transfer count
302 limit
= frompos
- svpos
;
304 // Declare victory if anything was copied
306 return (AUDIO_SUCCESS
);
310 // Default Data Copy out routine. Like Copy(), but only does one segment.
311 // If either src or dest are set non-blocking, a partial transfer may occur.
312 // Returns AUDIO_SUCCESS on normal completion, regardless of how much data
313 // was actually transferred (err.sys: AUDIO_COPY_SHORT_INPUT if input would
314 // block; AUDIO_COPY_ZERO_LIMIT if a zero-length copy was requested).
315 // Returns AUDIO_SUCCESS (err.sys: AUDIO_COPY_SHORT_OUTPUT) if more data was
316 // read than could be copied out (eg, if there was a short write to a
317 // non-blocking output). Short writes result in the input pointer being
318 // backed up to the right place in the input stream.
319 // Returns AUDIO_EOF if input or output position beyond end-of-file.
321 // XXX - If the input cannot seek backwards, this routine will spin trying
322 // to finish writing all input data to the output. We need to keep
323 // partial data in a state structure.
326 Audio
* to
, // audio object to copy to
340 // Validate basic arguments and state
341 tohdr
= to
->GetHeader();
342 if (err
= tohdr
.Validate())
345 return (RaiseError(AUDIO_ERR_BADARG
));
346 lim
= (size_t)tohdr
.Time_to_Bytes(limit
);
348 // If the destination is an AudioBuffer, we can copy more directly
349 if (to
->isBuffer()) {
350 tob
= (AudioBuffer
*) to
;
352 // Get the buffer address at the starting offset
353 bptr
= (caddr_t
)tob
->GetAddress(topos
);
354 bufsiz
= bptr
- (caddr_t
)tob
->GetAddress();
355 if ((bptr
== NULL
) || (tob
->GetByteCount() <= bufsiz
)) {
358 err
.sys
= AUDIO_COPY_OUTPUT_EOF
;
361 bufsiz
= tob
->GetByteCount() - bufsiz
;
363 // Limit the data transfer by the limit argument
364 if (!Undefined(limit
) && (lim
< bufsiz
))
367 // Read the data directly into buffer
368 (void) tohdr
.Bytes_to_Bytes(bufsiz
);
369 err
= ReadData((void*) bptr
, bufsiz
, frompos
);
370 limit
= tohdr
.Bytes_to_Time(bufsiz
);
372 tob
->SetLength(topos
);
376 // XXX - temporary bogus implementation
377 // XXX - max transfer buf will be 2 seconds of data (1 sec for stereo)
378 if (tohdr
.channels
< 2) {
379 bufsiz
= (size_t)tohdr
.Time_to_Bytes(2.0);
381 bufsiz
= (size_t)tohdr
.Time_to_Bytes(1.0);
383 if (!Undefined(limit
) && (lim
< bufsiz
))
387 if ((bptr
= new char[bufsiz
]) == NULL
)
388 return (AUDIO_UNIXERROR
);
391 err
= ReadData((void*)bptr
, bufsiz
, frompos
);
395 if (tohdr
.Bytes_to_Bytes(bufsiz
) != lim
) {
397 "Read returned a fraction of a sample frame?!\n"));
401 err
= to
->WriteData(bptr
, bufsiz
, topos
);
402 limit
= topos
- svto
;
404 // If the write was short, back up the input pointer
407 if (tohdr
.Bytes_to_Bytes(bufsiz
) != lim
) {
409 "Write returned a fraction of a sample frame?!\n"));
411 frompos
= svfrom
+ limit
;
413 err
.sys
= AUDIO_COPY_SHORT_OUTPUT
;