mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-12 00:56:40 -04:00
Load OpenAL library dynamically
That way the game will still start even if OpenAL library is missing. Not really an issue with macOS but tends to be an issue with some linux distributions.
This commit is contained in:
parent
88994cdcc7
commit
0b67f6be62
127
src/Audio.c
127
src/Audio.c
@ -201,28 +201,83 @@ static ALCdevice* audio_device;
|
||||
static ALCcontext* audio_context;
|
||||
static cc_bool alInited, alSupported;
|
||||
|
||||
#if defined CC_BUILD_WIN
|
||||
static const String alLib = String_FromConst("openal32.dll");
|
||||
#elif defined CC_BUILD_OSX
|
||||
static const String alLib = String_FromConst("/System/Library/Frameworks/OpenAL.framework/Versions/A/OpenAL")
|
||||
#else
|
||||
static const String alLib = String_FromConst("libopenal.so.1");
|
||||
#endif
|
||||
|
||||
static LPALCCREATECONTEXT _alcCreateContext;
|
||||
static LPALCMAKECONTEXTCURRENT _alcMakeContextCurrent;
|
||||
static LPALCDESTROYCONTEXT _alcDestroyContext;
|
||||
static LPALCOPENDEVICE _alcOpenDevice;
|
||||
static LPALCCLOSEDEVICE _alcCloseDevice;
|
||||
static LPALCGETERROR _alcGetError;
|
||||
|
||||
static LPALGETERROR _alGetError;
|
||||
static LPALGENSOURCES _alGenSources;
|
||||
static LPALDELETESOURCES _alDeleteSources;
|
||||
static LPALGETSOURCEI _alGetSourcei;
|
||||
static LPALSOURCEPLAY _alSourcePlay;
|
||||
static LPALSOURCESTOP _alSourceStop;
|
||||
static LPALSOURCEQUEUEBUFFERS _alSourceQueueBuffers;
|
||||
static LPALSOURCEUNQUEUEBUFFERS _alSourceUnqueueBuffers;
|
||||
static LPALGENBUFFERS _alGenBuffers;
|
||||
static LPALDELETEBUFFERS _alDeleteBuffers;
|
||||
static LPALBUFFERDATA _alBufferData;
|
||||
static LPALDISTANCEMODEL _alDistanceModel;
|
||||
|
||||
#define QUOTE(x) #x
|
||||
#define LoadALFunc(sym, type) (_ ## sym = (type)DynamicLib_Get2(lib, QUOTE(sym)))
|
||||
static cc_bool LoadALFuncs(void) {
|
||||
void* lib = DynamicLib_Load2(&alLib);
|
||||
if (!lib) { Logger_DynamicLibWarn("loading", &alLib); return false; }
|
||||
|
||||
return
|
||||
LoadALFunc(alcCreateContext, LPALCCREATECONTEXT) &&
|
||||
LoadALFunc(alcMakeContextCurrent, LPALCMAKECONTEXTCURRENT) &&
|
||||
LoadALFunc(alcDestroyContext, LPALCDESTROYCONTEXT) &&
|
||||
LoadALFunc(alcOpenDevice, LPALCOPENDEVICE) &&
|
||||
LoadALFunc(alcCloseDevice, LPALCCLOSEDEVICE) &&
|
||||
LoadALFunc(alcGetError, LPALCGETERROR) &&
|
||||
|
||||
LoadALFunc(alGetError, LPALGETERROR) &&
|
||||
LoadALFunc(alGenSources, LPALGENSOURCES) &&
|
||||
LoadALFunc(alDeleteSources, LPALDELETESOURCES) &&
|
||||
LoadALFunc(alGetSourcei, LPALGETSOURCEI) &&
|
||||
LoadALFunc(alSourcePlay, LPALSOURCEPLAY) &&
|
||||
LoadALFunc(alSourceStop, LPALSOURCESTOP) &&
|
||||
LoadALFunc(alSourceQueueBuffers, LPALSOURCEQUEUEBUFFERS) &&
|
||||
LoadALFunc(alSourceUnqueueBuffers, LPALSOURCEUNQUEUEBUFFERS) &&
|
||||
LoadALFunc(alGenBuffers, LPALGENBUFFERS) &&
|
||||
LoadALFunc(alDeleteBuffers, LPALDELETEBUFFERS) &&
|
||||
LoadALFunc(alBufferData, LPALBUFFERDATA) &&
|
||||
LoadALFunc(alDistanceModel, LPALDISTANCEMODEL);
|
||||
}
|
||||
|
||||
static cc_result CreateALContext(void) {
|
||||
ALenum err;
|
||||
audio_device = alcOpenDevice(NULL);
|
||||
if (!audio_device) return AL_ERR_INIT_DEVICE;
|
||||
if ((err = alcGetError(audio_device))) return err;
|
||||
audio_device = _alcOpenDevice(NULL);
|
||||
if (!audio_device) return AL_ERR_INIT_DEVICE;
|
||||
if ((err = _alcGetError(audio_device))) return err;
|
||||
|
||||
audio_context = alcCreateContext(audio_device, NULL);
|
||||
if (!audio_context) {
|
||||
alcCloseDevice(audio_device);
|
||||
return AL_ERR_INIT_CONTEXT;
|
||||
}
|
||||
if ((err = alcGetError(audio_device))) return err;
|
||||
audio_context = _alcCreateContext(audio_device, NULL);
|
||||
if (!audio_context) return AL_ERR_INIT_CONTEXT;
|
||||
if ((err = _alcGetError(audio_device))) return err;
|
||||
|
||||
alcMakeContextCurrent(audio_context);
|
||||
return alcGetError(audio_device);
|
||||
_alcMakeContextCurrent(audio_context);
|
||||
return _alcGetError(audio_device);
|
||||
}
|
||||
|
||||
static cc_bool Audio_SysInit(void) {
|
||||
static const String msg = String_FromConst("Failed to init OpenAL. No audio will play.");
|
||||
cc_result res;
|
||||
if (alInited) return alSupported;
|
||||
alInited = true;
|
||||
|
||||
if (!LoadALFuncs()) { Logger_WarnFunc(&msg); return false; }
|
||||
res = CreateALContext();
|
||||
if (res) { Logger_SimpleWarn(res, "initing OpenAL"); return false; }
|
||||
|
||||
@ -232,10 +287,10 @@ static cc_bool Audio_SysInit(void) {
|
||||
|
||||
static void Audio_SysFree(void) {
|
||||
if (!audio_device) return;
|
||||
alcMakeContextCurrent(NULL);
|
||||
_alcMakeContextCurrent(NULL);
|
||||
|
||||
if (audio_context) alcDestroyContext(audio_context);
|
||||
if (audio_device) alcCloseDevice(audio_device);
|
||||
if (audio_context) _alcDestroyContext(audio_context);
|
||||
if (audio_device) _alcCloseDevice(audio_device);
|
||||
|
||||
audio_context = NULL;
|
||||
audio_device = NULL;
|
||||
@ -245,18 +300,18 @@ static ALenum Audio_FreeSource(struct AudioContext* ctx) {
|
||||
ALenum err;
|
||||
if (ctx->source == -1) return 0;
|
||||
|
||||
alDeleteSources(1, &ctx->source);
|
||||
_alDeleteSources(1, &ctx->source);
|
||||
ctx->source = -1;
|
||||
if ((err = alGetError())) return err;
|
||||
if ((err = _alGetError())) return err;
|
||||
|
||||
alDeleteBuffers(ctx->count, ctx->buffers);
|
||||
if ((err = alGetError())) return err;
|
||||
_alDeleteBuffers(ctx->count, ctx->buffers);
|
||||
if ((err = _alGetError())) return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Audio_Open(AudioHandle* handle, int buffers) {
|
||||
int i, j;
|
||||
alDistanceModel(AL_NONE);
|
||||
_alDistanceModel(AL_NONE);
|
||||
|
||||
for (i = 0; i < Array_Elems(audioContexts); i++) {
|
||||
struct AudioContext* ctx = &audioContexts[i];
|
||||
@ -301,11 +356,11 @@ cc_result Audio_SetFormat(AudioHandle handle, struct AudioFormat* format) {
|
||||
ctx->format = *format;
|
||||
|
||||
if ((err = Audio_FreeSource(ctx))) return err;
|
||||
alGenSources(1, &ctx->source);
|
||||
if ((err = alGetError())) return err;
|
||||
_alGenSources(1, &ctx->source);
|
||||
if ((err = _alGetError())) return err;
|
||||
|
||||
alGenBuffers(ctx->count, ctx->buffers);
|
||||
if ((err = alGetError())) return err;
|
||||
_alGenBuffers(ctx->count, ctx->buffers);
|
||||
if ((err = _alGetError())) return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -315,23 +370,23 @@ cc_result Audio_BufferData(AudioHandle handle, int idx, void* data, cc_uint32 da
|
||||
ALenum err;
|
||||
ctx->completed[idx] = false;
|
||||
|
||||
alBufferData(buffer, ctx->dataFormat, data, dataSize, ctx->format.sampleRate);
|
||||
if ((err = alGetError())) return err;
|
||||
alSourceQueueBuffers(ctx->source, 1, &buffer);
|
||||
if ((err = alGetError())) return err;
|
||||
_alBufferData(buffer, ctx->dataFormat, data, dataSize, ctx->format.sampleRate);
|
||||
if ((err = _alGetError())) return err;
|
||||
_alSourceQueueBuffers(ctx->source, 1, &buffer);
|
||||
if ((err = _alGetError())) return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
cc_result Audio_Play(AudioHandle handle) {
|
||||
struct AudioContext* ctx = &audioContexts[handle];
|
||||
alSourcePlay(ctx->source);
|
||||
return alGetError();
|
||||
_alSourcePlay(ctx->source);
|
||||
return _alGetError();
|
||||
}
|
||||
|
||||
cc_result Audio_Stop(AudioHandle handle) {
|
||||
struct AudioContext* ctx = &audioContexts[handle];
|
||||
alSourceStop(ctx->source);
|
||||
return alGetError();
|
||||
_alSourceStop(ctx->source);
|
||||
return _alGetError();
|
||||
}
|
||||
|
||||
cc_result Audio_IsCompleted(AudioHandle handle, int idx, cc_bool* completed) {
|
||||
@ -340,12 +395,12 @@ cc_result Audio_IsCompleted(AudioHandle handle, int idx, cc_bool* completed) {
|
||||
ALuint buffer;
|
||||
ALenum err;
|
||||
|
||||
alGetSourcei(ctx->source, AL_BUFFERS_PROCESSED, &processed);
|
||||
if ((err = alGetError())) return err;
|
||||
_alGetSourcei(ctx->source, AL_BUFFERS_PROCESSED, &processed);
|
||||
if ((err = _alGetError())) return err;
|
||||
|
||||
if (processed > 0) {
|
||||
alSourceUnqueueBuffers(ctx->source, 1, &buffer);
|
||||
if ((err = alGetError())) return err;
|
||||
_alSourceUnqueueBuffers(ctx->source, 1, &buffer);
|
||||
if ((err = _alGetError())) return err;
|
||||
|
||||
for (i = 0; i < ctx->count; i++) {
|
||||
if (ctx->buffers[i] == buffer) ctx->completed[i] = true;
|
||||
@ -363,7 +418,7 @@ cc_result Audio_IsFinished(AudioHandle handle, cc_bool* finished) {
|
||||
res = Audio_AllCompleted(handle, finished);
|
||||
if (res) return res;
|
||||
|
||||
alGetSourcei(ctx->source, AL_SOURCE_STATE, &state);
|
||||
_alGetSourcei(ctx->source, AL_SOURCE_STATE, &state);
|
||||
*finished = state != AL_PLAYING; return 0;
|
||||
}
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user