[17] | 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 | } |
---|