From 2598dd510910d3a39eb665216760a705c26ccf50 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 6 Nov 2009 18:55:26 +0100 Subject: output/jack: dynamic destination port list Support up to 16 configured destination ports, that should really be enough for everybody. --- src/output/jack_output_plugin.c | 96 ++++++++++++++++++++++++++++++----------- 1 file changed, 71 insertions(+), 25 deletions(-) (limited to 'src/output/jack_output_plugin.c') diff --git a/src/output/jack_output_plugin.c b/src/output/jack_output_plugin.c index d4aea0f67..14493715f 100644 --- a/src/output/jack_output_plugin.c +++ b/src/output/jack_output_plugin.c @@ -36,6 +36,10 @@ #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "jack" +enum { + MAX_PORTS = 16, +}; + static const size_t sample_size = sizeof(jack_default_audio_sample_t); static const char *const port_names[2] = { @@ -52,7 +56,8 @@ struct jack_data { /* configuration */ - char *destination_ports[2]; + char *destination_ports[MAX_PORTS]; + unsigned num_destination_ports; size_t ringbuffer_size; @@ -217,6 +222,35 @@ mpd_jack_test_default_device(void) return true; } +static unsigned +parse_port_list(int line, const char *source, char **dest, GError **error_r) +{ + char **list = g_strsplit(source, ",", 0); + unsigned n = 0; + + for (n = 0; list[n] != NULL; ++n) { + if (n >= MAX_PORTS) { + g_set_error(error_r, jack_output_quark(), 0, + "too many port names in line %d", + line); + return 0; + } + + dest[n] = list[n]; + } + + g_free(list); + + if (n == 0) { + g_set_error(error_r, jack_output_quark(), 0, + "at least one port name expected in line %d", + line); + return 0; + } + + return n; +} + static void * mpd_jack_init(G_GNUC_UNUSED const struct audio_format *audio_format, const struct config_param *param, GError **error_r) @@ -248,22 +282,13 @@ mpd_jack_init(G_GNUC_UNUSED const struct audio_format *audio_format, } if (value != NULL) { - char **ports = g_strsplit(value, ",", 0); - - if (ports[0] == NULL || ports[1] == NULL || ports[2] != NULL) { - g_set_error(error_r, jack_output_quark(), 0, - "two port names expected in line %d", - param->line); + jd->num_destination_ports = + parse_port_list(param->line, value, + jd->destination_ports, error_r); + if (jd->num_destination_ports == 0) return NULL; - } - - jd->destination_ports[0] = ports[0]; - jd->destination_ports[1] = ports[1]; - - g_free(ports); } else { - jd->destination_ports[0] = NULL; - jd->destination_ports[1] = NULL; + jd->num_destination_ports = 0; } jd->ringbuffer_size = @@ -283,7 +308,7 @@ mpd_jack_finish(void *data) { struct jack_data *jd = data; - for (unsigned i = 0; i < G_N_ELEMENTS(jd->destination_ports); ++i) + for (unsigned i = 0; i < jd->num_destination_ports; ++i) g_free(jd->destination_ports[i]); g_free(jd); @@ -338,7 +363,8 @@ mpd_jack_stop(struct jack_data *jd) static bool mpd_jack_start(struct jack_data *jd, GError **error_r) { - const char *destination_ports[2], **jports; + const char *destination_ports[MAX_PORTS], **jports; + unsigned num_destination_ports; assert(jd->client != NULL); @@ -363,7 +389,7 @@ mpd_jack_start(struct jack_data *jd, GError **error_r) return false; } - if (jd->destination_ports[1] == NULL) { + if (jd->num_destination_ports == 0) { /* no output ports were configured - ask libjack for defaults */ jports = jack_get_ports(jd->client, NULL, NULL, @@ -375,19 +401,39 @@ mpd_jack_start(struct jack_data *jd, GError **error_r) return false; } - destination_ports[0] = jports[0]; - destination_ports[1] = jports[1] != NULL ? jports[1] : jports[0]; - - g_debug("destination_ports: %s %s", jports[0], jports[1]); + assert(*jports != NULL); + + for (num_destination_ports = 0; + num_destination_ports < MAX_PORTS && + jports[num_destination_ports] != NULL; + ++num_destination_ports) { + g_debug("destination_port[%u] = '%s'\n", + num_destination_ports, + jports[num_destination_ports]); + destination_ports[num_destination_ports] = + jports[num_destination_ports]; + } } else { /* use the configured output ports */ - destination_ports[0] = jd->destination_ports[0]; - destination_ports[1] = jd->destination_ports[1]; + num_destination_ports = jd->num_destination_ports; + memcpy(destination_ports, jd->destination_ports, + num_destination_ports * sizeof(*destination_ports)); jports = NULL; } + assert(num_destination_ports > 0); + + if (jd->audio_format.channels == 2 && num_destination_ports == 1) { + /* mix stereo signal on one speaker */ + + destination_ports[1] = destination_ports[0]; + num_destination_ports = 2; + } + + assert(jd->audio_format.channels <= num_destination_ports); + for (unsigned i = 0; i < jd->audio_format.channels; ++i) { int ret; @@ -406,7 +452,7 @@ mpd_jack_start(struct jack_data *jd, GError **error_r) } } - if (jd->audio_format.channels == 1) { + if (jd->audio_format.channels == 1 && num_destination_ports == 2) { /* mono input file: connect the one source channel to the both destination channels */ int ret; -- cgit v1.2.3