Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/openal-0.0.8/src/alc/alc_context.c @ 17

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

added openal

File size: 39.7 KB
Line 
1/* -*- mode: C; tab-width:8; c-basic-offset:8 -*-
2 * vi:set ts=8:
3 *
4 * alc_context.c
5 *
6 * Context management and application level calls.
7 */
8
9#include "al_siteconfig.h"
10
11#include <AL/alc.h>
12#include <AL/alext.h>
13#include <stdlib.h>
14#include <string.h>
15
16#include "al_mixer.h"
17#include "al_main.h"
18#include "al_debug.h"
19#include "al_ext.h"
20#include "al_listen.h"
21#include "al_source.h"
22#include "al_spool.h"
23#include "al_buffer.h"
24#include "al_filter.h"
25#include "al_distance.h"
26#include "al_cpu_caps.h"
27
28#include "alc/alc_error.h"
29#include "alc/alc_device.h"
30#include "alc/alc_speaker.h"
31#include "alc/alc_context.h"
32
33#include "backends/alc_backend.h"
34
35/*
36 * CONTEXT_BASE is the number which we start at for context ids.
37 */
38#define CONTEXT_BASE   0x9000
39
40/*
41 * canon_max and canon_min are the max/min values for PCM data in our
42 * canonical format, respectively.
43 */
44const int canon_max = ((1<<(16-1))-1),
45          canon_min = -(1<<(16-1));
46
47/*
48 * canon_format is the canonical format that we represent data internally as.
49 */
50ALenum canon_format = _ALC_CANON_FMT;
51
52/*
53 * canon_speed is the sampling rate at which we internally represent data.
54 */
55ALuint canon_speed = _ALC_CANON_SPEED;
56
57/*
58 * _alcCCId holds the context id of the current context.
59 */
60ALuint _alcCCId = (ALuint) -1;
61
62/*
63 * al_contexts is our context pool.
64 */
65static struct {
66        ALuint size;
67        ALuint items;
68
69        ALuint *map;
70        ALboolean *inuse;
71        AL_context *pool;
72} al_contexts = { 0, 0, NULL, NULL, NULL };
73
74/*
75 * all_context_mutex is the mutex guarding operations which require all the
76 * contexts to be locked.
77 */
78static MutexID all_context_mutex = NULL;
79
80/*
81 * contex_mutexen is a set of mutexes, one for each context, guarding each
82 * contex.
83 */
84static MutexID *context_mutexen  = NULL;
85
86/*
87 * _alcDestroyContext( AL_context *cc )
88 *
89 * Non locking version of alcDestroyContext.
90 */
91static void _alcDestroyContext( AL_context *cc );
92
93/*
94 * _alcReallocContexts( ALuint newsize )
95 *
96 * Increases data structures to accomodate at least newsize contexts.
97 */
98static void _alcReallocContexts( ALuint newsize );
99
100/*
101 * _alcGenerateNewCid( void )
102 *
103 * Returns a new unique ALuint suitable for use as a cid.
104 */
105static ALuint _alcGenerateNewCid( void );
106
107/*
108 * _alcCidToIndex( ALuint cid )
109 *
110 * Converts cid into a simple index, returning that.
111 */
112static ALuint _alcCidToIndex( ALuint cid );
113
114/*
115 * _alcIndexToCid( int index )
116 *
117 * Converts index to a cid, returning that.
118 */
119static ALuint _alcIndexToCid( int cindex );
120
121/*
122 * ALCCONTEXTP_TO_ALUINT and ALUINT_TO_ALCCONTEXTP are macros to ease the
123 * conversion of ALCcontext* to ALuint and visa versa.
124 *
125 * ToDo: I don't understand the need for the int64_t casts below...
126 */
127#if SIZEOF_VOID_P == 8
128#define ALCCONTEXTP_TO_ALUINT(vp) ((ALuint) (int64_t) (vp))
129#define ALUINT_TO_ALCCONTEXTP(al) ((ALCcontext *) (int64_t) (al))
130#else
131#define ALCCONTEXTP_TO_ALUINT(vp) ((ALuint) (vp))
132#define ALUINT_TO_ALCCONTEXTP(al) ((ALCcontext *) (al))
133#endif
134
135/*
136 * alcMakeContextCurrent( ALCcontext *handle )
137 *
138 * Makes the context refered to by handle the current context.  If handle does
139 * not refer to a context, ALC_INVALID_CONTEXT is set and ALC_FALSE returned.
140 * Otherwise, the operation suceeds and ALC_TRUE is returned.
141 */
142ALCboolean alcMakeContextCurrent( ALCcontext *handle )
143{
144        AL_context *cc;
145        int cid;
146        static ALboolean ispaused = AL_FALSE;
147        ALboolean should_init_mixer = AL_FALSE;
148
149        if(handle == NULL) {
150                /* NULL handle means pause */
151                if(ispaused == AL_FALSE) {
152                        if(al_contexts.items != 0) {
153                                /* only lock if a context has been
154                                 * created.  Otherwise, don't.
155                                 */
156
157                                /* Give mixer thread chance to catch up */
158
159                                _alLockMixerPause();
160
161                                _alcLockAllContexts();
162
163                                cc = _alcDCGetContext();
164                                if( cc == NULL ) {
165                                        /* I don't even want to think about it */
166
167                                        /* FIXME: wrong error */
168                                        _alcSetError( ALC_INVALID_CONTEXT );
169                                        _alcUnlockAllContexts();
170                                        return ALC_FALSE;
171                                }
172
173                                /*
174                                 * inform current audio device about
175                                 * impending stall.
176                                 */
177                                if( cc->write_device ) {
178                                        _alcDevicePause( cc->write_device );
179                                }
180                                if( cc->read_device ) {
181                                        _alcDevicePause( cc->read_device );
182                                }
183
184                                _alcCCId = (ALuint) -1;
185                                _alcUnlockAllContexts();
186                        }
187
188                        ispaused = AL_TRUE;
189                }
190
191                return ALC_TRUE;
192        }
193
194        cid = ALCCONTEXTP_TO_ALUINT( handle );
195
196        _alcLockAllContexts();
197
198        if( _alcIsContext( _alcCCId ) == AL_FALSE ) {
199                should_init_mixer = AL_TRUE;
200        }
201
202        _alcCCId = cid;
203
204        cc = _alcGetContext( cid );
205        if( cc == NULL ) {
206                /* I don't even want to think about it */
207
208                /* FIXME: wrong error */
209                _alcSetError( ALC_INVALID_CONTEXT );
210                _alcUnlockAllContexts( );
211                return ALC_FALSE;
212        }
213
214        if( should_init_mixer == AL_TRUE ) {
215                /* Set up mixer thread */
216                if(_alInitMixer() == AL_FALSE) {
217                        /* do something */
218                }
219        }
220
221        /* set device's current context */
222        if(cc->write_device) {
223                cc->write_device->cc = cc;
224                _alcDeviceSet( cc->write_device );
225        }
226
227        _alSetMixer( cc->should_sync ); /* set mixing stats */
228
229        if(cc->read_device) {
230                cc->read_device->cc = cc;
231                _alcDeviceSet( cc->read_device );
232        }
233
234
235        if(ispaused == AL_TRUE) {
236                /* someone unpaused us */
237                ispaused = AL_FALSE;
238
239                _alcDeviceResume( cc->write_device );
240                _alcDeviceResume( cc->read_device );
241
242                _alcUnlockAllContexts();
243                _alUnlockMixerPause();
244        } else {
245                /* just unlock contexts */
246                _alcUnlockAllContexts();
247        }
248
249        return ALC_TRUE;
250}
251
252/*
253 * alcDestroyContext( ALvoid *handle )
254 *
255 * Destroys the context referred to by handle.
256 */
257void alcDestroyContext( ALCcontext *handle )
258{
259        AL_context *cc;
260        int cid;
261
262        if( handle == NULL ) {
263                _alcSetError( ALC_INVALID_CONTEXT );
264                return;
265        }
266
267        cid = ALCCONTEXTP_TO_ALUINT( handle );
268
269        _alcLockContext( cid );
270        cc = _alcGetContext( cid );
271        if( cc == NULL ) {
272                _alcSetError( ALC_INVALID_CONTEXT );
273                _alcUnlockContext( cid );
274                return;
275        }
276
277        /*
278         * If this is the last context, run _alExit()
279         * to clean up the cruft
280         */
281        if( al_contexts.items == 1 ) {
282                /* unlock context for final time */
283                _alcUnlockContext( cid );
284
285                /* cleanup */
286                _alExit();
287
288                /*
289                 * Set NumContexts to 0
290                 */
291                al_contexts.items = 0;
292
293                /*
294                 * Destroy the all-locking-contexts
295                 */
296                _alDestroyMutex( all_context_mutex );
297                all_context_mutex = NULL;
298
299                return;
300        }
301
302        /* call internal destroyer */
303        _alcDestroyContext( cc );
304
305        /*
306         * Decrement the number of contexts in use.
307         */
308        al_contexts.items--;
309
310        _alcUnlockContext( cid );
311}
312
313/**
314 * alcProcessContext( ALvoid *alcHandle )
315 *
316 * Performs processing on a synced context, nop on a asynchronous
317 * context.
318 *
319 * If alcHandle is not valid, ALC_INVALID_CONTEXT is set.
320 */
321void alcProcessContext( ALCcontext *alcHandle )
322{
323        AL_context *cc;
324        ALboolean should_sync;
325        int cid;
326
327        if( alcHandle == NULL ) {
328                /*
329                 * invalid name?
330                 */
331                _alDebug(ALD_CONTEXT, __FILE__, __LINE__,
332                      "alcUpdateContext: alcHandle == NULL");
333
334                _alcSetError( ALC_INVALID_CONTEXT );
335                return;
336        }
337
338        cid = ALCCONTEXTP_TO_ALUINT( alcHandle );
339
340        /* determine whether we need to sync or not */
341        _alcLockAllContexts();
342
343        cc = _alcGetContext( cid );
344        if(cc == NULL) {
345                _alDebug( ALD_CONTEXT, __FILE__, __LINE__,
346                          "alcUpdateContext: invalid context id %d",
347                          cid );
348
349                _alcSetError( ALC_INVALID_CONTEXT );
350                _alcUnlockAllContexts();
351                return;
352        }
353
354        should_sync = cc->should_sync;
355        _alcUnlockAllContexts();
356
357        if( should_sync == AL_TRUE ) {
358                mixer_iterate( NULL );
359        } else {
360                /* unsuspend async contexts */
361                cc->issuspended = AL_FALSE;
362        }
363}
364
365/**
366 *
367 * alcSuspendContext( ALCcontext *alcHandle )
368 *
369 * Suspends processing on an asynchronous context.  This is a legal nop on a
370 * synced context.
371 *
372 * If alcHandle is not valid, ALC_INVALID_CONTEXT is returned.
373 */
374void alcSuspendContext( ALCcontext *alcHandle )
375{
376        AL_context *cc;
377        ALuint cid;
378
379        if( alcHandle == NULL ) {
380                /*
381                 * invalid name?
382                 */
383                _alDebug(ALD_CONTEXT, __FILE__, __LINE__,
384                      "alcUpdateContext: alcHandle == NULL");
385
386                _alcSetError( ALC_INVALID_CONTEXT );
387
388                return;
389        }
390
391        cid = ALCCONTEXTP_TO_ALUINT( alcHandle );
392
393        /* determine whether we need to sync or not */
394        _alcLockAllContexts();
395
396        cc = _alcGetContext( cid );
397        if( cc == NULL ) {
398                _alDebug( ALD_CONTEXT, __FILE__, __LINE__,
399                          "alcUpdateContext: invalid context id %d",
400                          cid );
401
402                _alcSetError( ALC_INVALID_CONTEXT );
403
404                _alcUnlockAllContexts();
405
406                return;
407        }
408
409        if( cc->should_sync == AL_FALSE) {
410                /*
411                 * only asynchronous contexts can be
412                 * suspended.
413                 */
414                cc->issuspended = AL_TRUE;
415        }
416
417        _alcUnlockAllContexts();
418
419        return;
420}
421
422/*
423 * alcCreateContext( ALCdevice *dev, ALCint *attrlist )
424 *
425 * Allocates, initialiaes, and returns an AL_context handle, suitable for
426 * passing to other alc functions.  Uses dev as the write device for the
427 * context.  attrlist is an int array, zero terminated, that contains
428 * attribute/value pairs used to initialize the context.
429 *
430 * We use a meet-or-exceed system here.  If any attribute in attrlist cannot
431 * have the required value met or exceeded, NULL is returned.  If dev is not
432 * valid, ALC_INVALID_DEVICE is set and NULL is returned.
433 *
434 * FIXME: not as well tested as I'd like.
435 */
436ALCcontext *alcCreateContext( ALCdevice *dev, const ALCint *attrlist )
437{
438        ALint cid;
439
440        if( dev == NULL ) {
441                _alcSetError( ALC_INVALID_DEVICE );
442
443                return NULL;
444        }
445       
446        _alDetectCPUCaps();
447       
448        if( al_contexts.items == 0 ) {
449                /*
450                 * This is the first context to be created.  Initialize the
451                 * library's data structures.
452                 */
453
454                /* get a context name for the new context */
455                cid = _alcGetNewContextId();
456
457                /* misc library initialization */
458                _alInit();
459
460                /* set the context attributes */
461                _alcLockContext( cid );
462                _alcSetContext( attrlist, cid, dev );
463                _alcUnlockContext( cid );
464
465                return ALUINT_TO_ALCCONTEXTP( cid );
466        }
467
468        _alcLockAllContexts();
469        cid = _alcGetNewContextId();
470        if(cid == -1) {
471                _alDebug( ALD_CONTEXT, __FILE__, __LINE__,
472                          "alcCreateContext failed." );
473
474                _alcSetError( ALC_INVALID_DEVICE );
475                _alcUnlockAllContexts();
476
477                return NULL;
478        }
479
480        _alcUnlockAllContexts();
481
482        _alcLockContext( cid );
483        _alcSetUse( cid, AL_TRUE );
484        _alcSetContext( attrlist, cid, dev );
485        _alcUnlockContext( cid );
486
487        return ALUINT_TO_ALCCONTEXTP( cid );
488}
489
490/*
491 * _alcDestroyContext( AL_context *cc )
492 *
493 * Non locking version of alcDestroyContext.
494 *
495 * FIXME: should assume that *all contexts* are locked?
496 */
497void _alcDestroyContext( AL_context *cc )
498{
499        free(cc->Flags);
500        cc->Flags = 0;
501        cc->NumFlags = 0;
502
503        _alDestroyListener( &cc->listener );
504        _alDestroySources( &cc->source_pool );
505}
506
507
508/*
509 * FL_alcLockContext( ALuint cid, const char *fn, int ln )
510 *
511 * Locks the mutex associated with the context named by cid, passing fn and ln
512 * to _alLockPrintf for debugging purposes.
513 */
514void FL_alcLockContext(ALuint cid, UNUSED(const char *fn), UNUSED(int ln)) {
515        int cindex;
516
517        _alLockPrintf("_alcLockContext", fn, ln);
518
519        cindex = _alcCidToIndex(cid);
520        if( cindex < 0 ) {
521                _alDebug(ALD_CONTEXT, __FILE__, __LINE__,
522                                "FL_alcLockContext: invalid context.");
523                return;
524        }
525
526        _alcLockAllContexts();
527
528        _alLockMutex(context_mutexen[cindex]);
529
530        _alcUnlockAllContexts();
531
532        return;
533}
534
535/*
536 * FL_alcUnlockContext( ALuint cid, const char *fn, int ln )
537 *
538 * Unlocks the mutex associated with the context named by cid, passing fn and ln
539 * to _alLockPrintf for debugging purposes.
540 */
541void FL_alcUnlockContext(ALuint cid, UNUSED(const char *fn), UNUSED(int ln)) {
542        int cindex;
543
544        _alLockPrintf("_alcUnlockContext", fn, ln);
545
546        cindex = _alcCidToIndex( cid );
547        if( cindex < 0 ) {
548                _alDebug(ALD_CONTEXT, __FILE__, __LINE__,
549                                "FL_alcUnlockContext: invalid context.");
550                return;
551        }
552
553        _alUnlockMutex(context_mutexen[cindex]);
554
555        return;
556}
557
558/*
559 * _alcGetContext( ALuint cid )
560 *
561 * Returns pointer to the AL_context named by cid, or NULL if cid is not a
562 * valid context name.
563 */
564AL_context *_alcGetContext( ALuint cid ) {
565        ALuint cindex;
566
567        cindex = _alcCidToIndex(cid);
568
569        if(cindex >= al_contexts.size) {
570                return NULL;
571        }
572
573        if(al_contexts.inuse[cindex] == AL_FALSE) {
574                return NULL;
575        }
576
577        return &al_contexts.pool[cindex];
578}
579
580
581/*
582 * void _alcSetContext( const ALCint *attrlist, ALuint cid, AL_device *dev )
583 *
584 * Sets context id paramaters according to an attribute list and device.
585 *
586 */
587void _alcSetContext(const ALCint *attrlist, ALuint cid, AL_device *dev ) {
588        AL_context *cc;
589        ALboolean reading_keys = AL_TRUE;
590        struct { int key; int val; } rdr;
591        ALuint refresh_rate = 15;
592        ALuint bufsiz;
593
594        cc = _alcGetContext( cid );
595        if(cc == NULL) {
596                return;
597        }
598
599        /* get ready to copy attrlist */
600        free(cc->Flags);
601        cc->Flags = 0;
602        cc->NumFlags = 0;
603
604        /* Set our preferred mixer stats */
605        if (dev->flags & ALCD_WRITE)
606        {
607                cc->write_device = dev;
608                /* At this point we know the listener position and the number of speakers. */
609                _alcSpeakerMove( cid );
610        }
611        if (dev->flags & ALCD_READ)
612        {
613                cc->read_device = dev;
614        }
615
616        while(attrlist && (reading_keys == AL_TRUE)) {
617                void *t = 0;
618
619                rdr.key = *attrlist++;
620                if(rdr.key != 0)
621                {
622                        rdr.val = *attrlist++;
623                }
624
625                t = realloc(cc->Flags,
626                                  (2 + cc->NumFlags) * 2 * sizeof *cc->Flags);
627                if(t)
628                {
629                        cc->Flags = t;
630
631                        cc->Flags[2 * cc->NumFlags] = rdr.key;
632                        cc->Flags[2 * cc->NumFlags + 1] = rdr.val;
633
634                        cc->NumFlags++;
635                }
636
637                switch(rdr.key) {
638                        case ALC_FREQUENCY:
639                                canon_speed = rdr.val;
640
641                                _alDebug( ALD_CONTEXT, __FILE__, __LINE__,
642                                        "cc->external_speed = %d", rdr.val );
643                                break;
644                        case ALC_REFRESH:
645                                refresh_rate = rdr.val;
646                                break;
647                        case ALC_SOURCES_LOKI:
648                                spool_resize(&cc->source_pool, rdr.val);
649
650                                _alDebug(ALD_CONTEXT,
651                                        __FILE__, __LINE__,
652                                        "ALC_SOURCES (%d)", rdr.val);
653                                break;
654                        case ALC_BUFFERS_LOKI:
655                                _alNumBufferHint( rdr.val );
656                                break;
657                        case ALC_SYNC:
658                                if(rdr.val == AL_TRUE) {
659                                        cc->should_sync = AL_TRUE;
660                                } else {
661                                        cc->should_sync = AL_FALSE;
662                                }
663                                break;
664                        case 0:
665                                reading_keys = AL_FALSE;
666                                break;
667                        default:
668                                reading_keys = AL_FALSE;
669                                _alDebug(ALD_CONTEXT,
670                                        __FILE__, __LINE__,
671                                        "unsupported context attr %d",
672                                        rdr.key );
673                                break;
674                }
675        }
676
677        /* okay, now post process */
678
679        if( refresh_rate > canon_speed ) {
680                /*
681                 * We don't accept refresh rates greater than the
682                 * sampling rate.
683                 */
684                refresh_rate = canon_speed;
685        }
686
687        bufsiz = _alSmallestPowerOfTwo(
688                                (ALuint) ((float) canon_speed / refresh_rate));
689        if (dev->flags & ALCD_WRITE)
690                cc->write_device->bufsiz = bufsiz;
691        if (dev->flags & ALCD_READ)
692                cc->read_device->bufsiz = bufsiz;
693
694        _alDebug( ALD_CONTEXT, __FILE__, __LINE__,
695                "new bufsiz = %d", bufsiz);
696
697        return;
698}
699
700/*
701 * _alcInitContext( ALuint cid )
702 *
703 * Initialize the context named by cid, and returns the AL_context associated
704 * with that id.
705 *
706 * assumes locked context
707 */
708AL_context *
709_alcInitContext( ALuint cid )
710{
711        AL_context *cc = _alcGetContext(cid);
712        if(cc == NULL) {
713                /* invalid context */
714                return NULL;
715        }
716
717        /* initialize spec parameters */
718        cc->doppler_factor = 1.0f;
719        cc->doppler_velocity = 1.0f;
720        cc->speed_of_sound = 343.3f;
721        cc->distance_model = AL_INVERSE_DISTANCE_CLAMPED;
722
723        _alUpdateDistanceModel(cc);
724
725        _alInitTimeFilters(cc->time_filters);
726
727        cc->alErrorIndex   = AL_NO_ERROR;
728
729        _alInitListener(&cc->listener);
730
731        /* Source initializations */
732        spool_init(&cc->source_pool);
733
734        cc->read_device = NULL;
735        cc->write_device = NULL;
736
737        /*
738         *_speaker_pos is initialized later when we know the output device and
739         * therefore the number of speakers
740         */
741
742        /*
743         * should_sync:
744         *      AL_FALSE:
745         *              we use async_mixer_iterate, and don't need
746         *              to have alcUpdateContext called to actually
747         *              mix the audio.
748         *      AL_TRUE:
749         *              we use sync_mixer_iterate, and need to have
750         *              alcUpdateContext called to actually mix the
751         *              audio.
752         */
753        cc->should_sync = AL_FALSE;
754        cc->issuspended = AL_FALSE; /* deviates */
755
756        cc->Flags = 0;
757        cc->NumFlags = 0;
758
759        return cc;
760}
761
762/*
763 * _alcSetUse( ALuint cid, ALboolean value )
764 *
765 * Sets the use flag of context with id cid to value.
766 *
767 * Assumes context is locked
768 *
769 * NOTES:
770 *    Can't use alcGetContext, because that checks the use flag,
771 *    which maybe set to false, which is what this function seeks
772 *    to correct.
773 *
774 */
775ALboolean _alcSetUse(ALuint cid, ALboolean val) {
776        ALuint cindex;
777
778        cindex = _alcCidToIndex(cid);
779
780        if(cindex >= al_contexts.size) {
781                return !val;
782        }
783
784        return al_contexts.inuse[cindex] = val;
785}
786
787/*
788 * _alcInUse( ALuint cid )
789 *
790 * Returns AL_TRUE if the context named by cid is in use, AL_FALSE otherwise.
791 */
792ALboolean _alcInUse(ALuint cid) {
793        ALuint cindex;
794
795        cindex = _alcCidToIndex(cid);
796
797        if(cindex >= al_contexts.size) {
798                return AL_FALSE;
799        }
800
801        return al_contexts.inuse[cindex];
802}
803
804/*
805 * FL_alcLockAllContexts( const char *fn, int ln )
806 *
807 * Locks the mutex associated guarding all contexts, passing fn and ln to
808 * _alLockPrintf for debugging purposes.
809 */
810void FL_alcLockAllContexts(UNUSED(const char *fn), UNUSED(int ln)) {
811        if( all_context_mutex == NULL ) {
812                return;
813        }
814
815        _alLockPrintf("_alcLockAllContexts", fn, ln);
816        _alLockMutex(all_context_mutex);
817}
818
819/*
820 * FL_alcUnlockAllContexts( const char *fn, int ln )
821 *
822 * Unlocks the mutex associated guarding all contexts, passing fn and ln to
823 * _alLockPrintf for debugging purposes.
824 */
825void FL_alcUnlockAllContexts(UNUSED(const char *fn), UNUSED(int ln)) {
826        if( all_context_mutex == NULL ) {
827                return;
828        }
829
830        _alLockPrintf("_alcUnlockAllContexts", fn, ln);
831        _alUnlockMutex(all_context_mutex);
832}
833
834/*
835 * _alcGetListener( ALuint cid )
836 *
837 * Returns a pointer to the listener associated with context named by cid, or
838 * NULL if cid does not name a valid context.
839 *
840 * assumes locked context
841 */
842AL_listener *_alcGetListener( ALuint cid ) {
843        AL_context *cc;
844
845        cc = _alcGetContext(cid);
846        if(cc == NULL) {
847                return NULL;
848        }
849
850        return &cc->listener;
851}
852
853/*
854 * _alcDestroyAll( void )
855 *
856 * Deallocates the data structures for all contexts.
857 */
858void _alcDestroyAll( void ) {
859        AL_context *freer;
860        ALuint i;
861        ALuint cid;
862
863        for(i = 0; i < al_contexts.items; i++) {
864                cid = _alcIndexToCid( i );
865
866                if(context_mutexen[i] != NULL) {
867                        _alDestroyMutex( context_mutexen[i] );
868                        context_mutexen[i] = NULL;
869                }
870
871                if(_alcInUse(cid) == AL_TRUE) {
872                        freer = _alcGetContext( cid );
873
874                        if(freer != NULL) {
875                                _alcDestroyContext( freer );
876                        }
877                }
878        }
879
880        free( context_mutexen );
881        context_mutexen = NULL;
882
883        free( al_contexts.map );
884        free( al_contexts.pool );
885        free( al_contexts.inuse );
886
887        al_contexts.map   = NULL;
888        al_contexts.pool  = NULL;
889        al_contexts.inuse = NULL;
890        al_contexts.items = 0;
891        al_contexts.size  = 0;
892
893        return;
894}
895
896/*
897 * _alcGetNewContextId( void )
898 *
899 * Returns a new id for use as a context name, setting its use flag to
900 * AL_TRUE, and returns the id.
901 *
902 * If there are no unused contexts, at least one more is created,
903 * and it is modified and returned in the manner described above.
904 *
905 * assumes locked contexts
906 */
907ALint _alcGetNewContextId(void) {
908        ALuint i;
909        ALuint cid;
910        ALuint cindex;
911
912        for(i = 0; i < al_contexts.size; i++) {
913                if(al_contexts.inuse[i] == AL_TRUE) {
914                        continue;
915                }
916
917                al_contexts.items++;
918                al_contexts.inuse[i] = AL_TRUE;
919                return al_contexts.map[i] = _alcGenerateNewCid();
920        }
921
922        _alcReallocContexts(al_contexts.size + 1);
923
924        cindex = al_contexts.size - 1;
925        cid = _alcGenerateNewCid();
926
927        assert(al_contexts.inuse[cindex] == AL_FALSE);
928
929        al_contexts.inuse[cindex] = AL_TRUE;
930        al_contexts.map[cindex]   = cid;
931
932        if(_alcInitContext(cid) == NULL) {
933                assert(0);
934                return -1;
935        }
936
937        al_contexts.items++;
938
939        /*
940         *  We create contexts at the end, so the context id
941         *  will be the last valid element index (al_contexts.items - 1)
942         */
943        return cid;
944}
945
946/*
947 * _alcReallocContexts( ALuint newsize )
948 *
949 * _alcReallocContexts resizes the context pool to at least
950 * newsize contexts, and creates mutex such that the new
951 * contexts can be locked.
952 *
953 * assumes locked contexts
954 */
955static void _alcReallocContexts(ALuint newsize) {
956        void *temp;
957        ALuint i;
958
959        if(al_contexts.size >= newsize) {
960                return;
961        }
962
963        /* resize context pool */
964        temp = realloc(al_contexts.pool, sizeof *al_contexts.pool * newsize);
965        if(temp == NULL) {
966                perror("_alcReallocContexts malloc");
967                exit(4);
968        }
969        al_contexts.pool = temp;
970
971        /* resize inuse flags */
972        temp = realloc(al_contexts.inuse, sizeof *al_contexts.inuse * newsize);
973        if(temp == NULL) {
974                perror("_alcReallocContexts malloc");
975                exit(4);
976        }
977        al_contexts.inuse = temp;
978
979        /* resize context map */
980        temp = realloc(al_contexts.map, sizeof *al_contexts.map * newsize);
981        if(temp == NULL) {
982                perror("_alcReallocContexts malloc");
983                exit(4);
984        }
985        al_contexts.map = temp;
986
987        temp = realloc(context_mutexen, sizeof *context_mutexen * newsize);
988        if(temp == NULL) {
989                perror("_alcReallocContexts malloc");
990                exit(4);
991        }
992        context_mutexen = temp;
993
994        /* initialize new data */
995        for(i = al_contexts.items; i < newsize; i++) {
996                al_contexts.inuse[i] = AL_FALSE;
997                al_contexts.map[i] = 0;
998                context_mutexen[i] = _alCreateMutex();
999        }
1000
1001        if(al_contexts.items == 0) {
1002                /* If al_contexts.items is <= 0, then were are creating
1003                 * the contexts for the first time, and must create the
1004                 * "lock all contexts" mutex as well.
1005                 */
1006
1007                all_context_mutex = _alCreateMutex();
1008                if(all_context_mutex == NULL) {
1009                        perror("CreateMutex");
1010                        exit(2);
1011                }
1012        }
1013
1014        al_contexts.size = newsize;
1015
1016        return;
1017}
1018
1019/*
1020 * _alcGetTimeFilters( ALuint cid )
1021 *
1022 * Returns a pointer to the time_filter_set associated with the context named
1023 * by cid, or NULL if cid does not name a context.
1024 *
1025 * assumes locked context cid
1026 */
1027time_filter_set *_alcGetTimeFilters( ALuint cid ) {
1028        AL_context *cc;
1029
1030        cc = _alcGetContext( cid );
1031        if(cc == NULL) {
1032                return NULL;
1033        }
1034
1035        return cc->time_filters;
1036}
1037
1038/*
1039 * _alcIndexToCid( int index )
1040 *
1041 * Converts index to a cid, returning that.
1042 */
1043static ALuint _alcCidToIndex( ALuint cid ) {
1044        ALuint i;
1045
1046        for(i = 0; i < al_contexts.size; i++) {
1047                if( al_contexts.map[i] == cid ) {
1048                        return i;
1049                }
1050        }
1051
1052        return -1;
1053}
1054
1055/*
1056 * _alcIndexToCid( int index )
1057 *
1058 * Converts index to a cid, returning that.
1059 */
1060static ALuint _alcIndexToCid(int ind)
1061{
1062        assert(ind >= 0);
1063        assert(ind < (int) al_contexts.size);
1064
1065        return al_contexts.map[ind];
1066}
1067
1068/*
1069 * _alcGenerateNewCid( void )
1070 *
1071 * Returns a new unique ALuint suitable for use as a cid.
1072 */
1073static ALuint _alcGenerateNewCid(void) {
1074        static ALuint base = CONTEXT_BASE;
1075
1076        return base++;
1077}
1078
1079/*
1080 * alcGetCurrentContext( void )
1081 *
1082 * Returns context handle suitable associated with current context,
1083 * suitable for use with every function that takes a context handle,
1084 * or NULL if there is no current context.
1085 */
1086ALCcontext *alcGetCurrentContext( void )
1087{
1088        if(al_contexts.items == 0)
1089        {
1090                return NULL;
1091        }
1092
1093        if( _alcCCId == (ALuint) -1 )
1094        {
1095                /* We are paused */
1096                return NULL;
1097        }
1098
1099        return ALUINT_TO_ALCCONTEXTP( _alcCCId );
1100}
1101
1102/*
1103 * _alcGetReadBufsiz( ALuint cid )
1104 *
1105 * Returns the preferred read buffer size of the context named by cid,
1106 * in bytes.
1107 */
1108ALuint _alcGetReadBufsiz( ALuint cid ) {
1109        AL_context *cc = _alcGetContext( cid );
1110
1111        if(cc == NULL) {
1112                return 0;
1113        }
1114
1115        if( cc->read_device == NULL) {
1116                return 0;
1117        }
1118
1119        return cc->read_device->bufsiz;
1120}
1121
1122/*
1123 * _alcGetWriteBufsiz( ALuint cid )
1124 *
1125 * Returns the preferred write buffer size of the context named by cid,
1126 * in bytes.
1127 *
1128 * assumes locked context
1129 */
1130ALuint _alcGetWriteBufsiz( ALuint cid ) {
1131        AL_context *cc = _alcGetContext( cid );
1132
1133        if(cc == NULL) {
1134                return 0;
1135        }
1136
1137        if( cc->write_device == NULL) {
1138                return 0;
1139        }
1140
1141        return cc->write_device->bufsiz;
1142}
1143
1144/*
1145 * _alcGetReadFormat( ALuint cid )
1146 *
1147 * Returns the preferred read openal format of the context named by cid.
1148 *
1149 * assumes locked context
1150 */
1151ALenum _alcGetReadFormat( ALuint cid ) {
1152        AL_context *cc;
1153
1154        cc = _alcGetContext( cid );
1155        if(cc == NULL) {
1156                return 0;
1157        }
1158
1159        if( cc->read_device == NULL) {
1160                return 0;
1161        }
1162
1163        return cc->read_device->format;
1164}
1165
1166/*
1167 * _alcGetWriteFormat( ALuint cid )
1168 *
1169 * Returns the preferred write openal format of the context named by cid.
1170 */
1171ALenum _alcGetWriteFormat( ALuint cid ) {
1172        AL_context *cc;
1173
1174        cc = _alcGetContext( cid );
1175        if(cc == NULL) {
1176                return 0;
1177        }
1178
1179        if( cc->write_device == NULL) {
1180                return 0;
1181        }
1182
1183        return cc->write_device->format;
1184}
1185
1186/*
1187 * _alcGetReadSpeed( ALuint cid )
1188 *
1189 * Returns the preferred sampling rate of the read device associated with the
1190 * context named by cid.
1191 *
1192 * assumed locked context
1193 */
1194ALuint _alcGetReadSpeed(ALuint cid) {
1195        AL_context *cc;
1196
1197        cc = _alcGetContext( cid );
1198        if(cc == NULL) {
1199                return 0;
1200        }
1201
1202        if( cc->read_device == NULL) {
1203                return 0;
1204        }
1205
1206        return cc->read_device->speed;
1207}
1208
1209/*
1210 * _alcGetWriteSpeed( ALuint cid )
1211 *
1212 * Returns the preferred sampling rate of the write device associated with the
1213 * context named by cid.
1214 *
1215 * assumes locked context
1216 */
1217ALuint _alcGetWriteSpeed( ALuint cid ) {
1218        AL_context *cc;
1219
1220        cc = _alcGetContext( cid );
1221        if(cc == NULL) {
1222                return 0;
1223        }
1224
1225        if( cc->write_device == NULL) {
1226                return 0;
1227        }
1228
1229        return cc->write_device->speed;
1230}
1231
1232/*
1233 * _alcDeviceRead( ALuint cid, ALvoid *dataptr, ALuint bytes_to_read )
1234 *
1235 * Reads bytes_to_read worth of data from the read device
1236 * associated with the context named cid.
1237 *
1238 * assumes locked context
1239 */
1240ALsizei _alcDeviceRead( ALuint cid, ALvoid *dataptr, ALuint bytes_to_read )
1241{
1242        AL_context *cc;
1243
1244        cc = _alcGetContext( cid );
1245        if( cc == NULL ) {
1246                return 0;
1247        }
1248
1249        if( cc->read_device == NULL ) {
1250                return 0;
1251        }
1252
1253        return alcBackendRead_(cc->read_device->handle, dataptr, bytes_to_read);
1254}
1255
1256/*
1257 * _alcDeviceWrite( ALuint cid, ALvoid *dataptr, ALuint bytes_to_write )
1258 *
1259 * Writes bytes_to_write worth of data from dataptr to the write device
1260 * associated with the context named cid.
1261 *
1262 * assumes locked context
1263 */
1264void _alcDeviceWrite( ALuint cid, ALvoid *dataptr, ALuint bytes_to_write ) {
1265        AL_context *cc;
1266
1267        cc = _alcGetContext( cid );
1268        if( cc == NULL ) {
1269                return;
1270        }
1271
1272        if( cc->write_device == NULL ) {
1273                return;
1274        }
1275
1276        alcBackendWrite_( cc->write_device->handle, dataptr, bytes_to_write );
1277
1278        return;
1279}
1280
1281/*
1282 * _alcIsContext( ALuint cid )
1283 *
1284 * Returns AL_TRUE if cid names a valid context, AL_FALSE otherwise.
1285 *
1286 * assumes locked context
1287 */
1288ALboolean _alcIsContext( ALuint cid ) {
1289        AL_context *cc;
1290
1291        cc = _alcGetContext( cid );
1292        if( cc == NULL ) {
1293                return AL_FALSE;
1294        }
1295
1296        return AL_TRUE;
1297}
1298
1299/*
1300 * _alcIsContextSuspended( ALuint cid )
1301 *
1302 * Returns AL_TRUE if this context is suspended, AL_FALSE otherwise.
1303 * Suspended contexts do not have their sources updated, or mixed.
1304 *
1305 * assumes locked context
1306 */
1307ALboolean _alcIsContextSuspended( ALuint cid ) {
1308        AL_context *cc;
1309
1310        cc = _alcGetContext( cid );
1311        if( cc == NULL ) {
1312                return AL_TRUE;
1313        }
1314
1315        return cc->issuspended;
1316}
1317
1318/*
1319 * alcIsExtensionPresent( UNUSED(ALCdevice *device), ALCubyte *extName )
1320 *
1321 * Returns AL_TRUE if the alc extension extName is present, AL_FALSE
1322 * otherwise.
1323 */
1324ALCboolean alcIsExtensionPresent( UNUSED(ALCdevice *device), const ALCchar *extName ) {
1325        return alIsExtensionPresent( extName );
1326}
1327
1328#define DEFINE_ALC_PROC(p) { #p, (AL_funcPtr)p }
1329
1330typedef struct
1331{
1332        const ALCchar *name;
1333        AL_funcPtr value;
1334} funcNameAddressPair;
1335
1336funcNameAddressPair alcProcs[] = {
1337        DEFINE_ALC_PROC(alcCaptureCloseDevice),
1338        DEFINE_ALC_PROC(alcCaptureOpenDevice),
1339        DEFINE_ALC_PROC(alcCaptureSamples),
1340        DEFINE_ALC_PROC(alcCaptureStart),
1341        DEFINE_ALC_PROC(alcCaptureStop),
1342        DEFINE_ALC_PROC(alcCloseDevice),
1343        DEFINE_ALC_PROC(alcCreateContext),
1344        DEFINE_ALC_PROC(alcDestroyContext),
1345        DEFINE_ALC_PROC(alcGetContextsDevice),
1346        DEFINE_ALC_PROC(alcGetCurrentContext),
1347        DEFINE_ALC_PROC(alcGetEnumValue),
1348        DEFINE_ALC_PROC(alcGetError),
1349        DEFINE_ALC_PROC(alcGetIntegerv),
1350        DEFINE_ALC_PROC(alcGetProcAddress),
1351        DEFINE_ALC_PROC(alcGetString),
1352        DEFINE_ALC_PROC(alcIsExtensionPresent),
1353        DEFINE_ALC_PROC(alcMakeContextCurrent),
1354        DEFINE_ALC_PROC(alcOpenDevice),
1355        DEFINE_ALC_PROC(alcProcessContext),
1356        DEFINE_ALC_PROC(alcSuspendContext)
1357};
1358
1359#undef DEFINE_ALC_PROC
1360
1361static int
1362compareFuncNameAddressPairs(const void *s1, const void *s2)
1363{
1364        const funcNameAddressPair *p1 = (const funcNameAddressPair*)s1;
1365        const funcNameAddressPair *p2 = (const funcNameAddressPair*)s2;
1366        return strcmp((const char*)(p1->name), (const char*)(p2->name));
1367}
1368
1369static ALCboolean
1370getStandardProcAddress(AL_funcPtr *value, const ALCchar *funcName)
1371{
1372        funcNameAddressPair key;
1373        funcNameAddressPair *p;
1374        key.name = funcName;
1375        p = bsearch(&key, alcProcs,
1376                    sizeof(alcProcs) / sizeof(alcProcs[0]),
1377                    sizeof(alcProcs[0]),
1378                    compareFuncNameAddressPairs);
1379        if (p == NULL) {
1380                return ALC_FALSE;
1381        }
1382        *value = p->value;
1383        return ALC_TRUE;
1384}
1385
1386static ALCboolean
1387getExtensionProcAddress( AL_funcPtr *procAddress, UNUSED(ALCdevice *device), const ALCchar *funcName )
1388{
1389        /* TODO: using _alGetExtensionProcAddress is a HACK */
1390        return (_alGetExtensionProcAddress( procAddress, (const ALchar*)funcName) == AL_TRUE) ? ALC_TRUE : ALC_FALSE;
1391}
1392
1393/*
1394 * alcGetProcAddress( UNUSED(ALCdevice *device), ALCubyte *funcName ).
1395 *
1396 * Returns the alc extension function named funcName, or NULL if it doesn't
1397 * exist.
1398 */
1399void *
1400alcGetProcAddress( ALCdevice *device, const ALCchar *funcName )
1401{
1402        AL_funcPtr value;
1403        if (getStandardProcAddress(&value, funcName) == ALC_TRUE) {
1404                return (void *)value; /* NOTE: The cast is not valid ISO C! */
1405        }
1406        if (getExtensionProcAddress(&value, device, funcName) == ALC_TRUE) {
1407                return (void *)value; /* NOTE: The cast is not valid ISO C! */
1408        }
1409        _alcSetError( ALC_INVALID_VALUE );
1410        return NULL;
1411}
1412
1413#define DEFINE_ALC_ENUM(e) { #e, e }
1414
1415typedef struct
1416{
1417        const ALCchar *name;
1418        ALCenum value;
1419} enumNameValuePair;
1420
1421enumNameValuePair alcEnums[] = {
1422        /* this has to be sorted! */
1423        DEFINE_ALC_ENUM(ALC_ALL_ATTRIBUTES),
1424        DEFINE_ALC_ENUM(ALC_ATTRIBUTES_SIZE),
1425        DEFINE_ALC_ENUM(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER),
1426        DEFINE_ALC_ENUM(ALC_CAPTURE_DEVICE_SPECIFIER),
1427        DEFINE_ALC_ENUM(ALC_CAPTURE_SAMPLES),
1428        DEFINE_ALC_ENUM(ALC_DEFAULT_DEVICE_SPECIFIER),
1429        DEFINE_ALC_ENUM(ALC_DEVICE_SPECIFIER),
1430        DEFINE_ALC_ENUM(ALC_EXTENSIONS),
1431        DEFINE_ALC_ENUM(ALC_FALSE),
1432        DEFINE_ALC_ENUM(ALC_FREQUENCY),
1433        DEFINE_ALC_ENUM(ALC_INVALID_CONTEXT),
1434        DEFINE_ALC_ENUM(ALC_INVALID_DEVICE),
1435        DEFINE_ALC_ENUM(ALC_INVALID_ENUM),
1436        DEFINE_ALC_ENUM(ALC_INVALID_VALUE),
1437        DEFINE_ALC_ENUM(ALC_MAJOR_VERSION),
1438        DEFINE_ALC_ENUM(ALC_MINOR_VERSION),
1439        DEFINE_ALC_ENUM(ALC_MONO_SOURCES),
1440        DEFINE_ALC_ENUM(ALC_NO_ERROR),
1441        DEFINE_ALC_ENUM(ALC_OUT_OF_MEMORY),
1442        DEFINE_ALC_ENUM(ALC_REFRESH),
1443        DEFINE_ALC_ENUM(ALC_STEREO_SOURCES),
1444        DEFINE_ALC_ENUM(ALC_SYNC),
1445        DEFINE_ALC_ENUM(ALC_TRUE)
1446};
1447
1448#undef DEFINE_ALC_ENUM
1449
1450static int
1451compareEnumNameValuePairs(const void *s1, const void *s2)
1452{
1453        const enumNameValuePair *p1 = (const enumNameValuePair*)s1;
1454        const enumNameValuePair *p2 = (const enumNameValuePair*)s2;
1455        return strcmp((const char*)(p1->name), (const char*)(p2->name));
1456}
1457
1458static ALCboolean
1459getStandardEnumValue(ALCenum *value, const ALCchar *enumName)
1460{
1461        enumNameValuePair key;
1462        enumNameValuePair *p;
1463        key.name = enumName;
1464        p = bsearch(&key, alcEnums,
1465                    sizeof(alcEnums) / sizeof(alcEnums[0]),
1466                    sizeof(alcEnums[0]),
1467                    compareEnumNameValuePairs);
1468        if (p == NULL) {
1469                return ALC_FALSE;
1470        }
1471        *value = p->value;
1472        return ALC_TRUE;
1473}
1474
1475static ALCboolean
1476getExtensionEnumValue( UNUSED(ALCenum *value), UNUSED(ALCdevice *device), UNUSED(const ALCchar *enumName) )
1477{
1478        /* ToDo: Hook in our extension loader somehow */
1479        return ALC_FALSE;
1480}
1481
1482/*
1483 * alcGetEnumValue( ALCdevice *device, ALCubyte *enumName )
1484 *
1485 * Returns enum value for enumName.
1486 */
1487ALCenum
1488alcGetEnumValue( ALCdevice *device, const ALCchar *enumName )
1489{
1490        ALCenum value = 0;
1491        if (getStandardEnumValue(&value, enumName) == ALC_TRUE) {
1492                return value;
1493        }
1494        if (getExtensionEnumValue(&value, device, enumName) == ALC_TRUE) {
1495                return value;
1496        }
1497        _alcSetError( ALC_INVALID_VALUE );
1498        return value;
1499}
1500
1501ALCdevice *alcGetContextsDevice(ALCcontext *handle)
1502{
1503        AL_device *dc;
1504        AL_context *cc;
1505        ALuint cid = ALCCONTEXTP_TO_ALUINT( handle );
1506
1507        _alcLockAllContexts();
1508
1509        cc = _alcGetContext( cid );
1510        if( cc == NULL )
1511        {
1512                _alcSetError( ALC_INVALID_CONTEXT );
1513                _alcUnlockAllContexts( );
1514
1515                return NULL;
1516        }
1517
1518        dc = cc->write_device;
1519
1520        /* just unlock contexts */
1521        _alcUnlockAllContexts();
1522
1523        return dc;
1524}
1525
1526const ALCchar *alcGetString( ALCdevice *dev, ALCenum token )
1527{
1528        switch(token)
1529        {
1530                case ALC_DEFAULT_DEVICE_SPECIFIER:
1531                  return (const ALCchar *) "'((sampling-rate 44100) (device '(native))";
1532                  break;
1533                case ALC_DEVICE_SPECIFIER:
1534                  if(!dev)
1535                  {
1536                          _alcSetError(ALC_INVALID_DEVICE);
1537                          return (const ALCchar *) "";
1538                  }
1539
1540                  return dev->specifier;
1541                  break;
1542                case ALC_EXTENSIONS:
1543                  return (const ALCchar *) "";
1544                  break;
1545                case ALC_NO_ERROR:
1546                  return (const ALCchar *) "ALC_NO_ERROR";
1547                  break;
1548                case ALC_INVALID_DEVICE:
1549                  return (const ALCchar *) "ALC_INVALID_DEVICE";
1550                  break;
1551                case ALC_INVALID_CONTEXT:
1552                  return (const ALCchar *) "ALC_INVALID_CONTEXT";
1553                  break;
1554                case ALC_INVALID_ENUM:
1555                  return (const ALCchar *) "ALC_INVALID_ENUM";
1556                  break;
1557                case ALC_INVALID_VALUE:
1558                  return (const ALCchar *) "ALC_INVALID_VALUE";
1559                  break;
1560                default:
1561                  _alcSetError(ALC_INVALID_ENUM);
1562                  break;
1563        }
1564
1565        return (const ALCchar *) "";
1566}
1567
1568/* evil */
1569extern ALint __alcGetAvailableSamples (void);
1570
1571static AL_context *
1572_alcGetContextOfDevice (ALCdevice *deviceHandle)
1573{
1574  AL_context *cc;
1575
1576  if (deviceHandle == NULL)
1577    {
1578      _alcSetError (ALC_INVALID_DEVICE);
1579      return NULL;
1580    }
1581
1582  cc = deviceHandle->cc;
1583  if (cc == NULL)
1584    {
1585      _alcSetError (ALC_INVALID_CONTEXT);
1586      return NULL;
1587    }
1588
1589  return cc;
1590}
1591
1592static int
1593_alcIsDestinationValid (ALCsizei neededSize, ALCsizei size, ALCint *dest)
1594{
1595  if ((neededSize > size) || (dest == NULL))
1596    {
1597      _alcSetError (ALC_INVALID_VALUE);
1598      return 0;
1599    }
1600  return 1;
1601}
1602
1603/*
1604 * FIXME: Do we have to do some locking below? Move major/minor to
1605 * header and copy attributes at context creation time.
1606 */
1607void
1608alcGetIntegerv (ALCdevice *deviceHandle, ALCenum token,
1609                ALCsizei size, ALCint *dest)
1610{
1611  AL_context *cc;
1612  ALint i;
1613
1614  switch (token)
1615    {
1616    case ALC_ATTRIBUTES_SIZE:
1617      cc = _alcGetContextOfDevice (deviceHandle);
1618      if ((cc == NULL) || !_alcIsDestinationValid (1, size, dest))
1619        {
1620          return;
1621        }
1622      *dest = 2 * cc->NumFlags + 1;
1623      return;
1624
1625    case ALC_ALL_ATTRIBUTES:
1626      cc = _alcGetContextOfDevice (deviceHandle);
1627      if ((cc == NULL)
1628          || !_alcIsDestinationValid (2 * cc->NumFlags + 1, size, dest))
1629        {
1630          return;
1631        }
1632      for (i = 0; i < 2 * cc->NumFlags; i++)
1633        {
1634          dest[i] = cc->Flags[i];
1635        }
1636      dest[2 * cc->NumFlags] = 0;
1637      return;
1638
1639    case ALC_MAJOR_VERSION:
1640      if (!_alcIsDestinationValid (1, size, dest))
1641        {
1642          return;
1643        }
1644      *dest = 1;
1645      return;
1646
1647    case ALC_MINOR_VERSION:
1648      if (!_alcIsDestinationValid (1, size, dest))
1649        {
1650          return;
1651        }
1652      *dest = 0;
1653      return;
1654
1655    case ALC_CAPTURE_SAMPLES:
1656      cc = _alcGetContextOfDevice (deviceHandle);
1657      if ((cc == NULL) || !_alcIsDestinationValid (1, size, dest))
1658        {
1659          return;
1660        }
1661      *dest = __alcGetAvailableSamples ();
1662      return;
1663
1664    default:
1665      _alcSetError (ALC_INVALID_ENUM);
1666      return;
1667    }
1668}
1669
1670/*
1671 Capture functions
1672*/
1673
1674/* Hacked in ALC_EXT_capture support.  --ryan. */
1675/* This doesn't support multiple devices, device enumeration, or capture */
1676/*  devices seperate from an existing context. How painful. */
1677
1678/* ring buffer functionality... */
1679
1680typedef struct {
1681        ALubyte *buffer;
1682        ALsizei size;
1683        ALsizei write;
1684        ALsizei read;
1685        ALsizei used;
1686} __ALRingBuffer;
1687
1688static ALboolean __alRingBufferInit( __ALRingBuffer * ring, ALsizei size );
1689static ALvoid __alRingBufferShutdown( __ALRingBuffer * ring );
1690static ALsizei __alRingBufferSize( __ALRingBuffer * ring );
1691static ALvoid __alRingBufferPut( __ALRingBuffer * ring, ALubyte *data,
1692                                 ALsizei size );
1693static ALsizei __alRingBufferGet( __ALRingBuffer * ring, ALubyte *data,
1694                                  ALsizei size );
1695
1696static __ALRingBuffer captureRing;
1697
1698static ALboolean __alRingBufferInit( __ALRingBuffer * ring, ALsizei size )
1699{
1700        ALubyte *ptr = ( ALubyte * ) realloc( ring->buffer, size );
1701        if( ptr == NULL ) {
1702                return AL_FALSE;
1703        }
1704
1705        ring->buffer = ptr;
1706        ring->size = size;
1707        ring->write = 0;
1708        ring->read = 0;
1709        ring->used = 0;
1710        return AL_TRUE;
1711}
1712
1713static ALvoid __alRingBufferShutdown( __ALRingBuffer * ring )
1714{
1715        free( ring->buffer );
1716        ring->buffer = NULL;
1717}
1718
1719static ALsizei __alRingBufferSize( __ALRingBuffer * ring )
1720{
1721        return ring->used;
1722}
1723
1724static ALvoid __alRingBufferPut( __ALRingBuffer * ring, ALubyte *data,
1725                                 ALsizei _size )
1726{
1727        register ALsizei size = _size;
1728        register ALsizei cpy;
1729        register ALsizei avail;
1730
1731        if( !size ) {           /* just in case... */
1732                return;
1733        }
1734
1735        /* Putting more data than ring buffer holds in total? Replace it all. */
1736        if( size > ring->size ) {
1737                ring->write = 0;
1738                ring->read = 0;
1739                ring->used = ring->size;
1740                memcpy( ring->buffer, data + ( size - ring->size ),
1741                        ring->size );
1742                return;
1743        }
1744
1745        /* Buffer overflow? Push read pointer to oldest sample not overwritten. */
1746        avail = ring->size - ring->used;
1747        if( size > avail ) {
1748                ring->read += size - avail;
1749                if( ring->read > ring->size ) {
1750                        ring->read -= ring->size;
1751                }
1752        }
1753
1754        /* Clip to end of buffer and copy first block... */
1755        cpy = ring->size - ring->write;
1756        if( size < cpy ) {
1757                cpy = size;
1758        }
1759        if( cpy ) {
1760                memcpy( ring->buffer + ring->write, data, cpy );
1761        }
1762
1763        /* Wrap around to front of ring buffer and copy remaining data... */
1764        avail = size - cpy;
1765        if( avail ) {
1766                memcpy( ring->buffer, data + cpy, avail );
1767        }
1768
1769        /* Update write pointer... */
1770        ring->write += size;
1771        if( ring->write > ring->size ) {
1772                ring->write -= ring->size;
1773        }
1774
1775        ring->used += size;
1776        if( ring->used > ring->size ) {
1777                ring->used = ring->size;
1778        }
1779}
1780
1781static ALsizei __alRingBufferGet( __ALRingBuffer * ring, ALubyte *data,
1782                                  ALsizei _size )
1783{
1784        register ALsizei cpy;
1785        register ALsizei size = _size;
1786        register ALsizei avail = ring->used;
1787
1788        /* Clamp amount to read to available data... */
1789        if( size > avail ) {
1790                size = avail;
1791        }
1792
1793        /* Clip to end of buffer and copy first block... */
1794        cpy = ring->size - ring->read;
1795        if( cpy > size ) {
1796                cpy = size;
1797        }
1798        if( cpy ) {
1799                memcpy( data, ring->buffer + ring->read, cpy );
1800        }
1801
1802        /* Wrap around to front of ring buffer and copy remaining data... */
1803        avail = size - cpy;
1804        if( avail ) {
1805                memcpy( data + cpy, ring->buffer, avail );
1806        }
1807
1808        /* Update read pointer... */
1809        ring->read += size;
1810        if( ring->read > ring->size ) {
1811                ring->read -= ring->size;
1812        }
1813
1814        ring->used -= size;
1815
1816        return size;    /* may have been clamped if there wasn't enough data... */
1817}
1818
1819static ALenum captureFmt = AL_NONE;
1820static ALuint captureFreq = 0;
1821static ALint captureFmtSize = 0;
1822
1823ALCdevice *alcCaptureOpenDevice( const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei bufferSize )
1824{
1825        ALCdevice *retval;
1826        AL_context *cc;
1827        ALuint cid;
1828
1829        if ( deviceName != NULL )  { /* !!! FIXME */
1830                return NULL;
1831        }
1832
1833        switch( format ) { /* try to keep this sane for now... */
1834        case AL_FORMAT_MONO8:
1835        case AL_FORMAT_MONO16:
1836        case AL_FORMAT_STEREO8:
1837        case AL_FORMAT_STEREO16:
1838                break;  /* format okay. */
1839        default:
1840                return NULL;
1841        }
1842
1843        captureFmt = format;
1844        captureFreq = frequency;
1845        captureFmtSize = _alGetBitsFromFormat( format ) / 8;
1846        if( ( format == AL_FORMAT_STEREO8 ) || ( format == AL_FORMAT_STEREO16 ) ) {
1847                captureFmtSize *= 2;
1848        }
1849
1850        bufferSize *= captureFmtSize;
1851
1852        if ( !__alRingBufferInit( &captureRing, bufferSize )) {
1853                return NULL;
1854        }
1855
1856        if( !alCaptureInit_EXT( format, frequency, bufferSize) ) {
1857                return NULL;
1858        }
1859
1860        cid = _alcCCId;
1861        _alcLockContext( cid );
1862        cc = _alcGetContext(cid);
1863        retval = cc->read_device;
1864        retval->cc = cc;
1865        _alcUnlockContext( cid );
1866
1867        return retval;
1868}
1869
1870ALCboolean alcCaptureCloseDevice( ALCdevice *device )
1871{
1872        if( device == NULL ) {
1873                return ALC_FALSE;
1874        }
1875
1876        alCaptureDestroy_EXT();
1877        __alRingBufferShutdown( &captureRing );
1878        return ALC_TRUE;
1879}
1880
1881void alcCaptureStart( UNUSED(ALCdevice *device) )
1882{
1883        alCaptureStart_EXT();
1884
1885}
1886
1887void alcCaptureStop( UNUSED(ALCdevice *device) )
1888{
1889        alCaptureStop_EXT();
1890}
1891
1892/* !!! FIXME: Not ideal; reads samples in ALC_CAPTURE_SAMPLES query */
1893/* !!! FIXME: should query hardware here and do read in alcCaptureSamples() */
1894ALint __alcGetAvailableSamples( void )
1895{
1896        static ALubyte buf[2048];
1897        ALsizei got;
1898   
1899        while ( (got = alCaptureGetData_EXT(buf, sizeof (buf), captureFmt, captureFreq) ) > 0 ) {
1900                __alRingBufferPut( &captureRing, buf, got );
1901        }
1902
1903        /* printf("got %d have %d\n", (int) got, (int) (__alRingBufferSize(&captureRing) / captureFmtSize)); */
1904
1905        return __alRingBufferSize(&captureRing) / captureFmtSize;
1906}
1907
1908void alcCaptureSamples( UNUSED(ALCdevice *device), ALCvoid *buffer, ALCsizei samples )
1909{
1910        if( ( __alRingBufferSize(&captureRing) / captureFmtSize ) < samples ) {
1911                return;  /* !!! FIXME: This is an error condition! */
1912        }
1913
1914        __alRingBufferGet( &captureRing, buffer, samples * captureFmtSize );
1915}
Note: See TracBrowser for help on using the repository browser.