diff --git a/ext/jack/Makefile.am b/ext/jack/Makefile.am index 0a237dd6c9..17efdfa94c 100644 --- a/ext/jack/Makefile.am +++ b/ext/jack/Makefile.am @@ -1,11 +1,11 @@ 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 diff --git a/ext/jack/gstjackaudioclient.c b/ext/jack/gstjackaudioclient.c new file mode 100644 index 0000000000..c81125939d --- /dev/null +++ b/ext/jack/gstjackaudioclient.c @@ -0,0 +1,484 @@ +/* GStreamer + * Copyright (C) 2006 Wim Taymans + * + * 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 + +#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; +} diff --git a/ext/jack/gstjackaudioclient.h b/ext/jack/gstjackaudioclient.h new file mode 100644 index 0000000000..9092e7ded5 --- /dev/null +++ b/ext/jack/gstjackaudioclient.h @@ -0,0 +1,58 @@ +/* GStreamer + * Copyright (C) 2006 Wim Taymans + * + * 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 + +#include + +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__ */ diff --git a/ext/jack/gstjackaudiosink.c b/ext/jack/gstjackaudiosink.c index b57e51cf09..6f0ea57118 100644 --- a/ext/jack/gstjackaudiosink.c +++ b/ext/jack/gstjackaudiosink.c @@ -96,8 +96,6 @@ struct _GstJackRingBuffer gint sample_rate; gint buffer_size; gint channels; - - jack_port_t **outport; }; struct _GstJackRingBufferClass @@ -123,6 +121,60 @@ static gboolean gst_jack_ring_buffer_pause (GstRingBuffer * buf); 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) @@ -206,7 +258,7 @@ jack_process_cb (jack_nframes_t nframes, void *arg) /* 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)) { @@ -343,30 +395,19 @@ static gboolean 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; @@ -391,17 +432,13 @@ static gboolean 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; @@ -426,37 +463,26 @@ gst_jack_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec) 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); + if (!gst_jack_audio_sink_allocate_channels (sink, channels)) + goto out_of_ports; - /* 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; - - 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 */ @@ -473,7 +499,7 @@ gst_jack_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec) 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 @@ -482,7 +508,7 @@ gst_jack_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec) /* 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 @@ -501,7 +527,7 @@ gst_jack_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec) 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; } @@ -550,30 +576,20 @@ gst_jack_ring_buffer_release (GstRingBuffer * buf) { 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; @@ -746,6 +762,8 @@ gst_jack_audio_sink_class_init (GstJackAudioSinkClass * klass) gstbaseaudiosink_class->create_ringbuffer = GST_DEBUG_FUNCPTR (gst_jack_audio_sink_create_ringbuffer); + + gst_jack_audio_client_init (); } static void @@ -754,6 +772,8 @@ gst_jack_audio_sink_init (GstJackAudioSink * sink, { sink->connect = DEFAULT_PROP_CONNECT; sink->server = g_strdup (DEFAULT_PROP_SERVER); + sink->ports = NULL; + sink->port_count = 0; } static void @@ -806,14 +826,17 @@ gst_jack_audio_sink_getcaps (GstBaseSink * bsink) 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) { @@ -822,13 +845,13 @@ gst_jack_audio_sink_getcaps (GstBaseSink * bsink) } 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); diff --git a/ext/jack/gstjackaudiosink.h b/ext/jack/gstjackaudiosink.h index 245521b2a1..12c82a834f 100644 --- a/ext/jack/gstjackaudiosink.h +++ b/ext/jack/gstjackaudiosink.h @@ -27,6 +27,8 @@ #include #include +#include "gstjackaudioclient.h" + G_BEGIN_DECLS #define GST_TYPE_JACK_AUDIO_SINK (gst_jack_audio_sink_get_type()) @@ -63,6 +65,7 @@ typedef enum { struct _GstJackAudioSink { GstBaseAudioSink element; + /*< private >*/ /* cached caps */ GstCaps *caps; @@ -71,17 +74,15 @@ struct _GstJackAudioSink { 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);