/* x11amp - esound output plugin * Copyright (C) 1999 Galex Yen * * this program is free software * * Description: * This program is an output plugin for x11amp v0.9 or greater. * The program uses the esound daemon to output audio in order * to allow more than one program to play audio on the same * device at the same time. * * Contains code Copyright (C) 1998-1999 Mikael Alm, Olle Hallnas, * Thomas Nillson and 4Front Technologies */ #include "Esd.h" #define NFRAGS 32 #define min(x,y) (x)<(y)?(x):(y) static gboolean going=FALSE; static gboolean paused=FALSE; static gboolean do_pause=FALSE; static gboolean unpause=FALSE; static gboolean remove_prebuffer=FALSE; static gint flush; static gint bps; static AFormat format; static gint channels; static gint frequency; static gint wr_index=0,rd_index=0; static gint output_time_offset; static void *buffer; static gint buffer_size,prebuffer_size,blk_size; static gboolean prebuffer; static gint fd=0; static gint written=0,output_bytes=0; static gint fragsize; static gint length; static pthread_t buffer_thread; gint abuffer_get_written_time(void) { if(!going) return 0; return (gint)(((gfloat)written*1000)/(gfloat)(bps)); } gint abuffer_get_output_time(void) { if(!fd||!going) return 0; return output_time_offset+(gint)((gfloat)((output_bytes)*1000.0)/(gfloat)bps); } gint abuffer_used(void) { /* printf("wr_index : %d rd_index : %d\n", wr_index, rd_index);*/ if(wr_index>=rd_index) return wr_index-rd_index; return buffer_size-(rd_index-wr_index); } gint abuffer_playing(void) { if (!abuffer_used()&&length<=0) return FALSE; return TRUE; } gint abuffer_free(void) { if(remove_prebuffer&&prebuffer) { prebuffer=FALSE; remove_prebuffer=FALSE; } if(prebuffer) remove_prebuffer=TRUE; if(rd_index>wr_index) return (rd_index-wr_index)-((1L<0) { cnt=min(length,buffer_size-wr_index); memcpy(buffer+wr_index,ptr+off,cnt); wr_index=(wr_index+cnt)%buffer_size; length-=cnt; off=cnt; } } void abuffer_close(void) { wr_index=0; rd_index=0; going=0; pthread_join(buffer_thread,NULL); } void abuffer_flush(gint time) { flush=time; while(flush!=-1) usleep(10000); } void abuffer_pause(short p) { if(p==TRUE) do_pause=TRUE; else unpause=TRUE; } void *abuffer_loop(void *arg) { gint cnt; esd_format_t esdfmt; char *tempbuffer; esdfmt = ESD_PLAY; if (channels-1) esdfmt |= ESD_STEREO; else esdfmt |= ESD_MONO; if ((format==FMT_U8) || (format==FMT_S8)) esdfmt |= ESD_BITS8; else esdfmt |= ESD_BITS16; fd=esd_play_stream(esdfmt, frequency, "localhost", "x11amp - plugin"); if(fd==-1) { g_free(buffer); pthread_exit(NULL); } /* there is this pesky problem with esd... when I start playing a song a loud popping sound often occurs. This buffer of 0's seems to help. */ tempbuffer=g_malloc0(ESD_BUF_SIZE*4); memset(tempbuffer,0,ESD_BUF_SIZE*4); write(fd,tempbuffer,ESD_BUF_SIZE*4); g_free(tempbuffer); while(going) { /*printf("in loop\n");*/ if (abuffer_used()>0&&!paused) { if(!prebuffer) { length=min((1L<0) { cnt=min(length,buffer_size-rd_index); output_bytes+=write(fd,buffer+rd_index,cnt); rd_index=(rd_index+cnt)%buffer_size; length-=cnt; } } else if(abuffer_used()>prebuffer_size) prebuffer=FALSE; else{ usleep(10000); } } else { usleep(10000); /*printf("WARNING: Buffer underrun!\n");*/ } if(do_pause&&!paused) { do_pause=FALSE; paused=TRUE; } if(unpause&&paused) { unpause=FALSE; paused=FALSE; } if(flush!=-1) { output_time_offset=flush; written=(flush/10)*(bps/100); rd_index=wr_index=output_bytes=0; flush=-1; prebuffer=TRUE; } } esd_close(fd); g_free(buffer); pthread_exit(NULL); } void abuffer_set_audio_params(void) { /* nothing yet */ } int abuffer_open(AFormat fmt,gint rate,gint nch) { bps=rate*nch; if ((fmt==FMT_U16_LE) || (fmt==FMT_U16_BE) || (fmt==FMT_U16_NE) || (fmt==FMT_S16_LE) || (fmt==FMT_S16_BE) || (fmt==FMT_S16_NE)) { bps*=2; } format=fmt; frequency=rate; channels=nch; fragsize=0; while((1L<