+2007-03-08 Wim Taymans <wim@fluendo.com>
+
+ Includes patch by: Paul Davis <paul at linuxaudiosystems dot com>
+
+ * ext/jack/Makefile.am:
+ * ext/jack/gstjackaudioclient.c: (gst_jack_audio_client_init),
+ (jack_process_cb), (jack_sample_rate_cb), (jack_buffer_size_cb),
+ (jack_shutdown_cb), (connection_find),
+ (gst_jack_audio_make_connection), (gst_jack_audio_get_connection),
+ (gst_jack_audio_unref_connection),
+ (gst_jack_audio_connection_add_client),
+ (gst_jack_audio_connection_remove_client),
+ (gst_jack_audio_client_new), (gst_jack_audio_client_free),
+ (gst_jack_audio_client_get_client),
+ (gst_jack_audio_client_set_active):
+ * ext/jack/gstjackaudioclient.h:
+ Make an object to manage client connections to the jack server which we
+ will use in the future to run selected jack elements with the same jack
+ connection.
+ Make some stuff a bit more threadsafe.
+ Activate the jack client ASAP.
+
+ * ext/jack/gstjackaudiosink.c:
+ (gst_jack_audio_sink_allocate_channels),
+ (gst_jack_audio_sink_free_channels), (jack_process_cb),
+ (gst_jack_ring_buffer_open_device),
+ (gst_jack_ring_buffer_close_device),
+ (gst_jack_ring_buffer_acquire), (gst_jack_ring_buffer_release),
+ (gst_jack_audio_sink_class_init), (gst_jack_audio_sink_init),
+ (gst_jack_audio_sink_getcaps):
+ * ext/jack/gstjackaudiosink.h:
+ Use new client object to manage connections.
+ Don't remove and recreate all ports, try to reuse them.
+
2007-03-07 Sebastian Dröge <slomo@circular-chaos.org>
* ext/wavpack/gstwavpack.c: (plugin_init):
-Subproject commit c4f56a657d79aee0e3fc25ef2bcf876f9f3c1593
+Subproject commit 7c5a0ab68de1fed4e5a1fd473160debc2c4c7b89
plugin_LTLIBRARIES = libgstjack.la
-libgstjack_la_SOURCES = gstjack.c gstjackaudiosink.c
+libgstjack_la_SOURCES = gstjack.c gstjackaudiosink.c gstjackaudioclient.c
libgstjack_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(JACK_CFLAGS)
libgstjack_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) $(JACK_LIBS)
libgstjack_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-noinst_HEADERS = gstjackaudiosink.h
+noinst_HEADERS = gstjackaudiosink.h gstjackaudioclient.h
EXTRA_DIST = README
--- /dev/null
+/* GStreamer
+ * Copyright (C) 2006 Wim Taymans <wim@fluendo.com>
+ *
+ * gstjackaudioclient.c: jack audio client implementation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+
+#include "gstjackaudioclient.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_jack_audio_client_debug);
+#define GST_CAT_DEFAULT gst_jack_audio_client_debug
+
+void
+gst_jack_audio_client_init (void)
+{
+ GST_DEBUG_CATEGORY_INIT (gst_jack_audio_client_debug, "jackclient", 0,
+ "jackclient helpers");
+}
+
+/* a list of global connections indexed by id and server. */
+G_LOCK_DEFINE_STATIC (connections_lock);
+static GList *connections;
+
+/* the connection to a server */
+typedef struct
+{
+ gint refcount;
+ GMutex *lock;
+
+ /* id/server pair and the connection */
+ gchar *id;
+ gchar *server;
+ jack_client_t *client;
+
+ /* lists of GstJackAudioClients */
+ gint n_clients;
+ GList *src_clients;
+ GList *sink_clients;
+} GstJackAudioConnection;
+
+/* an object sharing a jack_client_t connection. */
+struct _GstJackAudioClient
+{
+ GstJackAudioConnection *conn;
+
+ GstJackClientType type;
+ gboolean active;
+
+ void (*shutdown) (void *arg);
+ JackProcessCallback process;
+ JackBufferSizeCallback buffer_size;
+ JackSampleRateCallback sample_rate;
+ gpointer user_data;
+};
+
+typedef jack_default_audio_sample_t sample_t;
+
+typedef struct
+{
+ jack_nframes_t nframes;
+ gpointer user_data;
+} JackCB;
+
+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->process)
+ res = client->process (nframes, client->user_data);
+ }
+ 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)
+ res = client->process (nframes, client->user_data);
+ }
+ g_mutex_unlock (conn->lock);
+
+ return res;
+}
+
+/* we error out */
+static int
+jack_sample_rate_cb (jack_nframes_t nframes, void *arg)
+{
+ return 0;
+}
+
+/* we error out */
+static int
+jack_buffer_size_cb (jack_nframes_t nframes, void *arg)
+{
+ return 0;
+}
+
+static void
+jack_shutdown_cb (void *arg)
+{
+ GstJackAudioConnection *conn = (GstJackAudioConnection *) arg;
+ GList *walk;
+
+ g_mutex_lock (conn->lock);
+ for (walk = conn->src_clients; walk; walk = g_list_next (walk)) {
+ GstJackAudioClient *client = (GstJackAudioClient *) walk->data;
+
+ if (client->shutdown)
+ client->shutdown (client->user_data);
+ }
+ for (walk = conn->sink_clients; walk; walk = g_list_next (walk)) {
+ GstJackAudioClient *client = (GstJackAudioClient *) walk->data;
+
+ if (client->shutdown)
+ client->shutdown (client->user_data);
+ }
+ g_mutex_unlock (conn->lock);
+}
+
+typedef struct
+{
+ const gchar *id;
+ const gchar *server;
+} FindData;
+
+static gint
+connection_find (GstJackAudioConnection * conn, FindData * data)
+{
+ /* id's must match */
+ if (strcmp (conn->id, data->id))
+ return 1;
+
+ /* both the same or NULL */
+ if (conn->server == data->server)
+ return 0;
+
+ /* we cannot compare NULL */
+ if (conn->server == NULL || data->server == NULL)
+ return 1;
+
+ if (strcmp (conn->server, data->server))
+ return 1;
+
+ return 0;
+}
+
+/* make a connection with @id and @server. Returns NULL on failure with the
+ * status set. */
+static GstJackAudioConnection *
+gst_jack_audio_make_connection (const gchar * id, const gchar * server,
+ jack_status_t * status)
+{
+ GstJackAudioConnection *conn;
+ jack_options_t options;
+ jack_client_t *jclient;
+ gint res;
+
+ *status = 0;
+
+ GST_DEBUG ("new client %s, connecting to server %s", id,
+ GST_STR_NULL (server));
+
+ /* never start a server */
+ options = JackNoStartServer;
+ /* if we have a servername, use it */
+ if (server != NULL)
+ options |= JackServerName;
+ /* open the client */
+ jclient = jack_client_open (id, options, status, server);
+ if (jclient == NULL)
+ goto could_not_open;
+
+ /* now create object */
+ conn = g_new (GstJackAudioConnection, 1);
+ conn->refcount = 1;
+ conn->lock = g_mutex_new ();
+ conn->id = g_strdup (id);
+ conn->server = g_strdup (server);
+ conn->client = jclient;
+ conn->n_clients = 0;
+ conn->src_clients = NULL;
+ conn->sink_clients = NULL;
+
+ /* set our callbacks */
+ jack_set_process_callback (jclient, jack_process_cb, conn);
+ /* these callbacks cause us to error */
+ jack_set_buffer_size_callback (jclient, jack_buffer_size_cb, conn);
+ jack_set_sample_rate_callback (jclient, jack_sample_rate_cb, conn);
+ jack_on_shutdown (jclient, jack_shutdown_cb, conn);
+
+ /* all callbacks are set, activate the client */
+ if ((res = jack_activate (jclient)))
+ goto could_not_activate;
+
+ GST_DEBUG ("opened connection %p", conn);
+
+ return conn;
+
+ /* ERRORS */
+could_not_open:
+ {
+ GST_DEBUG ("failed to open jack client, %d", *status);
+ return NULL;
+ }
+could_not_activate:
+ {
+ GST_ERROR ("Could not activate client (%d)", res);
+ *status = JackFailure;
+ g_mutex_free (conn->lock);
+ g_free (conn->id);
+ g_free (conn->server);
+ g_free (conn);
+ return NULL;
+ }
+}
+
+static GstJackAudioConnection *
+gst_jack_audio_get_connection (const gchar * id, const gchar * server,
+ jack_status_t * status)
+{
+ GstJackAudioConnection *conn;
+ GList *found;
+ FindData data;
+
+ GST_DEBUG ("getting connection for id %s, server %s", id,
+ GST_STR_NULL (server));
+
+ data.id = id;
+ data.server = server;
+
+ G_LOCK (connections_lock);
+ found =
+ g_list_find_custom (connections, &data, (GCompareFunc) connection_find);
+ if (found != NULL) {
+ /* we found it, increase refcount and return it */
+ conn = (GstJackAudioConnection *) found->data;
+ conn->refcount++;
+
+ GST_DEBUG ("found connection %p", conn);
+ } else {
+ /* make new connection */
+ conn = gst_jack_audio_make_connection (id, server, status);
+ if (conn != NULL) {
+ GST_DEBUG ("created connection %p", conn);
+ /* add to list on success */
+ connections = g_list_prepend (connections, conn);
+ } else {
+ GST_WARNING ("could not create connection");
+ }
+ }
+ G_UNLOCK (connections_lock);
+
+ return conn;
+}
+
+static void
+gst_jack_audio_unref_connection (GstJackAudioConnection * conn)
+{
+ gint res;
+
+ GST_DEBUG ("unref connection %p", conn);
+
+ G_LOCK (connections_lock);
+ conn->refcount--;
+ if (conn->refcount == 0) {
+ GST_DEBUG ("closing connection %p", conn);
+ /* remove from list */
+ connections = g_list_remove (connections, conn);
+
+ /* grab lock to be sure that we are not in one of the callbacks */
+ g_mutex_lock (conn->lock);
+ if ((res = jack_deactivate (conn->client))) {
+ /* we only warn, this means the server is probably shut down and the client
+ * is gone anyway. */
+ GST_WARNING ("Could not deactivate Jack client (%d)", res);
+ }
+ /* close connection */
+ if ((res = jack_client_close (conn->client))) {
+ /* we assume the client is gone. */
+ GST_WARNING ("close failed (%d)", res);
+ }
+ g_mutex_unlock (conn->lock);
+
+ /* free resources */
+ g_mutex_free (conn->lock);
+ g_free (conn->id);
+ g_free (conn->server);
+ g_free (conn);
+ }
+ G_UNLOCK (connections_lock);
+}
+
+static void
+gst_jack_audio_connection_add_client (GstJackAudioConnection * conn,
+ GstJackAudioClient * client)
+{
+ g_mutex_lock (conn->lock);
+ switch (client->type) {
+ case GST_JACK_CLIENT_SOURCE:
+ conn->src_clients = g_list_append (conn->src_clients, client);
+ conn->n_clients++;
+ break;
+ case GST_JACK_CLIENT_SINK:
+ conn->sink_clients = g_list_append (conn->sink_clients, client);
+ conn->n_clients++;
+ break;
+ default:
+ g_warning ("trying to add unknown client type");
+ break;
+ }
+ g_mutex_unlock (conn->lock);
+}
+
+static void
+gst_jack_audio_connection_remove_client (GstJackAudioConnection * conn,
+ GstJackAudioClient * client)
+{
+ g_mutex_lock (conn->lock);
+ switch (client->type) {
+ case GST_JACK_CLIENT_SOURCE:
+ conn->src_clients = g_list_remove (conn->src_clients, client);
+ conn->n_clients--;
+ break;
+ case GST_JACK_CLIENT_SINK:
+ conn->sink_clients = g_list_remove (conn->sink_clients, client);
+ conn->n_clients--;
+ break;
+ default:
+ g_warning ("trying to remove unknown client type");
+ break;
+ }
+ g_mutex_unlock (conn->lock);
+}
+
+/**
+ * gst_jack_audio_client_get:
+ * @id: the client id
+ * @server: the server to connect to or NULL for the default server
+ * @type: the client type
+ * @shutdown: a callback when the jack server shuts down
+ * @process: a callback when samples are available
+ * @buffer_size: a callback when the buffer_size changes
+ * @sample_rate: a callback when the sample_rate changes
+ * @user_data: user data passed to the callbacks
+ * @status: pointer to hold the jack status code in case of errors
+ *
+ * Get the jack client connection for @id and @server. Connections to the same
+ * @id and @server will receive the same physical Jack client connection and
+ * will therefore be scheduled in the same process callback.
+ *
+ * Returns: a #GstJackAudioClient.
+ */
+GstJackAudioClient *
+gst_jack_audio_client_new (const gchar * id, const gchar * server,
+ GstJackClientType type, void (*shutdown) (void *arg),
+ JackProcessCallback process, JackBufferSizeCallback buffer_size,
+ JackSampleRateCallback sample_rate, gpointer user_data,
+ jack_status_t * status)
+{
+ GstJackAudioClient *client;
+ GstJackAudioConnection *conn;
+
+ g_return_val_if_fail (id != NULL, NULL);
+ g_return_val_if_fail (status != NULL, NULL);
+
+ /* first get a connection for the id/server pair */
+ conn = gst_jack_audio_get_connection (id, server, status);
+ if (conn == NULL)
+ goto no_connection;
+
+ /* make new client using the connection */
+ client = g_new (GstJackAudioClient, 1);
+ client->active = FALSE;
+ client->conn = conn;
+ client->type = type;
+ client->shutdown = shutdown;
+ client->process = process;
+ client->buffer_size = buffer_size;
+ client->sample_rate = sample_rate;
+ client->user_data = user_data;
+
+ /* add the client to the connection */
+ gst_jack_audio_connection_add_client (conn, client);
+
+ return client;
+
+ /* ERRORS */
+no_connection:
+ {
+ GST_DEBUG ("Could not get server connection (%d)", *status);
+ return NULL;
+ }
+}
+
+/**
+ * gst_jack_audio_client_free:
+ * @client: a #GstJackAudioClient
+ *
+ * Free the resources used by @client.
+ */
+void
+gst_jack_audio_client_free (GstJackAudioClient * client)
+{
+ GstJackAudioConnection *conn;
+
+ g_return_if_fail (client != NULL);
+
+ conn = client->conn;
+
+ /* remove from connection first so that it's not scheduled anymore after this
+ * call */
+ gst_jack_audio_connection_remove_client (conn, client);
+ gst_jack_audio_unref_connection (conn);
+
+ g_free (client);
+}
+
+/**
+ * gst_jack_audio_client_get_client:
+ * @client: a #GstJackAudioClient
+ *
+ * Get the jack audio client for @client. This function is used to perform
+ * operations on the jack server from this client.
+ *
+ * Returns: The jack audio client.
+ */
+jack_client_t *
+gst_jack_audio_client_get_client (GstJackAudioClient * client)
+{
+ g_return_val_if_fail (client != NULL, NULL);
+
+ /* no lock needed, the connection and the client does not change
+ * once the client is created. */
+ return client->conn->client;
+}
+
+/**
+ * gst_jack_audio_client_set_active:
+ * @client: a #GstJackAudioClient
+ * @active: new mode for the client
+ *
+ * Activate or deactive @client. When a client is activated it will receive
+ * callbacks when data should be processed.
+ *
+ * Returns: 0 if all ok.
+ */
+gint
+gst_jack_audio_client_set_active (GstJackAudioClient * client, gboolean active)
+{
+ g_return_val_if_fail (client != NULL, -1);
+
+ /* make sure that we are not dispatching the client */
+ g_mutex_lock (client->conn->lock);
+ client->active = active;
+ g_mutex_unlock (client->conn->lock);
+
+ return 0;
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) 2006 Wim Taymans <wim@fluendo.com>
+ *
+ * gstjackaudioclient.h:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_JACK_AUDIO_CLIENT_H__
+#define __GST_JACK_AUDIO_CLIENT_H__
+
+#include <jack/jack.h>
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+ GST_JACK_CLIENT_SOURCE,
+ GST_JACK_CLIENT_SINK
+} GstJackClientType;
+
+typedef struct _GstJackAudioClient GstJackAudioClient;
+
+void gst_jack_audio_client_init (void);
+
+
+GstJackAudioClient * gst_jack_audio_client_new (const gchar *id, const gchar *server,
+ GstJackClientType type,
+ void (*shutdown) (void *arg),
+ JackProcessCallback process,
+ JackBufferSizeCallback buffer_size,
+ JackSampleRateCallback sample_rate,
+ gpointer user_data,
+ jack_status_t *status);
+void gst_jack_audio_client_free (GstJackAudioClient *client);
+
+jack_client_t * gst_jack_audio_client_get_client (GstJackAudioClient *client);
+
+gboolean gst_jack_audio_client_set_active (GstJackAudioClient *client, gboolean active);
+
+G_END_DECLS
+
+#endif /* __GST_JACK_AUDIO_CLIENT_H__ */
gint sample_rate;
gint buffer_size;
gint channels;
-
- jack_port_t **outport;
};
struct _GstJackRingBufferClass
static gboolean gst_jack_ring_buffer_stop (GstRingBuffer * buf);
static guint gst_jack_ring_buffer_delay (GstRingBuffer * buf);
+static gboolean
+gst_jack_audio_sink_allocate_channels (GstJackAudioSink * sink, gint channels)
+{
+ jack_client_t *client;
+
+ client = gst_jack_audio_client_get_client (sink->client);
+
+ /* remove ports we don't need */
+ while (sink->port_count > channels) {
+ jack_port_unregister (client, sink->ports[--sink->port_count]);
+ }
+
+ /* alloc enough output ports */
+ sink->ports = g_realloc (sink->ports, sizeof (jack_port_t *) * channels);
+
+ /* create an output port for each channel */
+ while (sink->port_count < channels) {
+ gchar *name;
+
+ /* port names start from 1 */
+ name = g_strdup_printf ("out_%d", sink->port_count + 1);
+ sink->ports[sink->port_count] =
+ jack_port_register (client, name,
+ JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
+ if (sink->ports[sink->port_count] == NULL)
+ return FALSE;
+
+ sink->port_count++;
+
+ g_free (name);
+ }
+ return TRUE;
+}
+
+static void
+gst_jack_audio_sink_free_channels (GstJackAudioSink * sink)
+{
+ gint res, i = 0;
+ jack_client_t *client;
+
+ client = gst_jack_audio_client_get_client (sink->client);
+
+ /* get rid of all ports */
+ while (sink->port_count) {
+ GST_LOG_OBJECT (sink, "unregister port %d", i);
+ if ((res = jack_port_unregister (client, sink->ports[i++]))) {
+ GST_DEBUG_OBJECT (sink, "unregister of port failed (%d)", res);
+ }
+ sink->port_count--;
+ }
+ g_free (sink->ports);
+ sink->ports = NULL;
+}
+
/* ringbuffer abstract base class */
static GType
gst_jack_ring_buffer_get_type (void)
/* get target buffers */
for (i = 0; i < channels; i++) {
- buffers[i] = (sample_t *) jack_port_get_buffer (abuf->outport[i], nframes);
+ buffers[i] = (sample_t *) jack_port_get_buffer (sink->ports[i], nframes);
}
if (gst_ring_buffer_prepare_read (buf, &readseg, &readptr, &len)) {
gst_jack_ring_buffer_open_device (GstRingBuffer * buf)
{
GstJackAudioSink *sink;
- jack_options_t options;
jack_status_t status = 0;
sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
GST_DEBUG_OBJECT (sink, "open");
- /* never start a server */
- options = JackNoStartServer;
- /* if we have a servername, use it */
- if (sink->server != NULL)
- options |= JackServerName;
- /* open the client */
- sink->client = jack_client_open ("GStreamer", options, &status, sink->server);
+ sink->client = gst_jack_audio_client_new ("GStreamer", sink->server,
+ GST_JACK_CLIENT_SINK,
+ jack_shutdown_cb,
+ jack_process_cb, jack_buffer_size_cb, jack_sample_rate_cb, buf, &status);
if (sink->client == NULL)
goto could_not_open;
- /* set our callbacks */
- jack_set_process_callback (sink->client, jack_process_cb, buf);
- /* these callbacks cause us to error */
- jack_set_buffer_size_callback (sink->client, jack_buffer_size_cb, buf);
- jack_set_sample_rate_callback (sink->client, jack_sample_rate_cb, buf);
- jack_on_shutdown (sink->client, jack_shutdown_cb, buf);
-
GST_DEBUG_OBJECT (sink, "opened");
return TRUE;
gst_jack_ring_buffer_close_device (GstRingBuffer * buf)
{
GstJackAudioSink *sink;
- gint res;
sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
GST_DEBUG_OBJECT (sink, "close");
- if ((res = jack_client_close (sink->client))) {
- /* just a warning, we assume the client is gone. */
- GST_ELEMENT_WARNING (sink, RESOURCE, CLOSE,
- (NULL), ("Jack client close error (%d)", res));
- }
+ gst_jack_audio_sink_free_channels (sink);
+ gst_jack_audio_client_free (sink->client);
sink->client = NULL;
return TRUE;
const char **ports;
gint sample_rate, buffer_size;
gint i, channels, res;
+ jack_client_t *client;
sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
abuf = GST_JACK_RING_BUFFER_CAST (buf);
GST_DEBUG_OBJECT (sink, "acquire");
+ client = gst_jack_audio_client_get_client (sink->client);
+
/* sample rate must be that of the server */
- sample_rate = jack_get_sample_rate (sink->client);
+ sample_rate = jack_get_sample_rate (client);
if (sample_rate != spec->rate)
goto wrong_samplerate;
channels = spec->channels;
- /* alloc enough output ports */
- abuf->outport = g_new (jack_port_t *, channels);
-
- /* create an output port for each channel */
- for (i = 0; i < channels; i++) {
- gchar *name;
-
- /* port names start from 1 */
- name = g_strdup_printf ("out_%d", i + 1);
- abuf->outport[i] = jack_port_register (sink->client, name,
- JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
- if (abuf->outport[i] == NULL)
- goto out_of_ports;
+ if (!gst_jack_audio_sink_allocate_channels (sink, channels))
+ goto out_of_ports;
- g_free (name);
- }
-
- buffer_size = jack_get_buffer_size (sink->client);
+ buffer_size = jack_get_buffer_size (client);
/* the segment size in bytes, this is large enough to hold a buffer of 32bit floats
* for all channels */
buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize);
memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data));
- if ((res = jack_activate (sink->client)))
+ if ((res = gst_jack_audio_client_set_active (sink->client, TRUE)))
goto could_not_activate;
/* if we need to automatically connect the ports, do so now. We must do this
/* find all the physical input ports. A physical input port is a port
* associated with a hardware device. Someone needs connect to a physical
* port in order to hear something. */
- ports = jack_get_ports (sink->client, NULL, NULL,
+ ports = jack_get_ports (client, NULL, NULL,
JackPortIsPhysical | JackPortIsInput);
if (ports == NULL) {
/* no ports? fine then we don't do anything except for posting a warning
break;
}
/* connect the port to a physical port */
- if ((res = jack_connect (sink->client, jack_port_name (abuf->outport[i]),
+ if ((res = jack_connect (client, jack_port_name (sink->ports[i]),
ports[i])))
goto cannot_connect;
}
{
GstJackAudioSink *sink;
GstJackRingBuffer *abuf;
- gint i, res;
+ gint res;
abuf = GST_JACK_RING_BUFFER_CAST (buf);
sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
GST_DEBUG_OBJECT (sink, "release");
- if ((res = jack_deactivate (sink->client))) {
+ if ((res = gst_jack_audio_client_set_active (sink->client, FALSE))) {
/* we only warn, this means the server is probably shut down and the client
* is gone anyway. */
GST_ELEMENT_WARNING (sink, RESOURCE, CLOSE, (NULL),
("Could not deactivate Jack client (%d)", res));
}
- /* remove all ports */
- for (i = 0; i < abuf->channels; i++) {
- GST_LOG_OBJECT (sink, "unregister port %d", i);
- if ((res = jack_port_unregister (sink->client, abuf->outport[i]))) {
- GST_DEBUG_OBJECT (sink, "unregister of port failed (%d)", res);
- }
- abuf->outport[i] = NULL;
- }
- g_free (abuf->outport);
- abuf->outport = NULL;
abuf->channels = -1;
abuf->buffer_size = -1;
abuf->sample_rate = -1;
gstbaseaudiosink_class->create_ringbuffer =
GST_DEBUG_FUNCPTR (gst_jack_audio_sink_create_ringbuffer);
+
+ gst_jack_audio_client_init ();
}
static void
{
sink->connect = DEFAULT_PROP_CONNECT;
sink->server = g_strdup (DEFAULT_PROP_SERVER);
+ sink->ports = NULL;
+ sink->port_count = 0;
}
static void
const char **ports;
gint min, max;
gint rate;
+ jack_client_t *client;
if (sink->client == NULL)
goto no_client;
+ client = gst_jack_audio_client_get_client (sink->client);
+
if (sink->connect == GST_JACK_CONNECT_AUTO) {
/* get a port count, this is the number of channels we can automatically
* connect. */
- ports = jack_get_ports (sink->client, NULL, NULL,
+ ports = jack_get_ports (client, NULL, NULL,
JackPortIsPhysical | JackPortIsInput);
max = 0;
if (ports != NULL) {
} else
max = 0;
} else {
- /* we allow any number of pads, somoething else is going to connect the
+ /* we allow any number of pads, something else is going to connect the
* pads. */
max = G_MAXINT;
}
min = MIN (1, max);
- rate = jack_get_sample_rate (sink->client);
+ rate = jack_get_sample_rate (client);
GST_DEBUG_OBJECT (sink, "got %d-%d ports, samplerate: %d", min, max, rate);
#include <gst/gst.h>
#include <gst/audio/gstbaseaudiosink.h>
+#include "gstjackaudioclient.h"
+
G_BEGIN_DECLS
#define GST_TYPE_JACK_AUDIO_SINK (gst_jack_audio_sink_get_type())
struct _GstJackAudioSink {
GstBaseAudioSink element;
+ /*< private >*/
/* cached caps */
GstCaps *caps;
gchar *server;
/* our client */
- jack_client_t *client;
+ GstJackAudioClient *client;
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
+ /* our ports */
+ jack_port_t **ports;
+ int port_count;
};
struct _GstJackAudioSinkClass {
GstBaseAudioSinkClass parent_class;
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
};
GType gst_jack_audio_sink_get_type (void);