568ec43b09242982428e682367b8437e5a62495b
[alsa-plugins.git] / jack / pcm_jack.c
1 /*
2  *  PCM - JACK plugin
3  *
4  *  Copyright (c) 2003 by Maarten de Boer <mdeboer@iua.upf.es>
5  *                2005 Takashi Iwai <tiwai@suse.de>
6  *
7  *   This library is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU Lesser General Public License as
9  *   published by the Free Software Foundation; either version 2.1 of
10  *   the License, or (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU Lesser General Public License for more details.
16  *
17  *   You should have received a copy of the GNU Lesser General Public
18  *   License along with this library; if not, write to the Free Software
19  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
20  *
21  */
22
23 #include <byteswap.h>
24 #include <sys/shm.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <jack/jack.h>
28 #include <alsa/asoundlib.h>
29 #include <alsa/pcm_external.h>
30
31 typedef enum _jack_format {
32         SND_PCM_JACK_FORMAT_RAW
33 } snd_pcm_jack_format_t;
34
35 typedef struct {
36         snd_pcm_ioplug_t io;
37
38         int fd;
39         int activated;          /* jack is activated? */
40
41         char **port_names;
42         unsigned int num_ports;
43         unsigned int hw_ptr;
44         unsigned int sample_bits;
45         snd_pcm_uframes_t min_avail;
46
47         unsigned int channels;
48         snd_pcm_channel_area_t *areas;
49
50         jack_port_t **ports;
51         jack_client_t *client;
52 } snd_pcm_jack_t;
53
54 static int snd_pcm_jack_stop(snd_pcm_ioplug_t *io);
55
56 static int pcm_poll_block_check(snd_pcm_ioplug_t *io)
57 {
58         static char buf[32];
59         snd_pcm_sframes_t avail;
60         snd_pcm_jack_t *jack = io->private_data;
61
62         if (io->state == SND_PCM_STATE_RUNNING ||
63             (io->state == SND_PCM_STATE_PREPARED && io->stream == SND_PCM_STREAM_CAPTURE)) {
64                 avail = snd_pcm_avail_update(io->pcm);
65                 if (avail >= 0 && avail < jack->min_avail) {
66                         while (read(io->poll_fd, &buf, sizeof(buf)) == sizeof(buf))
67                                 ;
68                         return 1;
69                 }
70         }
71
72         return 0;
73 }
74
75 static int pcm_poll_unblock_check(snd_pcm_ioplug_t *io)
76 {
77         static char buf[1];
78         snd_pcm_sframes_t avail;
79         snd_pcm_jack_t *jack = io->private_data;
80
81         avail = snd_pcm_avail_update(io->pcm);
82         if (avail < 0 || avail >= jack->min_avail) {
83                 write(jack->fd, &buf, 1);
84                 return 1;
85         }
86
87         return 0;
88 }
89
90 static void snd_pcm_jack_free(snd_pcm_jack_t *jack)
91 {
92         if (jack) {
93                 unsigned int i;
94                 if (jack->client)
95                         jack_client_close(jack->client);
96                 if (jack->port_names) {
97                         for (i = 0; i < jack->num_ports; i++)
98                                 free(jack->port_names[i]);
99                         free(jack->port_names);
100                 }
101                 if (jack->fd >= 0)
102                         close(jack->fd);
103                 if (jack->io.poll_fd >= 0)
104                         close(jack->io.poll_fd);
105                 free(jack->areas);
106                 free(jack);
107         }
108 }
109
110 static int snd_pcm_jack_close(snd_pcm_ioplug_t *io)
111 {
112         snd_pcm_jack_t *jack = io->private_data;
113         snd_pcm_jack_free(jack);
114         return 0;
115 }
116
117 static int snd_pcm_jack_poll_revents(snd_pcm_ioplug_t *io,
118                                      struct pollfd *pfds, unsigned int nfds,
119                                      unsigned short *revents)
120 {
121         assert(pfds && nfds == 1 && revents);
122
123         *revents = pfds[0].revents & ~(POLLIN | POLLOUT);
124         if (pfds[0].revents & POLLIN && !pcm_poll_block_check(io))
125                 *revents |= (io->stream == SND_PCM_STREAM_PLAYBACK) ? POLLOUT : POLLIN;
126         return 0;
127 }
128
129 static snd_pcm_sframes_t snd_pcm_jack_pointer(snd_pcm_ioplug_t *io)
130 {
131         snd_pcm_jack_t *jack = io->private_data;
132         return jack->hw_ptr;
133 }
134
135 static int
136 snd_pcm_jack_process_cb(jack_nframes_t nframes, snd_pcm_ioplug_t *io)
137 {
138         snd_pcm_jack_t *jack = io->private_data;
139         const snd_pcm_channel_area_t *areas;
140         snd_pcm_uframes_t xfer = 0;
141         unsigned int channel;
142         
143         for (channel = 0; channel < io->channels; channel++) {
144                 jack->areas[channel].addr = 
145                         jack_port_get_buffer (jack->ports[channel], nframes);
146                 jack->areas[channel].first = 0;
147                 jack->areas[channel].step = jack->sample_bits;
148         }
149                 
150         if (io->state != SND_PCM_STATE_RUNNING) {
151                 if (io->stream == SND_PCM_STREAM_PLAYBACK) {
152                         for (channel = 0; channel < io->channels; channel++)
153                                 snd_pcm_area_silence(&jack->areas[channel], 0, nframes, io->format);
154                         return 0;
155                 }
156         }
157         
158         areas = snd_pcm_ioplug_mmap_areas(io);
159
160         while (xfer < nframes) {
161                 snd_pcm_uframes_t frames = nframes - xfer;
162                 snd_pcm_uframes_t offset = jack->hw_ptr;
163                 snd_pcm_uframes_t cont = io->buffer_size - offset;
164
165                 if (cont < frames)
166                         frames = cont;
167
168                 for (channel = 0; channel < io->channels; channel++) {
169                         if (io->stream == SND_PCM_STREAM_PLAYBACK)
170                                 snd_pcm_area_copy(&jack->areas[channel], xfer, &areas[channel], offset, frames, io->format);
171                         else
172                                 snd_pcm_area_copy(&areas[channel], offset, &jack->areas[channel], xfer, frames, io->format);
173                 }
174                 
175                 jack->hw_ptr += frames;
176                 jack->hw_ptr %= io->buffer_size;
177                 xfer += frames;
178         }
179
180         pcm_poll_unblock_check(io); /* unblock socket for polling if needed */
181
182         return 0;
183 }
184
185 static int snd_pcm_jack_prepare(snd_pcm_ioplug_t *io)
186 {
187         snd_pcm_jack_t *jack = io->private_data;
188         unsigned int i;
189         snd_pcm_sw_params_t *swparams;
190         int err;
191
192         jack->hw_ptr = 0;
193
194         jack->min_avail = io->period_size;
195         snd_pcm_sw_params_alloca(&swparams);
196         err = snd_pcm_sw_params_current(io->pcm, swparams);
197         if (err == 0) {
198                 snd_pcm_sw_params_get_avail_min(swparams, &jack->min_avail);
199         }
200
201         /* deactivate jack connections if this is XRUN recovery */
202         snd_pcm_jack_stop(io);
203
204         if (io->stream == SND_PCM_STREAM_PLAYBACK)
205                 pcm_poll_unblock_check(io); /* playback pcm initially accepts writes */
206         else
207                 pcm_poll_block_check(io); /* block capture pcm if that's XRUN recovery */
208
209         if (jack->ports)
210                 return 0;
211
212         jack->ports = calloc(io->channels, sizeof(jack_port_t*));
213
214         for (i = 0; i < io->channels; i++) {
215                 char port_name[32];
216                 if (io->stream == SND_PCM_STREAM_PLAYBACK) {
217
218                         sprintf(port_name, "out_%03d", i);
219                         jack->ports[i] = jack_port_register(jack->client, port_name,
220                                                             JACK_DEFAULT_AUDIO_TYPE,
221                                                             JackPortIsOutput, 0);
222                 } else {
223                         sprintf(port_name, "in_%03d", i);
224                         jack->ports[i] = jack_port_register(jack->client, port_name,
225                                                             JACK_DEFAULT_AUDIO_TYPE,
226                                                             JackPortIsInput, 0);
227                 }
228         }
229
230         jack_set_process_callback(jack->client,
231                                   (JackProcessCallback)snd_pcm_jack_process_cb, io);
232         return 0;
233 }
234
235 static int snd_pcm_jack_start(snd_pcm_ioplug_t *io)
236 {
237         snd_pcm_jack_t *jack = io->private_data;
238         unsigned int i;
239         
240         if (jack_activate (jack->client))
241                 return -EIO;
242
243         jack->activated = 1;
244
245         for (i = 0; i < io->channels && i < jack->num_ports; i++) {
246                 if (jack->port_names[i]) {
247                         const char *src, *dst;
248                         if (io->stream == SND_PCM_STREAM_PLAYBACK) {
249                                 src = jack_port_name(jack->ports[i]);
250                                 dst = jack->port_names[i];
251                         } else {
252                                 src = jack->port_names[i];
253                                 dst = jack_port_name(jack->ports[i]);
254                         }
255                         if (jack_connect(jack->client, src, dst)) {
256                                 fprintf(stderr, "cannot connect %s to %s\n", src, dst);
257                                 return -EIO;
258                         }
259                 }
260         }
261         
262         return 0;
263 }
264
265 static int snd_pcm_jack_stop(snd_pcm_ioplug_t *io)
266 {
267         snd_pcm_jack_t *jack = io->private_data;
268         
269         if (jack->activated) {
270                 jack_deactivate(jack->client);
271                 jack->activated = 0;
272         }
273 #if 0
274         unsigned i;
275         for (i = 0; i < io->channels; i++) {
276                 if (jack->ports[i]) {
277                         jack_port_unregister(jack->client, jack->ports[i]);
278                         jack->ports[i] = NULL;
279                 }
280         }
281 #endif
282         return 0;
283 }
284
285 static snd_pcm_ioplug_callback_t jack_pcm_callback = {
286         .close = snd_pcm_jack_close,
287         .start = snd_pcm_jack_start,
288         .stop = snd_pcm_jack_stop,
289         .pointer = snd_pcm_jack_pointer,
290         .prepare = snd_pcm_jack_prepare,
291         .poll_revents = snd_pcm_jack_poll_revents,
292 };
293
294 #define ARRAY_SIZE(ary) (sizeof(ary)/sizeof(ary[0]))
295
296 static int jack_set_hw_constraint(snd_pcm_jack_t *jack)
297 {
298         unsigned int access_list[] = {
299                 SND_PCM_ACCESS_MMAP_INTERLEAVED,
300                 SND_PCM_ACCESS_MMAP_NONINTERLEAVED,
301                 SND_PCM_ACCESS_RW_INTERLEAVED,
302                 SND_PCM_ACCESS_RW_NONINTERLEAVED
303         };
304         unsigned int format = SND_PCM_FORMAT_FLOAT;
305         unsigned int rate = jack_get_sample_rate(jack->client);
306         int err;
307
308         jack->sample_bits = snd_pcm_format_physical_width(format);
309         if ((err = snd_pcm_ioplug_set_param_list(&jack->io, SND_PCM_IOPLUG_HW_ACCESS,
310                                                  ARRAY_SIZE(access_list), access_list)) < 0 ||
311             (err = snd_pcm_ioplug_set_param_list(&jack->io, SND_PCM_IOPLUG_HW_FORMAT,
312                                                  1, &format)) < 0 ||
313             (err = snd_pcm_ioplug_set_param_minmax(&jack->io, SND_PCM_IOPLUG_HW_CHANNELS,
314                                                    jack->channels, jack->channels)) < 0 ||
315             (err = snd_pcm_ioplug_set_param_minmax(&jack->io, SND_PCM_IOPLUG_HW_RATE,
316                                                    rate, rate)) < 0 ||
317             (err = snd_pcm_ioplug_set_param_minmax(&jack->io, SND_PCM_IOPLUG_HW_PERIOD_BYTES,
318                                                    128, 64*1024)) < 0 ||
319             (err = snd_pcm_ioplug_set_param_minmax(&jack->io, SND_PCM_IOPLUG_HW_PERIODS,
320                                                    2, 64)) < 0)
321                 return err;
322
323         return 0;
324 }
325
326 static int parse_ports(snd_pcm_jack_t *jack, snd_config_t *conf)
327 {
328         snd_config_iterator_t i, next;
329         char **ports = NULL;
330         unsigned int cnt = 0;
331         unsigned int channel;
332
333         if (conf) {
334                 snd_config_for_each(i, next, conf) {
335                         snd_config_t *n = snd_config_iterator_entry(i);
336                         const char *id;
337                         if (snd_config_get_id(n, &id) < 0)
338                                 continue;
339                         cnt++;
340                 }
341                 jack->port_names = ports = calloc(cnt, sizeof(char*));
342                 if (ports == NULL)
343                         return -ENOMEM;
344                 jack->num_ports = cnt;
345                 snd_config_for_each(i, next, conf) {
346                         snd_config_t *n = snd_config_iterator_entry(i);
347                         const char *id;
348                         const char *port;
349
350                         if (snd_config_get_id(n, &id) < 0)
351                                 continue;
352                         channel = atoi(id);
353                         if (snd_config_get_string(n, &port) < 0)
354                                 continue;
355                         ports[channel] = port ? strdup(port) : NULL;
356                 }
357         }
358         return 0;
359 }
360
361 static int make_nonblock(int fd)
362 {
363         int fl;
364
365         if ((fl = fcntl(fd, F_GETFL)) < 0)
366                 return fl;
367
368         if (fl & O_NONBLOCK)
369                 return 0;
370
371         return fcntl(fd, F_SETFL, fl | O_NONBLOCK);
372 }
373
374 static int snd_pcm_jack_open(snd_pcm_t **pcmp, const char *name,
375                              const char *client_name,
376                              snd_config_t *playback_conf,
377                              snd_config_t *capture_conf,
378                              snd_pcm_stream_t stream, int mode)
379 {
380         snd_pcm_jack_t *jack;
381         int err;
382         int fd[2];
383         static unsigned int num = 0;
384         char jack_client_name[32];
385         
386         assert(pcmp);
387         jack = calloc(1, sizeof(*jack));
388         if (!jack)
389                 return -ENOMEM;
390
391         jack->fd = -1;
392         jack->io.poll_fd = -1;
393
394         err = parse_ports(jack, stream == SND_PCM_STREAM_PLAYBACK ?
395                           playback_conf : capture_conf);
396         if (err) {
397                 snd_pcm_jack_free(jack);
398                 return err;
399         }
400
401         jack->channels = jack->num_ports;
402         if (jack->channels == 0) {
403                 SNDERR("define the %s_ports section",
404                        stream == SND_PCM_STREAM_PLAYBACK ? "playback" : "capture");
405                 snd_pcm_jack_free(jack);
406                 return -EINVAL;
407         }
408
409         if (client_name == NULL)
410                 err = snprintf(jack_client_name, sizeof(jack_client_name),
411                                "alsa-jack.%s%s.%d.%d", name,
412                                stream == SND_PCM_STREAM_PLAYBACK ? "P" : "C",
413                                getpid(), num++);
414         else
415                 err = snprintf(jack_client_name, sizeof(jack_client_name),
416                                "%s", client_name);
417
418         if (err >= (int)sizeof(jack_client_name)) {
419                 fprintf(stderr, "%s: WARNING: JACK client name '%s' truncated to %d characters, might not be unique\n",
420                         __func__, jack_client_name, (int)strlen(jack_client_name));
421         }
422
423         jack->client = jack_client_open(jack_client_name, JackNoStartServer, NULL);
424
425         if (jack->client == 0) {
426                 snd_pcm_jack_free(jack);
427                 return -ENOENT;
428         }
429
430         jack->areas = calloc(jack->channels, sizeof(snd_pcm_channel_area_t));
431         if (! jack->areas) {
432                 snd_pcm_jack_free(jack);
433                 return -ENOMEM;
434         }
435
436         socketpair(AF_LOCAL, SOCK_STREAM, 0, fd);
437         
438         make_nonblock(fd[0]);
439         make_nonblock(fd[1]);
440
441         jack->fd = fd[0];
442
443         jack->io.version = SND_PCM_IOPLUG_VERSION;
444         jack->io.name = "ALSA <-> JACK PCM I/O Plugin";
445         jack->io.callback = &jack_pcm_callback;
446         jack->io.private_data = jack;
447         jack->io.poll_fd = fd[1];
448         jack->io.poll_events = POLLIN;
449         jack->io.mmap_rw = 1;
450
451         err = snd_pcm_ioplug_create(&jack->io, name, stream, mode);
452         if (err < 0) {
453                 snd_pcm_jack_free(jack);
454                 return err;
455         }
456
457         err = jack_set_hw_constraint(jack);
458         if (err < 0) {
459                 snd_pcm_ioplug_delete(&jack->io);
460                 return err;
461         }
462
463         *pcmp = jack->io.pcm;
464
465         return 0;
466 }
467
468
469 SND_PCM_PLUGIN_DEFINE_FUNC(jack)
470 {
471         snd_config_iterator_t i, next;
472         snd_config_t *playback_conf = NULL;
473         snd_config_t *capture_conf = NULL;
474         const char *client_name = NULL;
475         int err;
476         
477         snd_config_for_each(i, next, conf) {
478                 snd_config_t *n = snd_config_iterator_entry(i);
479                 const char *id;
480                 if (snd_config_get_id(n, &id) < 0)
481                         continue;
482                 if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0 || strcmp(id, "hint") == 0)
483                         continue;
484                 if (strcmp(id, "name") == 0) {
485                         snd_config_get_string(n, &client_name);
486                         continue;
487                 }
488                 if (strcmp(id, "playback_ports") == 0) {
489                         if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
490                                 SNDERR("Invalid type for %s", id);
491                                 return -EINVAL;
492                         }
493                         playback_conf = n;
494                         continue;
495                 }
496                 if (strcmp(id, "capture_ports") == 0) {
497                         if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
498                                 SNDERR("Invalid type for %s", id);
499                                 return -EINVAL;
500                         }
501                         capture_conf = n;
502                         continue;
503                 }
504                 SNDERR("Unknown field %s", id);
505                 return -EINVAL;
506         }
507
508         err = snd_pcm_jack_open(pcmp, name, client_name, playback_conf, capture_conf, stream, mode);
509
510         return err;
511 }
512
513 SND_PCM_PLUGIN_SYMBOL(jack);