Search
j0ke.net Open Build Service
>
Projects
>
multimedia
:
EL6
>
libmikmod
> libmikmod-esd.patch
Sign Up
|
Log In
Username
Password
Cancel
Overview
Repositories
Revisions
Requests
Users
Advanced
Attributes
Meta
File libmikmod-esd.patch of Package libmikmod
--- libmikmod-3.2.0-beta2/drivers/drv_esd.c 2004-01-31 23:39:40.000000000 +0100 +++ libmikmod-3.2.0-beta2.new/drivers/drv_esd.c 2008-02-18 12:09:07.000000000 +0100 @@ -81,7 +81,6 @@ static int sndfd=-1; static esd_format_t format; -static SBYTE *audiobuffer=NULL; static CHAR *espeaker=NULL; #ifdef MIKMOD_DYNAMIC @@ -100,7 +99,7 @@ if (libesd) return 0; /* load libesd.so */ - libesd=dlopen("libesd.so",RTLD_LAZY|RTLD_GLOBAL); + libesd=dlopen("libesd.so.0",RTLD_LAZY|RTLD_GLOBAL); if (!libesd) return 1; /* resolve function references */ @@ -124,23 +123,88 @@ } #endif +/* A simple chunk fifo buffer, as we cannot query to ask how much free space + there is with esd, we keep a fifo filled and try to write the entire fifo + non blocking, stopping when we get -EAGAIN */ + +#define AUDIO_BUF_SIZE (ESD_BUF_SIZE * 4) + +static SBYTE audiobuffer[AUDIO_BUF_SIZE]; +static int audiobuffer_start, audiobuffer_end, audiobuffer_empty; + +static void audiobuffer_init(void) +{ + audiobuffer_empty = 1; + audiobuffer_start = audiobuffer_end = 0; +} + +/* Get a free chunk of the fifo, the caller is expected to use all of it, so + all of it gets marked filled */ +static SBYTE *audiobuffer_get_free_chunk(int *size) +{ + int end = audiobuffer_end; + + if (audiobuffer_empty) + { + audiobuffer_empty = 0; + *size = AUDIO_BUF_SIZE; + } + else if (audiobuffer_end > audiobuffer_start) + { + *size = AUDIO_BUF_SIZE - audiobuffer_end; + audiobuffer_end = 0; + } + else + { + *size = audiobuffer_start - audiobuffer_end; + audiobuffer_end = audiobuffer_start; + } + + return audiobuffer + end; +} + +/* Get a filled chunk from the fifo, the caller must call audiobuffer_mark_free + to tell the fifo how much of the chunk it has consumed */ +static SBYTE *audiobuffer_get_filled_chunk(int *size) +{ + if (audiobuffer_empty) + { + *size = 0; + } + else if (audiobuffer_end > audiobuffer_start) + { + *size = audiobuffer_end - audiobuffer_start; + } + else + { + *size = AUDIO_BUF_SIZE - audiobuffer_start; + } + + return audiobuffer + audiobuffer_start; +} + +/* Tell the fifo to mark size bytes as free starting from the current head of + the fifo */ +static void audiobuffer_mark_free(int size) +{ + audiobuffer_start = (audiobuffer_start + size) % AUDIO_BUF_SIZE; + if (audiobuffer_start == audiobuffer_end) + { + audiobuffer_empty = 1; + audiobuffer_start = audiobuffer_end = 0; + } +} + /* I hope to have this function integrated into libesd someday...*/ static ssize_t esd_writebuf(int fd,const void *buffer,size_t count) { - ssize_t start=0; + ssize_t res; - while (start<count) { - ssize_t res; + res = write(fd, (char*)buffer, count); + if (res < 0 && errno == EAGAIN) + return 0; - res=write(fd,(char*)buffer+start,count-start); - if (res<0) { - /* connection lost */ - if (errno==EPIPE) - return -1-start; - } else - start+=res; - } - return start; + return res; } static void ESD_CommandLine(CHAR *cmdline) @@ -193,13 +257,14 @@ _mm_errno=MMERR_OPENING_AUDIO; return 1; } + fcntl(sndfd, F_SETFL, fcntl(sndfd, F_GETFL) | O_NONBLOCK); } else { _mm_errno=MMERR_OUT_OF_MEMORY; return 1; } - - if (!(audiobuffer=(SBYTE*)_mm_malloc(ESD_BUF_SIZE*sizeof(char)))) - return 1; + + /* Initialize the audiobuffer */ + audiobuffer_init(); return VC_Init(); } @@ -218,7 +283,6 @@ static void ESD_Exit_internal(void) { VC_Exit(); - _mm_free(audiobuffer); if (sndfd>=0) { esd_closestream(sndfd); sndfd=-1; @@ -234,19 +298,50 @@ #endif } -static void ESD_Update_internal(int count) +typedef ULONG (*VC_WriteBytesFunc)(SBYTE*, ULONG); + +static void ESD_Update_internal(VC_WriteBytesFunc WriteBytes) { static time_t losttime; if (sndfd>=0) { - if (esd_writebuf(sndfd,audiobuffer,count)<0) { - /* if we lost our connection with esd, clean up and work as the - nosound driver until we can reconnect */ - esd_closestream(sndfd); - sndfd=-1; - signal(SIGPIPE,SIG_DFL); - losttime=time(NULL); + SBYTE *chunk; + int size; + ssize_t written; + + /* Fill fifo */ + chunk = audiobuffer_get_free_chunk(&size); + while (size) + { + WriteBytes(chunk, size); + chunk = audiobuffer_get_free_chunk(&size); } + + /* And write untill fifo empty, or we would block */ + chunk = audiobuffer_get_filled_chunk(&size); + while (size) + { + written = esd_writebuf(sndfd, chunk, size); + if (written < 0) + { + /* if we lost our connection with esd, clean up + and work as the nosound driver until we can + reconnect */ + esd_closestream(sndfd); + sndfd = -1; + signal(SIGPIPE, SIG_DFL); + losttime = time(NULL); + break; + } + + /* Stop if the buffer is full */ + if (written == 0) + break; + + audiobuffer_mark_free(written); + + chunk = audiobuffer_get_filled_chunk(&size); + } } else { /* an alarm would be better, but then the library user could not use alarm(2) himself... */ @@ -255,8 +350,11 @@ /* Attempt to reconnect every 5 seconds */ if (!(SETENV)) if ((sndfd=esd_playstream(format,md_mixfreq,espeaker,"libmikmod"))>=0) { - VC_SilenceBytes(audiobuffer,ESD_BUF_SIZE); - esd_writebuf(sndfd,audiobuffer,ESD_BUF_SIZE); + /* reconnected, clear fifo (contains old sound) and recurse + to play sound */ + audiobuffer_init(); + fcntl(sndfd, F_SETFL, fcntl(sndfd, F_GETFL) | O_NONBLOCK); + ESD_Update_internal(WriteBytes); } } } @@ -264,22 +362,24 @@ static void ESD_Update(void) { - ESD_Update_internal(VC_WriteBytes(audiobuffer,ESD_BUF_SIZE)); + ESD_Update_internal(VC_WriteBytes); } static void ESD_Pause(void) { - ESD_Update_internal(VC_SilenceBytes(audiobuffer,ESD_BUF_SIZE)); + ESD_Update_internal(VC_SilenceBytes); } static BOOL ESD_PlayStart(void) { if (sndfd<0) - if (!(SETENV)) + if (!(SETENV)) { if ((sndfd=esd_playstream(format,md_mixfreq,espeaker,"libmikmod"))<0) { _mm_errno=MMERR_OPENING_AUDIO; return 1; } + fcntl(sndfd, F_SETFL, fcntl(sndfd, F_GETFL) | O_NONBLOCK); + } /* since the default behaviour of SIGPIPE on most Unices is to kill the program, we'll prefer handle EPIPE ourselves should the esd die - recent esdlib use a do-nothing handler, which prevents us from receiving EPIPE, @@ -289,6 +389,7 @@ /* silence buffers */ VC_SilenceBytes(audiobuffer,ESD_BUF_SIZE); esd_writebuf(sndfd,audiobuffer,ESD_BUF_SIZE); + audiobuffer_init(); return VC_PlayStart(); } @@ -299,6 +400,7 @@ /* silence buffers */ VC_SilenceBytes(audiobuffer,ESD_BUF_SIZE); esd_writebuf(sndfd,audiobuffer,ESD_BUF_SIZE); + audiobuffer_init(); signal(SIGPIPE,SIG_DFL); }