diff options
author | 2010-01-25 22:19:44 +0100 | |
---|---|---|
committer | 2010-01-25 22:19:44 +0100 | |
commit | 90877724d03c71111c2b47fd6ea6eb3ebce88dd4 (patch) | |
tree | 61313bbe6adb421ef865becb47c4db79bee24883 /plugins | |
parent | 0b39142b67849cb20dffcdac48b2886a33968fbb (diff) |
multiple fixes in streamer, alsa and oss
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/alsa/alsa.c | 185 | ||||
-rw-r--r-- | plugins/oss/oss.c | 9 |
2 files changed, 101 insertions, 93 deletions
diff --git a/plugins/alsa/alsa.c b/plugins/alsa/alsa.c index 11273220..157814ce 100644 --- a/plugins/alsa/alsa.c +++ b/plugins/alsa/alsa.c @@ -26,12 +26,11 @@ #define trace(...) { fprintf(stderr, __VA_ARGS__); } //#define trace(fmt,...) +#define min(x,y) ((x)<(y)?(x):(y)) + static DB_output_t plugin; DB_functions_t *deadbeef; -#define BUFFER_MIN 1024 -#define BUFFER_MAX 4096 - static snd_pcm_t *audio; //static int bufsize = -1; static int alsa_terminate; @@ -40,12 +39,37 @@ static int state; // one of output_state_t static uintptr_t mutex; static intptr_t alsa_tid; +static snd_pcm_uframes_t buffer_size; +static snd_pcm_uframes_t period_size; + static int conf_alsa_resample = 0; static char conf_alsa_soundcard[100] = "default"; +//static snd_async_handler_t *pcm_callback; + static void palsa_callback (char *stream, int len); +#if 0 +static void +alsa_callback (snd_async_handler_t *pcm_callback) { + snd_pcm_t *pcm_handle = snd_async_handler_get_pcm(pcm_callback); + snd_pcm_sframes_t avail; + int err; + printf ("alsa_callback\n"); + + avail = snd_pcm_avail_update(pcm_handle); + while (avail >= period_size) { + char buf[avail * 4]; + palsa_callback (buf, avail * 4); + if ((err = snd_pcm_writei (pcm_handle, buf, period_size)) < 0) { + perror ("snd_pcm_writei"); + } + avail = snd_pcm_avail_update(pcm_handle); + } +} +#endif + static void palsa_thread (void *context); @@ -151,13 +175,20 @@ palsa_set_hw_params (int samplerate) { snd_pcm_hw_params_get_channels (hw_params, &nchan); trace ("alsa channels: %d\n", nchan); - unsigned int buffer_time = 100000; - int dir; - if ((err = snd_pcm_hw_params_set_buffer_time_min (audio, hw_params, &buffer_time, &dir)) < 0) { - trace ("Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(err)); - goto error; - } - trace ("alsa buffer time: %d usec\n", buffer_time); + buffer_size = 1024; + period_size = 64; + snd_pcm_hw_params_set_buffer_size_near (audio, hw_params, &buffer_size); + snd_pcm_hw_params_set_period_size_near (audio, hw_params, &period_size, NULL); + trace ("alsa buffer size: %d frames\n", buffer_size); + trace ("alsa period size: %d frames\n", period_size); + +// unsigned int buffer_time = 100000; +// int dir; +// if ((err = snd_pcm_hw_params_set_buffer_time_min (audio, hw_params, &buffer_time, &dir)) < 0) { +// trace ("Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(err)); +// goto error; +// } +// trace ("alsa buffer time: %d usec\n", buffer_time); // snd_pcm_uframes_t size; // if ((err = snd_pcm_hw_params_get_buffer_size (hw_params, &size)) < 0) { // trace ("Unable to get buffer size for playback: %s\n", snd_strerror(err)); @@ -216,24 +247,29 @@ palsa_init (void) { goto open_error; } -// if ((err = snd_pcm_sw_params_set_avail_min (audio, sw_params, bufsize/2)) < 0) { -// trace ("cannot set minimum available count (%s)\n", -// snd_strerror (err)); -// goto open_error; -// } -// snd_pcm_uframes_t av; -// if ((err = snd_pcm_sw_params_get_avail_min (sw_params, &av)) < 0) { -// trace ("snd_pcm_sw_params_get_avail_min failed (%s)\n", -// snd_strerror (err)); -// goto open_error; -// } -// trace ("alsa period size: %d frames\n", (int)av); + snd_pcm_sw_params_set_start_threshold (audio, sw_params, buffer_size - period_size); - if ((err = snd_pcm_sw_params_set_start_threshold (audio, sw_params, 0U)) < 0) { - trace ("cannot set start mode (%s)\n", + if ((err = snd_pcm_sw_params_set_avail_min (audio, sw_params, period_size)) < 0) { + trace ("cannot set minimum available count (%s)\n", snd_strerror (err)); goto open_error; } + + snd_pcm_uframes_t av; + if ((err = snd_pcm_sw_params_get_avail_min (sw_params, &av)) < 0) { + trace ("snd_pcm_sw_params_get_avail_min failed (%s)\n", + snd_strerror (err)); + goto open_error; + } + trace ("alsa avail_min: %d frames\n", (int)av); + + +// if ((err = snd_pcm_sw_params_set_start_threshold (audio, sw_params, 0U)) < 0) { +// trace ("cannot set start mode (%s)\n", +// snd_strerror (err)); +// goto open_error; +// } + if ((err = snd_pcm_sw_params (audio, sw_params)) < 0) { trace ("cannot set software parameters (%s)\n", snd_strerror (err)); @@ -272,6 +308,7 @@ open_error: int palsa_change_rate (int rate) { + return 0; if (!audio) { return 0; } @@ -298,7 +335,10 @@ int palsa_free (void) { trace ("palsa_free\n"); if (audio && !alsa_terminate) { + palsa_stop (); + deadbeef->mutex_lock (mutex); alsa_terminate = 1; + deadbeef->mutex_unlock (mutex); printf ("waiting for alsa thread to finish\n"); if (alsa_tid) { deadbeef->thread_join (alsa_tid); @@ -336,6 +376,7 @@ palsa_hw_pause (int pause) { int palsa_play (void) { int err; + trace ("palsa_play\n"); if (state == OUTPUT_STATE_STOPPED) { if (!audio) { if (palsa_init () < 0) { @@ -345,6 +386,7 @@ palsa_play (void) { } else { if ((err = snd_pcm_prepare (audio)) < 0) { + perror ("snd_pcm_prepare"); trace ("cannot prepare audio interface for use (%s)\n", snd_strerror (err)); return -1; @@ -352,8 +394,15 @@ palsa_play (void) { } } if (state != OUTPUT_STATE_PLAYING) { - state = OUTPUT_STATE_PLAYING; + deadbeef->mutex_lock (mutex); +// trace ("alsa: installing async handler\n"); +// if (snd_async_add_pcm_handler (&pcm_callback, audio, alsa_callback, NULL) < 0) { +// perror ("snd_async_add_pcm_handler"); +// } +// trace ("pcm_callback=%p\n", pcm_callback); snd_pcm_start (audio); + deadbeef->mutex_unlock (mutex); + state = OUTPUT_STATE_PLAYING; } return 0; } @@ -371,6 +420,12 @@ palsa_stop (void) { else { deadbeef->mutex_lock (mutex); snd_pcm_drop (audio); +#if 0 + if (pcm_callback) { + snd_async_del_handler (pcm_callback); + pcm_callback = NULL; + } +#endif deadbeef->mutex_unlock (mutex); } deadbeef->streamer_reset (1); @@ -437,95 +492,51 @@ palsa_thread (void *context) { if (alsa_terminate) { break; } - if (state != OUTPUT_STATE_PLAYING) { + if (state != OUTPUT_STATE_PLAYING || !deadbeef->streamer_ok_to_read (-1)) { usleep (10000); continue; } deadbeef->mutex_lock (mutex); - /* wait till the interface is ready for data, or 1 second - has elapsed. - */ -#if 0 - if ((err = snd_pcm_wait (audio, 500)) < 0 && state == OUTPUT_STATE_PLAYING) { + if ((err = snd_pcm_wait (audio, 1000)) < 0) { + perror ("snd_pcm_wait"); if (err == -ESTRPIPE) { + perror ("snd_pcm_writei"); trace ("alsa: trying to recover from suspend...\n"); deadbeef->sendmessage (M_REINIT_SOUND, 0, 0, 0); deadbeef->mutex_unlock (mutex); break; } else { - trace ("alsa: trying to recover from xrun...\n"); + // this pretty frequent condition, no spam here + perror ("snd_pcm_wait"); +// trace ("alsa: trying to recover from xrun...\n"); snd_pcm_prepare (audio); + snd_pcm_start (audio); deadbeef->mutex_unlock (mutex); continue; } } - /* find out how much space is available for playback data */ - - snd_pcm_sframes_t frames_to_deliver; - if ((frames_to_deliver = snd_pcm_avail_update (audio)) < 0) { - if (frames_to_deliver == -EPIPE) { - deadbeef->mutex_unlock (mutex); - trace ("an xrun occured\n"); - continue; - } else { - deadbeef->mutex_unlock (mutex); - trace ("unknown ALSA avail update return value (%d)\n", - (int)frames_to_deliver); - continue; - } - } - - int nowait = 0; - if (frames_to_deliver < BUFFER_MIN) { - trace ("alsa: frames_to_deliver clipped from %d to %d\n", frames_to_deliver, BUFFER_MIN); - frames_to_deliver = BUFFER_MIN; - } - else if (frames_to_deliver > BUFFER_MAX) { - trace ("alsa: frames_to_deliver clipped from %d to %d\n", frames_to_deliver, BUFFER_MAX); - frames_to_deliver = BUFFER_MAX; - nowait = 1; - } -#endif - int frames_to_deliver = 2048; - char buf[frames_to_deliver*4]; - palsa_callback (buf, frames_to_deliver*4); - if ((err = snd_pcm_writei (audio, buf, frames_to_deliver)) < 0) { - //trace ("write %d frames failed (%s)\n", (int)frames_to_deliver, snd_strerror (err)); - perror ("snd_pcm_writei"); - if (err == -ESTRPIPE) { - trace ("alsa: trying to recover from suspend...\n"); - deadbeef->sendmessage (M_REINIT_SOUND, 0, 0, 0); - deadbeef->mutex_unlock (mutex); + int written = 0; + snd_pcm_sframes_t frames_to_deliver = snd_pcm_avail_update (audio); + while (frames_to_deliver >= period_size) { + char buf[period_size * 4]; + palsa_callback (buf, period_size * 4); + if ((err = snd_pcm_writei (audio, buf, period_size)) < 0) { break; } -// else if (frames_to_deliver == -EPIPE) { -// deadbeef->mutex_unlock (mutex); -// trace ("an xrun occured\n"); -// continue; -// } - else { - trace ("alsa: trying to recover from xrun...\n"); - snd_pcm_prepare (audio); - deadbeef->mutex_unlock (mutex); - continue; - } - snd_pcm_prepare (audio); - snd_pcm_start (audio); + written += period_size; + frames_to_deliver = snd_pcm_avail_update (audio); } +// trace ("wrote %d frames\n", written); deadbeef->mutex_unlock (mutex); - usleep (1000); // this must be here to prevent mutex deadlock +// usleep (1000); // this must be here to prevent mutex deadlock } } static void palsa_callback (char *stream, int len) { - if (!deadbeef->streamer_ok_to_read (len)) { - memset (stream, 0, len); - return; - } int bytesread = deadbeef->streamer_read (stream, len); // FIXME: move volume control to streamer_read for copy optimization diff --git a/plugins/oss/oss.c b/plugins/oss/oss.c index 06eb5a78..13fd8ec7 100644 --- a/plugins/oss/oss.c +++ b/plugins/oss/oss.c @@ -48,7 +48,7 @@ static int state; static int fd; static uintptr_t mutex; -#define BLOCKSIZE 4096 +#define BLOCKSIZE 8192 static void oss_thread (void *context); @@ -241,7 +241,7 @@ oss_thread (void *context) { if (oss_terminate) { break; } - if (state != OUTPUT_STATE_PLAYING) { + if (state != OUTPUT_STATE_PLAYING || !deadbeef->streamer_ok_to_read (-1)) { usleep (10000); continue; } @@ -252,6 +252,7 @@ oss_thread (void *context) { int res = write (fd, buf, sizeof (buf)); deadbeef->mutex_unlock (mutex); if (res != sizeof (buf)) { + perror ("oss write"); fprintf (stderr, "oss: failed to write buffer\n"); } usleep (1000); // this must be here to prevent mutex deadlock @@ -260,10 +261,6 @@ oss_thread (void *context) { static void oss_callback (char *stream, int len) { - if (!deadbeef->streamer_ok_to_read (len)) { - memset (stream, 0, len); - return; - } int bytesread = deadbeef->streamer_read (stream, len); int16_t ivolume = deadbeef->volume_get_amp () * 1000; for (int i = 0; i < bytesread/2; i++) { |