summaryrefslogtreecommitdiffstats
path: root/Alc
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2009-09-27 00:21:40 -0700
committerChris Robinson <[email protected]>2009-09-27 00:21:40 -0700
commit8024df299121f2d25c4e4b24f8c55ebdac2d9e4c (patch)
treee3f2ce6634bda5a75521015aaf275fff9ac9c2b4 /Alc
parentf72b6fe717898172c9915fd70c0710bfcf7d843e (diff)
Load backend libs on-demand
Diffstat (limited to 'Alc')
-rw-r--r--Alc/alsa.c224
-rw-r--r--Alc/dsound.c97
-rw-r--r--Alc/portaudio.c149
-rw-r--r--Alc/pulseaudio.c225
4 files changed, 405 insertions, 290 deletions
diff --git a/Alc/alsa.c b/Alc/alsa.c
index eb58199e..f174abff 100644
--- a/Alc/alsa.c
+++ b/Alc/alsa.c
@@ -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();
} //}}}
//}}}