From patchwork Tue Jan 29 14:30:56 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Timo Wischer X-Patchwork-Id: 10786413 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B79E413B4 for ; Tue, 29 Jan 2019 14:31:40 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A3EAC2C8D7 for ; Tue, 29 Jan 2019 14:31:40 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A204B2C7F4; Tue, 29 Jan 2019 14:31:40 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C9AC92C8E6 for ; Tue, 29 Jan 2019 14:31:39 +0000 (UTC) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id A42582674B9; Tue, 29 Jan 2019 15:31:34 +0100 (CET) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 48F9F26757B; Tue, 29 Jan 2019 15:31:32 +0100 (CET) Received: from smtp1.de.adit-jv.com (smtp1.de.adit-jv.com [93.241.18.167]) by alsa0.perex.cz (Postfix) with ESMTP id 5C44B2674B9; Tue, 29 Jan 2019 15:31:29 +0100 (CET) Received: from localhost (smtp1.de.adit-jv.com [127.0.0.1]) by smtp1.de.adit-jv.com (Postfix) with ESMTP id 3A40B3C00C3; Tue, 29 Jan 2019 15:31:29 +0100 (CET) Received: from smtp1.de.adit-jv.com ([127.0.0.1]) by localhost (smtp1.de.adit-jv.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id LvZzu26zrIjf; Tue, 29 Jan 2019 15:31:22 +0100 (CET) Received: from HI2EXCH01.adit-jv.com (hi2exch01.adit-jv.com [10.72.92.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by smtp1.de.adit-jv.com (Postfix) with ESMTPS id 977C23C013F; Tue, 29 Jan 2019 15:31:20 +0100 (CET) Received: from vmlxhi-087.adit-jv.com (10.72.93.172) by HI2EXCH01.adit-jv.com (10.72.92.24) with Microsoft SMTP Server (TLS) id 14.3.435.0; Tue, 29 Jan 2019 15:31:20 +0100 From: To: , Date: Tue, 29 Jan 2019 15:30:56 +0100 Message-ID: <1548772256-30547-3-git-send-email-twischer@de.adit-jv.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1548772256-30547-1-git-send-email-twischer@de.adit-jv.com> References: <1548772256-30547-1-git-send-email-twischer@de.adit-jv.com> MIME-Version: 1.0 X-Originating-IP: [10.72.93.172] Cc: Timo Wischer , alsa-devel@alsa-project.org Subject: [alsa-devel] [PATCH - JACK plugin v2 2/2] jack: Support to connect multiple JACK ports with same ALSA channel X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP From: Timo Wischer The following example will connect ALSA channel 0 to JACK port "system:playback_1" and "system:playback_3" and ALSA channel 1 to JACK port "system:playback_2" and "system:playback_4": pcm.jack { type jack playback_ports { 0 [ system:playback_1 system:playback_3 ] 1 [ system:playback_2 system:playback_4 ] } } The old syntax with only one port for one channel is still supported: playback_ports { 0 system:playback_1 1 system:playback_2 } Without this patch an additional JACK client has to be used to automatically connect the second JACK port but this could take some time. Therefore it misses for example the first audio period on the second port. Signed-off-by: Timo Wischer diff --git a/jack/pcm_jack.c b/jack/pcm_jack.c index 724cbc2..5dc78fb 100644 --- a/jack/pcm_jack.c +++ b/jack/pcm_jack.c @@ -31,13 +31,21 @@ #define MAX_PERIODS_MULTIPLE 64 +typedef struct snd_pcm_jack_port_list { + struct snd_pcm_jack_port_list *next; + /* will always be allocated with size of the string. + * See snd_pcm_jack_port_list_add(). + */ + char name[0]; +} snd_pcm_jack_port_list_t; + typedef struct { snd_pcm_ioplug_t io; int fd; int activated; /* jack is activated? */ - char **port_names; + snd_pcm_jack_port_list_t **port_names; unsigned int num_ports; snd_pcm_uframes_t boundary; snd_pcm_uframes_t hw_ptr; @@ -63,6 +71,29 @@ static snd_pcm_uframes_t snd_pcm_ioplug_avail(const snd_pcm_ioplug_t *io, } #endif +/* adds one element to the head of the list */ +static int snd_pcm_jack_port_list_add(snd_pcm_jack_t *jack, + const unsigned int channel, + const char * const name) +{ + const size_t name_size = strlen(name) + 1; + const size_t elem_size = sizeof(snd_pcm_jack_port_list_t) + name_size; + snd_pcm_jack_port_list_t * const elem = calloc(1, elem_size); + + if (elem == NULL) + return -ENOMEM; + + /* Above it is guaranteed that elem->name is big enough for the size of + * name because strlen(name) + 1 will be used to allocate the buffer. + */ + strcpy(elem->name, name); + elem->next = jack->port_names[channel]; + + jack->port_names[channel] = elem; + + return 0; +} + static int pcm_poll_block_check(snd_pcm_ioplug_t *io) { static char buf[32]; @@ -113,9 +144,19 @@ static void snd_pcm_jack_free(snd_pcm_jack_t *jack) if (jack->port_names) { unsigned int i; - for (i = 0; i < jack->num_ports; i++) - free(jack->port_names[i]); + for (i = 0; i < jack->num_ports; i++) { + snd_pcm_jack_port_list_t *port_elem = + jack->port_names[i]; + + while (port_elem != NULL) { + snd_pcm_jack_port_list_t *next_port_elem = + port_elem->next; + free(port_elem); + port_elem = next_port_elem; + } + } free(jack->port_names); + jack->port_names = NULL; } if (jack->fd >= 0) close(jack->fd); @@ -298,17 +339,22 @@ static int snd_pcm_jack_prepare(snd_pcm_ioplug_t *io) jack->activated = 1; for (i = 0; i < io->channels && i < jack->num_ports; i++) { - if (jack->port_names[i]) { + const char * const own_port = jack_port_name(jack->ports[i]); + snd_pcm_jack_port_list_t *port_elem; + + for (port_elem = jack->port_names[i]; port_elem != NULL; + port_elem = port_elem->next) { const char *src, *dst; if (io->stream == SND_PCM_STREAM_PLAYBACK) { - src = jack_port_name(jack->ports[i]); - dst = jack->port_names[i]; + src = own_port; + dst = port_elem->name; } else { - src = jack->port_names[i]; - dst = jack_port_name(jack->ports[i]); + src = port_elem->name; + dst = own_port; } if (jack_connect(jack->client, src, dst)) { - fprintf(stderr, "cannot connect %s to %s\n", src, dst); + fprintf(stderr, "cannot connect %s to %s\n", + src, dst); return -EIO; } } @@ -416,7 +462,7 @@ static int jack_set_hw_constraint(snd_pcm_jack_t *jack) static int parse_ports(snd_pcm_jack_t *jack, snd_config_t *conf) { snd_config_iterator_t i, next; - char **ports = NULL; + snd_pcm_jack_port_list_t **ports = NULL; unsigned int cnt = 0; unsigned int channel; @@ -431,7 +477,7 @@ static int parse_ports(snd_pcm_jack_t *jack, snd_config_t *conf) continue; cnt++; } - jack->port_names = ports = calloc(cnt, sizeof(char*)); + jack->port_names = ports = calloc(cnt, sizeof(jack->port_names[0])); if (ports == NULL) return -ENOMEM; jack->num_ports = cnt; @@ -439,13 +485,31 @@ static int parse_ports(snd_pcm_jack_t *jack, snd_config_t *conf) snd_config_t *n = snd_config_iterator_entry(i); const char *id; const char *port; + int err; if (snd_config_get_id(n, &id) < 0) continue; channel = atoi(id); - if (snd_config_get_string(n, &port) < 0) + if (snd_config_get_string(n, &port) >= 0) { + err = snd_pcm_jack_port_list_add(jack, channel, port); + if (err < 0) + return err; + } else if (snd_config_get_type(n) == SND_CONFIG_TYPE_COMPOUND) { + snd_config_iterator_t k, next_k; + + snd_config_for_each(k, next_k, n) { + snd_config_t *m = snd_config_iterator_entry(k); + + if (snd_config_get_string(m, &port) < 0) + continue; + err = snd_pcm_jack_port_list_add(jack, channel, + port); + if (err < 0) + return err; + } + } else { continue; - ports[channel] = port ? strdup(port) : NULL; + } } return 0;