changeset 3696:418ac922ce87

Use a mutex/condvar/timed wait to allow tickless operation in the output loop. Add suggestions on how to improve produce_audio() API.
author William Pitcock <nenolod@atheme.org>
date Sat, 06 Oct 2007 20:35:52 -0500
parents cad078740bef
children cdc65ca04db4
files src/audacious/output.c src/audacious/playback.c src/audacious/plugin.h
diffstat 3 files changed, 42 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/src/audacious/output.c	Sat Oct 06 16:36:47 2007 -0500
+++ b/src/audacious/output.c	Sat Oct 06 20:35:52 2007 -0500
@@ -412,17 +412,19 @@
 
 /* called by input plugin when data is ready */
 void
-produce_audio(gint time,        /* position             */
-              AFormat fmt,      /* output format        */
-              gint nch,         /* channels             */
-              gint length,      /* length of sample     */
-              gpointer ptr,     /* data                 */
-              int *going        /* 0 when time to stop  */
+produce_audio(gint unused,	 /* will become InputPlayback soon */
+              AFormat fmt,       /* output format        */
+              gint nch,          /* channels             */
+              gint length,       /* length of sample     */
+              gpointer ptr,      /* data                 */
+              int *going         /* 0 when time to stop  */
               )
 {
     static Flow *postproc_flow = NULL;
-    OutputPlugin *op = get_current_output_plugin();
-    int writeoffs;
+    InputPlayback *playback = get_current_input_playback();
+    OutputPlugin *op = playback->output;
+    gint writeoffs;
+    gint time = playback->output->written_time();
 
     if (postproc_flow == NULL)
     {
@@ -486,6 +488,11 @@
 
         while (op->buffer_free() < writable)   /* wait output buf */
         {
+            GTimeVal pb_abs_time;
+
+            g_get_current_time(&pb_abs_time);
+            g_time_val_add(&pb_abs_time, (cfg.output_buffer_size / 2) * 1000);
+
             if (going && !*going)              /* thread stopped? */
                 return;                        /* so finish */
 
@@ -493,7 +500,9 @@
                 return;                        /* yes, so finish */
 
             /* else sleep for retry */
-            g_usleep((cfg.output_buffer_size / 2) * 1000);
+            g_mutex_lock(playback->pb_change_mutex);
+            g_cond_timed_wait(playback->pb_change_cond, playback->pb_change_mutex, &pb_abs_time);
+            g_mutex_unlock(playback->pb_change_mutex);
         }
 
         if (ip_data.stop)
--- a/src/audacious/playback.c	Sat Oct 06 16:36:47 2007 -0500
+++ b/src/audacious/playback.c	Sat Oct 06 20:35:52 2007 -0500
@@ -94,6 +94,14 @@
     return 0;
 }
 
+static void
+playback_set_pb_change(InputPlayback *playback)
+{
+    g_mutex_lock(playback->pb_change_mutex);
+    g_cond_signal(playback->pb_change_cond);
+    g_mutex_unlock(playback->pb_change_mutex);
+}
+
 void
 playback_eof(void)
 {
@@ -245,6 +253,11 @@
 
         ip_data.playing = FALSE;
 
+        /* TODO: i'm unsure if this will work. we might have to
+           signal the change in stop() (e.g. in the plugins
+           directly.) --nenolod */
+        playback->set_pb_change(playback);
+
         if (playback->plugin->stop)
             playback->plugin->stop(playback);
 
@@ -368,7 +381,13 @@
     playback->pb_ready_mutex = g_mutex_new();
     playback->pb_ready_cond = g_cond_new();
     playback->pb_ready_val = 0;
+
+    playback->pb_change_mutex = g_mutex_new();
+    playback->pb_change_cond = g_cond_new();
+
+    /* init vtable functors */
     playback->set_pb_ready = playback_set_pb_ready;
+    playback->set_pb_change = playback_set_pb_change;
     
     set_current_input_playback(playback);
 
@@ -415,6 +434,7 @@
     }
     
     playback->plugin->seek(playback, time);
+    playback->set_pb_change(playback);
     free_vis_data();
     
     if (restore_pause)
--- a/src/audacious/plugin.h	Sat Oct 06 16:36:47 2007 -0500
+++ b/src/audacious/plugin.h	Sat Oct 06 20:35:52 2007 -0500
@@ -382,6 +382,10 @@
     GCond *pb_ready_cond;
     gint pb_ready_val;    
     gint (*set_pb_ready) (InputPlayback*);
+
+    GMutex *pb_change_mutex;
+    GCond *pb_change_cond;
+    void (*set_pb_change)(InputPlayback *self);
 };
 
 struct _InputPlugin {