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 | } |
---|