jack: when stopping playback, do one more cycle to flush the port. Fixes #582167
authorStefan Kost <ensonic@users.sf.net>
Mon, 11 May 2009 13:12:54 +0000 (16:12 +0300)
committerStefan Kost <ensonic@users.sf.net>
Thu, 28 May 2009 07:15:50 +0000 (10:15 +0300)
The gst_jack_audio_client_set_active() flags the port as deactivating and uses
a GCond to wait until the jack_process_cb() has run once more and cleared the
flag. This way the client zero's the buffer. This happens if one manyally go
to PAUSED and then to READY, while leting the mainloop run inbetween.

ext/jack/gstjackaudioclient.c
ext/jack/gstjackaudiosink.c

index 1aa1baf8a745b68e41018e4f482e4f1eec55ad5c..60e413819da1c08fa18eaedc7fe54071c7e091cc 100644 (file)
@@ -42,6 +42,7 @@ typedef struct
 {
   gint refcount;
   GMutex *lock;
+  GCond *flush_cond;
 
   /* id/server pair and the connection */
   gchar *id;
@@ -61,6 +62,7 @@ struct _GstJackAudioClient
 
   GstJackClientType type;
   gboolean active;
+  gboolean deactivate;
 
   void (*shutdown) (void *arg);
   JackProcessCallback process;
@@ -92,15 +94,25 @@ jack_process_cb (jack_nframes_t nframes, void *arg)
     GstJackAudioClient *client = (GstJackAudioClient *) walk->data;
 
     /* only call active clients */
-    if (client->active && client->process)
+    if ((client->active || client->deactivate) && client->process) {
       res = client->process (nframes, client->user_data);
+      if (client->deactivate) {
+        client->deactivate = FALSE;
+        g_cond_signal (conn->flush_cond);
+      }
+    }
   }
   for (walk = conn->sink_clients; walk; walk = g_list_next (walk)) {
     GstJackAudioClient *client = (GstJackAudioClient *) walk->data;
 
     /* only call active clients */
-    if (client->active && client->process)
+    if ((client->active || client->deactivate) && client->process) {
       res = client->process (nframes, client->user_data);
+      if (client->deactivate) {
+        client->deactivate = FALSE;
+        g_cond_signal (conn->flush_cond);
+      }
+    }
   }
   g_mutex_unlock (conn->lock);
 
@@ -203,6 +215,7 @@ gst_jack_audio_make_connection (const gchar * id, const gchar * server,
   conn = g_new (GstJackAudioConnection, 1);
   conn->refcount = 1;
   conn->lock = g_mutex_new ();
+  conn->flush_cond = g_cond_new ();
   conn->id = g_strdup (id);
   conn->server = g_strdup (server);
   conn->client = jclient;
@@ -325,6 +338,7 @@ gst_jack_audio_unref_connection (GstJackAudioConnection * conn)
 
     /* free resources */
     g_mutex_free (conn->lock);
+    g_cond_free (conn->flush_cond);
     g_free (conn->id);
     g_free (conn->server);
     g_free (conn);
@@ -409,9 +423,11 @@ gst_jack_audio_client_new (const gchar * id, const gchar * server,
   if (conn == NULL)
     goto no_connection;
 
+  GST_INFO ("new client %s", id);
+
   /* make new client using the connection */
   client = g_new (GstJackAudioClient, 1);
-  client->active = FALSE;
+  client->active = client->deactivate = FALSE;
   client->conn = conn;
   client->type = type;
   client->shutdown = shutdown;
@@ -446,6 +462,8 @@ gst_jack_audio_client_free (GstJackAudioClient * client)
 
   g_return_if_fail (client != NULL);
 
+  GST_INFO ("free client");
+
   conn = client->conn;
 
   /* remove from connection first so that it's not scheduled anymore after this
@@ -492,6 +510,14 @@ gst_jack_audio_client_set_active (GstJackAudioClient * client, gboolean active)
 
   /* make sure that we are not dispatching the client */
   g_mutex_lock (client->conn->lock);
+  if (client->active && !active) {
+    /* we need to process once more to flush the port */
+    client->deactivate = TRUE;
+
+    /* need to wait for process_cb run once more */
+    while (client->deactivate)
+      g_cond_wait (client->conn->flush_cond, client->conn->lock);
+  }
   client->active = active;
   g_mutex_unlock (client->conn->lock);
 
index 01383cbbf7697baaa8ab2dc5b7645fe5697ce396..58a699d0c657b8aa77c7eef589219727b330a172 100644 (file)
@@ -213,8 +213,8 @@ jack_process_cb (jack_nframes_t nframes, void *arg)
     if (nframes * sizeof (sample_t) != flen)
       goto wrong_size;
 
-    GST_DEBUG ("copy %d frames: %p, %d bytes, %d channels", nframes, readptr,
-        flen, channels);
+    GST_DEBUG_OBJECT (sink, "copy %d frames: %p, %d bytes, %d channels",
+        nframes, readptr, flen, channels);
     data = (sample_t *) readptr;
 
     /* the samples in the ringbuffer have the channels interleaved, we need to
@@ -231,6 +231,7 @@ jack_process_cb (jack_nframes_t nframes, void *arg)
     /* we wrote one segment */
     gst_ring_buffer_advance (buf, 1);
   } else {
+    GST_DEBUG_OBJECT (sink, "write %d frames silence", nframes);
     /* We are not allowed to read from the ringbuffer, write silence to all
      * jack output buffers */
     for (i = 0; i < channels; i++) {
@@ -607,7 +608,7 @@ gst_jack_ring_buffer_delay (GstRingBuffer * buf)
       res = latency;
   }
 
-  GST_DEBUG_OBJECT (sink, "delay %u", res);
+  GST_LOG_OBJECT (sink, "delay %u", res);
 
   return res;
 }