summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorGravatar Alexey Yakovenko <wakeroid@gmail.com>2010-01-25 22:19:44 +0100
committerGravatar Alexey Yakovenko <wakeroid@gmail.com>2010-01-25 22:19:44 +0100
commit90877724d03c71111c2b47fd6ea6eb3ebce88dd4 (patch)
tree61313bbe6adb421ef865becb47c4db79bee24883 /plugins
parent0b39142b67849cb20dffcdac48b2886a33968fbb (diff)
multiple fixes in streamer, alsa and oss
Diffstat (limited to 'plugins')
-rw-r--r--plugins/alsa/alsa.c185
-rw-r--r--plugins/oss/oss.c9
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++) {