de9c46e101593bff2da1955924d41a8f6553156c
[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->ports);
107                 free(jack);
108         }
109 }
110
111 static int snd_pcm_jack_close(snd_pcm_ioplug_t *io)
112 {
113         snd_pcm_jack_t *jack = io->private_data;
114         snd_pcm_jack_free(jack);
115         return 0;
116 }
117
118 static int snd_pcm_jack_poll_revents(snd_pcm_ioplug_t *io,
119                                      struct pollfd *pfds, unsigned int nfds,
120                                      unsigned short *revents)
121 {
122         assert(pfds && nfds == 1 && revents);
123
124         *revents = pfds[0].revents & ~(POLLIN | POLLOUT);
125         if (pfds[0].revents & POLLIN && !pcm_poll_block_check(io))
126                 *revents |= (io->stream == SND_PCM_STREAM_PLAYBACK) ? POLLOUT : POLLIN;
127         return 0;
128 }
129
130 static snd_pcm_sframes_t snd_pcm_jack_pointer(snd_pcm_ioplug_t *io)
131 {
132         snd_pcm_jack_t *jack = io->private_data;
133         return jack->hw_ptr;
134 }
135
136 static int
137 snd_pcm_jack_process_cb(jack_nframes_t nframes, snd_pcm_ioplug_t *io)
138 {
139         snd_pcm_jack_t *jack = io->private_data;
140         const snd_pcm_channel_area_t *areas;
141         snd_pcm_uframes_t xfer = 0;
142         unsigned int channel;
143         
144         for (channel = 0; channel < io->channels; channel++) {
145                 jack->areas[channel].addr = 
146                         jack_port_get_buffer (jack->ports[channel], nframes);
147                 jack->areas[channel].first = 0;
148                 jack->areas[channel].step = jack->sample_bits;
149         }
150                 
151         if (io->state != SND_PCM_STATE_RUNNING) {
152                 if (io->stream == SND_PCM_STREAM_PLAYBACK) {
153                         for (channel = 0; channel < io->channels; channel++)
154                                 snd_pcm_area_silence(&jack->areas[channel], 0, nframes, io->format);
155                         return 0;
156                 }
157         }
158         
159         areas = snd_pcm_ioplug_mmap_areas(io);
160
161         while (xfer < nframes) {
162                 snd_pcm_uframes_t frames = nframes - xfer;
163                 snd_pcm_uframes_t offset = jack->hw_ptr;
164                 snd_pcm_uframes_t cont = io->buffer_size - offset;
165
166                 if (cont < frames)
167                         frames = cont;
168
169                 for (channel = 0; channel < io->channels; channel++) {
170                         if (io->stream == SND_PCM_STREAM_PLAYBACK)
171                                 snd_pcm_area_copy(&jack->areas[channel], xfer, &areas[channel], offset, frames, io->format);
172                         else
173                                 snd_pcm_area_copy(&areas[channel], offset, &jack->areas[channel], xfer, frames, io->format);
174                 }
175                 
176                 jack->hw_ptr += frames;
177                 jack->hw_ptr %= io->buffer_size;
178                 xfer += frames;
179         }
180
181         pcm_poll_unblock_check(io); /* unblock socket for polling if needed */
182
183         return 0;
184 }
185
186 static int snd_pcm_jack_prepare(snd_pcm_ioplug_t *io)
187 {
188         snd_pcm_jack_t *jack = io->private_data;
189         unsigned int i;
190         snd_pcm_sw_params_t *swparams;
191         int err;
192
193         jack->hw_ptr = 0;
194
195         jack->min_avail = io->period_size;
196         snd_pcm_sw_params_alloca(&swparams);
197         err = snd_pcm_sw_params_current(io->pcm, swparams);
198         if (err == 0) {
199                 snd_pcm_sw_params_get_avail_min(swparams, &jack->min_avail);
200         }
201
202         /* deactivate jack connections if this is XRUN recovery */
203         snd_pcm_jack_stop(io);
204
205         if (io->stream == SND_PCM_STREAM_PLAYBACK)
206                 pcm_poll_unblock_check(io); /* playback pcm initially accepts writes */
207         else
208                 pcm_poll_block_check(io); /* block capture pcm if that's XRUN recovery */
209
210         if (jack->ports)
211                 return 0;
212
213         jack->ports = calloc(io->channels, sizeof(jack_port_t*));
214
215         for (i = 0; i < io->channels; i++) {
216                 char port_name[32];
217                 if (io->stream == SND_PCM_STREAM_PLAYBACK) {
218
219                         sprintf(port_name, "out_%03d", i);
220                         jack->ports[i] = jack_port_register(jack->client, port_name,
221                                                             JACK_DEFAULT_AUDIO_TYPE,
222                                                             JackPortIsOutput, 0);
223                 } else {
224                         sprintf(port_name, "in_%03d", i);
225                         jack->ports[i] = jack_port_register(jack->client, port_name,
226                                                             JACK_DEFAULT_AUDIO_TYPE,
227                                                             JackPortIsInput, 0);
228                 }
229         }
230
231         jack_set_process_callback(jack->client,
232                                   (JackProcessCallback)snd_pcm_jack_process_cb, io);
233         return 0;
234 }
235
236 static int snd_pcm_jack_start(snd_pcm_ioplug_t *io)
237 {
238         snd_pcm_jack_t *jack = io->private_data;
239         unsigned int i;
240         
241         if (jack_activate (jack->client))
242                 return -EIO;
243
244         jack->activated = 1;
245
246         for (i = 0; i < io->channels && i < jack->num_ports; i++) {
247                 if (jack->port_names[i]) {
248                         const char *src, *dst;
249                         if (io->stream == SND_PCM_STREAM_PLAYBACK) {
250                                 src = jack_port_name(jack->ports[i]);
251                                 dst = jack->port_names[i];
252                         } else {
253                                 src = jack->port_names[i];
254                                 dst = jack_port_name(jack->ports[i]);
255                         }
256                         if (jack_connect(jack->client, src, dst)) {
257                                 fprintf(stderr, "cannot connect %s to %s\n", src, dst);
258                                 return -EIO;
259                         }
260                 }
261         }
262         
263         return 0;
264 }
265
266 static int snd_pcm_jack_stop(snd_pcm_ioplug_t *io)
267 {
268         snd_pcm_jack_t *jack = io->private_data;
269         
270         if (jack->activated) {
271                 jack_deactivate(jack->client);
272                 jack->activated = 0;
273         }
274 #if 0
275         unsigned i;
276         for (i = 0; i < io->channels; i++) {
277                 if (jack->ports[i]) {
278                         jack_port_unregister(jack->client, jack->ports[i]);
279                         jack->ports[i] = NULL;
280                 }
281         }
282 #endif
283         return 0;
284 }
285
286 static snd_pcm_ioplug_callback_t jack_pcm_callback = {
287         .close = snd_pcm_jack_close,
288         .start = snd_pcm_jack_start,
289         .stop = snd_pcm_jack_stop,
290         .pointer = snd_pcm_jack_pointer,
291         .prepare = snd_pcm_jack_prepare,
292         .poll_revents = snd_pcm_jack_poll_revents,
293 };
294
295 #define ARRAY_SIZE(ary) (sizeof(ary)/sizeof(ary[0]))
296
297 static int jack_set_hw_constraint(snd_pcm_jack_t *jack)
298 {
299         unsigned int access_list[] = {
300                 SND_PCM_ACCESS_MMAP_INTERLEAVED,
301                 SND_PCM_ACCESS_MMAP_NONINTERLEAVED,
302                 SND_PCM_ACCESS_RW_INTERLEAVED,
303                 SND_PCM_ACCESS_RW_NONINTERLEAVED
304         };
305         unsigned int format = SND_PCM_FORMAT_FLOAT;
306         unsigned int rate = jack_get_sample_rate(jack->client);
307         int err;
308
309         jack->sample_bits = snd_pcm_format_physical_width(format);
310         if ((err = snd_pcm_ioplug_set_param_list(&jack->io, SND_PCM_IOPLUG_HW_ACCESS,
311                                                  ARRAY_SIZE(access_list), access_list)) < 0 ||
312             (err = snd_pcm_ioplug_set_param_list(&jack->io, SND_PCM_IOPLUG_HW_FORMAT,
313                                                  1, &format)) < 0 ||
314             (err = snd_pcm_ioplug_set_param_minmax(&jack->io, SND_PCM_IOPLUG_HW_CHANNELS,
315                                                    jack->channels, jack->channels)) < 0 ||
316             (err = snd_pcm_ioplug_set_param_minmax(&jack->io, SND_PCM_IOPLUG_HW_RATE,
317                                                    rate, rate)) < 0 ||
318             (err = snd_pcm_ioplug_set_param_minmax(&jack->io, SND_PCM_IOPLUG_HW_PERIOD_BYTES,
319                                                    128, 64*1024)) < 0 ||
320             (err = snd_pcm_ioplug_set_param_minmax(&jack->io, SND_PCM_IOPLUG_HW_PERIODS,
321                                                    2, 64)) < 0)
322                 return err;
323
324         return 0;
325 }
326
327 static int parse_ports(snd_pcm_jack_t *jack, snd_config_t *conf)
328 {
329         snd_config_iterator_t i, next;
330         char **ports = NULL;
331         unsigned int cnt = 0;
332         unsigned int channel;
333
334         if (conf) {
335                 snd_config_for_each(i, next, conf) {
336                         snd_config_t *n = snd_config_iterator_entry(i);
337                         const char *id;
338                         if (snd_config_get_id(n, &id) < 0)
339                                 continue;
340                         cnt++;
341                 }
342                 jack->port_names = ports = calloc(cnt, sizeof(char*));
343                 if (ports == NULL)
344                         return -ENOMEM;
345                 jack->num_ports = cnt;
346                 snd_config_for_each(i, next, conf) {
347                         snd_config_t *n = snd_config_iterator_entry(i);
348                         const char *id;
349                         const char *port;
350
351                         if (snd_config_get_id(n, &id) < 0)
352                                 continue;
353                         channel = atoi(id);
354                         if (snd_config_get_string(n, &port) < 0)
355                                 continue;
356                         ports[channel] = port ? strdup(port) : NULL;
357                 }
358         }
359         return 0;
360 }
361
362 static int make_nonblock(int fd)
363 {
364         int fl;
365
366         if ((fl = fcntl(fd, F_GETFL)) < 0)
367                 return fl;
368
369         if (fl & O_NONBLOCK)
370                 return 0;
371
372         return fcntl(fd, F_SETFL, fl | O_NONBLOCK);
373 }
374
375 static int snd_pcm_jack_open(snd_pcm_t **pcmp, const char *name,
376                              const char *client_name,
377                              snd_config_t *playback_conf,
378                              snd_config_t *capture_conf,
379                              snd_pcm_stream_t stream, int mode)
380 {
381         snd_pcm_jack_t *jack;
382         int err;
383         int fd[2];
384         static unsigned int num = 0;
385         char jack_client_name[32];
386         
387         assert(pcmp);
388         jack = calloc(1, sizeof(*jack));
389         if (!jack)
390                 return -ENOMEM;
391
392         jack->fd = -1;
393         jack->io.poll_fd = -1;
394
395         err = parse_ports(jack, stream == SND_PCM_STREAM_PLAYBACK ?
396                           playback_conf : capture_conf);
397         if (err) {
398                 snd_pcm_jack_free(jack);
399                 return err;
400         }
401
402         jack->channels = jack->num_ports;
403         if (jack->channels == 0) {
404                 SNDERR("define the %s_ports section",
405                        stream == SND_PCM_STREAM_PLAYBACK ? "playback" : "capture");
406                 snd_pcm_jack_free(jack);
407                 return -EINVAL;
408         }
409
410         if (client_name == NULL)
411                 err = snprintf(jack_client_name, sizeof(jack_client_name),
412                                "alsa-jack.%s%s.%d.%d", name,
413                                stream == SND_PCM_STREAM_PLAYBACK ? "P" : "C",
414                                getpid(), num++);
415         else
416                 err = snprintf(jack_client_name, sizeof(jack_client_name),
417                                "%s", client_name);
418
419         if (err >= (int)sizeof(jack_client_name)) {
420                 fprintf(stderr, "%s: WARNING: JACK client name '%s' truncated to %d characters, might not be unique\n",
421                         __func__, jack_client_name, (int)strlen(jack_client_name));
422         }
423
424         jack->client = jack_client_open(jack_client_name, JackNoStartServer, NULL);
425
426         if (jack->client == 0) {
427                 snd_pcm_jack_free(jack);
428                 return -ENOENT;
429         }
430
431         jack->areas = calloc(jack->channels, sizeof(snd_pcm_channel_area_t));
432         if (! jack->areas) {
433                 snd_pcm_jack_free(jack);
434                 return -ENOMEM;
435         }
436
437         socketpair(AF_LOCAL, SOCK_STREAM, 0, fd);
438         
439         make_nonblock(fd[0]);
440         make_nonblock(fd[1]);
441
442         jack->fd = fd[0];
443
444         jack->io.version = SND_PCM_IOPLUG_VERSION;
445         jack->io.name = "ALSA <-> JACK PCM I/O Plugin";
446         jack->io.callback = &jack_pcm_callback;
447         jack->io.private_data = jack;
448         jack->io.poll_fd = fd[1];
449         jack->io.poll_events = POLLIN;
450         jack->io.mmap_rw = 1;
451
452         err = snd_pcm_ioplug_create(&jack->io, name, stream, mode);
453         if (err < 0) {
454                 snd_pcm_jack_free(jack);
455                 return err;
456         }
457
458         err = jack_set_hw_constraint(jack);
459         if (err < 0) {
460                 snd_pcm_ioplug_delete(&jack->io);
461                 return err;
462         }
463
464         *pcmp = jack->io.pcm;
465
466         return 0;
467 }
468
469
470 SND_PCM_PLUGIN_DEFINE_FUNC(jack)
471 {
472         snd_config_iterator_t i, next;
473         snd_config_t *playback_conf = NULL;
474         snd_config_t *capture_conf = NULL;
475         const char *client_name = NULL;
476         int err;
477         
478         snd_config_for_each(i, next, conf) {
479                 snd_config_t *n = snd_config_iterator_entry(i);
480                 const char *id;
481                 if (snd_config_get_id(n, &id) < 0)
482                         continue;
483                 if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0 || strcmp(id, "hint") == 0)
484                         continue;
485                 if (strcmp(id, "name") == 0) {
486                         snd_config_get_string(n, &client_name);
487                         continue;
488                 }
489                 if (strcmp(id, "playback_ports") == 0) {
490                         if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
491                                 SNDERR("Invalid type for %s", id);
492                                 return -EINVAL;
493                         }
494                         playback_conf = n;
495                         continue;
496                 }
497                 if (strcmp(id, "capture_ports") == 0) {
498                         if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
499                                 SNDERR("Invalid type for %s", id);
500                                 return -EINVAL;
501                         }
502                         capture_conf = n;
503                         continue;
504                 }
505                 SNDERR("Unknown field %s", id);
506                 return -EINVAL;
507         }
508
509         err = snd_pcm_jack_open(pcmp, name, client_name, playback_conf, capture_conf, stream, mode);
510
511         return err;
512 }
513
514 SND_PCM_PLUGIN_SYMBOL(jack);