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