summaryrefslogtreecommitdiff
path: root/ext/jack/gstjackaudiosink.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/jack/gstjackaudiosink.c')
-rw-r--r--ext/jack/gstjackaudiosink.c130
1 files changed, 113 insertions, 17 deletions
diff --git a/ext/jack/gstjackaudiosink.c b/ext/jack/gstjackaudiosink.c
index ccdca5a54..4d18f7a36 100644
--- a/ext/jack/gstjackaudiosink.c
+++ b/ext/jack/gstjackaudiosink.c
@@ -401,7 +401,6 @@ gst_jack_ring_buffer_acquire (GstAudioRingBuffer * buf,
{
GstJackAudioSink *sink;
GstJackRingBuffer *abuf;
- const char **ports;
gint sample_rate, buffer_size;
gint i, rate, bpf, channels, res;
jack_client_t *client;
@@ -459,18 +458,39 @@ gst_jack_ring_buffer_acquire (GstAudioRingBuffer * buf,
/* if we need to automatically connect the ports, do so now. We must do this
* after activating the client. */
if (sink->connect == GST_JACK_CONNECT_AUTO
- || sink->connect == GST_JACK_CONNECT_AUTO_FORCED) {
+ || sink->connect == GST_JACK_CONNECT_AUTO_FORCED
+ || sink->connect == GST_JACK_CONNECT_EXPLICIT) {
+ const char **available_ports = NULL;
+ const char **jack_ports = NULL;
+ char **user_ports = NULL;
+
/* 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. */
- if (sink->port_pattern == NULL) {
- ports = jack_get_ports (client, NULL, NULL,
- JackPortIsPhysical | JackPortIsInput);
- } else {
- ports = jack_get_ports (client, sink->port_pattern, NULL,
- JackPortIsInput);
+ if (sink->port_names) {
+ user_ports = gst_jack_audio_client_get_port_names_from_string (client,
+ sink->port_names, JackPortIsInput);
+
+ if (user_ports)
+ available_ports = (const char **) user_ports;
}
- if (ports == NULL) {
+
+ if (!available_ports && sink->connect == GST_JACK_CONNECT_EXPLICIT)
+ goto wrong_port_names;
+
+ if (!available_ports) {
+ if (!sink->port_pattern) {
+ jack_ports = jack_get_ports (client, NULL, NULL,
+ JackPortIsPhysical | JackPortIsInput);
+ } else {
+ jack_ports = jack_get_ports (client, sink->port_pattern, NULL,
+ JackPortIsInput);
+ }
+
+ available_ports = jack_ports;
+ }
+
+ if (!available_ports) {
/* no ports? fine then we don't do anything except for posting a warning
* message. */
GST_ELEMENT_WARNING (sink, RESOURCE, NOT_FOUND, (NULL),
@@ -480,7 +500,7 @@ gst_jack_ring_buffer_acquire (GstAudioRingBuffer * buf,
for (i = 0; i < channels; i++) {
/* stop when all input ports are exhausted */
- if (ports[i] == NULL) {
+ if (!available_ports[i]) {
/* post a warning that we could not connect all ports */
GST_ELEMENT_WARNING (sink, RESOURCE, NOT_FOUND, (NULL),
("No more physical ports, leaving some ports unconnected"));
@@ -489,11 +509,18 @@ gst_jack_ring_buffer_acquire (GstAudioRingBuffer * buf,
GST_DEBUG_OBJECT (sink, "try connecting to %s",
jack_port_name (sink->ports[i]));
/* connect the port to a physical port */
- res = jack_connect (client, jack_port_name (sink->ports[i]), ports[i]);
- if (res != 0 && res != EEXIST)
+ res = jack_connect (client,
+ jack_port_name (sink->ports[i]), available_ports[i]);
+ if (res != 0 && res != EEXIST) {
+ jack_free (jack_ports);
+ g_strfreev (user_ports);
+
goto cannot_connect;
+ }
}
- jack_free (ports);
+
+ jack_free (jack_ports);
+ g_strfreev (user_ports);
}
done:
@@ -528,7 +555,12 @@ cannot_connect:
GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL),
("Could not connect output ports to physical ports (%d:%s)",
res, g_strerror (res)));
- jack_free (ports);
+ return FALSE;
+ }
+wrong_port_names:
+ {
+ GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL),
+ ("Invalid port-names was provided"));
return FALSE;
}
}
@@ -699,6 +731,7 @@ enum
PROP_PORT_PATTERN,
PROP_TRANSPORT,
PROP_LOW_LATENCY,
+ PROP_PORT_NAMES,
PROP_LAST
};
@@ -807,6 +840,19 @@ gst_jack_audio_sink_class_init (GstJackAudioSinkClass * klass)
GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
+ /**
+ * GstJackAudioSink:port-names:
+ *
+ * Comma-separated list of port name including "client_name:" prefix
+ *
+ * Since: 1.20
+ */
+ g_object_class_install_property (gobject_class, PROP_PORT_NAMES,
+ g_param_spec_string ("port-names", "Port Names",
+ "Comma-separated list of port name including \"client_name:\" prefix",
+ NULL, GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
gst_element_class_set_static_metadata (gstelement_class, "Audio Sink (Jack)",
"Sink/Audio", "Output audio to a JACK server",
"Wim Taymans <wim.taymans@gmail.com>");
@@ -857,6 +903,8 @@ gst_jack_audio_sink_dispose (GObject * object)
sink->port_pattern = NULL;
}
+ g_clear_pointer (&sink->port_names, g_free);
+
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@@ -896,6 +944,10 @@ gst_jack_audio_sink_set_property (GObject * object, guint prop_id,
case PROP_LOW_LATENCY:
sink->low_latency = g_value_get_boolean (value);
break;
+ case PROP_PORT_NAMES:
+ g_free (sink->port_names);
+ sink->port_names = g_value_dup_string (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -932,6 +984,9 @@ gst_jack_audio_sink_get_property (GObject * object, guint prop_id,
case PROP_LOW_LATENCY:
g_value_set_boolean (value, sink->low_latency);
break;
+ case PROP_PORT_NAMES:
+ g_value_set_string (value, sink->port_names);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -950,14 +1005,42 @@ gst_jack_audio_sink_getcaps (GstBaseSink * bsink, GstCaps * filter)
if (sink->client == NULL)
goto no_client;
+ if (sink->connect == GST_JACK_CONNECT_EXPLICIT && !sink->port_names)
+ goto no_port_names;
+
client = gst_jack_audio_client_get_client (sink->client);
- if (sink->connect == GST_JACK_CONNECT_AUTO) {
+ if (sink->connect == GST_JACK_CONNECT_AUTO ||
+ sink->connect == GST_JACK_CONNECT_EXPLICIT) {
+ max = 0;
+
+ if (sink->port_names) {
+ gchar **user_ports =
+ gst_jack_audio_client_get_port_names_from_string (client,
+ sink->port_names, JackPortIsInput);
+
+ if (user_ports) {
+ max = g_strv_length (user_ports);
+ } else {
+ GST_ELEMENT_WARNING (sink, RESOURCE, NOT_FOUND,
+ ("Invalid \"port-names\" was requested"),
+ ("Requested \"port-names\" %s contains invalid name",
+ sink->port_names));
+ }
+
+ g_strfreev (user_ports);
+ }
+
+ if (max > 0)
+ goto found;
+
+ if (sink->connect == GST_JACK_CONNECT_EXPLICIT)
+ goto no_port_names;
+
/* get a port count, this is the number of channels we can automatically
* connect. */
ports = jack_get_ports (client, NULL, NULL,
JackPortIsPhysical | JackPortIsInput);
- max = 0;
if (ports != NULL) {
for (; ports[max]; max++);
jack_free (ports);
@@ -968,7 +1051,13 @@ gst_jack_audio_sink_getcaps (GstBaseSink * bsink, GstCaps * filter)
* pads. */
max = G_MAXINT;
}
- min = MIN (1, max);
+
+found:
+ if (sink->connect == GST_JACK_CONNECT_EXPLICIT) {
+ min = max;
+ } else {
+ min = MIN (1, max);
+ }
rate = jack_get_sample_rate (client);
@@ -996,6 +1085,13 @@ no_client:
/* base class will get template caps for us when we return NULL */
return NULL;
}
+no_port_names:
+ {
+ GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS,
+ ("User must provide valid port names"),
+ ("\"port-names\" contains invalid name or NULL string"));
+ return NULL;
+ }
}
static GstAudioRingBuffer *