diff options
author | Chris Robinson <[email protected]> | 2009-09-27 00:21:40 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2009-09-27 00:21:40 -0700 |
commit | 8024df299121f2d25c4e4b24f8c55ebdac2d9e4c (patch) | |
tree | e3f2ce6634bda5a75521015aaf275fff9ac9c2b4 | |
parent | f72b6fe717898172c9915fd70c0710bfcf7d843e (diff) |
Load backend libs on-demand
-rw-r--r-- | Alc/alsa.c | 224 | ||||
-rw-r--r-- | Alc/dsound.c | 97 | ||||
-rw-r--r-- | Alc/portaudio.c | 149 | ||||
-rw-r--r-- | Alc/pulseaudio.c | 225 |
4 files changed, 405 insertions, 290 deletions
@@ -116,6 +116,108 @@ static DevMap *allDevNameMap; static ALuint numDevNames; static DevMap *allCaptureDevNameMap; static ALuint numCaptureDevNames; +static volatile ALuint load_count; + + +void alsa_load(void) +{ + if(load_count == 0) + { + char *str; + +#ifdef HAVE_DLFCN_H + alsa_handle = dlopen("libasound.so.2", RTLD_NOW); + if(!alsa_handle) + return; + dlerror(); + +#define LOAD_FUNC(f) do { \ + p##f = dlsym(alsa_handle, #f); \ + if((str=dlerror()) != NULL) \ + { \ + dlclose(alsa_handle); \ + alsa_handle = NULL; \ + AL_PRINT("Could not load %s from libasound.so.2: %s\n", #f, str); \ + return; \ + } \ +} while(0) +#else + str = NULL; + alsa_handle = (void*)0xDEADBEEF; +#define LOAD_FUNC(f) p##f = f +#endif + +LOAD_FUNC(snd_strerror); +LOAD_FUNC(snd_pcm_open); +LOAD_FUNC(snd_pcm_close); +LOAD_FUNC(snd_pcm_nonblock); +LOAD_FUNC(snd_pcm_frames_to_bytes); +LOAD_FUNC(snd_pcm_hw_params_malloc); +LOAD_FUNC(snd_pcm_hw_params_free); +LOAD_FUNC(snd_pcm_hw_params_any); +LOAD_FUNC(snd_pcm_hw_params_set_access); +LOAD_FUNC(snd_pcm_hw_params_set_format); +LOAD_FUNC(snd_pcm_hw_params_set_channels); +LOAD_FUNC(snd_pcm_hw_params_set_periods_near); +LOAD_FUNC(snd_pcm_hw_params_set_rate_near); +LOAD_FUNC(snd_pcm_hw_params_set_rate); +LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near); +LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min); +LOAD_FUNC(snd_pcm_hw_params_set_period_size_near); +LOAD_FUNC(snd_pcm_hw_params_get_buffer_size); +LOAD_FUNC(snd_pcm_hw_params_get_period_size); +LOAD_FUNC(snd_pcm_hw_params_get_access); +LOAD_FUNC(snd_pcm_hw_params_get_periods); +LOAD_FUNC(snd_pcm_hw_params); +LOAD_FUNC(snd_pcm_sw_params_malloc); +LOAD_FUNC(snd_pcm_sw_params_current); +LOAD_FUNC(snd_pcm_sw_params_set_avail_min); +LOAD_FUNC(snd_pcm_sw_params); +LOAD_FUNC(snd_pcm_sw_params_free); +LOAD_FUNC(snd_pcm_prepare); +LOAD_FUNC(snd_pcm_start); +LOAD_FUNC(snd_pcm_resume); +LOAD_FUNC(snd_pcm_wait); +LOAD_FUNC(snd_pcm_state); +LOAD_FUNC(snd_pcm_avail_update); +LOAD_FUNC(snd_pcm_areas_silence); +LOAD_FUNC(snd_pcm_mmap_begin); +LOAD_FUNC(snd_pcm_mmap_commit); +LOAD_FUNC(snd_pcm_readi); +LOAD_FUNC(snd_pcm_writei); +LOAD_FUNC(snd_pcm_drain); + +LOAD_FUNC(snd_pcm_info_malloc); +LOAD_FUNC(snd_pcm_info_free); +LOAD_FUNC(snd_pcm_info_set_device); +LOAD_FUNC(snd_pcm_info_set_subdevice); +LOAD_FUNC(snd_pcm_info_set_stream); +LOAD_FUNC(snd_pcm_info_get_name); +LOAD_FUNC(snd_ctl_pcm_next_device); +LOAD_FUNC(snd_ctl_pcm_info); +LOAD_FUNC(snd_ctl_open); +LOAD_FUNC(snd_ctl_close); +LOAD_FUNC(snd_ctl_card_info_malloc); +LOAD_FUNC(snd_ctl_card_info_free); +LOAD_FUNC(snd_ctl_card_info); +LOAD_FUNC(snd_ctl_card_info_get_name); +LOAD_FUNC(snd_card_next); + +#undef LOAD_FUNC + } + ++load_count; +} + +void alsa_unload(void) +{ + if(load_count == 0 || --load_count > 0) + return; + +#ifdef HAVE_DLFCN_H + dlclose(alsa_handle); +#endif + alsa_handle = NULL; +} static int xrun_recovery(snd_pcm_t *handle, int err) @@ -339,9 +441,6 @@ static ALCboolean alsa_open_playback(ALCdevice *device, const ALCchar *deviceNam char driver[64]; int i; - if(!alsa_handle) - return ALC_FALSE; - strncpy(driver, GetConfigValue("alsa", "device", "default"), sizeof(driver)-1); driver[sizeof(driver)-1] = 0; if(!deviceName) @@ -363,6 +462,10 @@ static ALCboolean alsa_open_playback(ALCdevice *device, const ALCchar *deviceNam return ALC_FALSE; } + alsa_load(); + if(!alsa_handle) + return ALC_FALSE; + open_alsa: data = (alsa_data*)calloc(1, sizeof(alsa_data)); @@ -382,6 +485,7 @@ open_alsa: { free(data); AL_PRINT("Could not open playback device '%s': %s\n", driver, psnd_strerror(i)); + alsa_unload(); return ALC_FALSE; } @@ -397,6 +501,8 @@ static void alsa_close_playback(ALCdevice *device) psnd_pcm_close(data->pcmHandle); free(data); device->ExtraData = NULL; + + alsa_unload(); } static ALCboolean alsa_reset_playback(ALCdevice *device) @@ -565,9 +671,6 @@ static ALCboolean alsa_open_capture(ALCdevice *pDevice, const ALCchar *deviceNam char *err; int i; - if(!alsa_handle) - return ALC_FALSE; - strncpy(driver, GetConfigValue("alsa", "capture", "default"), sizeof(driver)-1); driver[sizeof(driver)-1] = 0; if(!deviceName) @@ -590,6 +693,10 @@ static ALCboolean alsa_open_capture(ALCdevice *pDevice, const ALCchar *deviceNam return ALC_FALSE; } + alsa_load(); + if(!alsa_handle) + return ALC_FALSE; + open_alsa: data = (alsa_data*)calloc(1, sizeof(alsa_data)); @@ -609,6 +716,7 @@ open_alsa: { free(data); AL_PRINT("Could not open capture device '%s': %s\n", driver, psnd_strerror(i)); + alsa_unload(); return ALC_FALSE; } @@ -627,6 +735,7 @@ open_alsa: AL_PRINT("Unknown format: 0x%x\n", pDevice->Format); psnd_pcm_close(data->pcmHandle); free(data); + alsa_unload(); return ALC_FALSE; } @@ -660,6 +769,7 @@ open_alsa: psnd_pcm_hw_params_free(p); psnd_pcm_close(data->pcmHandle); free(data); + alsa_unload(); return ALC_FALSE; } @@ -669,6 +779,7 @@ open_alsa: psnd_pcm_hw_params_free(p); psnd_pcm_close(data->pcmHandle); free(data); + alsa_unload(); return ALC_FALSE; } @@ -683,6 +794,7 @@ open_alsa: AL_PRINT("ring buffer create failed\n"); psnd_pcm_close(data->pcmHandle); free(data); + alsa_unload(); return ALC_FALSE; } @@ -694,6 +806,7 @@ open_alsa: psnd_pcm_close(data->pcmHandle); DestroyRingBuffer(data->ring); free(data); + alsa_unload(); return ALC_FALSE; } @@ -707,6 +820,7 @@ open_alsa: pDevice->ExtraData = NULL; free(data->buffer); free(data); + alsa_unload(); return ALC_FALSE; } @@ -727,6 +841,8 @@ static void alsa_close_capture(ALCdevice *pDevice) free(data->buffer); free(data); pDevice->ExtraData = NULL; + + alsa_unload(); } static void alsa_start_capture(ALCdevice *pDevice) @@ -773,89 +889,7 @@ BackendFuncs alsa_funcs = { void alc_alsa_init(BackendFuncs *func_list) { - char *str; - - if(func_list) *func_list = alsa_funcs; - -#ifdef HAVE_DLFCN_H - alsa_handle = dlopen("libasound.so.2", RTLD_NOW); - if(!alsa_handle) - return; - dlerror(); - -#define LOAD_FUNC(f) do { \ - p##f = (typeof(f)*)dlsym(alsa_handle, #f); \ - if((str=dlerror()) != NULL) \ - { \ - dlclose(alsa_handle); \ - alsa_handle = NULL; \ - AL_PRINT("Could not load %s from libasound.so.2: %s\n", #f, str); \ - return; \ - } \ -} while(0) -#else - str = NULL; - alsa_handle = (void*)0xDEADBEEF; -#define LOAD_FUNC(f) p##f = f -#endif - -LOAD_FUNC(snd_strerror); -LOAD_FUNC(snd_pcm_open); -LOAD_FUNC(snd_pcm_close); -LOAD_FUNC(snd_pcm_nonblock); -LOAD_FUNC(snd_pcm_frames_to_bytes); -LOAD_FUNC(snd_pcm_hw_params_malloc); -LOAD_FUNC(snd_pcm_hw_params_free); -LOAD_FUNC(snd_pcm_hw_params_any); -LOAD_FUNC(snd_pcm_hw_params_set_access); -LOAD_FUNC(snd_pcm_hw_params_set_format); -LOAD_FUNC(snd_pcm_hw_params_set_channels); -LOAD_FUNC(snd_pcm_hw_params_set_periods_near); -LOAD_FUNC(snd_pcm_hw_params_set_rate_near); -LOAD_FUNC(snd_pcm_hw_params_set_rate); -LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near); -LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min); -LOAD_FUNC(snd_pcm_hw_params_set_period_size_near); -LOAD_FUNC(snd_pcm_hw_params_get_buffer_size); -LOAD_FUNC(snd_pcm_hw_params_get_period_size); -LOAD_FUNC(snd_pcm_hw_params_get_access); -LOAD_FUNC(snd_pcm_hw_params_get_periods); -LOAD_FUNC(snd_pcm_hw_params); -LOAD_FUNC(snd_pcm_sw_params_malloc); -LOAD_FUNC(snd_pcm_sw_params_current); -LOAD_FUNC(snd_pcm_sw_params_set_avail_min); -LOAD_FUNC(snd_pcm_sw_params); -LOAD_FUNC(snd_pcm_sw_params_free); -LOAD_FUNC(snd_pcm_prepare); -LOAD_FUNC(snd_pcm_start); -LOAD_FUNC(snd_pcm_resume); -LOAD_FUNC(snd_pcm_wait); -LOAD_FUNC(snd_pcm_state); -LOAD_FUNC(snd_pcm_avail_update); -LOAD_FUNC(snd_pcm_areas_silence); -LOAD_FUNC(snd_pcm_mmap_begin); -LOAD_FUNC(snd_pcm_mmap_commit); -LOAD_FUNC(snd_pcm_readi); -LOAD_FUNC(snd_pcm_writei); -LOAD_FUNC(snd_pcm_drain); - -LOAD_FUNC(snd_pcm_info_malloc); -LOAD_FUNC(snd_pcm_info_free); -LOAD_FUNC(snd_pcm_info_set_device); -LOAD_FUNC(snd_pcm_info_set_subdevice); -LOAD_FUNC(snd_pcm_info_set_stream); -LOAD_FUNC(snd_pcm_info_get_name); -LOAD_FUNC(snd_ctl_pcm_next_device); -LOAD_FUNC(snd_ctl_pcm_info); -LOAD_FUNC(snd_ctl_open); -LOAD_FUNC(snd_ctl_close); -LOAD_FUNC(snd_ctl_card_info_malloc); -LOAD_FUNC(snd_ctl_card_info_free); -LOAD_FUNC(snd_ctl_card_info); -LOAD_FUNC(snd_ctl_card_info_get_name); -LOAD_FUNC(snd_card_next); - -#undef LOAD_FUNC + *func_list = alsa_funcs; } void alc_alsa_deinit(void) @@ -873,12 +907,6 @@ void alc_alsa_deinit(void) free(allCaptureDevNameMap); allCaptureDevNameMap = NULL; numCaptureDevNames = 0; - -#ifdef HAVE_DLFCN_H - if(alsa_handle) - dlclose(alsa_handle); -#endif - alsa_handle = NULL; } void alc_alsa_probe(int type) @@ -891,7 +919,7 @@ void alc_alsa_probe(int type) char name[128]; ALuint i; - if(!alsa_handle) alc_alsa_init(NULL); + alsa_load(); if(!alsa_handle) return; psnd_ctl_card_info_malloc(&info); @@ -907,6 +935,7 @@ void alc_alsa_probe(int type) AL_PRINT("no playback cards found...\n"); psnd_pcm_info_free(pcminfo); psnd_ctl_card_info_free(info); + alsa_unload(); return; } @@ -981,6 +1010,7 @@ void alc_alsa_probe(int type) AL_PRINT("no capture cards found...\n"); psnd_pcm_info_free(pcminfo); psnd_ctl_card_info_free(info); + alsa_unload(); return; } @@ -1048,4 +1078,6 @@ void alc_alsa_probe(int type) psnd_pcm_info_free(pcminfo); psnd_ctl_card_info_free(info); + + alsa_unload(); } diff --git a/Alc/dsound.c b/Alc/dsound.c index fe7a0b50..91ac6499 100644 --- a/Alc/dsound.c +++ b/Alc/dsound.c @@ -71,6 +71,53 @@ typedef struct { static const ALCchar dsDevice[] = "DirectSound Software"; static DevMap *DeviceList; static ALuint NumDevices; +static volatile ALuint load_count; + + +void DSoundLoad(void) +{ + if(load_count == 0) + { +#ifdef _WIN32 + ds_handle = LoadLibraryA("dsound.dll"); + if(ds_handle == NULL) + { + AL_PRINT("Failed to load dsound.dll\n"); + return; + } + +#define LOAD_FUNC(f) do { \ + p##f = (void*)GetProcAddress((HMODULE)ds_handle, #f); \ + if(p##f == NULL) \ + { \ + FreeLibrary(ds_handle); \ + ds_handle = NULL; \ + AL_PRINT("Could not load %s from dsound.dll\n", #f); \ + return; \ + } \ +} while(0) +#else + ds_handle = (void*)0xDEADBEEF; +#define LOAD_FUNC(f) p##f = f +#endif + +LOAD_FUNC(DirectSoundCreate); +LOAD_FUNC(DirectSoundEnumerateA); +#undef LOAD_FUNC + } + ++load_count; +} + +void DSoundUnload(void) +{ + if(load_count == 0 || --load_count > 0) + return; + +#ifdef _WIN32 + FreeLibrary(ds_handle); +#endif + ds_handle = NULL; +} static ALuint DSoundProc(ALvoid *ptr) @@ -157,9 +204,6 @@ static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceNam LPGUID guid = NULL; HRESULT hr; - if(ds_handle == NULL) - return ALC_FALSE; - if(!deviceName) deviceName = dsDevice; else if(strcmp(deviceName, dsDevice) != 0) @@ -177,12 +221,17 @@ static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceNam return ALC_FALSE; } + DSoundLoad(); + if(ds_handle == NULL) + return ALC_FALSE; + //Initialise requested device pData = calloc(1, sizeof(DSoundData)); if(!pData) { SetALCError(ALC_OUT_OF_MEMORY); + DSoundUnload(); return ALC_FALSE; } @@ -195,6 +244,7 @@ static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceNam if(pData->lpDS) IDirectSound_Release(pData->lpDS); free(pData); + DSoundUnload(); return ALC_FALSE; } @@ -210,6 +260,8 @@ static void DSoundClosePlayback(ALCdevice *device) IDirectSound_Release(pData->lpDS); free(pData); device->ExtraData = NULL; + + DSoundUnload(); } static ALCboolean DSoundResetPlayback(ALCdevice *device) @@ -479,34 +531,7 @@ static BOOL CALLBACK DSoundEnumDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, void alcDSoundInit(BackendFuncs *FuncList) { - if(FuncList) *FuncList = DSoundFuncs; - -#ifdef _WIN32 - ds_handle = LoadLibraryA("dsound.dll"); - if(ds_handle == NULL) - { - AL_PRINT("Failed to load dsound.dll\n"); - return; - } - -#define LOAD_FUNC(f) do { \ - p##f = (void*)GetProcAddress((HMODULE)ds_handle, #f); \ - if(p##f == NULL) \ - { \ - FreeLibrary(ds_handle); \ - ds_handle = NULL; \ - AL_PRINT("Could not load %s from dsound.dll\n", #f); \ - return; \ - } \ -} while(0) -#else - ds_handle = (void*)0xDEADBEEF; -#define LOAD_FUNC(f) p##f = f -#endif - -LOAD_FUNC(DirectSoundCreate); -LOAD_FUNC(DirectSoundEnumerateA); -#undef LOAD_FUNC + *FuncList = DSoundFuncs; } void alcDSoundDeinit(void) @@ -518,17 +543,11 @@ void alcDSoundDeinit(void) free(DeviceList); DeviceList = NULL; NumDevices = 0; - -#ifdef _WIN32 - if(ds_handle) - FreeLibrary(ds_handle); -#endif - ds_handle = NULL; } void alcDSoundProbe(int type) { - if(!ds_handle) alcDSoundInit(NULL); + DSoundLoad(); if(!ds_handle) return; if(type == DEVICE_PROBE) @@ -548,4 +567,6 @@ void alcDSoundProbe(int type) if(FAILED(hr)) AL_PRINT("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr); } + + DSoundUnload(); } diff --git a/Alc/portaudio.c b/Alc/portaudio.c index 7ef255f2..5c90f611 100644 --- a/Alc/portaudio.c +++ b/Alc/portaudio.c @@ -47,6 +47,81 @@ MAKE_FUNC(Pa_GetStreamInfo); static const ALCchar pa_device[] = "PortAudio Software"; +static volatile ALuint load_count; + + +void pa_load(void) +{ + const char *str; + PaError err; + + if(load_count == 0) + { +#ifdef HAVE_DLFCN_H +#if defined(__APPLE__) && defined(__MACH__) +# define PALIB "libportaudio.2.dylib" +#else +# define PALIB "libportaudio.so.2" +#endif + pa_handle = dlopen(PALIB, RTLD_NOW); + if(!pa_handle) + return; + dlerror(); + +#define LOAD_FUNC(f) do { \ + p##f = (typeof(f)*)dlsym(pa_handle, #f); \ + if((str=dlerror()) != NULL) \ + { \ + dlclose(pa_handle); \ + pa_handle = NULL; \ + AL_PRINT("Could not load %s from "PALIB": %s\n", #f, str); \ + return; \ + } \ +} while(0) +#else + str = NULL; + pa_handle = (void*)0xDEADBEEF; +#define LOAD_FUNC(f) p##f = f +#endif + +LOAD_FUNC(Pa_Initialize); +LOAD_FUNC(Pa_Terminate); +LOAD_FUNC(Pa_GetErrorText); +LOAD_FUNC(Pa_StartStream); +LOAD_FUNC(Pa_StopStream); +LOAD_FUNC(Pa_OpenStream); +LOAD_FUNC(Pa_CloseStream); +LOAD_FUNC(Pa_GetDefaultOutputDevice); +LOAD_FUNC(Pa_GetStreamInfo); + +#undef LOAD_FUNC + + if((err=pPa_Initialize()) != paNoError) + { + AL_PRINT("Pa_Initialize() returned an error: %s\n", pPa_GetErrorText(err)); +#ifdef HAVE_DLFCN_H + dlclose(pa_handle); +#endif + pa_handle = NULL; + return; + } + } + + ++load_count; +} + +void pa_unload(void) +{ + if(load_count == 0 || --load_count > 0) + return; + + pPa_Terminate(); +#ifdef HAVE_DLFCN_H + dlclose(pa_handle); +#endif + pa_handle = NULL; +} + typedef struct { PaStream *stream; @@ -75,14 +150,15 @@ static ALCboolean pa_open_playback(ALCdevice *device, const ALCchar *deviceName) pa_data *data; PaError err; - if(pa_handle == NULL) - return ALC_FALSE; - if(!deviceName) deviceName = pa_device; else if(strcmp(deviceName, pa_device) != 0) return ALC_FALSE; + pa_load(); + if(pa_handle == NULL) + return ALC_FALSE; + data = (pa_data*)calloc(1, sizeof(pa_data)); device->ExtraData = data; @@ -108,6 +184,7 @@ static ALCboolean pa_open_playback(ALCdevice *device, const ALCchar *deviceName) AL_PRINT("Unknown format: 0x%x\n", device->Format); device->ExtraData = NULL; free(data); + pa_unload(); return ALC_FALSE; } outParams.channelCount = aluChannelsFromFormat(device->Format); @@ -119,6 +196,7 @@ static ALCboolean pa_open_playback(ALCdevice *device, const ALCchar *deviceName) AL_PRINT("Pa_OpenStream() returned an error: %s\n", pPa_GetErrorText(err)); device->ExtraData = NULL; free(data); + pa_unload(); return ALC_FALSE; } streamInfo = pPa_GetStreamInfo(data->stream); @@ -130,6 +208,7 @@ static ALCboolean pa_open_playback(ALCdevice *device, const ALCchar *deviceName) pPa_CloseStream(data->stream); device->ExtraData = NULL; free(data); + pa_unload(); return ALC_FALSE; } @@ -153,6 +232,8 @@ static void pa_close_playback(ALCdevice *device) free(data); device->ExtraData = NULL; + + pa_unload(); } static ALCboolean pa_reset_playback(ALCdevice *device) @@ -196,76 +277,22 @@ static const BackendFuncs pa_funcs = { void alc_pa_init(BackendFuncs *func_list) { - const char *str; - PaError err; - - if(func_list) *func_list = pa_funcs; - -#ifdef HAVE_DLFCN_H -#if defined(__APPLE__) && defined(__MACH__) -# define PALIB "libportaudio.2.dylib" -#else -# define PALIB "libportaudio.so.2" -#endif - pa_handle = dlopen(PALIB, RTLD_NOW); - if(!pa_handle) - return; - dlerror(); - -#define LOAD_FUNC(f) do { \ - p##f = (typeof(f)*)dlsym(pa_handle, #f); \ - if((str=dlerror()) != NULL) \ - { \ - dlclose(pa_handle); \ - pa_handle = NULL; \ - AL_PRINT("Could not load %s from "PALIB": %s\n", #f, str); \ - return; \ - } \ -} while(0) -#else - str = NULL; - pa_handle = (void*)0xDEADBEEF; -#define LOAD_FUNC(f) p##f = f -#endif - - LOAD_FUNC(Pa_Initialize); - LOAD_FUNC(Pa_Terminate); - LOAD_FUNC(Pa_GetErrorText); - LOAD_FUNC(Pa_StartStream); - LOAD_FUNC(Pa_StopStream); - LOAD_FUNC(Pa_OpenStream); - LOAD_FUNC(Pa_CloseStream); - LOAD_FUNC(Pa_GetDefaultOutputDevice); - LOAD_FUNC(Pa_GetStreamInfo); -#undef LOAD_FUNC - - if((err=pPa_Initialize()) != paNoError) - { - AL_PRINT("Pa_Initialize() returned an error: %s\n", pPa_GetErrorText(err)); - alc_pa_deinit(); - return; - } + *func_list = pa_funcs; } void alc_pa_deinit(void) { - if(pa_handle) - { - pPa_Terminate(); -#ifdef HAVE_DLFCN_H - dlclose(pa_handle); - pa_handle = NULL; -#endif - } } void alc_pa_probe(int type) { - if(!pa_handle) alc_pa_init(NULL); + pa_load(); if(!pa_handle) return; if(type == DEVICE_PROBE) AppendDeviceList(pa_device); else if(type == ALL_DEVICE_PROBE) AppendAllDeviceList(pa_device); + + pa_unload(); } diff --git a/Alc/pulseaudio.c b/Alc/pulseaudio.c index 187a98b6..2c0552b6 100644 --- a/Alc/pulseaudio.c +++ b/Alc/pulseaudio.c @@ -109,6 +109,108 @@ typedef struct { static const ALCchar pulse_device[] = "PulseAudio Software"; static const ALCchar pulse_capture_device[] = "PulseAudio Capture"; +static volatile ALuint load_count; + + +void pulse_load(void) //{{{ +{ + if(load_count == 0) + { +#ifdef _WIN32 + pa_handle = LoadLibrary("libpulse-0.dll"); +#define LOAD_FUNC(x) do { \ + p##x = GetProcAddress(pa_handle, #x); \ + if(!(p##x)) { \ + AL_PRINT("Could not load %s from libpulse-0.dll\n", #x); \ + FreeLibrary(pa_handle); \ + pa_handle = NULL; \ + return; \ + } \ +} while(0) + +#elif defined (HAVE_DLFCN_H) + + const char *err; +#if defined(__APPLE__) && defined(__MACH__) + pa_handle = dlopen("libpulse.0.dylib", RTLD_NOW); +#else + pa_handle = dlopen("libpulse.so.0", RTLD_NOW); +#endif + dlerror(); + +#define LOAD_FUNC(x) do { \ + p##x = dlsym(pa_handle, #x); \ + if((err=dlerror() != NULL) { \ + AL_PRINT("Could not load %s from libpulse: %s\n", #x, err); \ + dlclose(pa_handle); \ + pa_handle = NULL; \ + return; \ + } \ +} while(0) + +#else + + pa_handle = (void*)0xDEADBEEF; +#define LOAD_FUNC(x) p##x = (x) + +#endif + if(!pa_handle) + return; + +LOAD_FUNC(pa_context_unref); +LOAD_FUNC(pa_sample_spec_valid); +LOAD_FUNC(pa_stream_drop); +LOAD_FUNC(pa_strerror); +LOAD_FUNC(pa_context_get_state); +LOAD_FUNC(pa_stream_get_state); +LOAD_FUNC(pa_threaded_mainloop_signal); +LOAD_FUNC(pa_stream_peek); +LOAD_FUNC(pa_threaded_mainloop_wait); +LOAD_FUNC(pa_threaded_mainloop_unlock); +LOAD_FUNC(pa_context_new); +LOAD_FUNC(pa_threaded_mainloop_stop); +LOAD_FUNC(pa_context_disconnect); +LOAD_FUNC(pa_threaded_mainloop_start); +LOAD_FUNC(pa_threaded_mainloop_get_api); +LOAD_FUNC(pa_context_set_state_callback); +LOAD_FUNC(pa_stream_write); +LOAD_FUNC(pa_xfree); +LOAD_FUNC(pa_stream_connect_record); +LOAD_FUNC(pa_stream_connect_playback); +LOAD_FUNC(pa_path_get_filename); +LOAD_FUNC(pa_get_binary_name); +LOAD_FUNC(pa_threaded_mainloop_free); +LOAD_FUNC(pa_context_errno); +LOAD_FUNC(pa_xmalloc0); +LOAD_FUNC(pa_stream_unref); +LOAD_FUNC(pa_threaded_mainloop_accept); +LOAD_FUNC(pa_stream_set_write_callback); +LOAD_FUNC(pa_threaded_mainloop_new); +LOAD_FUNC(pa_context_connect); +LOAD_FUNC(pa_stream_get_buffer_attr); +LOAD_FUNC(pa_stream_set_read_callback); +LOAD_FUNC(pa_stream_set_state_callback); +LOAD_FUNC(pa_stream_new); +LOAD_FUNC(pa_stream_disconnect); +LOAD_FUNC(pa_threaded_mainloop_lock); + +#undef LOAD_FUNC + } + ++load_count; +} //}}} + +void pulse_unload(void) //{{{ +{ + if(load_count == 0 || --load_count > 0) + return; + +#ifdef _WIN32 + FreeLibrary(pa_handle); +#elif defined (HAVE_DLFCN_H) + dlclose(pa_handle); +#endif + pa_handle = NULL; +} //}}} // PulseAudio I/O Callbacks //{{{ @@ -265,20 +367,26 @@ static void pulse_close(ALCdevice *device) //{{{ // OpenAL {{{ static ALCboolean pulse_open_playback(ALCdevice *device, const ALCchar *device_name) //{{{ { - if(!pa_handle) - return ALC_FALSE; - if(!device_name) device_name = pulse_device; else if(strcmp(device_name, pulse_device) != 0) return ALC_FALSE; - return pulse_open(device, device_name); + pulse_load(); + if(!pa_handle) + return ALC_FALSE; + + if(pulse_open(device, device_name) != ALC_FALSE) + return ALC_TRUE; + + pulse_unload(); + return ALC_FALSE; } //}}} static void pulse_close_playback(ALCdevice *device) //{{{ { pulse_close(device); + pulse_unload(); } //}}} static ALCboolean pulse_reset_playback(ALCdevice *device) //{{{ @@ -399,16 +507,20 @@ static ALCboolean pulse_open_capture(ALCdevice *device, const ALCchar *device_na pulse_data *data; pa_stream_state_t state; - if(!pa_handle) - return ALC_FALSE; - if(!device_name) device_name = pulse_capture_device; else if(strcmp(device_name, pulse_capture_device) != 0) return ALC_FALSE; + pulse_load(); + if(!pa_handle) + return ALC_FALSE; + if(pulse_open(device, device_name) == ALC_FALSE) + { + pulse_unload(); return ALC_FALSE; + } data = device->ExtraData; ppa_threaded_mainloop_lock(data->loop); @@ -421,6 +533,7 @@ static ALCboolean pulse_open_capture(ALCdevice *device, const ALCchar *device_na { ppa_threaded_mainloop_unlock(data->loop); pulse_close(device); + pulse_unload(); return ALC_FALSE; } @@ -449,6 +562,7 @@ static ALCboolean pulse_open_capture(ALCdevice *device, const ALCchar *device_na AL_PRINT("Unknown format: 0x%x\n", device->Format); ppa_threaded_mainloop_unlock(data->loop); pulse_close(device); + pulse_unload(); return ALC_FALSE; } @@ -457,6 +571,7 @@ static ALCboolean pulse_open_capture(ALCdevice *device, const ALCchar *device_na AL_PRINT("Invalid sample format\n"); ppa_threaded_mainloop_unlock(data->loop); pulse_close(device); + pulse_unload(); return ALC_FALSE; } @@ -468,6 +583,7 @@ static ALCboolean pulse_open_capture(ALCdevice *device, const ALCchar *device_na ppa_threaded_mainloop_unlock(data->loop); pulse_close(device); + pulse_unload(); return ALC_FALSE; } @@ -481,6 +597,7 @@ static ALCboolean pulse_open_capture(ALCdevice *device, const ALCchar *device_na data->stream = NULL; pulse_close(device); + pulse_unload(); return ALC_FALSE; } @@ -496,6 +613,7 @@ static ALCboolean pulse_open_capture(ALCdevice *device, const ALCchar *device_na data->stream = NULL; pulse_close(device); + pulse_unload(); return ALC_FALSE; } @@ -511,6 +629,7 @@ static ALCboolean pulse_open_capture(ALCdevice *device, const ALCchar *device_na static void pulse_close_capture(ALCdevice *device) //{{{ { pulse_close(device); + pulse_unload(); } //}}} static void pulse_start_capture(ALCdevice *device) //{{{ @@ -563,102 +682,16 @@ BackendFuncs pulse_funcs = { //{{{ void alc_pulse_init(BackendFuncs *func_list) //{{{ { - if(func_list) *func_list = pulse_funcs; - -#ifdef _WIN32 - pa_handle = LoadLibrary("libpulse-0.dll"); -#define LOAD_FUNC(x) do { \ - p##x = GetProcAddress(pa_handle, #x); \ - if(!(p##x)) { \ - AL_PRINT("Could not load %s from libpulse-0.dll\n", #x); \ - FreeLibrary(pa_handle); \ - pa_handle = NULL; \ - return; \ - } \ -} while(0) - -#elif defined (HAVE_DLFCN_H) - -#if defined(__APPLE__) && defined(__MACH__) - pa_handle = dlopen("libpulse.0.dylib", RTLD_NOW); -#else - pa_handle = dlopen("libpulse.so.0", RTLD_NOW); -#endif -#define LOAD_FUNC(x) do { \ - p##x = dlsym(pa_handle, #x); \ - if(!(p##x)) { \ - AL_PRINT("Could not load %s from libpulse\n", #x); \ - dlclose(pa_handle); \ - pa_handle = NULL; \ - return; \ - } \ -} while(0) - -#else - - pa_handle = (void*)0xDEADBEEF; -#define LOAD_FUNC(x) p##x = (x) - -#endif - if(!pa_handle) - return; - -LOAD_FUNC(pa_context_unref); -LOAD_FUNC(pa_sample_spec_valid); -LOAD_FUNC(pa_stream_drop); -LOAD_FUNC(pa_strerror); -LOAD_FUNC(pa_context_get_state); -LOAD_FUNC(pa_stream_get_state); -LOAD_FUNC(pa_threaded_mainloop_signal); -LOAD_FUNC(pa_stream_peek); -LOAD_FUNC(pa_threaded_mainloop_wait); -LOAD_FUNC(pa_threaded_mainloop_unlock); -LOAD_FUNC(pa_context_new); -LOAD_FUNC(pa_threaded_mainloop_stop); -LOAD_FUNC(pa_context_disconnect); -LOAD_FUNC(pa_threaded_mainloop_start); -LOAD_FUNC(pa_threaded_mainloop_get_api); -LOAD_FUNC(pa_context_set_state_callback); -LOAD_FUNC(pa_stream_write); -LOAD_FUNC(pa_xfree); -LOAD_FUNC(pa_stream_connect_record); -LOAD_FUNC(pa_stream_connect_playback); -LOAD_FUNC(pa_path_get_filename); -LOAD_FUNC(pa_get_binary_name); -LOAD_FUNC(pa_threaded_mainloop_free); -LOAD_FUNC(pa_context_errno); -LOAD_FUNC(pa_xmalloc0); -LOAD_FUNC(pa_stream_unref); -LOAD_FUNC(pa_threaded_mainloop_accept); -LOAD_FUNC(pa_stream_set_write_callback); -LOAD_FUNC(pa_threaded_mainloop_new); -LOAD_FUNC(pa_context_connect); -LOAD_FUNC(pa_stream_get_buffer_attr); -LOAD_FUNC(pa_stream_set_read_callback); -LOAD_FUNC(pa_stream_set_state_callback); -LOAD_FUNC(pa_stream_new); -LOAD_FUNC(pa_stream_disconnect); -LOAD_FUNC(pa_threaded_mainloop_lock); - -#undef LOAD_FUNC + *func_list = pulse_funcs; } //}}} void alc_pulse_deinit(void) //{{{ { - if(pa_handle) - { -#ifdef _WIN32 - FreeLibrary(pa_handle); -#elif defined (HAVE_DLFCN_H) - dlclose(pa_handle); -#endif - } - pa_handle = NULL; } //}}} void alc_pulse_probe(int type) //{{{ { - if(!pa_handle) alc_pulse_init(NULL); + pulse_load(); if(!pa_handle) return; if(type == DEVICE_PROBE) @@ -667,5 +700,7 @@ void alc_pulse_probe(int type) //{{{ AppendAllDeviceList(pulse_device); else if(type == CAPTURE_DEVICE_PROBE) AppendCaptureDeviceList(pulse_capture_device); + + pulse_unload(); } //}}} //}}} |