Add an SDL backend

This commit is contained in:
Chris Robinson 2008-12-07 01:05:39 -08:00
parent f6a4dbabdd
commit 8b54d59b8c
6 changed files with 336 additions and 1 deletions

View File

@ -67,6 +67,9 @@ static struct {
#ifdef HAVE_WINMM
{ "winmm", alcWinMMInit, EmptyFuncs },
#endif
#ifdef HAVE_SDL
{ "sdl", alc_sdl_init, EmptyFuncs },
#endif
{ "wave", alc_wave_init, EmptyFuncs },

306
Alc/sdl.c Normal file
View File

@ -0,0 +1,306 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2007 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include "alMain.h"
#include "AL/al.h"
#include "AL/alc.h"
#include <string.h>
#include <stdlib.h>
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#endif
#include <SDL/SDL.h>
static void *sdl_handle;
#define MAKE_FUNC(x) static typeof(x) * p##x
MAKE_FUNC(SDL_PauseAudio);
MAKE_FUNC(SDL_CloseAudio);
MAKE_FUNC(SDL_OpenAudio);
MAKE_FUNC(SDL_InitSubSystem);
MAKE_FUNC(SDL_GetError);
MAKE_FUNC(SDL_LockAudio);
MAKE_FUNC(SDL_UnlockAudio);
#undef MAKE_FUNC
static char *sdl_device;
/* SDL audio can only be initialized once per process */
static int initialized;
typedef struct {
SDL_AudioSpec audioSpec;
volatile int killNow;
ALvoid *thread;
ALubyte *mix_data;
int data_size;
int data_read;
int data_write;
} sdl_data;
static void SDLCALL fillAudio(void *userdata, Uint8 *stream, int len)
{
sdl_data *data = (sdl_data*)userdata;
int rem = data->data_size-data->data_read;
if(len >= rem)
{
memcpy(stream, data->mix_data + data->data_read, rem);
stream += rem;
len -= rem;
data->data_read = 0;
}
if(len > 0)
{
memcpy(stream, data->mix_data + data->data_read, len);
data->data_read += len;
}
}
static ALuint SDLProc(ALvoid *ptr)
{
ALCdevice *pDevice = (ALCdevice*)ptr;
sdl_data *data = (sdl_data*)pDevice->ExtraData;
int len, rem;
pSDL_PauseAudio(0);
while(!data->killNow)
{
pSDL_LockAudio();
len = (data->data_read-data->data_write+data->data_size)%data->data_size;
if(len == 0)
{
pSDL_UnlockAudio();
Sleep(1);
continue;
}
rem = data->data_size - data->data_write;
SuspendContext(NULL);
if(len > rem)
{
aluMixData(pDevice->Context, data->mix_data+data->data_write, rem, pDevice->Format);
aluMixData(pDevice->Context, data->mix_data, len-rem, pDevice->Format);
}
else
aluMixData(pDevice->Context, data->mix_data+data->data_write, len, pDevice->Format);
ProcessContext(NULL);
data->data_write = data->data_read;
pSDL_UnlockAudio();
}
pSDL_PauseAudio(1);
return 0;
}
static ALCboolean sdl_open_playback(ALCdevice *device, const ALCchar *deviceName)
{
SDL_AudioSpec sdlSpec;
ALuint frameSize;
sdl_data *data;
if(initialized || !sdl_device)
return ALC_FALSE;
if(deviceName)
{
if(strcmp(deviceName, sdl_device))
return ALC_FALSE;
device->szDeviceName = sdl_device;
}
else
device->szDeviceName = sdl_device;
data = (sdl_data*)calloc(1, sizeof(sdl_data));
data->killNow = 0;
frameSize = aluBytesFromFormat(device->Format) *
aluChannelsFromFormat(device->Format);
sdlSpec.freq = device->Frequency;
sdlSpec.channels = aluChannelsFromFormat(device->Format);
switch(aluBytesFromFormat(device->Format))
{
case 1:
sdlSpec.format = AUDIO_U8;
break;
case 2:
sdlSpec.format = AUDIO_S16SYS;
break;
default:
AL_PRINT("Unknown format?! %x\n", device->Format);
free(data);
return ALC_FALSE;
}
sdlSpec.samples = 1;
while(sdlSpec.samples < device->UpdateSize)
sdlSpec.samples <<= 1;
sdlSpec.samples >>= 1;
sdlSpec.callback = fillAudio;
sdlSpec.userdata = data;
if(pSDL_OpenAudio(&sdlSpec, &data->audioSpec) < 0)
{
AL_PRINT("Audio init failed: %s\n", pSDL_GetError());
free(data);
return ALC_FALSE;
}
if(!((data->audioSpec.format == AUDIO_U8 && aluBytesFromFormat(device->Format) == 1) ||
(data->audioSpec.format == AUDIO_S16SYS && aluBytesFromFormat(device->Format) == 2)))
{
AL_PRINT("Could not set %d-bit, got format %#x instead\n", aluBytesFromFormat(device->Format), data->audioSpec.format);
pSDL_CloseAudio();
free(data);
return ALC_FALSE;
}
if(aluChannelsFromFormat(device->Format) != data->audioSpec.channels)
{
AL_PRINT("Could not set %d channels, got %d instead\n", aluChannelsFromFormat(device->Format), data->audioSpec.channels);
pSDL_CloseAudio();
free(data);
return ALC_FALSE;
}
device->Frequency = data->audioSpec.freq;
device->UpdateSize = data->audioSpec.size / frameSize;
data->data_size = device->UpdateSize * frameSize * 2;
data->mix_data = malloc(data->data_size);
if(data->mix_data == NULL)
{
AL_PRINT("Could not allocate %d bytes\n", data->data_size);
pSDL_CloseAudio();
free(data);
return ALC_FALSE;
}
memset(data->mix_data, data->audioSpec.silence, data->data_size);
device->ExtraData = data;
data->thread = StartThread(SDLProc, device);
if(data->thread == NULL)
{
pSDL_CloseAudio();
device->ExtraData = NULL;
free(data->mix_data);
free(data);
return ALC_FALSE;
}
initialized = 1;
return ALC_TRUE;
}
static void sdl_close_playback(ALCdevice *device)
{
sdl_data *data = (sdl_data*)device->ExtraData;
data->killNow = 1;
StopThread(data->thread);
pSDL_CloseAudio();
initialized = 0;
free(data->mix_data);
free(data);
device->ExtraData = NULL;
}
static ALCboolean sdl_open_capture(ALCdevice *device, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize)
{
return ALC_FALSE;
(void)device;
(void)deviceName;
(void)frequency;
(void)format;
(void)SampleSize;
}
BackendFuncs sdl_funcs = {
sdl_open_playback,
sdl_close_playback,
sdl_open_capture,
NULL,
NULL,
NULL,
NULL,
NULL
};
void alc_sdl_init(BackendFuncs *func_list)
{
const char *str;
*func_list = sdl_funcs;
#ifdef HAVE_DLFCN_H
#if defined(__APPLE__) && defined(__MACH__)
# define SDLLIB "SDL.framework/SDL"
#else
# define SDLLIB "libSDL.so"
#endif
sdl_handle = dlopen(SDLLIB, RTLD_NOW);
if(!sdl_handle)
return;
dlerror();
#define LOAD_FUNC(f) do { \
p##f = (typeof(f)*)dlsym(sdl_handle, #f); \
if((str=dlerror()) != NULL) \
{ \
dlclose(sdl_handle); \
sdl_handle = NULL; \
AL_PRINT("Could not load %s from "SDLLIB": %s\n", #f, str); \
return; \
} \
} while(0)
#else
str = NULL;
sdl_handle = 0xDEADBEEF;
#define LOAD_FUNC(f) p##f = f
#endif
LOAD_FUNC(SDL_PauseAudio);
LOAD_FUNC(SDL_CloseAudio);
LOAD_FUNC(SDL_OpenAudio);
LOAD_FUNC(SDL_InitSubSystem);
LOAD_FUNC(SDL_GetError);
LOAD_FUNC(SDL_LockAudio);
LOAD_FUNC(SDL_UnlockAudio);
#undef LOAD_FUNC
if(pSDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
return;
sdl_device = AppendDeviceList("SDL Software");
AppendAllDeviceList(sdl_device);
}

View File

@ -26,6 +26,7 @@ OPTION(OSS "Check for OSS backend" ON)
OPTION(SOLARIS "Check for Solaris backend" ON)
OPTION(DSOUND "Check for DirectSound backend" ON)
OPTION(WINMM "Check for Windows Multimedia backend" ON)
OPTION(SDL "Check for SDL backend" ON)
OPTION(DLOPEN "Check for the dlopen API for loading optional libs" ON)
@ -320,6 +321,24 @@ IF(HAVE_WINDOWS_H)
ENDIF()
ENDIF()
# Check SDL backend
IF(SDL)
CHECK_INCLUDE_FILE(SDL/SDL.h HAVE_SDL_SDL_H)
IF(HAVE_SDL_SDL_H)
CHECK_LIBRARY_EXISTS(SDL SDL_Init "" HAVE_LIBSDL)
IF(HAVE_DLFCN_H OR HAVE_LIBSDL)
SET(HAVE_SDL 1)
SET(ALC_OBJS ${ALC_OBJS} Alc/sdl.c)
IF(HAVE_DLFCN_H)
SET(BACKENDS "${BACKENDS} SDL,")
ELSE()
SET(BACKENDS "${BACKENDS} SDL \(linked\),")
SET(EXTRA_LIBS SDL ${EXTRA_LIBS})
ENDIF()
ENDIF()
ENDIF()
ENDIF()
# This is always available
SET(BACKENDS "${BACKENDS} WaveFile")

View File

@ -147,6 +147,7 @@ void alc_oss_init(BackendFuncs *func_list);
void alc_solaris_init(BackendFuncs *func_list);
void alcDSoundInit(BackendFuncs *func_list);
void alcWinMMInit(BackendFuncs *FuncList);
void alc_sdl_init(BackendFuncs *func_list);
void alc_wave_init(BackendFuncs *func_list);

View File

@ -59,7 +59,7 @@ drivers = # Sets the backend driver list order, comma-seperated. Unknown
# backends and duplicated names are ignored, and unlisted backends
# won't be considered for use. An empty list means the default.
# Default is:
# alsa,oss,solaris,dsound,winmm,wave
# alsa,oss,solaris,dsound,winmm,sdl,wave
excludefx = # Sets which effects to exclude, preventing apps from using them.
# This can help for apps that try to use effects which are too CPU
@ -100,6 +100,9 @@ periods = 4 # Sets the number of updates for the output buffer. Default is 4
[winmm] # Windows Multimedia backend stuff
# Nothing yet...
[sdl] # SDL backend stuff
# Nothing yet...
[wave] # Wave File Writer stuff
file = # Sets the filename of the wave file to write to. An empty name
# prevents the backend from opening, even when explicitly requested.

View File

@ -19,6 +19,9 @@
/* Define if we have the Windows Multimedia backend */
#cmakedefine HAVE_WINMM
/* Define if we have the SDL backend */
#cmakedefine HAVE_SDL
/* Define if we have dlfcn.h */
#cmakedefine HAVE_DLFCN_H