1 /*
2 * CDDL HEADER START
3 *
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.
8 *
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.
13 *
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]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 1993-2001 by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <AudioExtent.h>
30 #include <AudioList.h>
31 #include <AudioDebug.h>
32
33 // class AudioList methods
34
35
36 // class AudioListEntry Constructor
37 AudioList::AudioListEntry::
AudioListEntry(Audio * obj)38 AudioListEntry(
39 Audio* obj): // audio object to point to
40 aptr(0), next(0), prev(0)
41 {
42 // A NULL object is only valid in dummy entries, such as list heads
43 newptr(obj);
44 }
45
46 // class AudioListEntry Destructor
47 AudioList::AudioListEntry::
~AudioListEntry()48 ~AudioListEntry()
49 {
50 newptr(0);
51 if (next != 0) {
52 next->prev = prev;
53 }
54 if (prev != 0) {
55 prev->next = next;
56 }
57 }
58
59 // Set a new extent pointer in an AudioListEntry
60 void AudioList::AudioListEntry::
newptr(Audio * newa)61 newptr(
62 Audio* newa) // new object
63 {
64 if (aptr != 0)
65 aptr->Dereference();
66 aptr = newa;
67 if (aptr != 0)
68 aptr->Reference();
69 }
70
71 // Link object into list
72 // Link in a new AudioListEntry
73 void AudioList::AudioListEntry::
link(AudioListEntry * after)74 link(
75 AudioListEntry* after) // link after this one
76 {
77 // Link object into list
78 prev = after;
79 next = after->next;
80 after->next = this;
81 if (next != 0)
82 next->prev = this;
83 }
84
85 // Split an AudioListEntry at the specified offset
86 void AudioList::AudioListEntry::
split(Double pos)87 split(
88 Double pos) // split offset
89 {
90 AudioExtent* e1;
91 AudioExtent* e2;
92 AudioListEntry* newp;
93
94 // Create two extents referencing this object
95 e1 = new AudioExtent(aptr, 0., pos);
96 e2 = new AudioExtent(aptr, pos, AUDIO_UNKNOWN_TIME);
97
98 // Set the current entry to the first extent and append the second
99 newptr(e1);
100 newp = new AudioListEntry(e2);
101 newp->link(this);
102 }
103
104
105 // class AudioList Constructor
106 AudioList::
AudioList(const char * local_name)107 AudioList(
108 const char *local_name): // name string
109 Audio(local_name), head(0)
110 {
111 }
112
113 // class AudioList Destructor
114 AudioList::
~AudioList()115 ~AudioList()
116 {
117 // Delete all entries in the list
118 while (first() != 0)
119 delete first();
120 }
121
122 // Get the first entry in the list
123 AudioList::AudioListEntry* AudioList::
first() const124 first() const
125 {
126 return (head.next);
127 }
128
129 // Get the extent and offset corresponding to a given position
130 // Return FALSE if no extents in list or position is beyond eof
131 Boolean AudioList::
getposition(Double & pos,AudioListEntry * & ep) const132 getposition(
133 Double& pos, // target position (updated)
134 AudioListEntry*& ep) const // returned extent pointer
135 {
136 Double length;
137
138 // Position must be specified
139 if (Undefined(pos))
140 return (FALSE);
141
142 // Get the first extent in the list
143 ep = first();
144 while (ep != 0) {
145 // Get length of extent
146 length = ep->aptr->GetLength();
147 if (Undefined(length)) {
148 // Can't determine sizes beyond this
149 return (TRUE);
150 }
151 // If the remaining offset is inside the current extent
152 if (length > pos)
153 return (TRUE);
154
155 // Move on to the next extent
156 pos -= length;
157 ep = ep->next;
158 }
159 return (FALSE);
160 }
161
162 // Get the total length of the audio list
163 Double AudioList::
GetLength() const164 GetLength() const
165 {
166 AudioListEntry* ep;
167 Double sum;
168 Double x;
169
170 for (sum = 0., ep = first(); ep != 0; ep = ep->next) {
171 // Accumulate times for each extent
172 // Indeterminate extents screw up the calculation
173 x = ep->aptr->GetLength();
174 if (Undefined(x))
175 return (x);
176 sum += x;
177 }
178 return (sum);
179 }
180
181 // Construct a name for the list
182 char *AudioList::
GetName() const183 GetName() const
184 {
185 // XXX - construct a better name
186 return (Audio::GetName());
187 }
188
189 // Get the audio header for the current read position
190 AudioHdr AudioList::
GetHeader()191 GetHeader()
192 {
193 return (GetHeader(ReadPosition()));
194 }
195
196 // Get the audio header for the given position
197 AudioHdr AudioList::
GetHeader(Double pos)198 GetHeader(
199 Double pos) // position
200 {
201 AudioListEntry* ep;
202
203 // Get the extent pointer for the given position
204 if (!getposition(pos, ep)) {
205 AudioHdr h;
206
207 if (pos != 0.) {
208 PrintMsg(_MGET_(
209 "AudioHdr:GetHeader()...position is beyond eof"),
210 Warning);
211 return (h);
212 }
213 if ((ep = first()) != 0)
214 return (ep->aptr->GetHeader());
215 return (h);
216 }
217 // Get the header for the proper offset in the extent
218 return (ep->aptr->GetDHeader(pos));
219 }
220
221 // Copy data from list into specified buffer.
222 // No data format translation takes place.
223 // The object's read position is not updated.
224 //
225 // Since list could contain extents of differing encodings,
226 // clients should always use GetHeader() in combination with ReadData()
227 AudioError AudioList::
ReadData(void * buf,size_t & len,Double & pos)228 ReadData(
229 void* buf, // destination buffer address
230 size_t& len, // buffer size (updated)
231 Double& pos) // start position (updated)
232 {
233 AudioListEntry* ep;
234 size_t cnt;
235 Double off;
236 Double newpos;
237 AudioError err;
238
239 // Save buffer size
240 cnt = len;
241
242 // Position must be valid
243 if (Undefined(pos) || (pos < 0.) || ((int)cnt < 0))
244 return (RaiseError(AUDIO_ERR_BADARG));
245
246 // Loop until data is returned or error
247 // XXX - THIS IS WRONG! THE HEADER COULD CHANGE!
248 do {
249 // Get the extent/offset for read position; clear return count
250 len = 0;
251 off = pos;
252 if (!getposition(off, ep)) {
253 err = AUDIO_EOF;
254 err.sys = AUDIO_COPY_INPUT_EOF;
255 return (err);
256 }
257
258 // Save the offset and read some data
259 newpos = off;
260 len = cnt;
261 err = ep->aptr->ReadData(buf, len, newpos);
262
263 // If no eof on this list entry, or no more data, we're done
264 if ((err != AUDIO_EOF) || (err.sys != AUDIO_COPY_INPUT_EOF) ||
265 (ep->next == 0)) {
266 break;
267 }
268
269 // Advance to next list entry
270 // XXX - Is this problemmatic, too?
271 pos += ep->aptr->GetLength() - off;
272 } while (TRUE);
273
274 // Update the byte count and position
275 pos += (newpos - off); // XXX - recalculate?
276 return (err);
277 }
278
279 // Write to AudioList is (currently) prohibited
280 AudioError AudioList::
WriteData(void *,size_t & len,Double &)281 WriteData(
282 void*, // destination buffer address
283 size_t& len, // buffer size (updated)
284 Double&) // start position (updated)
285 {
286 len = 0;
287 return (RaiseError(AUDIO_ERR_NOEFFECT));
288 }
289
290 // Insert an entry at the start
291 AudioError AudioList::
Insert(Audio * obj)292 Insert(
293 Audio* obj) // object to insert
294 {
295 Double pos; // insertion offset, in seconds
296
297 return (Insert(obj, pos = 0.));
298 }
299
300 // Insert an entry at a specified position
301 AudioError AudioList::
Insert(Audio * obj,Double pos)302 Insert(
303 Audio* obj, // object to insert
304 Double pos) // insertion offset, in seconds
305 {
306 AudioListEntry *ep;
307 AudioListEntry *prev;
308
309 // Find the insertion point
310 if (first() == 0) {
311 prev = &head; // this is the first extent
312 } else {
313 if (!getposition(pos, prev)) {
314 if (pos == 0.) {
315 // Append extent to end of list
316 return (Append(obj));
317 } else {
318 return (RaiseError(AUDIO_ERR_BADARG));
319 }
320 } else if (pos != 0.) {
321 // The insertion is in an extent, split it in two
322 prev->split(pos);
323 } else {
324 // Insert before the current position
325 prev = prev->prev;
326 }
327 }
328 // Create object and link into list
329 ep = new AudioListEntry(obj);
330 ep->link(prev);
331
332 return (AUDIO_SUCCESS);
333 }
334
335 // Append an entry to a list
336 AudioError AudioList::
Append(Audio * obj)337 Append(
338 Audio* obj) // object to append
339 {
340 AudioListEntry *ep;
341 AudioListEntry *prev;
342
343 // Find the last extent in the list
344 for (prev = &head; prev->next != 0; prev = prev->next)
345 continue;
346
347 // Create object and link into list
348 ep = new AudioListEntry(obj);
349 ep->link(prev);
350 return (AUDIO_SUCCESS);
351 }
352
353 // Copy routine for lists
354 AudioError AudioList::
AsyncCopy(Audio * to,Double & frompos,Double & topos,Double & limit)355 AsyncCopy(
356 Audio* to, // audio object to copy to
357 Double& frompos, // input pos (updated)
358 Double& topos, // output pos (updated)
359 Double& limit) // amt to copy (updated)
360 {
361 AudioListEntry* ep;
362 Double svlim;
363 Double newpos;
364 Double off;
365 AudioError err;
366
367 svlim = limit;
368 // Loop until data is returned or error
369 // XXX - THIS IS WRONG! THE HEADER COULD CHANGE!
370 do {
371 // Get the extent and offset for the read position
372 off = frompos;
373 if (!getposition(off, ep)) {
374 // nothing written, limit should reflect this
375 limit = 0.0;
376 err = AUDIO_EOF;
377 err.sys = AUDIO_COPY_INPUT_EOF;
378 return (err);
379 }
380
381 // Save the offset and do a copy
382 newpos = off;
383 limit = svlim;
384 err = ep->aptr->AsyncCopy(to, newpos, topos, limit);
385
386 // If no eof on this list entry, or no more data, we're done
387 if ((err != AUDIO_EOF) || (err.sys != AUDIO_COPY_INPUT_EOF) ||
388 (ep->next == 0)) {
389 break;
390 }
391
392 // Advance to next list entry
393 // XXX - Is this problemmatic, too?
394 frompos += ep->aptr->GetLength() - off;
395 } while (TRUE);
396
397 // Update the byte count and position
398 frompos += (newpos - off); // XXX - recalculate?
399 return (err);
400 }
401