OSDN Git Service

Maarten de Boer <mdeboer@iua.upf.es> - JACK plugin patch
authorJaroslav Kysela <perex@perex.cz>
Tue, 18 Feb 2003 17:38:32 +0000 (17:38 +0000)
committerJaroslav Kysela <perex@perex.cz>
Tue, 18 Feb 2003 17:38:32 +0000 (17:38 +0000)
- now multichannel works (before only 1 channel worked). i tested stereo,
  and it works fine.

- i extended the configuration. the jack ports to connect to are now not
hard-coded anymore. instead, they will have to be specified in the
asound.conf, which allows to connect to any other jack client.

my asound.conf now looks like this:

pcm.jackplug {
        type plug
        slave { pcm "jack" }
}

pcm.jack {
        type jack
        playback_ports {
                0 alsa_pcm:playback_1
                1 alsa_pcm:playback_2
        }
        capture_ports {
                0 alsa_pcm:capture_1
                1 alsa_pcm:capture_2
        }
}

include/pcm_plugin.h
src/pcm/pcm_jack.c

index 17f19cf..2f51b34 100644 (file)
@@ -187,6 +187,8 @@ int _snd_pcm_ladspa_open(snd_pcm_t **pcmp, const char *name,
  *  Jack plugin
  */
 int snd_pcm_jack_open(snd_pcm_t **pcmp, const char *name,
+                                       snd_config_t *playback_conf,
+                                       snd_config_t *capture_conf,
                      snd_pcm_stream_t stream, int mode);
 int _snd_pcm_jack_open(snd_pcm_t **pcmp, const char *name,
                        snd_config_t *root, snd_config_t *conf,
index fea11cb..dc66dbd 100644 (file)
  */
 
 #include "config.h"
-#ifdef HAVE_JACK
-#define USE_JACK
-#endif
 
 #include <byteswap.h>
 #include <sys/shm.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include "pcm_local.h"
-#ifdef USE_JACK
 #include <jack/jack.h>
-#endif
-
-#if 1
-#define JACK_PLAYBACK_PORT1    "alsa_pcm:playback_1"
-#define JACK_PLAYBACK_PORT2    "alsa_pcm:playback_2"
-#define JACK_CAPTURE_PORT1     "alsa_pcm:capture_1"
-#define JACK_CAPTURE_PORT2     "alsa_pcm:capture_2"
-#else
-#define JACK_PLAYBACK_PORT1    "alsa_pcm:out_1"
-#define JACK_PLAYBACK_PORT2    "alsa_pcm:out_2"
-#define JACK_CAPTURE_PORT1     "alsa_pcm:in_1"
-#define JACK_CAPTURE_PORT2     "alsa_pcm:in_2"
-#endif
 
 #define PCM_JACK_DEBUG
 
@@ -74,12 +57,16 @@ typedef struct {
        snd_pcm_uframes_t appl_ptr;
        snd_pcm_uframes_t hw_ptr;
 
+       char** playback_ports;
+       char** capture_ports;
+       unsigned int playback_ports_n;
+       unsigned int capture_ports_n;
+
        unsigned int channels;
+       snd_pcm_channel_area_t *areas;
 
-#ifdef USE_JACK
        jack_port_t **ports;
        jack_client_t *client;
-#endif
 } snd_pcm_jack_t;
 
 #endif /* DOC_HIDDEN */
@@ -92,11 +79,20 @@ static int snd_pcm_jack_close(snd_pcm_t *pcm)
 #ifdef PCM_JACK_DEBUG
        printf("snd_pcm_jack_close\n"); fflush(stdout);
 #endif
-#ifdef USE_JACK
        if (jack->client)
+       {
                jack_client_close(jack->client);
-#endif
+               jack->client = 0;
+       }
+
+       if (jack->playback_ports)
+               free(jack->playback_ports);
+       if (jack->capture_ports)
+               free(jack->capture_ports);
+       if (jack->areas)
+               free(jack->areas);
        free(jack);
+
        return err;
 }
 
@@ -198,38 +194,43 @@ static int snd_pcm_jack_delay(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sframes_t
        return 0;
 }
 
-#ifdef USE_JACK
 int
 snd_pcm_jack_process_cb (jack_nframes_t nframes, snd_pcm_t *pcm)
 {
        snd_pcm_jack_t *jack = pcm->private_data;
        const snd_pcm_channel_area_t *areas;
        snd_pcm_uframes_t xfer = 0, samples;
-       snd_pcm_channel_area_t area;    
        char buf[1];
-
+       unsigned int channel;
+       
 #ifdef PCM_JACK_DEBUG
-       printf("PROCESS!\n");
+       printf("PROCESS %d!\n",jack->state);
 #endif
 
-       area.addr = jack_port_get_buffer (jack->ports[0], nframes);
-       area.first = 0;
-       area.step = pcm->sample_bits;
-
+       for (channel = 0; channel < jack->channels; channel++) {
+               jack->areas[channel].addr = 
+                       jack_port_get_buffer (jack->ports[channel], nframes);
+               jack->areas[channel].first = 0;
+               jack->areas[channel].step = pcm->sample_bits;
+       }
+               
        if (jack->state != SND_PCM_STATE_RUNNING) {
-               if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
-                       snd_pcm_area_silence(&area, 0, nframes, pcm->format);
-               return 0;
+               if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
+                       for (channel = 0; channel < jack->channels; channel++) {
+                               snd_pcm_area_silence(&jack->areas[channel], 0, nframes, pcm->format);
+                       }
+                       return 0;
+               }
        }
-
-       areas = snd_pcm_mmap_areas(pcm);
        
+       areas = snd_pcm_mmap_areas(pcm);
+
        while (xfer < nframes)
        {
                snd_pcm_uframes_t frames = nframes - xfer;
                snd_pcm_uframes_t offset = snd_pcm_mmap_hw_offset(pcm);
                snd_pcm_uframes_t cont = pcm->buffer_size - offset;
-               
+
                if (cont < frames)
                        frames = cont;
 
@@ -238,17 +239,20 @@ snd_pcm_jack_process_cb (jack_nframes_t nframes, snd_pcm_t *pcm)
                        (int)offset,(int)jack->hw_ptr,(int)nframes,(int)frames,(int)pcm->buffer_size); fflush(stdout);
 #endif
 
-               if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
-                       snd_pcm_area_copy(&area, xfer, &areas[0], offset, frames, pcm->format);
-               } else {
-                       snd_pcm_area_copy(&areas[0], offset, &area, xfer, frames, pcm->format);
+               for (channel = 0; channel < jack->channels; channel++)
+               {
+                       if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
+                               snd_pcm_area_copy(&jack->areas[channel], xfer, &areas[channel], offset, frames, pcm->format);
+                       } else {
+                               snd_pcm_area_copy(&areas[channel], offset, &jack->areas[channel], xfer, frames, pcm->format);
+                       }
                }
                
                snd_pcm_mmap_hw_forward(pcm,frames);
                xfer += frames;
        }
 
-        if (pcm->stop_threshold < pcm->boundary) {
+       if (pcm->stop_threshold < pcm->boundary) {
                samples = snd_pcm_mmap_avail(pcm);
                if (samples >= pcm->stop_threshold) {
                        gettimeofday(&jack->trigger_tstamp, 0);
@@ -256,7 +260,7 @@ snd_pcm_jack_process_cb (jack_nframes_t nframes, snd_pcm_t *pcm)
                        jack->avail_max = samples;
                }
        }
-                               
+                                       
        write(jack->fd,buf,1); /* for polling */
 
 #ifdef PCM_JACK_DEBUG
@@ -265,7 +269,6 @@ snd_pcm_jack_process_cb (jack_nframes_t nframes, snd_pcm_t *pcm)
        
        return 0;      
 }
-#endif
 
 static int snd_pcm_jack_prepare(snd_pcm_t *pcm)
 {
@@ -281,7 +284,6 @@ static int snd_pcm_jack_prepare(snd_pcm_t *pcm)
 
        jack->appl_ptr = jack->hw_ptr = 0;
 
-#ifdef USE_JACK
        jack->ports = calloc (pcm->channels, sizeof(jack_port_t*));
        for (i = 0; i < pcm->channels; i++)
        {
@@ -329,53 +331,48 @@ static int snd_pcm_jack_start(snd_pcm_t *pcm)
        jack->activated = 1;
 
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
-               for (i = 0; i < pcm->channels; i++)
-               {
-                       if (jack_connect (jack->client, jack_port_name (jack->ports[i]), JACK_PLAYBACK_PORT1))
-                       {
-                               fprintf (stderr, "cannot connect output ports\n");
-                               return -EIO;
-                       }else{
-#ifdef PCM_JACK_DEBUG
-                               printf("connected %s to alsa_pcm:playback_1",jack_port_name(jack->ports[i]));
-#endif
-                       }
-                       if (jack_connect (jack->client, jack_port_name (jack->ports[i]),JACK_PLAYBACK_PORT2))
-                       {
-                               fprintf (stderr, "cannot connect output ports\n");
-                               return -EIO;
-                       }else{
+               for (i = 0; i < pcm->channels && i < jack->playback_ports_n; i++)
+               {       
+                       if ( jack->playback_ports[i]) {
+                               if (jack_connect (jack->client, 
+                                       jack_port_name (jack->ports[i]), 
+                                       jack->playback_ports[i]))
+                               {
+                                       fprintf(stderr, "cannot connect %s to %s",
+                                               jack_port_name(jack->ports[i]),
+                                               jack->playback_ports[i]);
+                                       return -EIO;
+                               }
 #ifdef PCM_JACK_DEBUG
-                               printf("connected %s to alsa_pcm:playback_2",jack_port_name(jack->ports[i]));
+                               printf("connected %s to %s\n",
+                                       jack_port_name(jack->ports[i]),
+                                       jack->playback_ports[i]);
+                               fflush(stdout);
 #endif
                        }
                }
-       } else {
-               for (i = 0; i < pcm->channels; i++)
-               {
-                       if (jack_connect (jack->client, 
-                               JACK_CAPTURE_PORT1,jack_port_name (jack->ports[i])))
-                       {
-                               fprintf (stderr, "cannot connect input ports\n");
-                               return -EIO;
-                       }else{
-#ifdef PCM_JACK_DEBUG
-                               printf("connected %s to alsa_pcm:capture_1",jack_port_name(jack->ports[i]));
-#endif
-                       }
-                       if (jack_connect (jack->client, 
-                               JACK_CAPTURE_PORT2,jack_port_name (jack->ports[i])))
-                       {
-                               fprintf (stderr, "cannot connect input ports\n");
-                               return -EIO;
-                       }else{
+       }else{
+               for (i = 0; i < pcm->channels && i < jack->capture_ports_n; i++)
+               {       
+                       if ( jack->capture_ports[i]) {
+                               if (jack_connect (jack->client, 
+                                       jack->capture_ports[i],
+                                       jack_port_name (jack->ports[i])))
+                               {
+                                       fprintf(stderr, "cannot connect %s to %s",
+                                               jack->capture_ports[i],
+                                               jack_port_name(jack->ports[i]));
+                                       return -EIO;
+                               }
 #ifdef PCM_JACK_DEBUG
-                               printf("connected %s to alsa_pcm:capture_2",jack_port_name(jack->ports[i]));
+                               printf("connected %s to %s\n",
+                                       jack->capture_ports[i],
+                                       jack_port_name(jack->ports[i]));
+                               fflush(stdout);
 #endif
                        }
                }
        }
-#endif
        
        jack->state = SND_PCM_STATE_RUNNING;
 
@@ -385,7 +382,6 @@ static int snd_pcm_jack_start(snd_pcm_t *pcm)
 static int snd_pcm_jack_drop(snd_pcm_t *pcm)
 {
        snd_pcm_jack_t *jack = pcm->private_data;
-       unsigned int i;
        
 #ifdef PCM_JACK_DEBUG
        printf("snd_pcm_jack_drop\n"); fflush(stdout);
@@ -614,6 +610,46 @@ static snd_pcm_fast_ops_t snd_pcm_jack_fast_ops = {
        mmap_commit: snd_pcm_jack_mmap_commit,
 };
 
+static int parse_ports(snd_config_t *conf,char*** ret_ports,int *ret_n)
+{
+       snd_config_iterator_t i, next;
+       char** ports = NULL;
+       unsigned int cnt = 0;
+       unsigned int channel;
+
+       if (conf) {
+               snd_config_for_each(i, next, conf) {
+                       snd_config_t *n = snd_config_iterator_entry(i);
+                       const char *id;
+                       if (snd_config_get_id(n, &id) < 0)
+                               continue;
+                       cnt++;
+               }
+               ports = calloc(cnt,sizeof(char*));
+               for (channel = 0; channel < cnt; channel++)
+                       ports[channel] = NULL;
+               
+               snd_config_for_each(i, next, conf) {
+                       snd_config_t *n = snd_config_iterator_entry(i);
+                       const char *id;
+                       const char *port;
+
+                       if (snd_config_get_id(n, &id) < 0)
+                               continue;
+
+                       channel = atoi(id);
+
+                       if (snd_config_get_string(n, &port) < 0)
+                               continue;
+
+                       ports[channel] = port ? strdup(port) : NULL;
+               }
+       }
+       *ret_ports = ports;
+       *ret_n = cnt;
+       return 0;
+}
+
 /**
  * \brief Creates a new jack PCM
  * \param pcmp Returns created PCM handle
@@ -626,6 +662,8 @@ static snd_pcm_fast_ops_t snd_pcm_jack_fast_ops = {
  *          changed in future.
  */
 int snd_pcm_jack_open(snd_pcm_t **pcmp, const char *name,
+       snd_config_t *playback_conf,
+       snd_config_t *capture_conf,
        snd_pcm_stream_t stream, int mode)
 {
        snd_pcm_t *pcm;
@@ -634,31 +672,53 @@ int snd_pcm_jack_open(snd_pcm_t **pcmp, const char *name,
        int fd[2];
        
        assert(pcmp);
+#ifdef PCM_JACK_DEBUG
        printf("snd_pcm_jack_open\n"); fflush(stdout);
+#endif
        jack = calloc(1, sizeof(snd_pcm_jack_t));
        if (!jack) {
                return -ENOMEM;
        }
-       jack->channels = 2;     /* FIXME: should be configurable */
 
-#ifdef USE_JACK
-       if (stream == SND_PCM_STREAM_PLAYBACK)
+       jack->playback_ports = NULL;
+       jack->playback_ports_n = 0;
+
+       jack->capture_ports = NULL;
+       jack->capture_ports_n = 0;
+       
+       err = parse_ports(playback_conf,
+               &jack->playback_ports,&jack->playback_ports_n);
+       if (err)
+               goto _free;
+
+       err = parse_ports(capture_conf,
+               &jack->capture_ports,&jack->capture_ports_n);
+       if (err)
+               goto _free;
+
+       if (stream == SND_PCM_STREAM_PLAYBACK) {
+               jack->channels = jack->playback_ports_n;
                jack->client = jack_client_new("alsaP");
-       else
+       }
+       else {
+               jack->channels = jack->capture_ports_n;
                jack->client = jack_client_new("alsaC");
-       
-       if (jack->client==0)
-               return -ENOENT; 
-#endif
+       }
 
+
+       if (jack->client==0) {
+               err = -ENOENT;  
+               goto _free;
+       }
+       
        jack->state = SND_PCM_STATE_OPEN;
 
        err = snd_pcm_new(&pcm, SND_PCM_TYPE_JACK, name, stream, mode);
        
        if (err < 0) {
-               free(jack);
-               return err;
+               goto _free;
        }
+
        pcm->ops = &snd_pcm_jack_ops;
        pcm->fast_ops = &snd_pcm_jack_fast_ops;
        pcm->private_data = jack;
@@ -671,11 +731,35 @@ int snd_pcm_jack_open(snd_pcm_t **pcmp, const char *name,
        pcm->poll_fd = fd[1];
        pcm->poll_events = POLLIN;
 
+       jack->areas = calloc(jack->channels,sizeof(snd_pcm_channel_area_t));
+
        snd_pcm_set_hw_ptr(pcm, &jack->hw_ptr, -1, 0);
        snd_pcm_set_appl_ptr(pcm, &jack->appl_ptr, -1, 0);
        *pcmp = pcm;
 
        return 0;
+
+_free:
+       if (jack) {
+               if (jack->playback_ports)
+               {
+                       unsigned int k;
+                       for (k = 0; k < jack->playback_ports_n; k++)
+                               if (jack->playback_ports[k])
+                                       free(jack->playback_ports[k]);
+                       free(jack->playback_ports);
+               }
+               if (jack->capture_ports)
+               {
+                       unsigned int k;
+                       for (k = 0; k < jack->capture_ports_n; k++)
+                               if (jack->capture_ports[k])
+                                       free(jack->capture_ports[k]);
+                       free(jack->capture_ports);
+               }
+               free(jack);
+       }
+       return err;
 }
 
 /*! \page pcm_plugins
@@ -702,6 +786,10 @@ int _snd_pcm_jack_open(snd_pcm_t **pcmp, const char *name,
                       snd_pcm_stream_t stream, int mode)
 {
        snd_config_iterator_t i, next;
+       snd_config_t *playback_conf = NULL;
+       snd_config_t *capture_conf = NULL;
+       int err;
+       
        snd_config_for_each(i, next, conf) {
                snd_config_t *n = snd_config_iterator_entry(i);
                const char *id;
@@ -709,10 +797,32 @@ int _snd_pcm_jack_open(snd_pcm_t **pcmp, const char *name,
                        continue;
                if (snd_pcm_conf_generic_id(id))
                        continue;
+               if (strcmp(id, "playback_ports") == 0) {
+                       if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
+                               SNDERR("Invalid type for %s", id);
+                               return -EINVAL;
+                       }
+                       playback_conf = n;
+                       continue;
+               }
+               if (strcmp(id, "capture_ports") == 0) {
+                       if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
+                               SNDERR("Invalid type for %s", id);
+                               return -EINVAL;
+                       }
+                       capture_conf = n;
+                       continue;
+               }
                SNDERR("Unknown field %s", id);
                return -EINVAL;
        }
-       return snd_pcm_jack_open(pcmp, name, stream, mode);
+
+       err = snd_pcm_jack_open(pcmp, name, 
+               playback_conf,
+               capture_conf,
+               stream, mode);
+               
+       return err;
 }
 #ifndef DOC_HIDDEN
 SND_DLSYM_BUILD_VERSION(_snd_pcm_jack_open, SND_PCM_DLSYM_VERSION);