Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/openal-0.0.8/src/al_mixer.c @ 28

Last change on this file since 28 was 17, checked in by landauf, 17 years ago

added openal

File size: 29.2 KB
Line 
1/* -*- mode: C; tab-width:8; c-basic-offset:8 -*-
2 * vi:set ts=8:
3 *
4 * al_mixer.c
5 *
6 * Place where most stuff happens.  The main mixer iteration function
7 * is defined here.
8 *
9 */
10#include "al_siteconfig.h"
11
12#include <AL/al.h>
13#include <signal.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <sys/time.h>
17#include <sys/types.h>
18#include <unistd.h>
19#include <string.h>
20
21#include "al_debug.h"
22#include "al_error.h"
23#include "al_types.h"
24#include "al_main.h"
25#include "al_buffer.h"
26#include "al_filter.h"
27#include "al_mixer.h"
28#include "al_mixmanager.h"
29#include "al_source.h"
30#include "al_mspool.h"
31#include "mixaudio16.h"
32
33#include "alc/alc_context.h"
34#include "alc/alc_device.h"
35#include "alc/alc_speaker.h"
36
37#include "audioconvert/audioconvert.h"
38
39#include "al_threadlib.h"
40#include "al_mutexlib.h"
41
42#include "backends/alc_backend.h"
43
44#define MIN(a,b) ((a) < (b) ? (a) : (b))
45#define MAX(a,b) ((a) > (b) ? (a) : (b))
46
47/*
48 * The mixing function checks this variable for equality with AL_TRUE.  When
49 * this is the case, it exits.  The default is AL_FALSE.
50 */
51ALboolean volatile time_for_mixer_to_die = AL_FALSE;
52
53/* our thread ID, if async */
54ThreadID mixthread = NULL;
55
56/*
57 * MixManager is the ALMixManager we use, in conjunction with MixFunc, to
58 * dispatch mixing functions for combining streams of PCM data.
59 */
60static ALMixManager MixManager;
61
62/*
63 * MixFunc is the ALMixFunc we use, in conjunction with MixManager, to
64 * dispatch mixing functions for combining streams of PCM data.
65 */
66static ALMixFunc MixFunc;
67
68/*
69 * mspool is our pool of mspool nodes.
70 */
71static _alMixPool mspool;
72
73/*
74 * s16le is the data structure we use to convert data from the canonical
75 * format into the external format.
76 */
77static acAudioCVT s16le;
78
79/*
80 * mix_mutex is the guard around mspool.
81 */
82static MutexID mix_mutex   = NULL;
83
84/*
85 * pause_mutex is an aid to mixer pausing.
86 */
87static MutexID pause_mutex = NULL;
88
89/*
90 * Size of how much data we should mix at a time for each source.
91 */
92static ALuint bufsiz = 0;
93
94static struct {
95        void *data;
96        ALuint length;
97} mixbuf = { NULL, 0 };
98
99/* streaming buffer array */
100static struct {
101        ALuint *streaming_buffers;
102        ALuint size;
103        ALuint items;
104} sbufs = { NULL, 0, 0 };
105
106/*
107 * sync_mixer_iterate( void *dummy )
108 *
109 * Non-threaded top level mixing logic.
110 */
111int sync_mixer_iterate( void *dummy );
112
113/*
114 * async_mixer_iterate( void *dummy )
115 *
116 * Threaded top level mixing logic.
117 */
118int async_mixer_iterate( void *dummy )AL_ATTRIBUTE_NORETURN_;
119
120/*
121 * Pointer to either sync or async_mixer_iterate.
122 */
123int (*mixer_iterate)( void *dummy ) = NULL;
124
125/*
126 * _alAddDataToMixer( void *dataptr, ALuint bytes_to_write )
127 *
128 * Mixes bytes_to_write data from dataptr to the system buffer.  If
129 * bytes_to_write exceeds the system buffer size, it is truncated and returns
130 * the maximum it could write.
131 */
132static ALuint _alAddDataToMixer( void *dataptr, ALuint bytes_to_write );
133
134/*
135 * _alProcessFlags( void )
136 *
137 * Processes flags set by the top-level mixing function.  These flags control
138 * things like deletion.
139 */
140static void _alProcessFlags( void );
141
142/*
143 * _alDestroyMixSource( void *ms )
144 *
145 * Finalize a _alMixSource object.
146 */
147static void _alDestroyMixSource( void *ms );
148
149/*
150 * _alAddBufferToStreamingList( ALuint bid )
151 *
152 * AL_buffers generated using alGenStreamingBuffers_LOKI need to be handled in
153 * a special way.  This function does that special handling.
154 */
155static void _alAddBufferToStreamingList( ALuint bid );
156
157/*
158 * _alTryLockMixerPause( void )
159 *
160 * Try to lock the mix_pause mutex.  Return AL_TRUE if lock suceeded, AL_FALSE
161 * otherwise.
162 */
163static ALboolean _alTryLockMixerPause( void );
164
165/*
166 * _alMixSources
167 *
168 * This is the where most of the action is directed.
169 *
170 * assumes locked mixbuf
171 */
172static void _alMixSources( void )
173{
174        AL_buffer *samp;
175        AL_source *src;
176        int *sampid;
177        _alMixSource *itr = NULL;
178        ALboolean islooping   = AL_FALSE;
179        ALboolean isstreaming = AL_FALSE;
180        ALboolean iscallback  = AL_FALSE;
181        ALboolean isinqueue   = AL_FALSE;
182        ALuint pitr; /* pool iterator */
183        ALuint nc = _alcDCGetNumSpeakers();
184
185        for(pitr = 0; pitr < mspool.size; pitr++)
186        {
187                if(mspool.pool[pitr].inuse == AL_FALSE)
188                {
189                        /* if not in use, can't be played anyway */
190                        continue;
191                }
192
193                itr = _alMixPoolIndex( &mspool, pitr );
194                assert(itr);
195
196                if(!(itr->flags & ALM_PLAY_ME))
197                {
198                        /*
199                         * current mix source on the way out, so
200                         * ignore it
201                         */
202                        _alDebug(ALD_MIXER, __FILE__, __LINE__,
203                                "_alMixSources: %d is on the out",
204                                itr->sid);
205                        continue;
206                }
207
208                _alDebug(ALD_MAXIMUS, __FILE__, __LINE__,
209                        "_alMixSources: currently on source id %d",
210                        itr->sid);
211
212                /* check for paused context. */
213                if( _alcIsContextSuspended( itr->context_id ) == AL_TRUE )
214                {
215                        continue;
216                }
217
218                _alLockSource( itr->context_id, itr->sid );
219
220                src = _alGetSource(itr->context_id, itr->sid);
221                if(src == NULL)
222                {
223                        /* not a valid src */
224                        itr->flags = ALM_DESTROY_ME;
225
226                        _alUnlockSource( itr->context_id, itr->sid );
227
228                        continue;
229                }
230
231                if(src->state == AL_PAUSED)
232                {
233                        /* Paused sources don't get mixed */
234                        _alUnlockSource( itr->context_id, itr->sid );
235                        continue;
236                }
237
238                sampid = _alGetSourceParam(src, AL_BUFFER);
239                if(sampid == NULL)
240                {
241                        /* source added with no buffer associated */
242                        itr->flags = ALM_DESTROY_ME;
243
244                        _alDebug(ALD_MIXER, __FILE__, __LINE__,
245                                "No bid associated with sid %d", itr->sid);
246
247                        _alUnlockSource( itr->context_id, itr->sid );
248
249                        continue;
250                }
251
252                samp = _alGetBuffer(*sampid);
253                if(samp == NULL)
254                {
255                        /* source added with no valid buffer associated */
256                        _alDebug(ALD_MIXER, __FILE__, __LINE__,
257                                "no such bid [sid|bid] [%d|%d]",
258                                itr->sid, *sampid);
259
260                        itr->flags = ALM_DESTROY_ME;
261
262                        _alUnlockSource( itr->context_id, itr->sid );
263
264                        continue;
265                }
266
267                /* get special needs */
268                islooping   = _alSourceIsLooping( src );
269                isinqueue   = _alSourceGetPendingBids( src ) > 0;
270                isstreaming = _alBidIsStreaming( *sampid );
271                iscallback  = _alBidIsCallback( *sampid );
272
273                /* apply each filter to sourceid sid */
274                _alApplyFilters(itr->context_id, itr->sid);
275
276                _alAddDataToMixer(src->srcParams.outbuf, bufsiz);
277
278                if(_alSourceShouldIncrement(src) == AL_TRUE)
279                {
280                        /*
281                         * soundpos is an offset into the original buffer
282                         * data, which is most likely mono.  We use nc (the
283                         * number of channels in mixer's format) to scale
284                         * soundpos.
285                         *
286                         * John Quigley noticed a bug resulting from the
287                         * mix manager getting unequal amounts of data.
288                         * so we always add the same amount of data to
289                         * the mixer, because we should be memsetting it
290                         * to 0 when we're applying the filters.
291                         */
292                        _alSourceIncrement(src, bufsiz / nc);
293                }
294
295                if((isinqueue == AL_TRUE) &&
296                   (src->srcParams.new_readindex >= 0))
297                {
298                        /*
299                         * If new_readindex is set, so should be
300                         * new_soundpos.
301                         */
302                        assert(src->srcParams.new_soundpos >= 0);
303
304                        src->bid_queue.read_index =src->srcParams.new_readindex;
305                        src->srcParams.soundpos =  src->srcParams.new_soundpos;
306
307                        /*
308                         * Sanity check so that we don't read past the size
309                         * of the next buffer in the queue.
310                         */
311
312#ifdef DEBUG_QUEUE
313                        if(src->bid_queue.read_index < src->bid_queue.size)
314                        {
315                                ALint ri = src->bid_queue.read_index;
316                                ALint bid = src->bid_queue.queue[ri];
317                                AL_buffer *samp = _alGetBuffer(bid);
318
319                                assert(samp);
320                                assert(src->srcParams.soundpos < samp->size);
321                        }
322#endif
323
324                        /*
325                         * Flag so that we don't do this again
326                         * until the next SplitSourceQueue.
327                         */
328                        src->srcParams.new_readindex = -1;
329                        src->srcParams.new_soundpos = -1;
330                }
331                else if(_alSourceBytesLeft(src, samp) <= 0)
332                {
333                        /*
334                         * end of sound.  streaming & looping are special
335                         * cases.
336                         */
337                        if(islooping == AL_TRUE && _alSourceIsQueue( src ) == AL_FALSE )
338                        {
339                                if(iscallback == AL_TRUE)
340                                {
341                                        _alDebug(ALD_LOOP, __FILE__, __LINE__,
342                                        "%d callback loop reset ", itr->sid);
343
344                                        src->srcParams.soundpos = 0;
345
346                                        /*
347                                         * we've actually been fudging the
348                                         * size
349                                         */
350                                        samp->size /= nc;
351                                } else {
352                                        _alDebug(ALD_LOOP, __FILE__, __LINE__,
353                                        "%d loop reset", itr->sid);
354
355                                        /*
356                                         * Looping buffers are prefed via
357                                         * SplitSources, so soundpos is
358                                         * actually bigger than the buffer
359                                         * size (because they wrap around).
360                                         */
361                                        src->srcParams.soundpos %= samp->size;
362                                }
363                        }
364                        else if(!isstreaming && !isinqueue)
365                        {
366                            if ( _alSourceIsQueue( src ) )
367                             {
368                              _alDebug(ALD_QUEUE, __FILE__, __LINE__,
369                              "%d queue loop reset",src->sid );
370                              src->srcParams.new_readindex = 0;
371                              src->srcParams.new_soundpos = 0;
372                              src->bid_queue.read_index =src->srcParams.new_readindex;
373                              src->srcParams.soundpos =  src->srcParams.new_soundpos;
374                              itr->flags = ALM_PLAY_ME;
375                             } else
376                                {
377                                    _alDebug(ALD_LOOP, __FILE__, __LINE__,
378                                    "%d loop destroy",itr->sid);
379                                    /* This buffer is solo */
380                                    itr->flags = ALM_DESTROY_ME;
381                                }
382                        }
383                }
384
385                if(isinqueue && (_alSourceGetPendingBids(src) < 0))
386                {
387                        /*
388                         * the read index might have been incremented
389                         * past our tolerance
390                         */
391                        itr->flags = ALM_DESTROY_ME;
392                }
393
394                _alUnlockSource( itr->context_id, itr->sid );
395        }
396
397        return;
398}
399
400/*
401 * _alAddDataToMixer( void *dataptr, ALuint bytes_to_write )
402 *
403 *
404 * Mixes bytes_to_write data from dataptr to the system buffer.  If
405 * bytes_to_write exceeds the system buffer size, it is truncated and returns
406 * the maximum it could write.
407 *
408 * assumes that mixer and default context are locked
409 */
410static ALuint _alAddDataToMixer( void *dataptr, ALuint bytes_to_write )
411{
412        if((dataptr == NULL) || (bytes_to_write == 0))
413        {
414                /* Most likely, thread is waiting to die */
415                return 0;
416        }
417
418        if(bytes_to_write > bufsiz)
419        {
420                bytes_to_write = bufsiz;
421        }
422
423        /* add entry to mix manager */
424        _alMixManagerAdd( &MixManager, dataptr, bytes_to_write );
425
426        return bytes_to_write;
427}
428
429/*
430 * void _alDestroyMixer( void )
431 *
432 * Deallocate data allocated in _alInitMixer.
433 */
434void _alDestroyMixer( void )
435{
436        if( mix_mutex != NULL )
437        {
438                _alDestroyMutex( mix_mutex );
439                mix_mutex = NULL;
440        }
441
442        _alMixPoolFree( &mspool, _alDestroyMixSource );
443        mspool.size = 0;
444
445        mixthread = NULL;
446
447        _alMixFuncDestroy(&MixFunc);
448        _alMixManagerDestroy(&MixManager);
449
450        free(mixbuf.data);
451        mixbuf.data   = NULL;
452        mixbuf.length = 0;
453
454        if( pause_mutex != NULL )
455        {
456                /* we may we destroyed while paused, which is bad, but
457                 * not horrible.  Try to lock it.  If sucessful, then
458                 * we weren't locked before, so we unlock and Destroy.
459                 * Otherwise, just unlock and destroy, since we aren't
460                 * going to be need async_mixer_iterate services anytime
461                 * soon anyway.
462                 */
463                _alTryLockMixerPause();
464                _alUnlockMixerPause(); /* at this point, we are either locked by
465                                          the context or by our own doing, so it's
466                                          okay to unlock.
467                                        */
468
469                _alDestroyMutex( pause_mutex );
470                pause_mutex = NULL;
471        }
472
473
474        return;
475}
476
477/*
478 * _alDestroyMixSource( void *ms )
479 *
480 * Finalize a _alMixSource object.
481 */
482static void _alDestroyMixSource( void *ms )
483{
484        _alMixSource *msrc = (_alMixSource *) ms;
485        ALuint sid = msrc->sid;
486        ALuint cid = msrc->context_id;
487        AL_source *src;
488        ALuint *bid;
489        ALuint i;
490
491        _alLockSource( cid, sid );
492
493        src = _alGetSource( cid, sid );
494        if(src == NULL) {
495                /*
496                 * source got nuked somewhere, or context was
497                 * destroyed while paused.
498                 */
499
500                _alDebug(ALD_MIXER, __FILE__, __LINE__,
501                        "_alDestroyMixSource: source id %d is not valid",
502                        msrc->sid);
503
504                _alUnlockSource( cid, sid );
505
506                return;
507        }
508
509        /*
510         * state should always be set to stopped by this point.
511         */
512        src->state = AL_STOPPED;
513
514        /* clear sid */
515        msrc->sid = 0;
516
517        /*
518         * Update buffer state
519         */
520        bid = _alGetSourceParam(src, AL_BUFFER);
521
522        if(_alSourceQueuedBuffers(src) > 1)
523        {
524                int ri;
525
526                ri = MIN(src->bid_queue.read_index, src->bid_queue.size - 1);
527
528                assert( ri >= 0 );
529                assert( ri < src->bid_queue.size );
530
531                bid = &src->bid_queue.queue[ri];
532        }
533        else if(bid == NULL)
534        {
535                /*
536                 * This shouldn't happend:  The buffer param of this
537                 * source is now invalid, but we're stopping it.  This
538                 * really is an ugly error: it most likely means that
539                 * there's a bug in the refcounting stuff somewhere.
540                 *
541                 * Actually, there's an exception to this.  For queued
542                 * sources, there will most likely be no buffer queued
543                 * at the end of the run.  So we have to special case
544                 * that.
545                 */
546                _alDebug(ALD_MIXER, __FILE__, __LINE__,
547                      "_alDestroyMixSource: no bid for source id %d",
548                      src->sid);
549
550                _alUnlockSource( cid, sid );
551
552                _alDCSetError( AL_INVALID_OPERATION );
553
554                return;
555        }
556
557        _alBidRemoveCurrentRef(*bid, src->sid);
558
559        if(src->bid_queue.size != 1)
560        {
561                /*
562                 * This is the last entry in the queue (or the source
563                 * was stopped) so we want to change the current state
564                 * for this bid/sid to queue.
565                 */
566                _alBidAddQueueRef(*bid, src->sid);
567        }
568
569        /*
570         * if we have a callback buffer, call the
571         * destructor on the source (because the source
572         * is over.
573         */
574        if(_alBidIsCallback(*bid) == AL_TRUE)
575        {
576                _alBidCallDestroyCallbackSource(src->sid);
577        }
578
579        /* streaming sources */
580        if(_alBidIsStreaming(*bid) == AL_TRUE)
581        {
582                for(i = 0; i < sbufs.size; i++)
583                {
584                        if(sbufs.streaming_buffers[i] == *bid)
585                        {
586                                sbufs.streaming_buffers[i] = 0;
587                                sbufs.items--;
588                        }
589                }
590        }
591
592        /*
593         * reset read index
594         * according to spec, a STOPPED source should
595         * have all of its buffers processed, so read_index
596         * should be the size of the queue.
597         *
598         * Hmmm, this is tricky, because many setter functions work of the
599         * assumptions that read_index points to something valid!  Okay, we're
600         * making the queue sourcestate getter ( used to access a lot of
601         * stuff ) return NULL, or assert or whatever, should catch these
602         * quick.
603         */
604        src->bid_queue.read_index = src->bid_queue.size;
605
606        _alUnlockSource( cid, sid );
607
608        return;
609}
610
611/*
612 * _alInitMixer( void )
613 *
614 * Create and initialize data structures needed by the mixing function.
615 */
616ALboolean _alInitMixer( void )
617{
618        bufsiz = _alcDCGetWriteBufsiz();
619
620        mix_mutex = _alCreateMutex();
621        if(mix_mutex == NULL)
622        {
623                return AL_FALSE;
624        }
625
626        pause_mutex = _alCreateMutex();
627        if(pause_mutex == NULL)
628        {
629                _alDestroyMutex( mix_mutex );
630                mix_mutex = NULL;
631
632                return AL_FALSE;
633        }
634
635        /* init Mixer funcs */
636        if( _alMixFuncInit(&MixFunc, MAXMIXSOURCES ) == AL_FALSE)
637        {
638                _alDestroyMutex( mix_mutex );
639                _alDestroyMutex( pause_mutex );
640                mix_mutex = NULL;
641                pause_mutex = NULL;
642
643                return AL_FALSE;
644        }
645
646        /* init MixManager */
647        if(_alMixManagerInit(&MixManager, MAXMIXSOURCES) == AL_FALSE)
648        {
649                _alDestroyMutex(mix_mutex);
650                _alDestroyMutex(pause_mutex);
651                mix_mutex = NULL;
652                pause_mutex = NULL;
653
654                _alMixFuncDestroy( &MixFunc );
655
656                return AL_FALSE;
657        }
658
659        mspool.size = 0;
660
661        return AL_TRUE;
662}
663
664/*
665 * _alSetMixer( ALboolean synchronous )
666 *
667 * Sets mixer to match the current context.  If synchronous is AL_FALSE, a
668 * seperate thread is launched.
669 *
670 * assumes locked context
671 */
672void _alSetMixer( ALboolean synchronous )
673{
674        AL_context *dc;
675        ALuint ex_format;
676        ALuint ex_speed;
677
678        dc =  _alcDCGetContext();
679        if(dc == NULL) {
680                _alDebug(ALD_MIXER, __FILE__, __LINE__,
681                        "_alSetMixer with no default context?  weird");
682                return;
683        }
684
685        if ( dc->write_device ) {
686                ex_format   = _alcDCGetWriteFormat();
687                ex_speed    = _alcDCGetWriteSpeed();
688                bufsiz      = _alcDCGetWriteBufsiz();
689        } else {
690                ex_format   = _alcDCGetReadFormat();
691                ex_speed    = _alcDCGetReadSpeed();
692                bufsiz      = _alcDCGetReadBufsiz();
693        }
694
695        _alDebug(ALD_CONVERT, __FILE__, __LINE__,
696                "_alSetMixer f|c|s [0x%x|%d|%d] -> [0x%x|%d|%d]",
697                /* from */
698                canon_format,
699                _alGetChannelsFromFormat( ex_format ), /* ignore channel settings.  We handle this */
700                canon_speed,
701                /* to */
702                ex_format,
703                _alGetChannelsFromFormat( ex_format ),
704                ex_speed);
705
706        if(acBuildAudioCVT(&s16le,
707                /* from */
708                _al_AL2ACFMT( canon_format ),
709                _alGetChannelsFromFormat( ex_format ), /* ignore channel settings.  We handle this */
710                canon_speed,
711
712                /* to */
713                _al_AL2ACFMT(ex_format),
714                _alGetChannelsFromFormat(ex_format),/* ignore channel settings.  We handle this */
715                ex_speed) < 0)
716        {
717                _alDebug(ALD_CONVERT, __FILE__, __LINE__,
718                        "Couldn't build audio convertion data structure.");
719        }
720
721        if( s16le.len_mult > 1.0 )
722        {
723                /*
724                 * we always alloc the larger value, because
725                 * we need the extra space
726                 */
727                mixbuf.length = bufsiz * s16le.len_mult;
728        } else {
729                mixbuf.length = bufsiz;
730        }
731
732        free(mixbuf.data);
733        mixbuf.data = malloc(mixbuf.length);
734        assert(mixbuf.data);
735
736        s16le.buf     = mixbuf.data;
737        s16le.len     = bufsiz;
738
739        if(synchronous == AL_TRUE) {
740                mixer_iterate = sync_mixer_iterate;
741        } else {
742            mixer_iterate = async_mixer_iterate;
743#ifndef USE_BACKEND_NATIVE_DARWIN
744/*Since the new darwin backend uses a core audio thread, we don't need the mixing thread anymore and use the sync mixer */
745                if(mixthread == NULL) {
746                        mixthread = _alCreateThread(mixer_iterate);
747                }
748#endif
749        }
750
751        return;
752}
753
754/*
755 * _alAllocMixSource( ALuint sid )
756 *
757 * Reserve an _alMixSource, associate it with the source named sid.  Returns
758 * AL_TRUE if reservation was true, AL_FALSE if sid is invalid or allocation
759 * was not possible.
760 *
761 * If sid is not a valid source, AL_INVALID_NAME is set.
762 *
763 * Assumes locked context
764 */
765static ALboolean _alAllocMixSource( ALuint sid )
766{
767        AL_source *src;
768        ALuint *bid;
769        _alMixSource *msrc;
770        ALuint context_id = _alcCCId; /* current context id */
771        int msindex;
772
773        src = _alGetSource( context_id, sid );
774        if( src == NULL ) {
775                _alDebug(ALD_SOURCE, __FILE__, __LINE__,
776                      "_alAllocMixSource: source id %d is not valid", sid);
777
778                _alSetError( context_id, AL_INVALID_NAME );
779
780                return AL_FALSE;
781        }
782
783        /*
784         *  Make sure that the source isn't already playing.
785         */
786        if( src->state == AL_PLAYING ) {
787                /*
788                 * The source in question is already playing.
789                 *
790                 * Legal NOP
791                 */
792                _alDebug(ALD_MIXER, __FILE__, __LINE__,
793                        "_alAllocMixSource: source id %d already playing", sid);
794
795                return AL_FALSE;
796        }
797
798        if ( src->state == AL_STOPPED ) {
799                /*
800                 *  The source in question has been stopped.  Promote to
801                 *  initial and play.
802                 */
803
804                src->srcParams.soundpos = 0;
805                src->bid_queue.read_index = 0;
806                src->state = AL_INITIAL;
807        }
808
809        /*
810         *  Add reference for buffer
811         */
812        _alLockBuffer();
813
814        bid = _alGetSourceParam( src, AL_BUFFER );
815        if(bid == NULL) {
816                _alUnlockBuffer();
817
818                /*
819                 * The source in question does not have the BUFFER
820                 * attribute set.
821                 */
822                _alDebug(ALD_MIXER, __FILE__, __LINE__,
823                        "_alAllocMixSource: source id %d has BUFFER unset",sid);
824
825                _alSetError(context_id, AL_INVALID_OPERATION);
826
827                return AL_FALSE;
828        }
829
830        if( _alIsBuffer(*bid) == AL_FALSE ) {
831                /*
832                 * The source in question has a buffer id, but it is not
833                 * valid.
834                 */
835                _alUnlockBuffer();
836
837                _alDebug(ALD_MIXER, __FILE__, __LINE__,
838                        "_alAllocMixSource: source %d has invalid BUFFER %d:%d",
839                        sid, src->bid_queue.read_index, *bid);
840
841                _alSetError(context_id, AL_INVALID_NAME);
842
843                return AL_FALSE;
844        }
845
846        _alUnlockBuffer();
847
848        /* streaming buffers added to increment list */
849        if( _alBidIsStreaming(*bid) == AL_TRUE ) {
850                _alAddBufferToStreamingList(*bid);
851        }
852
853        if( src->bid_queue.read_index < src->bid_queue.size - 1 )
854        {
855                _alBidRemoveQueueRef(*bid, sid);
856        }
857
858        _alBidAddCurrentRef(*bid,  sid);
859
860        /*
861         *  Allocate space.
862         */
863        msindex = _alMixPoolAlloc( &mspool );
864        if(msindex == -1) {
865                return AL_FALSE;
866        }
867
868        /*
869         *  Initialization mojo.
870         *
871         *  set sid to source's id, flags to ALM_PLAY_ME, and
872         *  set the source's flags so that we know it's playing,
873         *  and reset soundpos.
874         */
875        msrc = _alMixPoolIndex( &mspool, msindex );
876
877        /* set mixsource information */
878        msrc->context_id    = context_id;
879        msrc->sid           = sid;
880        msrc->flags         = ALM_PLAY_ME;
881
882        /* set source information */
883        if(src->state != AL_PAUSED)
884        {
885                src->srcParams.soundpos = 0;
886                src->bid_queue.read_index     = 0;
887        }
888
889        src->state                    = AL_PLAYING;
890
891        return AL_TRUE;
892}
893
894/*
895 * _alRemoveSourceFromMixer( ALuint sid )
896 *
897 * Removes the source named sid from the mixer queue.
898 */
899ALboolean _alRemoveSourceFromMixer( ALuint sid ) {
900        AL_source *src;
901        ALuint i;
902
903        src = _alDCGetSource( sid );
904        if(src == NULL) {
905                _alDebug( ALD_MIXER, __FILE__, __LINE__,
906                          "_alRemoveSourceFromMixer: %d is an invalid source id",
907                          sid );
908
909                _alDCSetError( AL_INVALID_NAME );
910
911                return AL_FALSE;
912        }
913
914        /*
915         *      We are stopping now.    Which means we set the state:
916         *
917         *      active  -> stopped
918         *      paused  -> stopped
919         *      initial -> NOP
920         *      stopped -> NOP
921         *
922         */
923        switch(src->state) {
924                case AL_INITIAL:
925                case AL_STOPPED:
926                        /* Stop on a non active source is a legal NOP */
927                        _alDebug( ALD_MIXER, __FILE__, __LINE__,
928                                  "_alRemoveSourceFromMixer(%d): source is not playing",
929                                  sid );
930
931                        return AL_FALSE;
932                        break;
933                default:
934                        /* We're okay, otherwise */
935                        break;
936        }
937
938        for(i = 0; i < mspool.size; i++) {
939                if((mspool.pool[i].data.sid == sid) &&
940                         (mspool.pool[i].inuse == AL_TRUE)) {
941                        _alMixPoolDealloc( &mspool, i, _alDestroyMixSource );
942
943                        _alDebug( ALD_MIXER, __FILE__, __LINE__,
944                                        "_alRemoveSourceFromMixer: removed sid %d",
945                                        sid );
946
947                        return AL_TRUE;
948                }
949        }
950
951        /*
952         * We really shouldn't end up here.  It means that the ->flags
953         * attribute got weird somewhere.
954         */
955        _alDebug(ALD_MIXER, __FILE__, __LINE__,
956                "_alRemoveSourceFromMixer(%d): Could not remove source",
957                sid);
958
959        return AL_FALSE;
960}
961
962/*
963 * _alAddSourceToMixer( ALuint sid )
964 *
965 * Adds the source named sid to the mixing queue.  Sets AL_INVALID_NAME if sid
966 * is invalid.
967 *
968 * assumes that context is locked
969 * assumes that mixbuf is locked
970 */
971void _alAddSourceToMixer( ALuint sid )
972{
973        AL_source *src;
974
975        src = _alDCGetSource( sid );
976        if(src == NULL) {
977                /* invalid name */
978                _alDebug( ALD_MIXER, __FILE__, __LINE__,
979                          "_alAddSourceToMixer: source id %d is not valid",
980                          sid );
981
982                _alDCSetError( AL_INVALID_NAME );
983                return;
984        }
985
986        /*
987         * Now, we are going to set the state:
988         *
989         * initial -> active
990         * paused  -> active
991         * stopped -> active
992         * active  -> active, but reset
993         *
994         * Paused sources are already in the mixer, but being
995         * ignored, so we just "turn them on." initial and stopped
996         * sources need to have new mixsources alloced for them.
997         */
998        switch(src->state) {
999                case AL_PAUSED:
1000                        /* Paused sources, when played again, resume
1001                         * at their old location.  We don't need to
1002                         * alloc a new mixsource.
1003                         */
1004                        src->state = AL_PLAYING;
1005                        return;
1006                case AL_PLAYING:
1007                        /* This source is already playing.
1008                         *
1009                         * No state change, but reset.
1010                         */
1011                        src->srcParams.soundpos = 0;
1012
1013                        return;
1014                default:
1015                        /* alloc a mix source */
1016                        break;
1017        }
1018
1019        if(_alAllocMixSource( sid ) == AL_FALSE) {
1020                /* most likely, the buffer associated with the
1021                 * source in question has been deleted.  Return
1022                 * asap.
1023                 *
1024                 * We shouldn't set the error because _alAllocMixSource
1025                 * will actually be better aware of what the problem is,
1026                 * and so will set the error accordingly.
1027                 */
1028                _alDebug( ALD_MIXER, __FILE__, __LINE__,
1029                           "_alAddSourceToMixer: Could not add source sid %d",
1030                          sid );
1031
1032                return;
1033        }
1034
1035        _alDebug(ALD_MIXER, __FILE__, __LINE__,
1036                "_alAddSourceToMixer: added sid %d", sid);
1037
1038        return;
1039}
1040
1041/*
1042 * FL_alLockMixBuf(UNUSED(const char *fn), UNUSED(int ln))
1043 *
1044 * Locks the mutex guarding mixer data structures.
1045 */
1046void FL_alLockMixBuf( UNUSED(const char *fn), UNUSED(int ln) ) {
1047        _alLockPrintf("_alLockMixbuf", fn, ln);
1048
1049        _alLockMutex( mix_mutex );
1050
1051        return;
1052}
1053
1054/*
1055 * FL_alUnlockMixBuf(UNUSED(const char *fn), UNUSED(int ln))
1056 *
1057 * Unlocks the mutex guarding mixer data structures.
1058 */
1059void FL_alUnlockMixBuf(UNUSED(const char *fn), UNUSED(int ln)) {
1060        _alLockPrintf("_alUnlockMixbuf", fn, ln);
1061
1062        _alUnlockMutex( mix_mutex );
1063
1064        return;
1065}
1066
1067/*
1068 * async_mixer_iterate(UNUSED(void *dummy))
1069 *
1070 * threaded version of top level mixing function.  Doesn't end until the last
1071 * context is deleted.
1072 */
1073int async_mixer_iterate(UNUSED(void *dummy)) {
1074        ALuint bytes_to_write = 0;
1075
1076        /* clear buffer */
1077        memset(mixbuf.data, 0, mixbuf.length);
1078
1079        do {
1080                if(_alTryLockMixerPause() == AL_TRUE)
1081                {
1082                        _alLockMixBuf();
1083
1084                        _alMixSources();
1085
1086                        _alProcessFlags();
1087
1088                        _alUnlockMixBuf();
1089
1090                        /* we've accumulated sources, now mix */
1091                        _alMixManagerMix( &MixManager, &MixFunc, mixbuf.data );
1092
1093                        if(acConvertAudio(&s16le) < 0)
1094                        {
1095                                _alDebug(ALD_MAXIMUS, __FILE__, __LINE__,
1096                                "Couldn't execute conversion from canon.");
1097                                /*
1098                                 * most likely we're just early.
1099                                 * Don't sweat it.
1100                                 */
1101                                continue;
1102                        }
1103
1104                        bytes_to_write = s16le.len_cvt;
1105
1106                        if(bytes_to_write)
1107                        {
1108                                _alcDCDeviceWrite(mixbuf.data, bytes_to_write);
1109                        }
1110
1111                        /* clear buffer */
1112                        memset(mixbuf.data, 0, mixbuf.length);
1113
1114                        _alUnlockMixerPause();
1115                }
1116                /* give other threads a chance to acquire the mixer lock */
1117                _alMicroSleep(1);
1118        } while(time_for_mixer_to_die == AL_FALSE);
1119
1120        time_for_mixer_to_die = AL_FALSE;
1121
1122        _alExitThread();
1123#ifndef HAVE___ATTRIBUTE__
1124        return 0;
1125#endif
1126}
1127
1128/*
1129 * _alAddBufferToStreamingList( ALuint bid )
1130 *
1131 * Adds a buffer name to the streaming list, for special handling.
1132 *
1133 *  FIXME: need to free sbufs.stremaing_buffers on exit.
1134 */
1135static void _alAddBufferToStreamingList( ALuint bid ) {
1136        void *temp;
1137        int offset;
1138        ALuint newsize;
1139        ALuint i;
1140
1141        if(sbufs.items >= sbufs.size) {
1142                /* realloc */
1143                newsize = sbufs.size + 1;
1144
1145                temp = realloc(sbufs.streaming_buffers,
1146                                newsize * sizeof *sbufs.streaming_buffers);
1147                if(temp == NULL) {
1148                        /* what a bummer */
1149                        return;
1150                }
1151                sbufs.streaming_buffers = temp;
1152
1153                for(i = sbufs.size; i < newsize; i++) {
1154                        sbufs.streaming_buffers[i] = 0;
1155                }
1156
1157                sbufs.size = newsize;
1158        }
1159
1160        /* add bid to streaming list */
1161        for(i = 0, offset = sbufs.items; i < sbufs.size; i++) {
1162                offset = (offset + 1) % sbufs.size;
1163
1164                if(sbufs.streaming_buffers[offset] == 0) {
1165                        sbufs.streaming_buffers[offset] = bid;
1166
1167                        sbufs.items++;
1168
1169                        return;
1170                }
1171        }
1172
1173        return;
1174}
1175
1176/*
1177 * _alTryLockMixerPause( void )
1178 *
1179 * The function that alcMakeContextCurrent calls to pause
1180 * asynchronous mixers.  Return AL_TRUE if the pause mutex was locked,
1181 * AL_FALSE otherwise.
1182 */
1183static ALboolean _alTryLockMixerPause( void ) {
1184        if(_alTryLockMutex( pause_mutex ) == 0) {
1185                return AL_TRUE;
1186        }
1187
1188        return AL_FALSE;
1189}
1190
1191/*
1192 * _alLockMixerPause( void )
1193 *
1194 * The function that alcMakeContextCurrent calls to pause
1195 * asynchronous mixers
1196 */
1197void _alLockMixerPause( void ) {
1198        _alLockMutex( pause_mutex );
1199
1200        return;
1201}
1202
1203/*
1204 * _alUnlockMixerPause( void )
1205 *
1206 * The function that alcMakeContextCurrent calls to resume
1207 * asynchronous mixers
1208 */
1209void _alUnlockMixerPause( void ) {
1210        _alUnlockMutex( pause_mutex );
1211
1212        return;
1213}
1214
1215
1216/*
1217 * _alProcessFlags( void )
1218 *
1219 * The mixing function (_alMixSources), in the course of its job marks the
1220 * mixsource nodes with commands that need to be executed after the completion
1221 * of the mixsource's iteration through the loop.  This is the function where
1222 * such things are done.
1223 *
1224 * Also, we process streaming buffers here because they need to be visited
1225 * once per call to _alMixSources, but the presence of multiple sources
1226 * refering to the same buffer precludes us from doing the processing in
1227 * _alMixSources.
1228 *
1229 * assumes locked mixbuf
1230 */
1231void _alProcessFlags( void ) {
1232        _alMixSource *itr = NULL;
1233        AL_buffer *bitr; /* buffer iterator */
1234        ALuint i;
1235        ALuint k;
1236
1237        for(i = 0; i < mspool.size; i++) {
1238                if(mspool.pool[i].inuse == AL_FALSE) {
1239                        /* skip mixsources not in use */
1240                        continue;
1241                }
1242
1243                itr = _alMixPoolIndex(&mspool, i);
1244                if(itr == NULL)
1245                {
1246                        /* shouldn't happen */
1247                        continue;
1248                }
1249
1250                if(itr->flags & ALM_DESTROY_ME)
1251                {
1252                        /* this source associated with this mixsource
1253                         * has expired (either because it has been stopped
1254                         * or just run out.  Remove it.
1255                         */
1256                        if( alIsSource(itr->sid) == AL_FALSE )
1257                        {
1258                                /* sanity check */
1259                                continue;
1260                        }
1261
1262                        /* deallocated mixsource */
1263                        _alMixPoolDealloc( &mspool, i, _alDestroyMixSource );
1264                }
1265        }
1266
1267        _alLockBuffer();
1268
1269        /* process streaming buffers */
1270        i = sbufs.items;
1271        k = sbufs.size - 1;
1272
1273        while(i--) {
1274                int nc;
1275
1276                while(sbufs.streaming_buffers[k] == 0) {
1277                        /*
1278                         * We don't worry about underflow because
1279                         * we are keying off of the number of sbuf
1280                         * items.
1281                         */
1282                        k--;
1283                }
1284
1285                bitr = _alGetBuffer(sbufs.streaming_buffers[k]);
1286                if(bitr == NULL) {
1287                        _alDebug(ALD_STREAMING, __FILE__, __LINE__,
1288                                "invalid buffer id %d",
1289                                sbufs.streaming_buffers[k]);
1290
1291                        /* invalid buffer
1292                         *
1293                         * Most likely, the buffer got deleted at some
1294                         * point.  We remove here, decrement the items
1295                         * count and get on with life.
1296                         */
1297                        sbufs.streaming_buffers[k] = 0;
1298                        sbufs.items--;
1299
1300                        continue;
1301                }
1302
1303                /* get the buffer's number of channels, so multichannel
1304                 * streaming sounds work properly.
1305                 */
1306                nc = _alcDCGetNumSpeakers();
1307
1308                if(nc <= 0) {
1309                        nc = 1;
1310                }
1311
1312                if(_alGetBufferState(bitr) == AL_UNUSED) {
1313                        /* refcount 0?  Don't bother. */
1314                        sbufs.streaming_buffers[k] = 0;
1315                        sbufs.items--;
1316
1317                        continue;
1318                }
1319
1320                bitr->streampos += bufsiz/nc;
1321
1322                if(bitr->streampos >= bitr->size) {
1323                        if(bitr->flags & ALB_STREAMING_WRAP) {
1324                                /* If we have the wrap flag, wrap.
1325                                 * Otherwise, what?  End the source?
1326                                 * Loop forever?
1327                                 */
1328
1329                                _alDebug(ALD_STREAMING, __FILE__, __LINE__,
1330                                        "Wrapping\n");
1331
1332                                bitr->streampos = 0;
1333                                bitr->flags &= ~ALB_STREAMING_WRAP;
1334                        }
1335                }
1336        }
1337
1338        _alUnlockBuffer();
1339
1340        return;
1341}
1342
1343/*
1344 * sync_mixer_iterate(UNUSED(void *dummy))
1345 *
1346 * non-threaded version of top level mixing function.  Called many times.
1347 */
1348int sync_mixer_iterate(UNUSED(void *dummy))
1349{
1350        ALshort *dataptr = mixbuf.data;
1351        int bytes_to_write = 0;
1352
1353        /* clear buffer */
1354        if(dataptr)
1355        {
1356                memset( dataptr, 0, bufsiz );
1357        }
1358
1359        _alLockMixBuf();
1360        _alMixSources();
1361        _alProcessFlags();
1362        _alUnlockMixBuf();
1363
1364        /* we've accumulated sources, now mix */
1365        _alMixManagerMix(&MixManager, &MixFunc, mixbuf.data);
1366
1367        if(acConvertAudio(&s16le) < 0)
1368        {
1369                _alDebug(ALD_CONVERT, __FILE__, __LINE__,
1370                        "Couldn't execute conversion from canon.");
1371                return -1;
1372        }
1373
1374        bytes_to_write = s16le.len_cvt;
1375
1376        if(dataptr)
1377        {
1378                _alcDCDeviceWrite( dataptr, bytes_to_write );
1379        }
1380
1381        return 0;
1382}
Note: See TracBrowser for help on using the repository browser.