/* -*- mode: C; tab-width:8; c-basic-offset:8 -*- * vi:set ts=8: * * al_queue.c * * Stuff related to the management and use of buffer queue. * * FIXME: clean this mess up */ #include "al_siteconfig.h" #include #include #include #include "al_config.h" #include "al_buffer.h" #include "al_debug.h" #include "al_error.h" #include "al_main.h" #include "al_source.h" #include "al_queue.h" #include "al_types.h" #include "al_mixer.h" #include "alc/alc_context.h" /* * alSourceQueueBuffers( ALuint sid, ALsizei numBuffers, ALuint *bids ) * * Queue bids[0..numBuffers-1] to the source named sid, setting * AL_INVALID_VALUE if numBuffers < 0, or AL_INVALID_NAME if either sid or and * bid in bids[0..numBuffers-1] is not a valid buffer. */ void alSourceQueueBuffers( ALuint sid, ALsizei numBuffers, const ALuint *bids ) { AL_source *src; ALsizei i; if( numBuffers == 0) { /* with n == 0, we NOP */ return; } if( numBuffers < 0) { _alDebug(ALD_SOURCE, __FILE__, __LINE__, "alSourceQueueBuffers: illegal n value %d\n", numBuffers ); _alcDCLockContext(); _alDCSetError( AL_INVALID_VALUE ); _alcDCUnlockContext(); return; } _alLockMixBuf(); SOURCELOCK(); src = _alDCGetSource( sid ); if( src == NULL ) { _alDCSetError( AL_INVALID_NAME ); _alDebug(ALD_SOURCE, __FILE__, __LINE__, "alSourceQueueBuffers: invalid sid %d\n", sid ); SOURCEUNLOCK(); _alUnlockMixBuf(); return; } _alLockBuffer(); /* make sure that bids are valid */ for( i = 0; i < numBuffers; i++ ) { if( _alIsBuffer( bids[i] ) == AL_FALSE ) { /* * we have an invalid bid. bid 0 is okay but the * rest are not. */ if( bids[i] != 0 ) { _alUnlockBuffer(); _alDCSetError( AL_INVALID_NAME ); SOURCEUNLOCK(); _alUnlockMixBuf(); return; } } } /* now, append the bids */ for( i = 0; i < numBuffers; i++ ) { if( bids[i] != 0 ) { /* * only append non-0 bids, because we don't * need them anyway. */ _alSourceQueueAppend( src, bids[i] ); } } /* we're done */ _alUnlockBuffer(); SOURCEUNLOCK(); _alUnlockMixBuf(); return; } /* * _alSourceQueueGetCurrentState( AL_source *src ) * * Returns the current AL_sourcestate of the current queue entry for AL_source * *src. * * assumes locked sources */ AL_sourcestate *_alSourceQueueGetCurrentState( AL_source *src ) { int rind = src->bid_queue.read_index; /* * This assert means we're querying a value with the read * index beyond our size. * * Well, like a dumbass I made looping source queue specific. Now I'm * paying the price. Okay, return return return. */ /* assert( rind < src->bid_queue.size ); */ if(rind >= src->bid_queue.size) { return NULL; } return &src->bid_queue.queuestate[rind]; } /* * _alSourceQueueInit( AL_source *src ) * * Initialize an AL_source queue. * * assumes locked context */ void _alSourceQueueInit( AL_source *src ) { src->bid_queue.queue = NULL; src->bid_queue.queuestate = NULL; src->bid_queue.size = 0; _alSourceQueueClear( src ); return; } /* * _alSourceQueueClear( AL_source *src ) * * Clears a source's queue, removing all entries. * * assumes locked context */ void _alSourceQueueClear( AL_source *src ) { ALuint bid; int i; for(i = 0; i < src->bid_queue.size; i++) { bid = src->bid_queue.queue[i]; if(bid != 0) { /* bid 0 is a special name */ _alBidRemoveQueueRef(bid, src->sid); } } src->bid_queue.read_index = 0; src->bid_queue.write_index = 0; src->bid_queue.size = 0; _alSourceQueueAppend(src, 0); return; } /* * _alSourceQueueAppend( AL_source *src, ALuint bid ) * * Append bid to source's queue. * * assumes locked context */ void _alSourceQueueAppend( AL_source *src, ALuint bid ) { int size = src->bid_queue.size; int newsize = size + 1; int windex = src->bid_queue.write_index; void *temp; if(src->bid_queue.size > 0) { if(src->bid_queue.queue[windex] == 0) { /* * special case. bid == 0 is the "no bid" * bid, which means that it's just a place * holder to allow buffer specific source * parameters to be set. * * Don't bother to resize, just overwrite. */ src->bid_queue.queue[windex] = bid; return; } } temp = realloc(src->bid_queue.queue, newsize * sizeof *src->bid_queue.queue); if(temp == NULL) { return; } src->bid_queue.queue = temp; src->bid_queue.queue[size] = 0; temp = realloc(src->bid_queue.queuestate, newsize * sizeof *src->bid_queue.queuestate); if(temp == NULL) { return; } src->bid_queue.queuestate = temp; /* * If this is a "real" append operation, ie not bid == NONE, * then increment the write index so that buffer specific * source setting operations take place. */ if(bid != 0) { windex++; src->bid_queue.write_index++; } /* * Initialize sourcestate flags. */ _alSourceStateInit(&src->bid_queue.queuestate[windex]); /* * Set bid and new size. */ src->bid_queue.queue[windex] = bid; src->bid_queue.size = newsize; return; } /* * _alSourceQueueHead( AL_source *src, ALuint bid ) * * Truncates a source's queue with a single entry of bid. * * assumes locked context */ void _alSourceQueueHead( AL_source *src, ALuint bid ) { _alSourceQueueClear( src ); src->bid_queue.queue[0] = bid; src->bid_queue.write_index = 0; src->bid_queue.read_index = 0; src->bid_queue.size = 1; return; } /* * alSourceUnqueueBuffers( ALuint sid, ALsizei n, ALuint *bids ) * * Unqueues first occurance of each bid in bids[0..n-1] from source named sid. */ void alSourceUnqueueBuffers( ALuint sid, ALsizei n, ALuint *bids ) { _alLockMixBuf(); _alcDCLockContext(); _alSourceUnqueueBuffers( sid, n, bids ); _alcDCUnlockContext(); _alUnlockMixBuf(); return; } /* * _alSourceStateInit( AL_sourcestate *srcstate ) * * Initialize an AL_sourcestate object to the default settings. */ void _alSourceStateInit( AL_sourcestate *srcstate ) { srcstate->flags = ALQ_NONE; return; } /* * _alSourceUnqueueBuffers( ALuint sid, ALsizei n, ALuint *bids ) * * Non locking version of alSourceUnqueueBuffers. * * assumes locked context */ void _alSourceUnqueueBuffers(ALuint sid, ALsizei n, ALuint *bids ) { AL_source *src; ALuint *tempqueue; AL_sourcestate *tempstate; int newsize; int i; if(n == 0) { /* legal nop */ return; } if(n < 0) { /* bad n */ _alDCSetError( AL_INVALID_VALUE ); _alDebug(ALD_SOURCE, __FILE__, __LINE__, "alSourceUnqueueBuffers: invalid numBuffers %d", n ); return; } src = _alDCGetSource( sid ); if(src == NULL) { _alDCSetError(AL_INVALID_NAME); return; } if(n > src->bid_queue.read_index) { /* User has requested too many buffers unqueued */ _alDCSetError( AL_INVALID_VALUE ); _alDebug(ALD_SOURCE, __FILE__, __LINE__, "alSourceUnqueueBuffers: invalid numBuffers %d", n ); return; } /* make sure queue is valid */ for( i = 0; i < n; i++ ) { if(!_alIsBuffer(src->bid_queue.queue[i])) { _alDCSetError( AL_INVALID_NAME ); _alDebug(ALD_SOURCE, __FILE__, __LINE__, "alSourceUnqueueBuffers: invalid buffer name %d", n ); return; } } /* copy queue into bids */ newsize = src->bid_queue.size - n; for( i = 0; i < n; i++ ) { _alBidRemoveQueueRef( src->bid_queue.queue[i], src->sid ); _alBidRemoveCurrentRef( src->bid_queue.queue[i], src->sid ); } /* resize */ tempqueue = malloc(newsize * sizeof *tempqueue); tempstate = malloc(newsize * sizeof *tempstate); assert( tempqueue ); assert( tempstate ); if((tempqueue == NULL) || (tempstate == NULL)) { /* * since newsize is less than our current size, * we really shouldn't bomb out here, but should * instead just set the deleted bids to 0 or something[ */ _alDCSetError(AL_OUT_OF_MEMORY); _alDebug(ALD_SOURCE, __FILE__, __LINE__, "alSourceUnqueueBuffers: unable to allocate memory" ); return; } /* okay, we've succedded, so copy the bids for return */ memcpy( bids, src->bid_queue.queue, n * sizeof *bids ); /* copy the new queue and state */ memcpy( tempqueue, &src->bid_queue.queue[n], newsize * sizeof *tempqueue ); memcpy( tempstate, &src->bid_queue.queuestate[n], newsize * sizeof *tempstate ); /* * read_index now points to the wrong bid, so subtract by * old size - newsize. */ src->bid_queue.read_index -= (src->bid_queue.size - newsize); /* * write_indesx too */ src->bid_queue.write_index -= (src->bid_queue.size - newsize); free( src->bid_queue.queue ); free( src->bid_queue.queuestate ); src->bid_queue.queue = tempqueue; src->bid_queue.queuestate = tempstate; src->bid_queue.size = newsize; return; }