static void
jack_shutdown_cb (void *arg)
{
  GstJackAudioConnection *conn = (GstJackAudioConnection *) arg;
  GList *walk;

  GST_DEBUG ("disconnect client %s from server %s", conn->id,
      GST_STR_NULL (conn->server));

  g_mutex_lock (&conn->lock);
  for (walk = conn->src_clients; walk; walk = g_list_next (walk)) {
    GstJackAudioClient *client = (GstJackAudioClient *) walk->data;

    client->server_down = TRUE;
    g_cond_signal (&conn->flush_cond);
    if (client->shutdown)
      client->shutdown (client->user_data);
  }
  for (walk = conn->sink_clients; walk; walk = g_list_next (walk)) {
    GstJackAudioClient *client = (GstJackAudioClient *) walk->data;

    client->server_down = TRUE;
    g_cond_signal (&conn->flush_cond);
    if (client->shutdown)
      client->shutdown (client->user_data);
  }
  g_mutex_unlock (&conn->lock);
}
static int
jack_process_cb (jack_nframes_t nframes, void *arg)
{
  GstJackAudioConnection *conn = (GstJackAudioConnection *) arg;
  GList *walk;
  int res = 0;

  g_mutex_lock (conn->lock);
  /* call sources first, then sinks. Sources will either push data into the
   * ringbuffer of the sinks, which will then pull the data out of it, or
   * sinks will pull the data from the sources. */
  for (walk = conn->src_clients; walk; walk = g_list_next (walk)) {
    GstJackAudioClient *client = (GstJackAudioClient *) walk->data;

    /* only call active clients */
    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->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);

  return res;
}
static int
jack_process_cb (jack_nframes_t nframes, void *arg)
{
  GstJackAudioConnection *conn = (GstJackAudioConnection *) arg;
  GList *walk;
  int res = 0;
  jack_transport_state_t ts = jack_transport_query (conn->client, NULL);

  if (ts != conn->cur_ts) {
    conn->cur_ts = ts;
    switch (ts) {
      case JackTransportStopped:
        GST_DEBUG ("transport state is 'stopped'");
        conn->transport_state = GST_STATE_PAUSED;
        break;
      case JackTransportStarting:
        GST_DEBUG ("transport state is 'starting'");
        conn->transport_state = GST_STATE_READY;
        break;
      case JackTransportRolling:
        GST_DEBUG ("transport state is 'rolling'");
        conn->transport_state = GST_STATE_PLAYING;
        break;
      default:
        break;
    }
    GST_DEBUG ("num of clients: src=%d, sink=%d",
        g_list_length (conn->src_clients), g_list_length (conn->sink_clients));
  }

  g_mutex_lock (&conn->lock);
  /* call sources first, then sinks. Sources will either push data into the
   * ringbuffer of the sinks, which will then pull the data out of it, or
   * sinks will pull the data from the sources. */
  for (walk = conn->src_clients; walk; walk = g_list_next (walk)) {
    GstJackAudioClient *client = (GstJackAudioClient *) walk->data;

    /* only call active clients */
    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->deactivate) && client->process) {
      res = client->process (nframes, client->user_data);
      if (client->deactivate) {
        client->deactivate = FALSE;
        g_cond_signal (&conn->flush_cond);
      }
    }
  }

  /* handle transport state requisition, do sinks first, stop after the first
   * element that handled it */
  if (conn->transport_state != GST_STATE_VOID_PENDING) {
    for (walk = conn->sink_clients; walk; walk = g_list_next (walk)) {
      if (jack_handle_transport_change ((GstJackAudioClient *) walk->data,
              conn->transport_state)) {
        conn->transport_state = GST_STATE_VOID_PENDING;
        break;
      }
    }
  }
  if (conn->transport_state != GST_STATE_VOID_PENDING) {
    for (walk = conn->src_clients; walk; walk = g_list_next (walk)) {
      if (jack_handle_transport_change ((GstJackAudioClient *) walk->data,
              conn->transport_state)) {
        conn->transport_state = GST_STATE_VOID_PENDING;
        break;
      }
    }
  }
  g_mutex_unlock (&conn->lock);

  return res;
}