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:: 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:: 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:: 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:: 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:: 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:: 105 AudioList( 106 const char *local_name): // name string 107 Audio(local_name), head(0) 108 { 109 } 110 111 // class AudioList Destructor 112 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:: 122 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:: 130 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:: 162 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:: 181 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:: 189 GetHeader() 190 { 191 return (GetHeader(ReadPosition())); 192 } 193 194 // Get the audio header for the given position 195 AudioHdr AudioList:: 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:: 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:: 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:: 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:: 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:: 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:: 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