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:: 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:: 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:: 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:: 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:: 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:: 107 AudioList( 108 const char *local_name): // name string 109 Audio(local_name), head(0) 110 { 111 } 112 113 // class AudioList Destructor 114 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:: 124 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:: 132 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:: 164 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:: 183 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:: 191 GetHeader() 192 { 193 return (GetHeader(ReadPosition())); 194 } 195 196 // Get the audio header for the given position 197 AudioHdr AudioList:: 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:: 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:: 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:: 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:: 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:: 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:: 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