1 | /* -*- mode: C; tab-width:8; c-basic-offset:8 -*- |
---|
2 | * vi:set ts=8: |
---|
3 | * |
---|
4 | * al_ext.c |
---|
5 | * |
---|
6 | * Defines the mojo for built-in or dlopened extensions. |
---|
7 | */ |
---|
8 | #include "al_siteconfig.h" |
---|
9 | |
---|
10 | #include <AL/al.h> |
---|
11 | #include <AL/alc.h> |
---|
12 | #include <AL/alext.h> |
---|
13 | #include <stdlib.h> |
---|
14 | #include <string.h> |
---|
15 | #include <stdio.h> |
---|
16 | |
---|
17 | #include "al_main.h" |
---|
18 | #include "al_types.h" |
---|
19 | #include "al_ext.h" |
---|
20 | #include "al_error.h" |
---|
21 | #include "al_debug.h" |
---|
22 | |
---|
23 | #include "al_mutexlib.h" |
---|
24 | |
---|
25 | #ifndef NODLOPEN |
---|
26 | #include <dlfcn.h> |
---|
27 | #endif |
---|
28 | |
---|
29 | /* |
---|
30 | * Maximum length of an extension function name. |
---|
31 | */ |
---|
32 | #define _AL_EXT_NAMELEN 240 |
---|
33 | |
---|
34 | /* |
---|
35 | * Maximum number of plugins supported |
---|
36 | */ |
---|
37 | #define MAX_EXT_LIBS 64 |
---|
38 | |
---|
39 | /* locking macros */ |
---|
40 | #define _alUnlockExtension() FL_alUnlockExtension(__FILE__, __LINE__) |
---|
41 | #define _alLockExtension() FL_alLockExtension(__FILE__, __LINE__) |
---|
42 | |
---|
43 | /* |
---|
44 | * FL_alLockExtension( const char *fn, int ln ) |
---|
45 | * |
---|
46 | * Lock mutex guarding extension data structures, passing fn and ln to |
---|
47 | * _alLockPrintf. |
---|
48 | */ |
---|
49 | static void FL_alLockExtension( const char *fn, int ln ); |
---|
50 | |
---|
51 | /* |
---|
52 | * FL_alUnlockExtension( const char *fn, int ln ) |
---|
53 | * |
---|
54 | * Unlock mutex guarding extension data structures, passing fn and ln to |
---|
55 | * _alLockPrintf. |
---|
56 | */ |
---|
57 | static void FL_alUnlockExtension( const char *fn, int ln ); |
---|
58 | |
---|
59 | /* data structure storing extension library fini functions */ |
---|
60 | static struct { |
---|
61 | void (*pool[MAX_EXT_LIBS])(void); |
---|
62 | int index; |
---|
63 | } FiniFunc; |
---|
64 | |
---|
65 | /* data structure storing extension functions. Simple binary tree. */ |
---|
66 | typedef struct _enode_t { |
---|
67 | ALubyte name[ _AL_EXT_NAMELEN + 1 ]; |
---|
68 | AL_funcPtr addr; |
---|
69 | |
---|
70 | struct _enode_t *left; |
---|
71 | struct _enode_t *right; |
---|
72 | } enode_t; |
---|
73 | |
---|
74 | /* |
---|
75 | * etree is the base for our function registry. |
---|
76 | */ |
---|
77 | static enode_t *etree = NULL; |
---|
78 | |
---|
79 | /* |
---|
80 | * ext_mutex is the mutex guarding extension data structures. |
---|
81 | */ |
---|
82 | static MutexID ext_mutex = NULL; |
---|
83 | |
---|
84 | /* |
---|
85 | * Adds a new node to treenode, with name name and address addr. Returns |
---|
86 | * treenode. |
---|
87 | */ |
---|
88 | static enode_t *add_node( enode_t *treenode, const ALubyte *name, AL_funcPtr addr ); |
---|
89 | |
---|
90 | /* |
---|
91 | * Returns the node that exists in treenode with a matching name, or NULL if |
---|
92 | * no such node exists. |
---|
93 | */ |
---|
94 | static enode_t *get_node( enode_t *treenode, const ALchar *name ); |
---|
95 | |
---|
96 | /* |
---|
97 | * _alDestroyExtension( void *extp ) |
---|
98 | * |
---|
99 | * Finalizes a enode_t, but not it's children. |
---|
100 | */ |
---|
101 | static void _alDestroyExtension( void *extp ); |
---|
102 | |
---|
103 | /* |
---|
104 | * tree_free( enode_t *treehead, void (*ff)(void *) ) |
---|
105 | * |
---|
106 | * Finalize an entire enode tree. |
---|
107 | */ |
---|
108 | static void tree_free( enode_t *treehead, void (*ff)(void *) ); |
---|
109 | |
---|
110 | /* |
---|
111 | * Allocate and return a new extension node. |
---|
112 | */ |
---|
113 | static enode_t *new_ext( const ALubyte *name, AL_funcPtr addr ); |
---|
114 | |
---|
115 | #ifndef NODLOPEN |
---|
116 | /* following functions unneeded in we don't have dlopen */ |
---|
117 | |
---|
118 | /* |
---|
119 | * _alExtPushFiniFunc( void (*func)(void) ) |
---|
120 | * |
---|
121 | * Pushes a func on the fini stack, so that fini functions can be called on |
---|
122 | * exit or unload. |
---|
123 | */ |
---|
124 | static void _alExtPushFiniFunc( void (*func)(void) ); |
---|
125 | |
---|
126 | #endif /* NODLOPEN */ |
---|
127 | |
---|
128 | /* |
---|
129 | * On the level of the specification, "Extension" is a |
---|
130 | * group of functions and/or tokens that express a particular |
---|
131 | * extended functionality of the API. |
---|
132 | * |
---|
133 | * In terms of this implementation 'Extension' refers |
---|
134 | * to particular function that is registered in the |
---|
135 | * dictionary for fast GetProcAddress(). A simple dlsym() |
---|
136 | * is not possible because of the Linux implementation's |
---|
137 | * dynamic plugin system. |
---|
138 | * |
---|
139 | * Also in terms of the implementation, 'Extension Group' |
---|
140 | * refers to an extension in the specification sense--a name |
---|
141 | * that surrounds a group of functions and/or tokens. It |
---|
142 | * is possible to use a simple linked list for this, and |
---|
143 | * IsExtensionPresent() simply traverses this list. |
---|
144 | */ |
---|
145 | |
---|
146 | #define _AL_EXT_GROUPLEN 256 |
---|
147 | |
---|
148 | typedef struct _egroup_node_t { |
---|
149 | ALubyte name[_AL_EXT_GROUPLEN+1]; |
---|
150 | struct _egroup_node_t* next; |
---|
151 | } egroup_node_t; |
---|
152 | |
---|
153 | /* linked list of exciting extension group names */ |
---|
154 | static egroup_node_t* egroup_list = NULL; |
---|
155 | |
---|
156 | /* |
---|
157 | * Returns TRUE is gname is a supported extension, FALSE otherwise. |
---|
158 | */ |
---|
159 | ALboolean alIsExtensionPresent( const ALchar* gname ) { |
---|
160 | egroup_node_t* group = egroup_list; |
---|
161 | |
---|
162 | while( group ) { |
---|
163 | |
---|
164 | if( strncmp( (const char*) group->name, |
---|
165 | (const char*) gname, |
---|
166 | _AL_EXT_GROUPLEN ) == 0 ) { |
---|
167 | return AL_TRUE; |
---|
168 | } |
---|
169 | |
---|
170 | group = group->next; |
---|
171 | } |
---|
172 | |
---|
173 | return AL_FALSE; |
---|
174 | } |
---|
175 | |
---|
176 | /* |
---|
177 | * Populate buffer, up to size-1, with a string representation of the |
---|
178 | * extension strings. Returns AL_TRUE if size was greater or equal to 1, |
---|
179 | * AL_FALSE otherwise. |
---|
180 | */ |
---|
181 | ALboolean _alGetExtensionStrings( ALchar* buffer, size_t size ) { |
---|
182 | egroup_node_t *group = egroup_list; |
---|
183 | |
---|
184 | if( size < 1 ) { |
---|
185 | return AL_FALSE; |
---|
186 | } |
---|
187 | |
---|
188 | buffer[0] = '\0'; |
---|
189 | |
---|
190 | while( group ) { |
---|
191 | size_t length = strlen( (char *) group->name ) + 1; |
---|
192 | |
---|
193 | if( length < size ) { |
---|
194 | strncat( (char *) buffer, (char *) group->name, size ); |
---|
195 | strncat( (char *) buffer, " ", size - length + 1 ); |
---|
196 | } else { |
---|
197 | break; |
---|
198 | } |
---|
199 | |
---|
200 | size -= length; |
---|
201 | group = group->next; |
---|
202 | } |
---|
203 | |
---|
204 | return AL_TRUE; |
---|
205 | } |
---|
206 | |
---|
207 | /* |
---|
208 | * Add an extension group (see above) to the current list of extensions, |
---|
209 | * returning AL_TRUE. AL_FALSE is returned on error. |
---|
210 | */ |
---|
211 | ALboolean _alRegisterExtensionGroup( const ALubyte* gname ) { |
---|
212 | egroup_node_t* group; |
---|
213 | |
---|
214 | if( gname == NULL ) { |
---|
215 | return AL_FALSE; |
---|
216 | } |
---|
217 | |
---|
218 | group = (egroup_node_t*) malloc( sizeof( *group ) ); |
---|
219 | |
---|
220 | if( group == NULL ) { |
---|
221 | return AL_FALSE; |
---|
222 | } |
---|
223 | |
---|
224 | strncpy( (char*) group->name, (const char*) gname, _AL_EXT_GROUPLEN ); |
---|
225 | group->next = egroup_list; |
---|
226 | egroup_list = group; |
---|
227 | |
---|
228 | return AL_TRUE; |
---|
229 | } |
---|
230 | |
---|
231 | /* |
---|
232 | * _alDestroyExtensionGroups( void ) |
---|
233 | * |
---|
234 | * Finalize the extension group data structures. |
---|
235 | */ |
---|
236 | void _alDestroyExtensionGroups( void ) { |
---|
237 | egroup_node_t *group = egroup_list; |
---|
238 | |
---|
239 | while( group ) { |
---|
240 | egroup_node_t *temp = group->next; |
---|
241 | free( group ); |
---|
242 | group = temp; |
---|
243 | } |
---|
244 | |
---|
245 | egroup_list = NULL; |
---|
246 | |
---|
247 | return; |
---|
248 | } |
---|
249 | |
---|
250 | /** |
---|
251 | * Extension support. |
---|
252 | */ |
---|
253 | |
---|
254 | #define DEFINE_AL_PROC(p) { #p, (AL_funcPtr)p } |
---|
255 | |
---|
256 | typedef struct |
---|
257 | { |
---|
258 | const ALchar *name; |
---|
259 | AL_funcPtr value; |
---|
260 | } funcNameAddressPair; |
---|
261 | |
---|
262 | funcNameAddressPair alProcs[] = { |
---|
263 | /* this has to be sorted! */ |
---|
264 | DEFINE_AL_PROC(alBuffer3f), |
---|
265 | DEFINE_AL_PROC(alBuffer3i), |
---|
266 | DEFINE_AL_PROC(alBufferData), |
---|
267 | DEFINE_AL_PROC(alBufferf), |
---|
268 | DEFINE_AL_PROC(alBufferfv), |
---|
269 | DEFINE_AL_PROC(alBufferi), |
---|
270 | DEFINE_AL_PROC(alBufferiv), |
---|
271 | DEFINE_AL_PROC(alDeleteBuffers), |
---|
272 | DEFINE_AL_PROC(alDeleteSources), |
---|
273 | DEFINE_AL_PROC(alDisable), |
---|
274 | DEFINE_AL_PROC(alDistanceModel), |
---|
275 | DEFINE_AL_PROC(alDopplerFactor), |
---|
276 | DEFINE_AL_PROC(alDopplerVelocity), |
---|
277 | DEFINE_AL_PROC(alEnable), |
---|
278 | DEFINE_AL_PROC(alGenBuffers), |
---|
279 | DEFINE_AL_PROC(alGenSources), |
---|
280 | DEFINE_AL_PROC(alGetBoolean), |
---|
281 | DEFINE_AL_PROC(alGetBooleanv), |
---|
282 | DEFINE_AL_PROC(alGetBuffer3f), |
---|
283 | DEFINE_AL_PROC(alGetBuffer3i), |
---|
284 | DEFINE_AL_PROC(alGetBufferf), |
---|
285 | DEFINE_AL_PROC(alGetBufferfv), |
---|
286 | DEFINE_AL_PROC(alGetBufferi), |
---|
287 | DEFINE_AL_PROC(alGetBufferiv), |
---|
288 | DEFINE_AL_PROC(alGetDouble), |
---|
289 | DEFINE_AL_PROC(alGetDoublev), |
---|
290 | DEFINE_AL_PROC(alGetEnumValue), |
---|
291 | DEFINE_AL_PROC(alGetError), |
---|
292 | DEFINE_AL_PROC(alGetFloat), |
---|
293 | DEFINE_AL_PROC(alGetFloatv), |
---|
294 | DEFINE_AL_PROC(alGetInteger), |
---|
295 | DEFINE_AL_PROC(alGetIntegerv), |
---|
296 | DEFINE_AL_PROC(alGetListener3f), |
---|
297 | DEFINE_AL_PROC(alGetListener3i), |
---|
298 | DEFINE_AL_PROC(alGetListenerf), |
---|
299 | DEFINE_AL_PROC(alGetListenerfv), |
---|
300 | DEFINE_AL_PROC(alGetListeneri), |
---|
301 | DEFINE_AL_PROC(alGetListeneriv), |
---|
302 | DEFINE_AL_PROC(alGetProcAddress), |
---|
303 | DEFINE_AL_PROC(alGetSource3f), |
---|
304 | /* DEFINE_AL_PROC(alGetSource3i), TODO: NOT YET IMPLEMENTED!!! */ |
---|
305 | DEFINE_AL_PROC(alGetSourcef), |
---|
306 | DEFINE_AL_PROC(alGetSourcefv), |
---|
307 | DEFINE_AL_PROC(alGetSourcei), |
---|
308 | DEFINE_AL_PROC(alGetSourceiv), |
---|
309 | DEFINE_AL_PROC(alGetString), |
---|
310 | DEFINE_AL_PROC(alIsBuffer), |
---|
311 | DEFINE_AL_PROC(alIsEnabled), |
---|
312 | DEFINE_AL_PROC(alIsExtensionPresent), |
---|
313 | DEFINE_AL_PROC(alIsSource), |
---|
314 | DEFINE_AL_PROC(alListener3f), |
---|
315 | DEFINE_AL_PROC(alListener3i), |
---|
316 | DEFINE_AL_PROC(alListenerf), |
---|
317 | DEFINE_AL_PROC(alListenerfv), |
---|
318 | DEFINE_AL_PROC(alListeneri), |
---|
319 | DEFINE_AL_PROC(alListeneriv), |
---|
320 | DEFINE_AL_PROC(alSource3f), |
---|
321 | /* DEFINE_AL_PROC(alSource3i), TODO: NOT YET IMPLEMENTED!!! */ |
---|
322 | DEFINE_AL_PROC(alSourcePause), |
---|
323 | DEFINE_AL_PROC(alSourcePausev), |
---|
324 | DEFINE_AL_PROC(alSourcePlay), |
---|
325 | DEFINE_AL_PROC(alSourcePlayv), |
---|
326 | DEFINE_AL_PROC(alSourceQueueBuffers), |
---|
327 | DEFINE_AL_PROC(alSourceRewind), |
---|
328 | DEFINE_AL_PROC(alSourceRewindv), |
---|
329 | DEFINE_AL_PROC(alSourceStop), |
---|
330 | DEFINE_AL_PROC(alSourceStopv), |
---|
331 | DEFINE_AL_PROC(alSourceUnqueueBuffers), |
---|
332 | DEFINE_AL_PROC(alSourcef), |
---|
333 | DEFINE_AL_PROC(alSourcefv), |
---|
334 | DEFINE_AL_PROC(alSourcei), |
---|
335 | /* DEFINE_AL_PROC(alSourceiv), TODO: NOT YET IMPLEMENTED!!! */ |
---|
336 | DEFINE_AL_PROC(alSpeedOfSound) |
---|
337 | }; |
---|
338 | |
---|
339 | #undef DEFINE_AL_PROC |
---|
340 | |
---|
341 | static int |
---|
342 | compareFuncNameAddressPairs(const void *s1, const void *s2) |
---|
343 | { |
---|
344 | const funcNameAddressPair *p1 = (const funcNameAddressPair*)s1; |
---|
345 | const funcNameAddressPair *p2 = (const funcNameAddressPair*)s2; |
---|
346 | return strcmp((const char*)(p1->name), (const char*)(p2->name)); |
---|
347 | } |
---|
348 | |
---|
349 | static ALboolean |
---|
350 | getStandardProcAddress(AL_funcPtr *value, const ALchar *funcName) |
---|
351 | { |
---|
352 | funcNameAddressPair key; |
---|
353 | funcNameAddressPair *p; |
---|
354 | key.name = funcName; |
---|
355 | p = bsearch(&key, alProcs, |
---|
356 | sizeof(alProcs) / sizeof(alProcs[0]), |
---|
357 | sizeof(alProcs[0]), |
---|
358 | compareFuncNameAddressPairs); |
---|
359 | if (p == NULL) { |
---|
360 | return AL_FALSE; |
---|
361 | } |
---|
362 | *value = p->value; |
---|
363 | return AL_TRUE; |
---|
364 | } |
---|
365 | |
---|
366 | /* TODO: exporting this is a HACK */ |
---|
367 | ALboolean |
---|
368 | _alGetExtensionProcAddress( AL_funcPtr *procAddress, const ALchar *funcName ) |
---|
369 | { |
---|
370 | enode_t *retpair; |
---|
371 | retpair = get_node( etree, funcName ); |
---|
372 | if(retpair == NULL) { |
---|
373 | return AL_FALSE; |
---|
374 | } |
---|
375 | *procAddress = retpair->addr; |
---|
376 | return AL_TRUE; |
---|
377 | } |
---|
378 | |
---|
379 | /* |
---|
380 | * alGetProcAddress( const ALubyte *fname ) |
---|
381 | * |
---|
382 | * Obtain the address of a function (usually an extension) with the name |
---|
383 | * fname. All addresses are context-independent. |
---|
384 | */ |
---|
385 | void * |
---|
386 | alGetProcAddress( const ALchar *funcName ) |
---|
387 | { |
---|
388 | AL_funcPtr value = NULL; |
---|
389 | if (getStandardProcAddress(&value, funcName) == AL_TRUE) { |
---|
390 | return (void *)value; /* NOTE: The cast is not valid ISO C! */ |
---|
391 | } |
---|
392 | if (_alGetExtensionProcAddress(&value, funcName) == AL_TRUE) { |
---|
393 | return (void *)value; /* NOTE: The cast is not valid ISO C! */ |
---|
394 | } |
---|
395 | _alDCSetError( AL_INVALID_VALUE ); |
---|
396 | return (void *)value; /* NOTE: The cast is not valid ISO C! */ |
---|
397 | } |
---|
398 | |
---|
399 | |
---|
400 | /* |
---|
401 | * _alRegisterExtension is called to register an extension in our tree. |
---|
402 | * extensions are not via GetProcAddress until they have been registered. |
---|
403 | * |
---|
404 | * Returns AL_TRUE if the name/addr pair was added, AL_FALSE otherwise. |
---|
405 | */ |
---|
406 | ALboolean _alRegisterExtension( const ALubyte *name, AL_funcPtr addr ) { |
---|
407 | enode_t *temp; |
---|
408 | |
---|
409 | _alLockExtension(); |
---|
410 | |
---|
411 | temp = add_node( etree, name, addr ); |
---|
412 | if(temp == NULL) { |
---|
413 | _alUnlockExtension(); |
---|
414 | _alDebug(ALD_EXT, __FILE__, __LINE__, |
---|
415 | "could not add extension %s", name); |
---|
416 | return AL_FALSE; |
---|
417 | } |
---|
418 | |
---|
419 | _alUnlockExtension(); |
---|
420 | etree = temp; |
---|
421 | |
---|
422 | _alDebug(ALD_EXT, __FILE__, __LINE__, |
---|
423 | "registered %s at %p", name, (void*)addr); |
---|
424 | |
---|
425 | return AL_TRUE; |
---|
426 | } |
---|
427 | |
---|
428 | /* |
---|
429 | * _alDestroyExtension( void *extp ) |
---|
430 | * |
---|
431 | * Finalizes a enode_t, but not it's children. |
---|
432 | */ |
---|
433 | static void _alDestroyExtension(void *extp) { |
---|
434 | free( extp ); |
---|
435 | |
---|
436 | return; |
---|
437 | } |
---|
438 | |
---|
439 | /* |
---|
440 | * _alInitExtensions( void ) |
---|
441 | * |
---|
442 | * Initializes extension bookkeeping data structures. |
---|
443 | * |
---|
444 | * Not much to do here, since the structures are built via the register calls. |
---|
445 | * So just init the mutex. Return AL_TRUE unless the mutex could not be |
---|
446 | * initialized. |
---|
447 | */ |
---|
448 | ALboolean _alInitExtensions( void ) { |
---|
449 | if(ext_mutex == NULL) { |
---|
450 | ext_mutex = _alCreateMutex(); |
---|
451 | if(ext_mutex == NULL) { |
---|
452 | return AL_FALSE; |
---|
453 | } |
---|
454 | } |
---|
455 | |
---|
456 | return AL_TRUE; |
---|
457 | } |
---|
458 | |
---|
459 | /* |
---|
460 | * _alDestroyExtensions( void ) |
---|
461 | * |
---|
462 | * Destroy extension book keeping structures. |
---|
463 | */ |
---|
464 | void _alDestroyExtensions( void ) { |
---|
465 | int i; |
---|
466 | |
---|
467 | tree_free( etree, _alDestroyExtension ); |
---|
468 | _alDestroyMutex( ext_mutex ); |
---|
469 | |
---|
470 | etree = NULL; |
---|
471 | ext_mutex = NULL; |
---|
472 | |
---|
473 | for(i = FiniFunc.index - 1; i >= 0; i--) { |
---|
474 | FiniFunc.pool[i](); /* call fini funcs */ |
---|
475 | FiniFunc.index--; |
---|
476 | } |
---|
477 | |
---|
478 | return; |
---|
479 | } |
---|
480 | |
---|
481 | /* |
---|
482 | * Adds a function with name "name" and address "addr" to the tree with root |
---|
483 | * at treehead. |
---|
484 | * |
---|
485 | * assumes locked extensions |
---|
486 | */ |
---|
487 | static enode_t *add_node( enode_t *treehead, const ALubyte *name, AL_funcPtr addr ) { |
---|
488 | int i; |
---|
489 | enode_t *retval; |
---|
490 | |
---|
491 | if((addr == NULL) || (name == NULL)) { |
---|
492 | return NULL; |
---|
493 | } |
---|
494 | |
---|
495 | if(treehead == NULL) { |
---|
496 | retval = new_ext( name, addr ); |
---|
497 | if(retval == NULL) { |
---|
498 | return NULL; |
---|
499 | } |
---|
500 | |
---|
501 | return retval; |
---|
502 | } |
---|
503 | |
---|
504 | i = ustrncmp( name, treehead->name, _AL_EXT_NAMELEN ); |
---|
505 | |
---|
506 | if(i < 0) { |
---|
507 | treehead->left = add_node( treehead->left, name, addr ); |
---|
508 | } |
---|
509 | if(i == 0) { |
---|
510 | return treehead; |
---|
511 | } |
---|
512 | if(i > 0) { |
---|
513 | treehead->right = add_node( treehead->right, name, addr ); |
---|
514 | } |
---|
515 | |
---|
516 | return treehead; |
---|
517 | } |
---|
518 | |
---|
519 | /* |
---|
520 | * Returns a new extension node, using name and addr as initializers, or NULL |
---|
521 | * if resources were not available. |
---|
522 | */ |
---|
523 | static enode_t *new_ext( const ALubyte *name, AL_funcPtr addr ) { |
---|
524 | enode_t *retval = malloc( sizeof *retval ); |
---|
525 | if(retval == NULL) { |
---|
526 | return NULL; |
---|
527 | } |
---|
528 | |
---|
529 | ustrncpy( retval->name, name, _AL_EXT_NAMELEN ); |
---|
530 | retval->addr = addr; |
---|
531 | retval->left = NULL; |
---|
532 | retval->right = NULL; |
---|
533 | |
---|
534 | return retval; |
---|
535 | } |
---|
536 | |
---|
537 | /* |
---|
538 | * tree_free( enode_t *treehead, void (*ff)(void *) ) |
---|
539 | * |
---|
540 | * Destroy the tree with root at treehead, calling ff on each data item. |
---|
541 | */ |
---|
542 | static void tree_free( enode_t *treehead, void (*ff)(void *) ) { |
---|
543 | enode_t *temp; |
---|
544 | |
---|
545 | if(treehead == NULL) { |
---|
546 | return; |
---|
547 | } |
---|
548 | |
---|
549 | if(treehead->left) { |
---|
550 | tree_free( treehead->left, ff ); |
---|
551 | } |
---|
552 | |
---|
553 | temp = treehead->right; |
---|
554 | free( treehead ); |
---|
555 | |
---|
556 | tree_free( temp, ff ); |
---|
557 | |
---|
558 | return; |
---|
559 | } |
---|
560 | |
---|
561 | /* |
---|
562 | * Retrieve enode_t pointer for extension with name "name" from |
---|
563 | * tree with root "treehead", or NULL if not found. |
---|
564 | */ |
---|
565 | static enode_t *get_node( enode_t *treehead, const ALchar *name ) { |
---|
566 | int i; |
---|
567 | |
---|
568 | if((name == NULL) || (treehead == NULL)) { |
---|
569 | return NULL; |
---|
570 | } |
---|
571 | |
---|
572 | i = ustrncmp(name, treehead->name, _AL_EXT_NAMELEN); |
---|
573 | if(i < 0) { |
---|
574 | return get_node(treehead->left, name); |
---|
575 | } |
---|
576 | if(i > 0) { |
---|
577 | return get_node(treehead->right, name); |
---|
578 | } |
---|
579 | |
---|
580 | return treehead; |
---|
581 | } |
---|
582 | |
---|
583 | #ifdef NODLOPEN |
---|
584 | |
---|
585 | ALboolean _alLoadDL(UNUSED(const char *fname)) { |
---|
586 | return AL_FALSE; |
---|
587 | } |
---|
588 | |
---|
589 | #else |
---|
590 | |
---|
591 | /* |
---|
592 | * _alLoadDL( const char *fname ) |
---|
593 | * |
---|
594 | * Load the plugin named by fname, returning AL_TRUE on sucess, AL_FALSE on |
---|
595 | * error. |
---|
596 | * |
---|
597 | * FIXME: some sort of locking is in order. |
---|
598 | * |
---|
599 | * FIXME: stick the fini_func function somewhere so we |
---|
600 | * can actually call it. |
---|
601 | */ |
---|
602 | ALboolean _alLoadDL( const char *fname ) { |
---|
603 | void *handle; |
---|
604 | AL_extension *ext_table; |
---|
605 | static void (*init_func)( void ); |
---|
606 | static void (*fini_func)( void ); |
---|
607 | int i; |
---|
608 | |
---|
609 | handle = dlopen( fname, RTLD_GLOBAL | RTLD_NOW ); |
---|
610 | if(handle == NULL) { |
---|
611 | _alDebug(ALD_EXT, __FILE__, __LINE__, |
---|
612 | "Could not load %s:\n\t%s", fname, dlerror()); |
---|
613 | return AL_FALSE; |
---|
614 | } |
---|
615 | |
---|
616 | ext_table = dlsym(handle, LAL_EXT_TABLE_STR); |
---|
617 | if(ext_table == NULL) { |
---|
618 | _alDebug(ALD_EXT, __FILE__, __LINE__, |
---|
619 | "%s has no extension table.", fname); |
---|
620 | return AL_FALSE; |
---|
621 | } |
---|
622 | |
---|
623 | init_func = (void (*)(void)) dlsym(handle, LAL_EXT_INIT_STR); |
---|
624 | fini_func = (void (*)(void)) dlsym(handle, LAL_EXT_FINI_STR); |
---|
625 | |
---|
626 | for( i = 0; (ext_table[i].name != NULL) && |
---|
627 | (ext_table[i].addr != NULL); i++) { |
---|
628 | _alRegisterExtension( ext_table[i].name, ext_table[i].addr ); |
---|
629 | } |
---|
630 | |
---|
631 | if(init_func != NULL) { |
---|
632 | /* initialize library */ |
---|
633 | init_func(); |
---|
634 | } |
---|
635 | |
---|
636 | if(fini_func != NULL) { |
---|
637 | _alExtPushFiniFunc( fini_func ); |
---|
638 | } |
---|
639 | |
---|
640 | return AL_TRUE; |
---|
641 | } |
---|
642 | #endif |
---|
643 | |
---|
644 | /* |
---|
645 | * lal_addTimeFilter( const char *name, time_filter *addr ) |
---|
646 | * |
---|
647 | * Adds or replaces a time filter in the filter pipeline. Returns AL_TRUE on |
---|
648 | * success, AL_FALSE on error. |
---|
649 | * |
---|
650 | * Not super-well tested. |
---|
651 | * |
---|
652 | * FIXME: set error? Probably not. |
---|
653 | */ |
---|
654 | ALboolean lal_addTimeFilter( const char *name, time_filter *addr ) { |
---|
655 | AL_context *cc; |
---|
656 | time_filter_set *tfs; |
---|
657 | int i; |
---|
658 | int scmp; |
---|
659 | |
---|
660 | /* check args */ |
---|
661 | if((name == NULL) || (addr == NULL)) { |
---|
662 | return AL_FALSE; |
---|
663 | } |
---|
664 | |
---|
665 | _alcDCLockContext(); |
---|
666 | |
---|
667 | cc = _alcDCGetContext(); |
---|
668 | if(cc == NULL) { |
---|
669 | _alcDCUnlockContext(); |
---|
670 | return AL_FALSE; |
---|
671 | } |
---|
672 | |
---|
673 | tfs = cc->time_filters; |
---|
674 | |
---|
675 | for(i = 0; (i < _ALC_MAX_FILTERS) && (tfs->filter != NULL); i++) { |
---|
676 | scmp = strncmp(tfs[i].name, name, _ALF_MAX_NAME); |
---|
677 | if(scmp == 0) { |
---|
678 | /* overwrite existing filter */ |
---|
679 | tfs[i].filter = addr; |
---|
680 | |
---|
681 | _alcDCUnlockContext(); |
---|
682 | return AL_TRUE; |
---|
683 | } |
---|
684 | } |
---|
685 | |
---|
686 | if(i == _ALC_MAX_FILTERS) { |
---|
687 | /* no room for new filter */ |
---|
688 | _alcDCUnlockContext(); |
---|
689 | |
---|
690 | return AL_FALSE; |
---|
691 | } |
---|
692 | |
---|
693 | /* add new filter */ |
---|
694 | strncpy(tfs[i].name, name, _ALF_MAX_NAME); |
---|
695 | tfs[i].filter = addr; |
---|
696 | |
---|
697 | _alcDCUnlockContext(); |
---|
698 | |
---|
699 | return AL_TRUE; |
---|
700 | } |
---|
701 | |
---|
702 | /* |
---|
703 | * FL_alLockExtension( const char *fn, int ln ) |
---|
704 | * |
---|
705 | * Lock mutex guarding extension data structures, passing fn and ln to |
---|
706 | * _alLockPrintf. |
---|
707 | */ |
---|
708 | static void FL_alLockExtension(UNUSED(const char *fn), UNUSED(int ln)) { |
---|
709 | _alLockPrintf("_alLockExtension", fn, ln); |
---|
710 | |
---|
711 | if(ext_mutex == NULL) { |
---|
712 | /* |
---|
713 | * Sigh. Extensions are loaded from config, so they |
---|
714 | * need to have locks even before _alMain is called, |
---|
715 | * so InitExtension may not be called at this point. |
---|
716 | */ |
---|
717 | ext_mutex = _alCreateMutex(); |
---|
718 | } |
---|
719 | |
---|
720 | _alLockMutex( ext_mutex ); |
---|
721 | |
---|
722 | return; |
---|
723 | } |
---|
724 | |
---|
725 | /* |
---|
726 | * FL_alUnlockExtension( const char *fn, int ln ) |
---|
727 | * |
---|
728 | * Unlock mutex guarding extension data structures, passing fn and ln to |
---|
729 | * _alLockPrintf. |
---|
730 | */ |
---|
731 | static void FL_alUnlockExtension(UNUSED(const char *fn), UNUSED(int ln)) { |
---|
732 | _alLockPrintf("_alUnlockExtension", fn, ln); |
---|
733 | |
---|
734 | _alUnlockMutex( ext_mutex ); |
---|
735 | |
---|
736 | return; |
---|
737 | } |
---|
738 | |
---|
739 | |
---|
740 | #ifndef NODLOPEN |
---|
741 | /* avoid errors on platforms that don't support dlopen */ |
---|
742 | |
---|
743 | /* |
---|
744 | * _alExtPushFiniFunc( void (*func)(void) ) |
---|
745 | * |
---|
746 | * Saves fini func to call on dlclose time. |
---|
747 | */ |
---|
748 | static void _alExtPushFiniFunc( void (*func)(void) ) { |
---|
749 | if(FiniFunc.index >= MAX_EXT_LIBS) { |
---|
750 | return; |
---|
751 | } |
---|
752 | |
---|
753 | FiniFunc.pool[FiniFunc.index] = func; |
---|
754 | FiniFunc.index++; |
---|
755 | |
---|
756 | return; |
---|
757 | } |
---|
758 | #endif /* NODLOPEN */ |
---|
759 | |
---|
760 | #define DEFINE_AL_ENUM(e) { #e, e } |
---|
761 | |
---|
762 | typedef struct |
---|
763 | { |
---|
764 | const ALchar *name; |
---|
765 | ALenum value; |
---|
766 | } enumNameValuePair; |
---|
767 | |
---|
768 | enumNameValuePair alEnums[] = { |
---|
769 | /* this has to be sorted! */ |
---|
770 | DEFINE_AL_ENUM(AL_BITS), |
---|
771 | DEFINE_AL_ENUM(AL_BUFFER), |
---|
772 | DEFINE_AL_ENUM(AL_BUFFERS_PROCESSED), |
---|
773 | DEFINE_AL_ENUM(AL_BUFFERS_QUEUED), |
---|
774 | DEFINE_AL_ENUM(AL_BYTE_OFFSET), |
---|
775 | DEFINE_AL_ENUM(AL_CHANNELS), |
---|
776 | DEFINE_AL_ENUM(AL_CONE_INNER_ANGLE), |
---|
777 | DEFINE_AL_ENUM(AL_CONE_OUTER_ANGLE), |
---|
778 | DEFINE_AL_ENUM(AL_CONE_OUTER_GAIN), |
---|
779 | DEFINE_AL_ENUM(AL_DIRECTION), |
---|
780 | DEFINE_AL_ENUM(AL_DISTANCE_MODEL), |
---|
781 | DEFINE_AL_ENUM(AL_DOPPLER_FACTOR), |
---|
782 | DEFINE_AL_ENUM(AL_DOPPLER_VELOCITY), |
---|
783 | DEFINE_AL_ENUM(AL_EXPONENT_DISTANCE), |
---|
784 | DEFINE_AL_ENUM(AL_EXPONENT_DISTANCE_CLAMPED), |
---|
785 | DEFINE_AL_ENUM(AL_EXTENSIONS), |
---|
786 | DEFINE_AL_ENUM(AL_FALSE), |
---|
787 | DEFINE_AL_ENUM(AL_FORMAT_MONO16), |
---|
788 | DEFINE_AL_ENUM(AL_FORMAT_MONO8), |
---|
789 | DEFINE_AL_ENUM(AL_FORMAT_STEREO16), |
---|
790 | DEFINE_AL_ENUM(AL_FORMAT_STEREO8), |
---|
791 | DEFINE_AL_ENUM(AL_FREQUENCY), |
---|
792 | DEFINE_AL_ENUM(AL_GAIN), |
---|
793 | DEFINE_AL_ENUM(AL_INITIAL), |
---|
794 | DEFINE_AL_ENUM(AL_INVALID_ENUM), |
---|
795 | DEFINE_AL_ENUM(AL_INVALID_NAME), |
---|
796 | DEFINE_AL_ENUM(AL_INVALID_OPERATION), |
---|
797 | DEFINE_AL_ENUM(AL_INVALID_VALUE), |
---|
798 | DEFINE_AL_ENUM(AL_INVERSE_DISTANCE), |
---|
799 | DEFINE_AL_ENUM(AL_INVERSE_DISTANCE_CLAMPED), |
---|
800 | DEFINE_AL_ENUM(AL_LINEAR_DISTANCE), |
---|
801 | DEFINE_AL_ENUM(AL_LINEAR_DISTANCE_CLAMPED), |
---|
802 | DEFINE_AL_ENUM(AL_LOOPING), |
---|
803 | DEFINE_AL_ENUM(AL_MAX_DISTANCE), |
---|
804 | DEFINE_AL_ENUM(AL_MAX_GAIN), |
---|
805 | DEFINE_AL_ENUM(AL_MIN_GAIN), |
---|
806 | DEFINE_AL_ENUM(AL_NONE), |
---|
807 | DEFINE_AL_ENUM(AL_NO_ERROR), |
---|
808 | DEFINE_AL_ENUM(AL_ORIENTATION), |
---|
809 | DEFINE_AL_ENUM(AL_OUT_OF_MEMORY), |
---|
810 | DEFINE_AL_ENUM(AL_PAUSED), |
---|
811 | DEFINE_AL_ENUM(AL_PENDING), |
---|
812 | DEFINE_AL_ENUM(AL_PITCH), |
---|
813 | DEFINE_AL_ENUM(AL_PLAYING), |
---|
814 | DEFINE_AL_ENUM(AL_POSITION), |
---|
815 | DEFINE_AL_ENUM(AL_PROCESSED), |
---|
816 | DEFINE_AL_ENUM(AL_REFERENCE_DISTANCE), |
---|
817 | DEFINE_AL_ENUM(AL_RENDERER), |
---|
818 | DEFINE_AL_ENUM(AL_ROLLOFF_FACTOR), |
---|
819 | DEFINE_AL_ENUM(AL_SAMPLE_OFFSET), |
---|
820 | DEFINE_AL_ENUM(AL_SEC_OFFSET), |
---|
821 | DEFINE_AL_ENUM(AL_SIZE), |
---|
822 | DEFINE_AL_ENUM(AL_SOURCE_RELATIVE), |
---|
823 | DEFINE_AL_ENUM(AL_SOURCE_STATE), |
---|
824 | DEFINE_AL_ENUM(AL_SOURCE_TYPE), |
---|
825 | DEFINE_AL_ENUM(AL_SPEED_OF_SOUND), |
---|
826 | DEFINE_AL_ENUM(AL_STATIC), |
---|
827 | DEFINE_AL_ENUM(AL_STOPPED), |
---|
828 | DEFINE_AL_ENUM(AL_STREAMING), |
---|
829 | DEFINE_AL_ENUM(AL_TRUE), |
---|
830 | DEFINE_AL_ENUM(AL_UNDETERMINED), |
---|
831 | DEFINE_AL_ENUM(AL_UNUSED), |
---|
832 | DEFINE_AL_ENUM(AL_VELOCITY), |
---|
833 | DEFINE_AL_ENUM(AL_VENDOR), |
---|
834 | DEFINE_AL_ENUM(AL_VERSION) |
---|
835 | }; |
---|
836 | |
---|
837 | #undef DEFINE_AL_ENUM |
---|
838 | |
---|
839 | static int |
---|
840 | compareEnumNameValuePairs(const void *s1, const void *s2) |
---|
841 | { |
---|
842 | const enumNameValuePair *p1 = (const enumNameValuePair*)s1; |
---|
843 | const enumNameValuePair *p2 = (const enumNameValuePair*)s2; |
---|
844 | return strcmp((const char*)(p1->name), (const char*)(p2->name)); |
---|
845 | } |
---|
846 | |
---|
847 | static ALboolean |
---|
848 | getStandardEnumValue(ALenum *value, const ALchar *enumName) |
---|
849 | { |
---|
850 | enumNameValuePair key; |
---|
851 | enumNameValuePair *p; |
---|
852 | key.name = enumName; |
---|
853 | p = bsearch(&key, alEnums, |
---|
854 | sizeof(alEnums) / sizeof(alEnums[0]), |
---|
855 | sizeof(alEnums[0]), |
---|
856 | compareEnumNameValuePairs); |
---|
857 | if (p == NULL) { |
---|
858 | return AL_FALSE; |
---|
859 | } |
---|
860 | *value = p->value; |
---|
861 | return AL_TRUE; |
---|
862 | } |
---|
863 | |
---|
864 | static ALboolean |
---|
865 | getExtensionEnumValue( ALenum *value, const ALchar *enumName ) |
---|
866 | { |
---|
867 | /* ToDo: Hook in our extension loader somehow */ |
---|
868 | const char *name = (const char*)enumName; |
---|
869 | if (strcmp(name, "AL_BYTE_LOKI") == 0) { |
---|
870 | *value = AL_BYTE_LOKI; |
---|
871 | return AL_TRUE; |
---|
872 | } else if (strcmp(name, "AL_FORMAT_QUAD16_LOKI") == 0) { |
---|
873 | *value = AL_FORMAT_QUAD16_LOKI; |
---|
874 | return AL_TRUE; |
---|
875 | } else if (strcmp(name, "AL_FORMAT_QUAD8_LOKI") == 0) { |
---|
876 | *value = AL_FORMAT_QUAD8_LOKI; |
---|
877 | return AL_TRUE; |
---|
878 | } else { |
---|
879 | return AL_FALSE; |
---|
880 | } |
---|
881 | } |
---|
882 | |
---|
883 | /* |
---|
884 | * alGetEnumValue( const ALubyte *enumName ) |
---|
885 | * |
---|
886 | * Returns the integer value of an enumeration (usually an extension) |
---|
887 | * with the name ename. |
---|
888 | */ |
---|
889 | ALenum |
---|
890 | alGetEnumValue( const ALchar *enumName ) |
---|
891 | { |
---|
892 | ALenum value = 0; |
---|
893 | if (getStandardEnumValue(&value, enumName) == AL_TRUE) { |
---|
894 | return value; |
---|
895 | } |
---|
896 | if (getExtensionEnumValue(&value, enumName) == AL_TRUE) { |
---|
897 | return value; |
---|
898 | } |
---|
899 | _alDCSetError( AL_INVALID_VALUE ); |
---|
900 | return value; |
---|
901 | } |
---|