8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / audio / utilities / Audio.cc
blob938bab7d361c6a645661dd9b2b0ee02b541c173d
1 /*
2 * CDDL HEADER START
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
7 * with the License.
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]
20 * CDDL HEADER END
23 * Copyright (c) 1993-2001 by Sun Microsystems, Inc.
24 * All rights reserved.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <string.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <Audio.h>
33 #include <AudioDebug.h>
34 #include <AudioBuffer.h>
36 // class Audio methods
39 // Initialize monotonically increasing id counter
40 int
41 Audio::idctr = 0;
43 // Constructor
44 Audio::
45 Audio(
46 const char *str): // name
47 id(++idctr), refcnt(0), readpos(0.), writepos(0.), errorfunc(0)
49 char *s;
51 s = (char *)((str == NULL) ? "" : str);
52 name = new char[strlen(s) + 1];
53 (void) strcpy(name, s);
55 #ifndef DEBUG
56 // errorfunc is always set if compiling DEBUG;
57 // otherwise, only if requested
58 if (GetDebug() > 0)
59 #endif
60 errorfunc = AudioStderrMsg;
61 PrintMsg(_MGET_("Audio object create"), InitMessage);
64 // Destructor
65 Audio::
66 ~Audio()
68 // If there are outstanding references, there is a programming error
69 if (refcnt < 0) {
70 PrintMsg(_MGET_("Audio object multiple destroy"), InitFatal);
71 } else if (refcnt > 0) {
72 PrintMsg(_MGET_("Referenced Audio object destroyed"),
73 InitFatal);
74 } else {
75 refcnt = -1;
76 PrintMsg(_MGET_("Audio object destroy"), InitMessage);
78 delete name;
81 // Raise error code
82 AudioError Audio::
83 RaiseError(
84 AudioError code, // error code
85 AudioSeverity sev, // error severity
86 char *msg) const // additional message
88 if (code == AUDIO_SUCCESS)
89 return (code);
91 if (errorfunc != 0) {
92 // XXX - Userfunc return value ignored for now
93 (void) (*errorfunc)(this, code, sev, msg);
95 if ((sev == Fatal) || (sev == InitFatal))
96 abort();
97 return (code);
100 // Print out messages
101 void Audio::
102 PrintMsg(
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);
113 abort();
117 // Increment reference count
118 void Audio::
119 Reference()
121 if (refcnt < 0) {
122 PrintMsg(_MGET_("Reference to destroyed Audio object"), Fatal);
123 } else {
124 refcnt++;
128 // Decrement reference count
129 void Audio::
130 Dereference()
132 if (refcnt < 0) {
133 PrintMsg(_MGET_("Dereference of destroyed Audio object"),
134 Fatal);
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
143 void Audio::
144 SetName(
145 const char *str) // new name string
147 delete name;
148 name = new char[strlen(str) + 1];
149 (void) strcpy(name, str);
153 // Set the current read/write position pointer
154 Double Audio::
155 setpos(
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
161 newpos += pos;
162 else if (w == Relative_eof) { // offset from end-of-file
163 if (!Undefined(GetLength()))
164 newpos += GetLength();
165 else
166 return (AUDIO_UNKNOWN_TIME);
169 // If seek before start of file, set to start of file
170 if (newpos < 0.)
171 newpos = 0.;
172 pos = newpos;
173 return (pos);
176 // Set a new read position
177 Double Audio::
178 SetReadPosition(
179 Double pos, // new position or offset
180 Whence w) // Absolute | Relative
182 return (setpos(readpos, pos, w));
185 // Set a new write position
186 Double Audio::
187 SetWritePosition(
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
195 AudioError Audio::
196 Read(
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
205 AudioError Audio::
206 Write(
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
215 AudioError Audio::
216 AppendData(
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.
229 AudioError Audio::
230 Copy(
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.
245 AudioError Audio::
246 Copy(
247 Audio* to, // audio object to copy to
248 Double& frompos,
249 Double& topos,
250 Double& limit)
252 Double len;
253 Double svpos;
254 AudioError err;
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();
262 svpos = frompos;
263 do {
264 // Calculate remaining copy size
265 if (Undefined(limit)) {
266 len = limit;
267 } else {
268 len = limit - (frompos - svpos);
269 if (len < 0.)
270 len = 0.;
272 // Copy one segment
273 err = AsyncCopy(to, frompos, topos, len);
274 if (!err) {
275 switch (err.sys) {
276 default:
277 case 0:
278 break;
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
285 // further.
286 // For now, punt and return immediately.
287 case AUDIO_COPY_SHORT_OUTPUT:
288 goto outofloop;
290 // If a zero-length transfer was requested, we're done
291 case AUDIO_COPY_ZERO_LIMIT:
292 goto outofloop;
294 // If the input would block, we're done
295 case AUDIO_COPY_SHORT_INPUT:
296 goto outofloop;
299 } while (err == AUDIO_SUCCESS);
300 outofloop:
301 // Calculate total transfer count
302 limit = frompos - svpos;
304 // Declare victory if anything was copied
305 if (limit > 0.)
306 return (AUDIO_SUCCESS);
307 return (err);
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.
324 AudioError Audio::
325 AsyncCopy(
326 Audio* to, // audio object to copy to
327 Double& frompos,
328 Double& topos,
329 Double& limit)
331 caddr_t bptr;
332 size_t bufsiz;
333 size_t lim;
334 Double svfrom;
335 Double svto;
336 AudioBuffer* tob;
337 AudioHdr tohdr;
338 AudioError err;
340 // Validate basic arguments and state
341 tohdr = to->GetHeader();
342 if (err = tohdr.Validate())
343 return (err);
344 if (limit < 0.)
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)) {
356 limit = 0.;
357 err = AUDIO_EOF;
358 err.sys = AUDIO_COPY_OUTPUT_EOF;
359 return (err);
361 bufsiz = tob->GetByteCount() - bufsiz;
363 // Limit the data transfer by the limit argument
364 if (!Undefined(limit) && (lim < bufsiz))
365 bufsiz = lim;
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);
371 topos += limit;
372 tob->SetLength(topos);
373 return (err);
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);
380 } else {
381 bufsiz = (size_t)tohdr.Time_to_Bytes(1.0);
383 if (!Undefined(limit) && (lim < bufsiz))
384 bufsiz = lim;
386 limit = 0.;
387 if ((bptr = new char[bufsiz]) == NULL)
388 return (AUDIO_UNIXERROR);
390 svfrom = frompos;
391 err = ReadData((void*)bptr, bufsiz, frompos);
392 if (!err) {
393 svto = topos;
394 lim = bufsiz;
395 if (tohdr.Bytes_to_Bytes(bufsiz) != lim) {
396 AUDIO_DEBUG((1,
397 "Read returned a fraction of a sample frame?!\n"));
398 lim = bufsiz;
400 if (bufsiz > 0) {
401 err = to->WriteData(bptr, bufsiz, topos);
402 limit = topos - svto;
404 // If the write was short, back up the input pointer
405 if (bufsiz < lim) {
406 lim = bufsiz;
407 if (tohdr.Bytes_to_Bytes(bufsiz) != lim) {
408 AUDIO_DEBUG((1,
409 "Write returned a fraction of a sample frame?!\n"));
411 frompos = svfrom + limit;
412 if (!err)
413 err.sys = AUDIO_COPY_SHORT_OUTPUT;
417 delete bptr;
418 return (err);