mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-10 17:35:59 +00:00
jack: Add port-names property to select ports explicitly
By this new property, user can select physical port to connect, and element will pick requested port instead of random ones. User should provide full port name including "client_name:" prefix. An example is jackaudiosrc port-names="system:capture_1,system:capture_3" ! ... jackaudiosink port-names="system:playback_2" In addition to "port-names" property, a new connect type "explicit" is added so that element can post error message if requested "port-names" contains invalid port(s). Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/merge_requests/1037>
This commit is contained in:
parent
4ed342db5d
commit
4a5197dc27
9 changed files with 323 additions and 35 deletions
|
@ -8356,6 +8356,18 @@
|
|||
"type": "gboolean",
|
||||
"writable": true
|
||||
},
|
||||
"port-names": {
|
||||
"blurb": "Comma-separated list of port name including \"client_name:\" prefix",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "NULL",
|
||||
"mutable": "ready",
|
||||
"readable": true,
|
||||
"type": "gchararray",
|
||||
"writable": true
|
||||
},
|
||||
"port-pattern": {
|
||||
"blurb": "A pattern to select which ports to connect to (NULL = first physical ports)",
|
||||
"conditionally-available": false,
|
||||
|
@ -8465,6 +8477,18 @@
|
|||
"type": "gboolean",
|
||||
"writable": true
|
||||
},
|
||||
"port-names": {
|
||||
"blurb": "Comma-separated list of port name including \"client_name:\" prefix",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "NULL",
|
||||
"mutable": "ready",
|
||||
"readable": true,
|
||||
"type": "gchararray",
|
||||
"writable": true
|
||||
},
|
||||
"port-pattern": {
|
||||
"blurb": "A pattern to select which ports to connect to (NULL = first physical ports)",
|
||||
"conditionally-available": false,
|
||||
|
@ -8525,6 +8549,11 @@
|
|||
"desc": "Automatically connect ports to as many physical ports as possible",
|
||||
"name": "auto-forced",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"desc": "Connect ports to explicitly requested physical ports",
|
||||
"name": "explicit",
|
||||
"value": "3"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -37,6 +37,9 @@ gst_jack_connect_get_type (void)
|
|||
{GST_JACK_CONNECT_AUTO_FORCED,
|
||||
"Automatically connect ports to as many physical ports as possible",
|
||||
"auto-forced"},
|
||||
{GST_JACK_CONNECT_EXPLICIT,
|
||||
"Connect ports to explicitly requested physical ports",
|
||||
"explicit"},
|
||||
{0, NULL, NULL},
|
||||
};
|
||||
GType tmp = g_enum_register_static ("GstJackConnect", jack_connect_enums);
|
||||
|
|
|
@ -45,7 +45,17 @@ GST_ELEMENT_REGISTER_DECLARE (jackaudiosink);
|
|||
typedef enum {
|
||||
GST_JACK_CONNECT_NONE,
|
||||
GST_JACK_CONNECT_AUTO,
|
||||
GST_JACK_CONNECT_AUTO_FORCED
|
||||
GST_JACK_CONNECT_AUTO_FORCED,
|
||||
|
||||
/**
|
||||
* GstJackConnect::explicit
|
||||
*
|
||||
* In this mode, the element will try to connect to explicitly requested
|
||||
* port specified by "port-names".
|
||||
*
|
||||
* Since: 1.20
|
||||
*/
|
||||
GST_JACK_CONNECT_EXPLICIT,
|
||||
} GstJackConnect;
|
||||
|
||||
/**
|
||||
|
|
|
@ -635,3 +635,54 @@ gst_jack_audio_client_get_transport_state (GstJackAudioClient * client)
|
|||
client->conn->transport_state = GST_STATE_VOID_PENDING;
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_jack_audio_client_get_port_names_from_string:
|
||||
* @jclient: a jack_client_t handle
|
||||
* @port_names: comma-separated jack port name(s)
|
||||
* @port_flags: JackPortFlags
|
||||
*
|
||||
* Returns: a newly-allocated %NULL-terminated array of strings or %NULL
|
||||
* if @port_names contains invalid port name. Use g_strfreev() to free it.
|
||||
*/
|
||||
gchar **
|
||||
gst_jack_audio_client_get_port_names_from_string (jack_client_t * jclient,
|
||||
const gchar * port_names, gint port_flags)
|
||||
{
|
||||
gchar **p = NULL;
|
||||
guint i, len;
|
||||
|
||||
g_return_val_if_fail (jclient != NULL, NULL);
|
||||
|
||||
if (!port_names)
|
||||
return NULL;
|
||||
|
||||
p = g_strsplit (port_names, ",", 0);
|
||||
len = g_strv_length (p);
|
||||
|
||||
if (len < 1)
|
||||
goto invalid;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
jack_port_t *port = jack_port_by_name (jclient, p[i]);
|
||||
int flags;
|
||||
|
||||
if (!port) {
|
||||
GST_WARNING ("Couldn't get jack port by name %s", p[i]);
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
flags = jack_port_flags (port);
|
||||
if ((flags & port_flags) != port_flags) {
|
||||
GST_WARNING ("Port flags 0x%x doesn't match expected flags 0x%x",
|
||||
flags, port_flags);
|
||||
goto invalid;
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
|
||||
invalid:
|
||||
g_strfreev (p);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -56,6 +56,10 @@ gboolean gst_jack_audio_client_set_active (GstJackAudioClient *
|
|||
|
||||
GstState gst_jack_audio_client_get_transport_state (GstJackAudioClient *client);
|
||||
|
||||
gchar ** gst_jack_audio_client_get_port_names_from_string (jack_client_t *jclient,
|
||||
const gchar *port_names,
|
||||
gint port_flags);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_JACK_AUDIO_CLIENT_H__ */
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -56,6 +56,7 @@ struct _GstJackAudioSink {
|
|||
gchar *port_pattern;
|
||||
guint transport;
|
||||
gboolean low_latency;
|
||||
gchar *port_names;
|
||||
|
||||
/* our client */
|
||||
GstJackAudioClient *client;
|
||||
|
|
|
@ -407,7 +407,6 @@ gst_jack_ring_buffer_acquire (GstAudioRingBuffer * buf,
|
|||
{
|
||||
GstJackAudioSrc *src;
|
||||
GstJackRingBuffer *abuf;
|
||||
const char **ports;
|
||||
gint sample_rate, buffer_size;
|
||||
gint i, bpf, rate, channels, res;
|
||||
jack_client_t *client;
|
||||
|
@ -467,20 +466,38 @@ 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 (src->connect == GST_JACK_CONNECT_AUTO
|
||||
|| src->connect == GST_JACK_CONNECT_AUTO_FORCED) {
|
||||
|| src->connect == GST_JACK_CONNECT_AUTO_FORCED
|
||||
|| src->connect == GST_JACK_CONNECT_EXPLICIT) {
|
||||
const char **available_ports = NULL;
|
||||
const char **jack_ports = NULL;
|
||||
char **user_ports = NULL;
|
||||
|
||||
/* find all the physical output ports. A physical output port is a port
|
||||
* associated with a hardware device. Someone needs connect to a physical
|
||||
* port in order to capture something. */
|
||||
|
||||
if (src->port_pattern == NULL) {
|
||||
ports = jack_get_ports (client, NULL, NULL,
|
||||
JackPortIsPhysical | JackPortIsOutput);
|
||||
} else {
|
||||
ports = jack_get_ports (client, src->port_pattern, NULL,
|
||||
JackPortIsOutput);
|
||||
if (src->port_names) {
|
||||
user_ports = gst_jack_audio_client_get_port_names_from_string (client,
|
||||
src->port_names, JackPortIsOutput);
|
||||
|
||||
if (user_ports)
|
||||
available_ports = (const char **) user_ports;
|
||||
}
|
||||
|
||||
if (ports == NULL) {
|
||||
if (!available_ports && src->connect == GST_JACK_CONNECT_EXPLICIT)
|
||||
goto wrong_port_names;
|
||||
|
||||
if (!available_ports) {
|
||||
if (!src->port_pattern) {
|
||||
jack_ports = jack_get_ports (client, NULL, NULL,
|
||||
JackPortIsPhysical | JackPortIsOutput);
|
||||
} else {
|
||||
jack_ports = jack_get_ports (client, src->port_pattern, NULL,
|
||||
JackPortIsOutput);
|
||||
}
|
||||
}
|
||||
|
||||
if (!available_ports) {
|
||||
/* no ports? fine then we don't do anything except for posting a warning
|
||||
* message. */
|
||||
GST_ELEMENT_WARNING (src, RESOURCE, NOT_FOUND, (NULL),
|
||||
|
@ -490,7 +507,7 @@ gst_jack_ring_buffer_acquire (GstAudioRingBuffer * buf,
|
|||
|
||||
for (i = 0; i < channels; i++) {
|
||||
/* stop when all output ports are exhausted */
|
||||
if (ports[i] == NULL) {
|
||||
if (!available_ports[i]) {
|
||||
/* post a warning that we could not connect all ports */
|
||||
GST_ELEMENT_WARNING (src, RESOURCE, NOT_FOUND, (NULL),
|
||||
("No more physical ports, leaving some ports unconnected"));
|
||||
|
@ -500,11 +517,18 @@ gst_jack_ring_buffer_acquire (GstAudioRingBuffer * buf,
|
|||
jack_port_name (src->ports[i]));
|
||||
|
||||
/* connect the physical port to a port */
|
||||
res = jack_connect (client, ports[i], jack_port_name (src->ports[i]));
|
||||
if (res != 0 && res != EEXIST)
|
||||
res = jack_connect (client,
|
||||
available_ports[i], jack_port_name (src->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:
|
||||
|
||||
|
@ -539,7 +563,12 @@ cannot_connect:
|
|||
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
|
||||
("Could not connect input ports to physical ports (%d:%s)",
|
||||
res, g_strerror (res)));
|
||||
jack_free (ports);
|
||||
return FALSE;
|
||||
}
|
||||
wrong_port_names:
|
||||
{
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
|
||||
("Invalid port-names was provided"));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
@ -701,6 +730,7 @@ enum
|
|||
PROP_PORT_PATTERN,
|
||||
PROP_TRANSPORT,
|
||||
PROP_LOW_LATENCY,
|
||||
PROP_PORT_NAMES,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
|
@ -825,6 +855,19 @@ gst_jack_audio_src_class_init (GstJackAudioSrcClass * klass)
|
|||
GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* GstJackAudioSrc: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_add_static_pad_template (gstelement_class, &src_factory);
|
||||
|
||||
gst_element_class_set_static_metadata (gstelement_class,
|
||||
|
@ -875,6 +918,8 @@ gst_jack_audio_src_dispose (GObject * object)
|
|||
src->port_pattern = NULL;
|
||||
}
|
||||
|
||||
g_clear_pointer (&src->port_names, g_free);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
@ -912,6 +957,10 @@ gst_jack_audio_src_set_property (GObject * object, guint prop_id,
|
|||
case PROP_LOW_LATENCY:
|
||||
src->low_latency = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_PORT_NAMES:
|
||||
g_free (src->port_names);
|
||||
src->port_names = g_value_dup_string (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -946,6 +995,9 @@ gst_jack_audio_src_get_property (GObject * object, guint prop_id,
|
|||
case PROP_LOW_LATENCY:
|
||||
g_value_set_boolean (value, src->low_latency);
|
||||
break;
|
||||
case PROP_PORT_NAMES:
|
||||
g_value_set_string (value, src->port_names);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -964,14 +1016,42 @@ gst_jack_audio_src_getcaps (GstBaseSrc * bsrc, GstCaps * filter)
|
|||
if (src->client == NULL)
|
||||
goto no_client;
|
||||
|
||||
if (src->connect == GST_JACK_CONNECT_EXPLICIT && !src->port_names)
|
||||
goto no_port_names;
|
||||
|
||||
client = gst_jack_audio_client_get_client (src->client);
|
||||
|
||||
if (src->connect == GST_JACK_CONNECT_AUTO) {
|
||||
if (src->connect == GST_JACK_CONNECT_AUTO ||
|
||||
src->connect == GST_JACK_CONNECT_EXPLICIT) {
|
||||
max = 0;
|
||||
|
||||
if (src->port_names) {
|
||||
gchar **user_ports =
|
||||
gst_jack_audio_client_get_port_names_from_string (client,
|
||||
src->port_names, JackPortIsOutput);
|
||||
|
||||
if (user_ports) {
|
||||
max = g_strv_length (user_ports);
|
||||
} else {
|
||||
GST_ELEMENT_WARNING (src, RESOURCE, NOT_FOUND,
|
||||
("Invalid \"port-names\" was requested"),
|
||||
("Requested \"port-names\" %s contains invalid name",
|
||||
src->port_names));
|
||||
}
|
||||
|
||||
g_strfreev (user_ports);
|
||||
}
|
||||
|
||||
if (max > 0)
|
||||
goto found;
|
||||
|
||||
if (src->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 | JackPortIsOutput);
|
||||
max = 0;
|
||||
if (ports != NULL) {
|
||||
for (; ports[max]; max++);
|
||||
|
||||
|
@ -983,7 +1063,13 @@ gst_jack_audio_src_getcaps (GstBaseSrc * bsrc, GstCaps * filter)
|
|||
* pads. */
|
||||
max = G_MAXINT;
|
||||
}
|
||||
min = MIN (1, max);
|
||||
|
||||
found:
|
||||
if (src->connect == GST_JACK_CONNECT_EXPLICIT) {
|
||||
min = max;
|
||||
} else {
|
||||
min = MIN (1, max);
|
||||
}
|
||||
|
||||
rate = jack_get_sample_rate (client);
|
||||
|
||||
|
@ -1011,6 +1097,13 @@ no_client:
|
|||
/* base class will get template caps for us when we return NULL */
|
||||
return NULL;
|
||||
}
|
||||
no_port_names:
|
||||
{
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS,
|
||||
("User must provide valid port names"),
|
||||
("\"port-names\" contains invalid name or NULL string"));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static GstAudioRingBuffer *
|
||||
|
|
|
@ -73,6 +73,7 @@ struct _GstJackAudioSrc
|
|||
gchar *port_pattern;
|
||||
guint transport;
|
||||
gboolean low_latency;
|
||||
gchar *port_names;
|
||||
|
||||
/* our client */
|
||||
GstJackAudioClient *client;
|
||||
|
|
Loading…
Reference in a new issue