Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files
Updated esd audio driver for 1.3 API.
  • Loading branch information
icculus committed Oct 6, 2006
1 parent ee2c46c commit f49f4b190c5b6d3c1b88875a4a8e8fe4efdcf819
Showing with 142 additions and 133 deletions.
  1. +142 −125 src/audio/esd/SDL_esdaudio.c
  2. +0 −8 src/audio/esd/SDL_esdaudio.h
@@ -46,39 +46,40 @@
#define ESD_DRIVER_NAME "esd"

/* Audio driver functions */
static int ESD_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void ESD_WaitAudio(_THIS);
static void ESD_PlayAudio(_THIS);
static Uint8 *ESD_GetAudioBuf(_THIS);
static void ESD_CloseAudio(_THIS);
static int ESD_OpenDevice(_THIS, const char *devname, int iscapture);
static void ESD_WaitDevice(_THIS);
static void ESD_PlayDevice(_THIS);
static Uint8 *ESD_GetDeviceBuf(_THIS);
static void ESD_CloseDevice(_THIS);

#ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC

static const char *esd_library = SDL_AUDIO_DRIVER_ESD_DYNAMIC;
static void *esd_handle = NULL;
static int esd_loaded = 0;

static int (*SDL_NAME(esd_open_sound)) (const char *host);
static int (*SDL_NAME(esd_close)) (int esd);
static int (*SDL_NAME(esd_play_stream)) (esd_format_t format, int rate,
const char *host, const char *name);

#define SDL_ESD_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) }
static struct
{
const char *name;
void **func;
} esd_functions[] = {
{
"esd_open_sound", (void **) &SDL_NAME(esd_open_sound)}, {
"esd_close", (void **) &SDL_NAME(esd_close)}, {
"esd_play_stream", (void **) &SDL_NAME(esd_play_stream)},};
SDL_ESD_SYM(esd_open_sound),
SDL_ESD_SYM(esd_close),
SDL_ESD_SYM(esd_play_stream),
};
#undef SDL_ESD_SYM

static void
UnloadESDLibrary()
{
if (esd_loaded) {
if (esd_handle != NULL) {
SDL_UnloadObject(esd_handle);
esd_handle = NULL;
esd_loaded = 0;
}
}

@@ -87,17 +88,18 @@ LoadESDLibrary(void)
{
int i, retval = -1;

esd_handle = SDL_LoadObject(esd_library);
if (esd_handle) {
esd_loaded = 1;
retval = 0;
for (i = 0; i < SDL_arraysize(esd_functions); ++i) {
*esd_functions[i].func =
SDL_LoadFunction(esd_handle, esd_functions[i].name);
if (!*esd_functions[i].func) {
retval = -1;
UnloadESDLibrary();
break;
if (esd_handle == NULL) {
esd_handle = SDL_LoadObject(esd_library);
if (esd_handle) {
retval = 0;
for (i = 0; i < SDL_arraysize(esd_functions); ++i) {
*esd_functions[i].func =
SDL_LoadFunction(esd_handle, esd_functions[i].name);
if (!*esd_functions[i].func) {
retval = -1;
UnloadESDLibrary();
break;
}
}
}
}
@@ -123,79 +125,48 @@ LoadESDLibrary(void)
/* Audio driver bootstrap functions */

static int
Audio_Available(void)
ESD_Available(void)
{
const char *esd_no_spawn = SDL_getenv("ESD_NO_SPAWN");
int connection = 0;
int available = 0;

if (esd_no_spawn == NULL) {
SDL_putenv("ESD_NO_SPAWN=1"); /* Don't start ESD if it's not running */
}

if (LoadESDLibrary() < 0) {
return available;
}
connection = SDL_NAME(esd_open_sound) (NULL);
if (connection >= 0) {
available = 1;
SDL_NAME(esd_close) (connection);
if (LoadESDLibrary() == 0) {
int connection;
if (SDL_getenv("ESD_NO_SPAWN") == NULL) {
SDL_putenv("ESD_NO_SPAWN=1"); /* Don't start ESD if it's not running */
}
connection = SDL_NAME(esd_open_sound) (NULL);
if (connection >= 0) {
available = 1;
SDL_NAME(esd_close) (connection);
}
UnloadESDLibrary();
}
UnloadESDLibrary();
return available;
}

static void
Audio_DeleteDevice(SDL_AudioDevice * device)
{
SDL_free(device->hidden);
SDL_free(device);
UnloadESDLibrary();
}

static SDL_AudioDevice *
Audio_CreateDevice(int devindex)
static int
ESD_Init(SDL_AudioDriverImpl *impl)
{
SDL_AudioDevice *this;

/* Initialize all variables that we clean on shutdown */
LoadESDLibrary();
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
if (this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if (this) {
SDL_free(this);
}
return (0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
audio_fd = -1;

/* Set the function pointers */
this->OpenAudio = ESD_OpenAudio;
this->WaitAudio = ESD_WaitAudio;
this->PlayAudio = ESD_PlayAudio;
this->GetAudioBuf = ESD_GetAudioBuf;
this->CloseAudio = ESD_CloseAudio;

this->free = Audio_DeleteDevice;

return this;
impl->OpenDevice = ESD_OpenDevice;
impl->PlayDevice = ESD_PlayDevice;
impl->WaitDevice = ESD_WaitDevice;
impl->GetDeviceBuf = ESD_GetDeviceBuf;
impl->CloseDevice = ESD_CloseDevice;
impl->OnlyHasDefaultOutputDevice = 1;

return 1;
}


AudioBootStrap ESD_bootstrap = {
ESD_DRIVER_NAME, "Enlightened Sound Daemon",
Audio_Available, Audio_CreateDevice, 0
ESD_Available, ESD_Init, 0
};

/* This function waits until it is possible to write a full sound buffer */
static void
ESD_WaitAudio(_THIS)
ESD_WaitDevice(_THIS)
{
Sint32 ticks;

@@ -205,28 +176,31 @@ ESD_WaitAudio(_THIS)
/* Note that this only works with thread implementations
that use a different process id for each thread.
*/
if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */
if (kill(parent, 0) < 0) {
/* Check every 10 loops */
if (this->hidden->parent && (((++cnt) % 10) == 0)) {
if (kill(this->hidden->parent, 0) < 0) {
this->enabled = 0;
}
}
}

/* Use timer for general audio synchronization */
ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS;
ticks = ((Sint32) (this->hidden->next_frame-SDL_GetTicks())) - FUDGE_TICKS;
if (ticks > 0) {
SDL_Delay(ticks);
}
}

static void
ESD_PlayAudio(_THIS)
ESD_PlayDevice(_THIS)
{
int written;
int written = 0;

/* Write the audio data, checking for EAGAIN on broken audio drivers */
do {
written = write(audio_fd, mixbuf, mixlen);
written = write(this->hidden->audio_fd,
this->hidden->mixbuf,
this->hidden->mixlen);
if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) {
SDL_Delay(1); /* Let a little CPU time go by */
}
@@ -235,7 +209,7 @@ ESD_PlayAudio(_THIS)
((errno == 0) || (errno == EAGAIN) || (errno == EINTR)));

/* Set the next write frame */
next_frame += frame_ticks;
this->hidden->next_frame += this->hidden->frame_ticks;

/* If we couldn't write, assume fatal error for now */
if (written < 0) {
@@ -244,22 +218,28 @@ ESD_PlayAudio(_THIS)
}

static Uint8 *
ESD_GetAudioBuf(_THIS)
ESD_GetDeviceBuf(_THIS)
{
return (mixbuf);
return (this->hidden->mixbuf);
}

static void
ESD_CloseAudio(_THIS)
ESD_CloseDevice(_THIS)
{
if (mixbuf != NULL) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
}
if (audio_fd >= 0) {
SDL_NAME(esd_close) (audio_fd);
audio_fd = -1;
if (this->hidden != NULL) {
if (this->hidden->mixbuf != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
if (this->hidden->audio_fd >= 0) {
SDL_NAME(esd_close) (this->hidden->audio_fd);
this->hidden->audio_fd = -1;
}

SDL_free(this->hidden);
this->hidden = NULL;
}
UnloadESDLibrary();
}

/* Try to get the name of the program */
@@ -288,59 +268,96 @@ get_progname(void)
return (progname);
}


static int
ESD_OpenAudio(_THIS, SDL_AudioSpec * spec)
ESD_OpenDevice(_THIS, const char *devname, int iscapture)
{
esd_format_t format;
esd_format_t format = (ESD_STREAM | ESD_PLAY);
SDL_AudioFormat test_format = 0;
int found = 0;

/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
this->hidden->audio_fd = -1;

if (LoadESDLibrary() < 0) {
ESD_CloseDevice(this);
SDL_SetError("ESD: failed to load library: %s", SDL_GetError());
return 0;
}

/* Convert audio spec to the ESD audio format */
format = (ESD_STREAM | ESD_PLAY);
switch (spec->format & 0xFF) {
case 8:
format |= ESD_BITS8;
break;
case 16:
format |= ESD_BITS16;
break;
default:
SDL_SetError("Unsupported ESD audio format");
return (-1);
/* Try for a closest match on audio format */
for (test_format = SDL_FirstAudioFormat(this->spec.format);
!found && test_format; test_format = SDL_NextAudioFormat()) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
#endif
found = 1;
switch (test_format) {
case AUDIO_U8:
format |= ESD_BITS8;
break;
case AUDIO_S16SYS:
format |= ESD_BITS16;
break;
default:
found = 0;
break;
}
}

if (!found) {
ESD_CloseDevice(this);
SDL_SetError("Couldn't find any hardware audio formats");
return 0;
}
if (spec->channels == 1) {

if (this->spec.channels == 1) {
format |= ESD_MONO;
} else {
format |= ESD_STEREO;
}
#if 0
spec->samples = ESD_BUF_SIZE; /* Darn, no way to change this yet */
this->spec.samples = ESD_BUF_SIZE; /* Darn, no way to change this yet */
#endif

/* Open a connection to the ESD audio server */
audio_fd =
SDL_NAME(esd_play_stream) (format, spec->freq, NULL, get_progname());
if (audio_fd < 0) {
this->hidden->audio_fd =
SDL_NAME(esd_play_stream)(format,this->spec.freq,NULL,get_progname());

if (this->hidden->audio_fd < 0) {
ESD_CloseDevice(this);
SDL_SetError("Couldn't open ESD connection");
return (-1);
return 0;
}

/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
frame_ticks = (float) (spec->samples * 1000) / spec->freq;
next_frame = SDL_GetTicks() + frame_ticks;
SDL_CalculateAudioSpec(&this->spec);
this->hidden->frame_ticks = (float) (this->spec.samples*1000) / this->spec.freq;
this->hidden->next_frame = SDL_GetTicks() + this->hidden->frame_ticks;

/* Allocate mixing buffer */
mixlen = spec->size;
mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen);
if (mixbuf == NULL) {
return (-1);
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
ESD_CloseDevice(this);
SDL_OutOfMemory();
return 0;
}
SDL_memset(mixbuf, spec->silence, spec->size);
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);

/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
this->hidden->parent = getpid();

/* We're ready to rock and roll. :-) */
return (0);
return 1;
}

/* vi: set ts=4 sw=4 expandtab: */

0 comments on commit f49f4b1

Please sign in to comment.