From b40069a51296860a428cd1a9ef51bcbcf522f1ba Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Tue, 16 Apr 2002 17:14:05 +0000 Subject: [PATCH] Finally we're on to a proper jack setup, with a specialized bin and elements that can only go in a jack bin. I had to... Original commit message from CVS: Finally we're on to a proper jack setup, with a specialized bin and elements that can only go in a jack bin. I had to fix the parser first to do this, but to run it, the syntax is like so: gst-launch jackbin.( filesrc ! mad ! jacksink ) But of course it's not fully functional yet. Sigh. --- common | 2 +- ext/jack/Makefile.am | 2 +- ext/jack/gstjack.c | 192 +++++--------------------------- ext/jack/gstjack.h | 54 +++++---- ext/jack/gstjackbin.c | 250 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 312 insertions(+), 188 deletions(-) create mode 100644 ext/jack/gstjackbin.c diff --git a/common b/common index 22ee9f5959..ae138c8944 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 22ee9f59590241153f1b162344d760c303b1305a +Subproject commit ae138c8944d9ac7cb076a914afc5ce71c3114e39 diff --git a/ext/jack/Makefile.am b/ext/jack/Makefile.am index 7c1b5c2376..981c5a9f77 100644 --- a/ext/jack/Makefile.am +++ b/ext/jack/Makefile.am @@ -2,7 +2,7 @@ plugindir = $(libdir)/gst plugin_LTLIBRARIES = libgstjack.la -libgstjack_la_SOURCES = gstjack.c +libgstjack_la_SOURCES = gstjack.c gstjackbin.c libgstjack_la_CFLAGS = $(GST_CFLAGS) $(JACK_CFLAGS) libgstjack_la_LIBADD = $(JACK_LIBS) libgstjack_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) diff --git a/ext/jack/gstjack.c b/ext/jack/gstjack.c index 0567f47390..fc29775068 100644 --- a/ext/jack/gstjack.c +++ b/ext/jack/gstjack.c @@ -35,6 +35,15 @@ */ +static GstElementDetails gst_jack_bin_details = { + "Jack Bin", + "Bin/Audio", + "Jack processing bin: see README for more info", + VERSION, + "Andy Wingo ", + "(C) 2002 " +}; + static GstElementDetails gst_jack_sink_details = { "Jack Sink", "Sink/Audio", @@ -54,7 +63,7 @@ static GstElementDetails gst_jack_src_details = { }; -static GstElement *parent_class = NULL; +static GstElementClass *parent_class = NULL; static void gst_jack_init(GstJack *this); static void gst_jack_class_init(GstJackClass *klass); @@ -72,12 +81,6 @@ static GstPadConnectReturn gst_jack_connect (GstPad *pad, GstCaps *caps); static void gst_jack_loop (GstElement *element); -/* jack callbacks */ -static int process (nframes_t nframes, void *arg); -static int buffer_size (nframes_t nframes, void *arg); -static int sample_rate (nframes_t nframes, void *arg); -static void shutdown (void *arg); - enum { ARG_0, @@ -229,12 +232,12 @@ gst_jack_request_new_pad (GstElement *element, GstPadTemplate *templ, const gcha g_return_val_if_fail ((this = GST_JACK (element)), NULL); - if (!this->client) + if (!this->bin) pad_list = &this->pads; else if (this->direction == GST_PAD_SRC) - pad_list = &this->client->src_pads; + pad_list = &this->bin->src_pads; else - pad_list = &this->client->src_pads; + pad_list = &this->bin->src_pads; if (name) { l = *pad_list; @@ -303,63 +306,31 @@ static GstElementStateReturn gst_jack_change_state (GstElement *element) { GstJack *this; - GstJackClient *client; - GstBin *bin; GList *l = NULL, **pads; - enum JackPortFlags flags; GstJackPad *pad; g_return_val_if_fail (element != NULL, FALSE); this = GST_JACK (element); - client = this->client; switch (GST_STATE_PENDING (element)) { case GST_STATE_NULL: - g_message ("jack: NULL state"); - if (client) { - g_message ("jack: closing client"); - jack_client_close (client->client); - } - + g_message ("jack client %s: NULL", GST_OBJECT_NAME (GST_OBJECT (this))); break; case GST_STATE_READY: - g_message ("jack: READY"); - if (!this->client) { - if (!(bin = gst_element_get_managing_bin (element))) { - g_warning ("jack element %s cannot be brought to READY state without a managing bin", + g_message ("jack client %s: READY", GST_OBJECT_NAME (GST_OBJECT (this))); + if (!this->bin) { + if (!(this->bin = (GstJackBin*)gst_element_get_managing_bin (element)) + || !GST_IS_JACK_BIN (this->bin)) { + this->bin = NULL; + g_warning ("jack element %s needs to be contained in a jack bin.", GST_OBJECT_NAME (GST_OBJECT (element))); return GST_STATE_FAILURE; } - client = g_object_get_data (G_OBJECT (bin), "gst-jack-client"); - - if (!client) { - g_message ("jack: making new client"); - client = g_new0 (GstJackClient, 1); - if (!(client->client = jack_client_new ("gst-jack"))) { - g_warning ("jack server not running?"); - return GST_STATE_FAILURE; - } - - jack_set_process_callback (client->client, process, client); - jack_set_buffer_size_callback (client->client, buffer_size, client); - jack_set_sample_rate_callback (client->client, sample_rate, client); - jack_on_shutdown (client->client, shutdown, client); - - client->refcount = 1; - g_object_set_data (G_OBJECT (bin), "gst-jack-client", client); - client->manager = bin; - GST_FLAG_SET (GST_OBJECT (bin), GST_BIN_SELF_SCHEDULABLE); - } else { - g_message ("jack: refcounting existing client"); - client->refcount++; - } - this->client = client; - /* fixme: verify that all names are unique */ l = this->pads; - pads = (this->direction == GST_PAD_SRC) ? &client->src_pads : &client->sink_pads; + pads = (this->direction == GST_PAD_SRC) ? &this->bin->src_pads : &this->bin->sink_pads; while (l) { pad = GST_JACK_PAD (l); g_message ("jack: appending pad %s:%s to list", pad->name, pad->peer_name); @@ -367,60 +338,13 @@ gst_jack_change_state (GstElement *element) l = g_list_next (l); } } - - /* fixme: there are a *lot* of problems here */ - if (GST_FLAG_IS_SET (GST_OBJECT (this), GST_JACK_OPEN)) { - l = this->pads; - while (l) { - g_message ("jack: unregistering pad %s:%s", GST_JACK_PAD (l)->name, GST_JACK_PAD (l)->peer_name); - jack_port_unregister (client->client, GST_JACK_PAD (l)->port); - l = g_list_next (l); - } - GST_FLAG_UNSET (GST_OBJECT (this), GST_JACK_OPEN); - } break; case GST_STATE_PAUSED: - g_message ("jack: PAUSED"); - g_assert (client); - - if (!GST_FLAG_IS_SET (GST_OBJECT (this), GST_JACK_OPEN)) { - l = this->pads; - while (l) { - pad = GST_JACK_PAD (l); - - if (this->direction == GST_PAD_SINK) - flags = JackPortIsOutput; - else - flags = JackPortIsInput; - - g_message ("jack: registering pad %s:%s", pad->name, pad->peer_name); - pad->port = jack_port_register (client->client, pad->name, JACK_DEFAULT_AUDIO_TYPE, flags, 0); - g_message ("connecting gst jack port %s to jack port %s", jack_port_name (pad->port), pad->peer_name); - if (jack_connect (client->client, jack_port_name (pad->port), pad->peer_name)) { - g_warning ("could not connect %s and %s", pad->peer_name, jack_port_name (pad->port)); - return GST_STATE_FAILURE; - } - - l = g_list_next (l); - } - g_message ("jack: setting OPEN flag"); - GST_FLAG_SET (GST_OBJECT (this), GST_JACK_OPEN); - } - - if (GST_FLAG_IS_SET (GST_OBJECT (this), GST_JACK_ACTIVE)) { - g_message ("jack: deactivating client"); - jack_deactivate (client->client); - GST_FLAG_UNSET (GST_OBJECT (this), GST_JACK_ACTIVE); - } + g_message ("jack client %s: PAUSED", GST_OBJECT_NAME (GST_OBJECT (this))); break; case GST_STATE_PLAYING: - g_message ("jack: PLAYING"); - if (!GST_FLAG_IS_SET (GST_OBJECT (this), GST_JACK_ACTIVE)) { - g_message ("jack: activating client"); - jack_activate (client->client); - GST_FLAG_SET (GST_OBJECT (this), GST_JACK_ACTIVE); - } + g_message ("jack client %s: PLAYING", GST_OBJECT_NAME (GST_OBJECT (this))); break; } @@ -444,7 +368,7 @@ gst_jack_connect (GstPad *pad, GstCaps *caps) if (GST_CAPS_IS_FIXED (caps)) { gst_caps_get_int (caps, "rate", &rate); - if (this->client && rate != this->client->rate) + if (this->bin && rate != this->bin->rate) return GST_PAD_CONNECT_REFUSED; return GST_PAD_CONNECT_OK; @@ -468,7 +392,7 @@ gst_jack_loop (GstElement *element) this = GST_JACK (element); g_return_if_fail(this != NULL); - len = this->client->nframes * sizeof (sample_t); + len = this->bin->nframes * sizeof (sample_t); do { pads = this->pads; @@ -515,69 +439,6 @@ gst_jack_loop (GstElement *element) } while (TRUE); } -/* jack callbacks */ - -static int -process (nframes_t nframes, void *arg) -{ - GstJackClient *client = (GstJackClient*) arg; - GstJackPad *pad; - GList *l; - - g_assert (client); - - g_message ("jack: process()"); - - l = client->src_pads; - while (l) { - pad = GST_JACK_PAD (l); - pad->data = jack_port_get_buffer (pad->port, nframes); - l = g_list_next (l); - } - - l = client->sink_pads; - while (l) { - pad = GST_JACK_PAD (l); - pad->data = jack_port_get_buffer (pad->port, nframes); - l = g_list_next (l); - } - - client->nframes = nframes; - - if (!gst_bin_iterate (client->manager)) { - g_warning ("bin failed to iterate"); - return -1; - } - - /* that's all folks */ - - return 0; -} - -static int -buffer_size (nframes_t nframes, void *arg) -{ - printf ("the maximum buffer size is now %lu\n", nframes); - return 0; -} - -static int -sample_rate (nframes_t nframes, void *arg) -{ - GstJackClient *client = (GstJackClient*) arg; - printf ("the sample rate is now %lu/sec\n", nframes); - client->rate = nframes; - return 0; -} - -static void -shutdown (void *arg) -{ - GstJackClient *client = (GstJackClient*) arg; - printf ("shutdown %p\n", client); -/* gst_element_set_state (GST_ELEMENT (client->manager), GST_STATE_READY); */ -} - static gboolean plugin_init (GModule *module, GstPlugin *plugin) { @@ -588,6 +449,9 @@ plugin_init (GModule *module, GstPlugin *plugin) return FALSE; } + factory = gst_element_factory_new ("jackbin", GST_TYPE_JACK_BIN, &gst_jack_bin_details); + g_return_val_if_fail (factory != NULL, FALSE); + factory = gst_element_factory_new ("jacksrc", GST_TYPE_JACK_SRC, &gst_jack_src_details); g_return_val_if_fail (factory != NULL, FALSE); gst_element_factory_add_pad_template (factory, gst_jack_src_request_pad_factory()); diff --git a/ext/jack/gstjack.h b/ext/jack/gstjack.h index da6940f2fd..38763cd6e3 100644 --- a/ext/jack/gstjack.h +++ b/ext/jack/gstjack.h @@ -42,11 +42,19 @@ #define GST_IS_JACK_SRC_CLASS(klass) G_TYPE_CHECK_CLASS_TYPE(klass, GST_TYPE_JACK_SRC) #define GST_TYPE_JACK_SRC gst_jack_src_get_type() +#define GST_JACK_BIN(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, GST_TYPE_JACK_BIN, GstJackBin) +#define GST_JACK_BIN_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, GST_TYPE_JACK_BIN, GstJackClass) +#define GST_IS_JACK_BIN(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, GST_TYPE_JACK_BIN) +#define GST_IS_JACK_BIN_CLASS(klass) G_TYPE_CHECK_CLASS_TYPE(klass, GST_TYPE_JACK_BIN) +#define GST_TYPE_JACK_BIN gst_jack_bin_get_type() + #define GST_JACK_PAD(l) ((GstJackPad*)l->data) /* l is a GList */ typedef struct _GstJack GstJack; typedef struct _GstJackClass GstJackClass; +typedef struct _GstJackBin GstJackBin; +typedef struct _GstJackBinClass GstJackBinClass; typedef GstJack GstJackSink; typedef GstJackClass GstJackSinkClass; typedef GstJack GstJackSrc; @@ -54,9 +62,9 @@ typedef GstJackClass GstJackSrcClass; enum { - GST_JACK_OPEN = GST_ELEMENT_FLAG_LAST, + GST_JACK_OPEN = GST_BIN_FLAG_LAST, GST_JACK_ACTIVE, - GST_JACK_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 3, + GST_JACK_FLAG_LAST = GST_BIN_FLAG_LAST + 3, }; @@ -69,24 +77,6 @@ typedef struct { jack_port_t *port; } GstJackPad; -typedef struct { - GstBin *manager; - - jack_client_t *client; - gint default_new_port_number; - - /* lists of GstJackPads */ - GList *sink_pads; - GList *src_pads; - - gchar *client_name; - - guint rate; - nframes_t nframes; - - guint refcount; -} GstJackClient; - struct _GstJack { GstElement element; @@ -98,16 +88,36 @@ struct _GstJack { gchar *port_name_prefix; - /* there is exactly one client per managing bin */ - GstJackClient *client; + GstJackBin *bin; }; struct _GstJackClass { GstElementClass parent_class; }; +struct _GstJackBin { + GstBin bin; + + jack_client_t *client; + gint default_new_port_number; + + /* lists of GstJackPads */ + GList *sink_pads; + GList *src_pads; + + gchar *client_name; + + guint rate; + nframes_t nframes; +}; + +struct _GstJackBinClass { + GstBinClass parent_class; +}; + GType gst_jack_get_type (void); +GType gst_jack_bin_get_type (void); GType gst_jack_sink_get_type (void); GType gst_jack_src_get_type (void); diff --git a/ext/jack/gstjackbin.c b/ext/jack/gstjackbin.c new file mode 100644 index 0000000000..8a4cc7634a --- /dev/null +++ b/ext/jack/gstjackbin.c @@ -0,0 +1,250 @@ +/* + Copyright (C) 2002 Andy Wingo + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU 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 + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include "gstjack.h" + + +static GstBinClass *parent_class = NULL; + +static void gst_jack_bin_init(GstJack *this); +static void gst_jack_bin_class_init(GstJackClass *klass); + +static GstElementStateReturn gst_jack_bin_change_state(GstElement *element); + +/* jack callbacks */ +static int process (nframes_t nframes, void *arg); +static int buffer_size (nframes_t nframes, void *arg); +static int sample_rate (nframes_t nframes, void *arg); +static void shutdown (void *arg); + + +GType +gst_jack_bin_get_type (void) +{ + static GType jack_bin_type = 0; + + if (!jack_bin_type) { + static const GTypeInfo jack_bin_info = { + sizeof(GstJackBinClass), + NULL, + NULL, + (GClassInitFunc)gst_jack_bin_class_init, + NULL, + NULL, + sizeof(GstJackBin), + 0, + (GInstanceInitFunc)gst_jack_bin_init, + }; + jack_bin_type = g_type_register_static (GST_TYPE_BIN, "GstJackBin", &jack_bin_info, 0); + } + return jack_bin_type; +} + +static void +gst_jack_bin_class_init(GstJackClass *klass) +{ + GObjectClass *object_class; + GstElementClass *element_class; + + object_class = (GObjectClass *)klass; + element_class = (GstElementClass *)klass; + + parent_class = g_type_class_ref(GST_TYPE_BIN); + + element_class->change_state = gst_jack_bin_change_state; +} + +static void +gst_jack_bin_init(GstJack *this) +{ +} + +static GstElementStateReturn +gst_jack_bin_change_state (GstElement *element) +{ + GstJackBin *this; + GList *l = NULL; + GstJackPad *pad; + + g_return_val_if_fail (element != NULL, FALSE); + this = GST_JACK_BIN (element); + + switch (GST_STATE_PENDING (element)) { + case GST_STATE_NULL: + g_message ("jack: NULL state"); + if (this->client) { + g_message ("jack: closing client"); + jack_client_close (this->client); + } + + break; + + case GST_STATE_READY: + g_message ("jack: READY"); + if (!this->client) { + if (!(this->client = jack_client_new ("gst-jack"))) { + g_warning ("jack server not running?"); + return GST_STATE_FAILURE; + } + + jack_set_process_callback (this->client, process, this); + jack_set_buffer_size_callback (this->client, buffer_size, this); + jack_set_sample_rate_callback (this->client, sample_rate, this); + jack_on_shutdown (this->client, shutdown, this); + } + + /* fixme: there are a *lot* of problems here */ + if (GST_FLAG_IS_SET (GST_OBJECT (this), GST_JACK_OPEN)) { + l = this->src_pads; + while (l) { + g_message ("jack: unregistering pad %s:%s", GST_JACK_PAD (l)->name, GST_JACK_PAD (l)->peer_name); + jack_port_unregister (this->client, GST_JACK_PAD (l)->port); + l = g_list_next (l); + } + l = this->sink_pads; + while (l) { + g_message ("jack: unregistering pad %s:%s", GST_JACK_PAD (l)->name, GST_JACK_PAD (l)->peer_name); + jack_port_unregister (this->client, GST_JACK_PAD (l)->port); + l = g_list_next (l); + } + GST_FLAG_UNSET (GST_OBJECT (this), GST_JACK_OPEN); + } + break; + + case GST_STATE_PAUSED: + g_message ("jack: PAUSED"); + + if (!GST_FLAG_IS_SET (GST_OBJECT (this), GST_JACK_OPEN)) { + l = this->src_pads; + while (l) { + pad = GST_JACK_PAD (l); + g_message ("jack: registering pad %s:%s", pad->name, pad->peer_name); + pad->port = jack_port_register (this->client, pad->name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); + g_message ("connecting gst jack port %s to jack port %s", jack_port_name (pad->port), pad->peer_name); + if (jack_connect (this->client, jack_port_name (pad->port), pad->peer_name)) { + g_warning ("could not connect %s and %s", pad->peer_name, jack_port_name (pad->port)); + return GST_STATE_FAILURE; + } + l = g_list_next (l); + } + l = this->sink_pads; + while (l) { + pad = GST_JACK_PAD (l); + g_message ("jack: registering pad %s:%s", pad->name, pad->peer_name); + pad->port = jack_port_register (this->client, pad->name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); + g_message ("connecting gst jack port %s to jack port %s", jack_port_name (pad->port), pad->peer_name); + if (jack_connect (this->client, jack_port_name (pad->port), pad->peer_name)) { + g_warning ("could not connect %s and %s", pad->peer_name, jack_port_name (pad->port)); + return GST_STATE_FAILURE; + } + l = g_list_next (l); + } + g_message ("jack: setting OPEN flag"); + GST_FLAG_SET (GST_OBJECT (this), GST_JACK_OPEN); + } + + if (GST_FLAG_IS_SET (GST_OBJECT (this), GST_JACK_ACTIVE)) { + g_message ("jack: deactivating client"); + jack_deactivate (this->client); + GST_FLAG_UNSET (GST_OBJECT (this), GST_JACK_ACTIVE); + } + break; + case GST_STATE_PLAYING: + g_message ("jack: PLAYING"); + if (!GST_FLAG_IS_SET (GST_OBJECT (this), GST_JACK_ACTIVE)) { + g_message ("jack: activating client"); + jack_activate (this->client); + GST_FLAG_SET (GST_OBJECT (this), GST_JACK_ACTIVE); + } + break; + } + + g_message ("jack: state change finished"); + + if (GST_ELEMENT_CLASS (parent_class)->change_state) + return GST_ELEMENT_CLASS (parent_class)->change_state (element); + + return GST_STATE_SUCCESS; +} + +/* jack callbacks */ + +/* keep in mind that these run in another thread, mm-kay? */ + +static int +process (nframes_t nframes, void *arg) +{ + GstJackBin *bin = (GstJackBin*) arg; + GstJackPad *pad; + GList *l; + + g_assert (bin); + + g_message ("jack: process()"); + + l = bin->src_pads; + while (l) { + pad = GST_JACK_PAD (l); + pad->data = jack_port_get_buffer (pad->port, nframes); + l = g_list_next (l); + } + + l = bin->sink_pads; + while (l) { + pad = GST_JACK_PAD (l); + pad->data = jack_port_get_buffer (pad->port, nframes); + l = g_list_next (l); + } + + bin->nframes = nframes; + + if (!gst_bin_iterate (GST_BIN_CAST (bin))) { + g_warning ("bin failed to iterate"); + return -1; + } + + /* that's all folks */ + + return 0; +} + +static int +buffer_size (nframes_t nframes, void *arg) +{ + printf ("the maximum buffer size is now %lu\n", nframes); + return 0; +} + +static int +sample_rate (nframes_t nframes, void *arg) +{ + GstJackBin *bin = (GstJackBin*) arg; + printf ("the sample rate is now %lu/sec\n", nframes); + bin->rate = nframes; + return 0; +} + +static void +shutdown (void *arg) +{ +/* GstJackClient *client = (GstJackClient*) arg; */ + printf ("shutdown %p\n", arg); +/* gst_element_set_state (GST_ELEMENT (client->manager), GST_STATE_READY); */ +} +