| 1 | /* -*- mode: C; tab-width:8; c-basic-offset:8 -*- |
|---|
| 2 | * vi:set ts=8: |
|---|
| 3 | * |
|---|
| 4 | * al_queue.c |
|---|
| 5 | * |
|---|
| 6 | * Stuff related to the management and use of buffer queue. |
|---|
| 7 | * |
|---|
| 8 | * FIXME: clean this mess up |
|---|
| 9 | */ |
|---|
| 10 | |
|---|
| 11 | #include "al_siteconfig.h" |
|---|
| 12 | |
|---|
| 13 | #include <AL/al.h> |
|---|
| 14 | #include <stdlib.h> |
|---|
| 15 | #include <string.h> |
|---|
| 16 | |
|---|
| 17 | #include "al_config.h" |
|---|
| 18 | #include "al_buffer.h" |
|---|
| 19 | #include "al_debug.h" |
|---|
| 20 | #include "al_error.h" |
|---|
| 21 | #include "al_main.h" |
|---|
| 22 | #include "al_source.h" |
|---|
| 23 | #include "al_queue.h" |
|---|
| 24 | #include "al_types.h" |
|---|
| 25 | #include "al_mixer.h" |
|---|
| 26 | |
|---|
| 27 | #include "alc/alc_context.h" |
|---|
| 28 | |
|---|
| 29 | /* |
|---|
| 30 | * alSourceQueueBuffers( ALuint sid, ALsizei numBuffers, ALuint *bids ) |
|---|
| 31 | * |
|---|
| 32 | * Queue bids[0..numBuffers-1] to the source named sid, setting |
|---|
| 33 | * AL_INVALID_VALUE if numBuffers < 0, or AL_INVALID_NAME if either sid or and |
|---|
| 34 | * bid in bids[0..numBuffers-1] is not a valid buffer. |
|---|
| 35 | */ |
|---|
| 36 | void alSourceQueueBuffers( ALuint sid, ALsizei numBuffers, const ALuint *bids ) { |
|---|
| 37 | AL_source *src; |
|---|
| 38 | ALsizei i; |
|---|
| 39 | |
|---|
| 40 | if( numBuffers == 0) { |
|---|
| 41 | /* with n == 0, we NOP */ |
|---|
| 42 | return; |
|---|
| 43 | } |
|---|
| 44 | |
|---|
| 45 | if( numBuffers < 0) { |
|---|
| 46 | _alDebug(ALD_SOURCE, __FILE__, __LINE__, |
|---|
| 47 | "alSourceQueueBuffers: illegal n value %d\n", numBuffers ); |
|---|
| 48 | |
|---|
| 49 | _alcDCLockContext(); |
|---|
| 50 | _alDCSetError( AL_INVALID_VALUE ); |
|---|
| 51 | _alcDCUnlockContext(); |
|---|
| 52 | |
|---|
| 53 | return; |
|---|
| 54 | } |
|---|
| 55 | |
|---|
| 56 | _alLockMixBuf(); |
|---|
| 57 | SOURCELOCK(); |
|---|
| 58 | |
|---|
| 59 | src = _alDCGetSource( sid ); |
|---|
| 60 | if( src == NULL ) { |
|---|
| 61 | _alDCSetError( AL_INVALID_NAME ); |
|---|
| 62 | |
|---|
| 63 | _alDebug(ALD_SOURCE, __FILE__, __LINE__, |
|---|
| 64 | "alSourceQueueBuffers: invalid sid %d\n", sid ); |
|---|
| 65 | |
|---|
| 66 | SOURCEUNLOCK(); |
|---|
| 67 | _alUnlockMixBuf(); |
|---|
| 68 | |
|---|
| 69 | return; |
|---|
| 70 | } |
|---|
| 71 | |
|---|
| 72 | _alLockBuffer(); |
|---|
| 73 | |
|---|
| 74 | /* make sure that bids are valid */ |
|---|
| 75 | for( i = 0; i < numBuffers; i++ ) { |
|---|
| 76 | if( _alIsBuffer( bids[i] ) == AL_FALSE ) { |
|---|
| 77 | /* |
|---|
| 78 | * we have an invalid bid. bid 0 is okay but the |
|---|
| 79 | * rest are not. |
|---|
| 80 | */ |
|---|
| 81 | if( bids[i] != 0 ) { |
|---|
| 82 | _alUnlockBuffer(); |
|---|
| 83 | |
|---|
| 84 | _alDCSetError( AL_INVALID_NAME ); |
|---|
| 85 | |
|---|
| 86 | SOURCEUNLOCK(); |
|---|
| 87 | _alUnlockMixBuf(); |
|---|
| 88 | |
|---|
| 89 | return; |
|---|
| 90 | } |
|---|
| 91 | } |
|---|
| 92 | } |
|---|
| 93 | |
|---|
| 94 | /* now, append the bids */ |
|---|
| 95 | for( i = 0; i < numBuffers; i++ ) { |
|---|
| 96 | if( bids[i] != 0 ) { |
|---|
| 97 | /* |
|---|
| 98 | * only append non-0 bids, because we don't |
|---|
| 99 | * need them anyway. |
|---|
| 100 | */ |
|---|
| 101 | _alSourceQueueAppend( src, bids[i] ); |
|---|
| 102 | } |
|---|
| 103 | } |
|---|
| 104 | |
|---|
| 105 | /* we're done */ |
|---|
| 106 | |
|---|
| 107 | _alUnlockBuffer(); |
|---|
| 108 | SOURCEUNLOCK(); |
|---|
| 109 | _alUnlockMixBuf(); |
|---|
| 110 | |
|---|
| 111 | return; |
|---|
| 112 | } |
|---|
| 113 | |
|---|
| 114 | /* |
|---|
| 115 | * _alSourceQueueGetCurrentState( AL_source *src ) |
|---|
| 116 | * |
|---|
| 117 | * Returns the current AL_sourcestate of the current queue entry for AL_source |
|---|
| 118 | * *src. |
|---|
| 119 | * |
|---|
| 120 | * assumes locked sources |
|---|
| 121 | */ |
|---|
| 122 | AL_sourcestate *_alSourceQueueGetCurrentState( AL_source *src ) |
|---|
| 123 | { |
|---|
| 124 | int rind = src->bid_queue.read_index; |
|---|
| 125 | |
|---|
| 126 | /* |
|---|
| 127 | * This assert means we're querying a value with the read |
|---|
| 128 | * index beyond our size. |
|---|
| 129 | * |
|---|
| 130 | * Well, like a dumbass I made looping source queue specific. Now I'm |
|---|
| 131 | * paying the price. Okay, return return return. |
|---|
| 132 | */ |
|---|
| 133 | /* assert( rind < src->bid_queue.size ); */ |
|---|
| 134 | |
|---|
| 135 | if(rind >= src->bid_queue.size) |
|---|
| 136 | { |
|---|
| 137 | return NULL; |
|---|
| 138 | } |
|---|
| 139 | |
|---|
| 140 | return &src->bid_queue.queuestate[rind]; |
|---|
| 141 | } |
|---|
| 142 | |
|---|
| 143 | /* |
|---|
| 144 | * _alSourceQueueInit( AL_source *src ) |
|---|
| 145 | * |
|---|
| 146 | * Initialize an AL_source queue. |
|---|
| 147 | * |
|---|
| 148 | * assumes locked context |
|---|
| 149 | */ |
|---|
| 150 | void _alSourceQueueInit( AL_source *src ) { |
|---|
| 151 | src->bid_queue.queue = NULL; |
|---|
| 152 | src->bid_queue.queuestate = NULL; |
|---|
| 153 | src->bid_queue.size = 0; |
|---|
| 154 | |
|---|
| 155 | _alSourceQueueClear( src ); |
|---|
| 156 | |
|---|
| 157 | return; |
|---|
| 158 | } |
|---|
| 159 | |
|---|
| 160 | /* |
|---|
| 161 | * _alSourceQueueClear( AL_source *src ) |
|---|
| 162 | * |
|---|
| 163 | * Clears a source's queue, removing all entries. |
|---|
| 164 | * |
|---|
| 165 | * assumes locked context |
|---|
| 166 | */ |
|---|
| 167 | void _alSourceQueueClear( AL_source *src ) { |
|---|
| 168 | ALuint bid; |
|---|
| 169 | int i; |
|---|
| 170 | |
|---|
| 171 | for(i = 0; i < src->bid_queue.size; i++) { |
|---|
| 172 | bid = src->bid_queue.queue[i]; |
|---|
| 173 | |
|---|
| 174 | if(bid != 0) { |
|---|
| 175 | /* bid 0 is a special name */ |
|---|
| 176 | _alBidRemoveQueueRef(bid, src->sid); |
|---|
| 177 | } |
|---|
| 178 | } |
|---|
| 179 | |
|---|
| 180 | src->bid_queue.read_index = 0; |
|---|
| 181 | src->bid_queue.write_index = 0; |
|---|
| 182 | src->bid_queue.size = 0; |
|---|
| 183 | |
|---|
| 184 | _alSourceQueueAppend(src, 0); |
|---|
| 185 | |
|---|
| 186 | return; |
|---|
| 187 | } |
|---|
| 188 | |
|---|
| 189 | /* |
|---|
| 190 | * _alSourceQueueAppend( AL_source *src, ALuint bid ) |
|---|
| 191 | * |
|---|
| 192 | * Append bid to source's queue. |
|---|
| 193 | * |
|---|
| 194 | * assumes locked context |
|---|
| 195 | */ |
|---|
| 196 | void _alSourceQueueAppend( AL_source *src, ALuint bid ) { |
|---|
| 197 | int size = src->bid_queue.size; |
|---|
| 198 | int newsize = size + 1; |
|---|
| 199 | int windex = src->bid_queue.write_index; |
|---|
| 200 | void *temp; |
|---|
| 201 | |
|---|
| 202 | if(src->bid_queue.size > 0) { |
|---|
| 203 | if(src->bid_queue.queue[windex] == 0) { |
|---|
| 204 | /* |
|---|
| 205 | * special case. bid == 0 is the "no bid" |
|---|
| 206 | * bid, which means that it's just a place |
|---|
| 207 | * holder to allow buffer specific source |
|---|
| 208 | * parameters to be set. |
|---|
| 209 | * |
|---|
| 210 | * Don't bother to resize, just overwrite. |
|---|
| 211 | */ |
|---|
| 212 | src->bid_queue.queue[windex] = bid; |
|---|
| 213 | |
|---|
| 214 | return; |
|---|
| 215 | } |
|---|
| 216 | } |
|---|
| 217 | |
|---|
| 218 | temp = realloc(src->bid_queue.queue, |
|---|
| 219 | newsize * sizeof *src->bid_queue.queue); |
|---|
| 220 | if(temp == NULL) { |
|---|
| 221 | return; |
|---|
| 222 | } |
|---|
| 223 | src->bid_queue.queue = temp; |
|---|
| 224 | src->bid_queue.queue[size] = 0; |
|---|
| 225 | |
|---|
| 226 | temp = realloc(src->bid_queue.queuestate, |
|---|
| 227 | newsize * sizeof *src->bid_queue.queuestate); |
|---|
| 228 | if(temp == NULL) { |
|---|
| 229 | return; |
|---|
| 230 | } |
|---|
| 231 | src->bid_queue.queuestate = temp; |
|---|
| 232 | |
|---|
| 233 | /* |
|---|
| 234 | * If this is a "real" append operation, ie not bid == NONE, |
|---|
| 235 | * then increment the write index so that buffer specific |
|---|
| 236 | * source setting operations take place. |
|---|
| 237 | */ |
|---|
| 238 | if(bid != 0) { |
|---|
| 239 | windex++; |
|---|
| 240 | src->bid_queue.write_index++; |
|---|
| 241 | } |
|---|
| 242 | |
|---|
| 243 | /* |
|---|
| 244 | * Initialize sourcestate flags. |
|---|
| 245 | */ |
|---|
| 246 | _alSourceStateInit(&src->bid_queue.queuestate[windex]); |
|---|
| 247 | |
|---|
| 248 | /* |
|---|
| 249 | * Set bid and new size. |
|---|
| 250 | */ |
|---|
| 251 | src->bid_queue.queue[windex] = bid; |
|---|
| 252 | src->bid_queue.size = newsize; |
|---|
| 253 | |
|---|
| 254 | |
|---|
| 255 | return; |
|---|
| 256 | } |
|---|
| 257 | |
|---|
| 258 | |
|---|
| 259 | /* |
|---|
| 260 | * _alSourceQueueHead( AL_source *src, ALuint bid ) |
|---|
| 261 | * |
|---|
| 262 | * Truncates a source's queue with a single entry of bid. |
|---|
| 263 | * |
|---|
| 264 | * assumes locked context |
|---|
| 265 | */ |
|---|
| 266 | void _alSourceQueueHead( AL_source *src, ALuint bid ) { |
|---|
| 267 | _alSourceQueueClear( src ); |
|---|
| 268 | |
|---|
| 269 | src->bid_queue.queue[0] = bid; |
|---|
| 270 | src->bid_queue.write_index = 0; |
|---|
| 271 | src->bid_queue.read_index = 0; |
|---|
| 272 | src->bid_queue.size = 1; |
|---|
| 273 | |
|---|
| 274 | return; |
|---|
| 275 | } |
|---|
| 276 | |
|---|
| 277 | /* |
|---|
| 278 | * alSourceUnqueueBuffers( ALuint sid, ALsizei n, ALuint *bids ) |
|---|
| 279 | * |
|---|
| 280 | * Unqueues first occurance of each bid in bids[0..n-1] from source named sid. |
|---|
| 281 | */ |
|---|
| 282 | void alSourceUnqueueBuffers( ALuint sid, ALsizei n, ALuint *bids ) { |
|---|
| 283 | _alLockMixBuf(); |
|---|
| 284 | _alcDCLockContext(); |
|---|
| 285 | |
|---|
| 286 | _alSourceUnqueueBuffers( sid, n, bids ); |
|---|
| 287 | |
|---|
| 288 | _alcDCUnlockContext(); |
|---|
| 289 | _alUnlockMixBuf(); |
|---|
| 290 | |
|---|
| 291 | return; |
|---|
| 292 | } |
|---|
| 293 | |
|---|
| 294 | /* |
|---|
| 295 | * _alSourceStateInit( AL_sourcestate *srcstate ) |
|---|
| 296 | * |
|---|
| 297 | * Initialize an AL_sourcestate object to the default settings. |
|---|
| 298 | */ |
|---|
| 299 | void _alSourceStateInit( AL_sourcestate *srcstate ) { |
|---|
| 300 | srcstate->flags = ALQ_NONE; |
|---|
| 301 | |
|---|
| 302 | return; |
|---|
| 303 | } |
|---|
| 304 | |
|---|
| 305 | /* |
|---|
| 306 | * _alSourceUnqueueBuffers( ALuint sid, ALsizei n, ALuint *bids ) |
|---|
| 307 | * |
|---|
| 308 | * Non locking version of alSourceUnqueueBuffers. |
|---|
| 309 | * |
|---|
| 310 | * assumes locked context |
|---|
| 311 | */ |
|---|
| 312 | void _alSourceUnqueueBuffers(ALuint sid, ALsizei n, ALuint *bids ) { |
|---|
| 313 | AL_source *src; |
|---|
| 314 | ALuint *tempqueue; |
|---|
| 315 | AL_sourcestate *tempstate; |
|---|
| 316 | int newsize; |
|---|
| 317 | int i; |
|---|
| 318 | |
|---|
| 319 | if(n == 0) { |
|---|
| 320 | /* legal nop */ |
|---|
| 321 | return; |
|---|
| 322 | } |
|---|
| 323 | |
|---|
| 324 | if(n < 0) { |
|---|
| 325 | /* bad n */ |
|---|
| 326 | _alDCSetError( AL_INVALID_VALUE ); |
|---|
| 327 | |
|---|
| 328 | _alDebug(ALD_SOURCE, __FILE__, __LINE__, |
|---|
| 329 | "alSourceUnqueueBuffers: invalid numBuffers %d", n ); |
|---|
| 330 | |
|---|
| 331 | return; |
|---|
| 332 | } |
|---|
| 333 | |
|---|
| 334 | src = _alDCGetSource( sid ); |
|---|
| 335 | if(src == NULL) { |
|---|
| 336 | _alDCSetError(AL_INVALID_NAME); |
|---|
| 337 | return; |
|---|
| 338 | } |
|---|
| 339 | |
|---|
| 340 | if(n > src->bid_queue.read_index) { |
|---|
| 341 | /* User has requested too many buffers unqueued */ |
|---|
| 342 | _alDCSetError( AL_INVALID_VALUE ); |
|---|
| 343 | |
|---|
| 344 | _alDebug(ALD_SOURCE, __FILE__, __LINE__, |
|---|
| 345 | "alSourceUnqueueBuffers: invalid numBuffers %d", n ); |
|---|
| 346 | |
|---|
| 347 | return; |
|---|
| 348 | } |
|---|
| 349 | |
|---|
| 350 | /* make sure queue is valid */ |
|---|
| 351 | for( i = 0; i < n; i++ ) |
|---|
| 352 | { |
|---|
| 353 | if(!_alIsBuffer(src->bid_queue.queue[i])) |
|---|
| 354 | { |
|---|
| 355 | _alDCSetError( AL_INVALID_NAME ); |
|---|
| 356 | _alDebug(ALD_SOURCE, __FILE__, __LINE__, |
|---|
| 357 | "alSourceUnqueueBuffers: invalid buffer name %d", |
|---|
| 358 | n ); |
|---|
| 359 | |
|---|
| 360 | return; |
|---|
| 361 | } |
|---|
| 362 | } |
|---|
| 363 | |
|---|
| 364 | /* copy queue into bids */ |
|---|
| 365 | newsize = src->bid_queue.size - n; |
|---|
| 366 | |
|---|
| 367 | for( i = 0; i < n; i++ ) |
|---|
| 368 | { |
|---|
| 369 | _alBidRemoveQueueRef( src->bid_queue.queue[i], src->sid ); |
|---|
| 370 | _alBidRemoveCurrentRef( src->bid_queue.queue[i], src->sid ); |
|---|
| 371 | } |
|---|
| 372 | |
|---|
| 373 | /* resize */ |
|---|
| 374 | tempqueue = malloc(newsize * sizeof *tempqueue); |
|---|
| 375 | tempstate = malloc(newsize * sizeof *tempstate); |
|---|
| 376 | |
|---|
| 377 | assert( tempqueue ); |
|---|
| 378 | assert( tempstate ); |
|---|
| 379 | |
|---|
| 380 | if((tempqueue == NULL) || (tempstate == NULL)) |
|---|
| 381 | { |
|---|
| 382 | /* |
|---|
| 383 | * since newsize is less than our current size, |
|---|
| 384 | * we really shouldn't bomb out here, but should |
|---|
| 385 | * instead just set the deleted bids to 0 or something[ |
|---|
| 386 | */ |
|---|
| 387 | _alDCSetError(AL_OUT_OF_MEMORY); |
|---|
| 388 | _alDebug(ALD_SOURCE, __FILE__, __LINE__, |
|---|
| 389 | "alSourceUnqueueBuffers: unable to allocate memory" ); |
|---|
| 390 | |
|---|
| 391 | return; |
|---|
| 392 | } |
|---|
| 393 | |
|---|
| 394 | /* okay, we've succedded, so copy the bids for return */ |
|---|
| 395 | memcpy( bids, src->bid_queue.queue, n * sizeof *bids ); |
|---|
| 396 | |
|---|
| 397 | /* copy the new queue and state */ |
|---|
| 398 | memcpy( tempqueue, |
|---|
| 399 | &src->bid_queue.queue[n], newsize * sizeof *tempqueue ); |
|---|
| 400 | memcpy( tempstate, |
|---|
| 401 | &src->bid_queue.queuestate[n], newsize * sizeof *tempstate ); |
|---|
| 402 | |
|---|
| 403 | /* |
|---|
| 404 | * read_index now points to the wrong bid, so subtract by |
|---|
| 405 | * old size - newsize. |
|---|
| 406 | */ |
|---|
| 407 | src->bid_queue.read_index -= (src->bid_queue.size - newsize); |
|---|
| 408 | |
|---|
| 409 | /* |
|---|
| 410 | * write_indesx too |
|---|
| 411 | */ |
|---|
| 412 | src->bid_queue.write_index -= (src->bid_queue.size - newsize); |
|---|
| 413 | |
|---|
| 414 | free( src->bid_queue.queue ); |
|---|
| 415 | free( src->bid_queue.queuestate ); |
|---|
| 416 | |
|---|
| 417 | src->bid_queue.queue = tempqueue; |
|---|
| 418 | src->bid_queue.queuestate = tempstate; |
|---|
| 419 | src->bid_queue.size = newsize; |
|---|
| 420 | |
|---|
| 421 | return; |
|---|
| 422 | } |
|---|