]> git.alsa-project.org Git - alsa-plugins.git/blob - jack/pcm_jack.c
41c6c5adc5419a81fe7eeee64952283941f6a1ed
[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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #define _GNU_SOURCE
24 #include <stdbool.h>
25 #include <errno.h>
26 #include <sys/shm.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <jack/jack.h>
30 #include <alsa/asoundlib.h>
31 #include <alsa/pcm_external.h>
32 #include <pthread.h>
33
34 #define MAX_PERIODS_MULTIPLE 64
35
36 typedef struct snd_pcm_jack_port_list {
37         struct snd_pcm_jack_port_list *next;
38         /* will always be allocated with size of the string.
39          * See snd_pcm_jack_port_list_add().
40          */
41         char name[0];
42 } snd_pcm_jack_port_list_t;
43
44 typedef struct {
45         snd_pcm_ioplug_t io;
46
47         int fd;
48         int activated;          /* jack is activated? */
49         pthread_mutex_t running_mutex;
50         int running;            /* jack is running? */
51
52         snd_pcm_jack_port_list_t **port_names;
53         unsigned int num_ports;
54         snd_pcm_uframes_t boundary;
55         snd_pcm_uframes_t hw_ptr;
56         unsigned int sample_bits;
57         snd_pcm_uframes_t min_avail;
58         int use_period_alignment;
59
60         snd_pcm_channel_area_t *areas;
61
62         jack_port_t **ports;
63         jack_client_t *client;
64
65         /* JACK thread -> ALSA thread */
66         bool xrun_detected;
67 } snd_pcm_jack_t;
68
69 /* snd_pcm_ioplug_avail() was introduced after alsa-lib 1.1.6 */
70 #if SND_LIB_VERSION < 0x10107
71 static snd_pcm_uframes_t snd_pcm_ioplug_avail(const snd_pcm_ioplug_t *io,
72                                               const snd_pcm_uframes_t hw_ptr,
73                                               const snd_pcm_uframes_t appl_ptr)
74 {
75         return io->buffer_size - snd_pcm_ioplug_hw_avail(io, hw_ptr, appl_ptr);
76 }
77 #endif
78
79 /* adds one element to the head of the list */
80 static int snd_pcm_jack_port_list_add(snd_pcm_jack_t *jack,
81                                       const unsigned int channel,
82                                       const char * const name)
83 {
84         const size_t name_size = strlen(name) + 1;
85         const size_t elem_size = sizeof(snd_pcm_jack_port_list_t) + name_size;
86         snd_pcm_jack_port_list_t * const elem = calloc(1, elem_size);
87
88         if (elem == NULL)
89                 return -ENOMEM;
90
91         /* Above it is guaranteed that elem->name is big enough for the size of
92          * name because strlen(name) + 1 will be used to allocate the buffer.
93          */
94         strcpy(elem->name, name);
95         elem->next = jack->port_names[channel];
96
97         jack->port_names[channel] = elem;
98
99         return 0;
100 }
101
102 static int pcm_poll_block_check(snd_pcm_ioplug_t *io)
103 {
104         static char buf[32];
105         snd_pcm_uframes_t avail;
106         snd_pcm_jack_t *jack = io->private_data;
107
108         if (io->state == SND_PCM_STATE_RUNNING ||
109             io->state == SND_PCM_STATE_DRAINING ||
110             (io->state == SND_PCM_STATE_PREPARED && io->stream == SND_PCM_STREAM_CAPTURE)) {
111                 avail = snd_pcm_ioplug_avail(io, jack->hw_ptr, io->appl_ptr);
112                 if (avail < jack->min_avail) {
113                         while (read(io->poll_fd, &buf, sizeof(buf)) == sizeof(buf))
114                                 ;
115                         return 1;
116                 }
117         }
118
119         return 0;
120 }
121
122 static int pcm_poll_unblock_check(snd_pcm_ioplug_t *io)
123 {
124         static char buf[1];
125         snd_pcm_uframes_t avail;
126         snd_pcm_jack_t *jack = io->private_data;
127
128         avail = snd_pcm_ioplug_avail(io, jack->hw_ptr, io->appl_ptr);
129         /* In draining state poll_fd is used to wait
130          * till all pending frames are played.
131          * Therefore it has to be guarantee that a poll event is also generated
132          * if the buffer contains less than min_avail frames
133          */
134         if (avail >= jack->min_avail || io->state == SND_PCM_STATE_DRAINING) {
135                 write(jack->fd, &buf, 1);
136                 return 1;
137         }
138
139         return 0;
140 }
141
142 static void snd_pcm_jack_free(snd_pcm_jack_t *jack)
143 {
144         if (jack == NULL)
145                 return;
146
147         if (jack->client)
148                 jack_client_close(jack->client);
149         if (jack->port_names) {
150                 unsigned int i;
151
152                 for (i = 0; i < jack->num_ports; i++) {
153                         snd_pcm_jack_port_list_t *port_elem =
154                                         jack->port_names[i];
155
156                         while (port_elem != NULL) {
157                                 snd_pcm_jack_port_list_t *next_port_elem =
158                                                 port_elem->next;
159                                 free(port_elem);
160                                 port_elem = next_port_elem;
161                         }
162                 }
163                 free(jack->port_names);
164                 jack->port_names = NULL;
165         }
166         pthread_mutex_destroy (&jack->running_mutex);
167         if (jack->fd >= 0)
168                 close(jack->fd);
169         if (jack->io.poll_fd >= 0)
170                 close(jack->io.poll_fd);
171         free(jack->areas);
172         free(jack->ports);
173         free(jack);
174 }
175
176 static int snd_pcm_jack_close(snd_pcm_ioplug_t *io)
177 {
178         snd_pcm_jack_t *jack = io->private_data;
179         snd_pcm_jack_free(jack);
180         return 0;
181 }
182
183 static int snd_pcm_jack_poll_revents(snd_pcm_ioplug_t *io,
184                                      struct pollfd *pfds, unsigned int nfds,
185                                      unsigned short *revents)
186 {
187         assert(pfds && nfds == 1 && revents);
188
189         *revents = pfds[0].revents & ~(POLLIN | POLLOUT);
190         if (pfds[0].revents & POLLIN && !pcm_poll_block_check(io))
191                 *revents |= (io->stream == SND_PCM_STREAM_PLAYBACK) ? POLLOUT : POLLIN;
192         return 0;
193 }
194
195 static snd_pcm_sframes_t snd_pcm_jack_pointer(snd_pcm_ioplug_t *io)
196 {
197         snd_pcm_jack_t *jack = io->private_data;
198
199         if (jack->xrun_detected)
200                 return -EPIPE;
201
202 #ifdef SND_PCM_IOPLUG_FLAG_BOUNDARY_WA
203         return jack->hw_ptr;
204 #else
205         return jack->hw_ptr % io->buffer_size;
206 #endif
207 }
208
209 static int
210 snd_pcm_jack_process_cb(jack_nframes_t nframes, snd_pcm_ioplug_t *io)
211 {
212         snd_pcm_jack_t *jack = io->private_data;
213         snd_pcm_uframes_t xfer = 0;
214         unsigned int channel;
215
216         if (pthread_mutex_trylock (&jack->running_mutex) == EBUSY) {
217                 /* Note that locking should only ever fail if
218                  * snd_pcm_jack_start or snd_pcm_jack_stop is called at the
219                  * same time, in which case dropping the current buffer is not
220                  * an issue. */
221                 return 0;
222         }
223         if (!jack->running) {
224                 pthread_mutex_unlock (&jack->running_mutex);
225                 return 0;
226         }
227         
228         for (channel = 0; channel < io->channels; channel++) {
229                 jack->areas[channel].addr = 
230                         jack_port_get_buffer (jack->ports[channel], nframes);
231                 jack->areas[channel].first = 0;
232                 jack->areas[channel].step = jack->sample_bits;
233         }
234
235         if (io->state == SND_PCM_STATE_RUNNING ||
236             io->state == SND_PCM_STATE_DRAINING) {
237                 snd_pcm_uframes_t hw_ptr = jack->hw_ptr;
238                 const snd_pcm_uframes_t hw_avail = snd_pcm_ioplug_hw_avail(io, hw_ptr,
239                                                                            io->appl_ptr);
240
241                 if (hw_avail > 0) {
242                         const snd_pcm_channel_area_t *areas = snd_pcm_ioplug_mmap_areas(io);
243                         const snd_pcm_uframes_t offset = hw_ptr % io->buffer_size;
244
245                         xfer = nframes;
246                         if (xfer > hw_avail)
247                                 xfer = hw_avail;
248
249                         if (io->stream == SND_PCM_STREAM_PLAYBACK)
250                                 snd_pcm_areas_copy_wrap(jack->areas, 0, nframes,
251                                                         areas, offset,
252                                                         io->buffer_size,
253                                                         io->channels, xfer,
254                                                         io->format);
255                         else
256                                 snd_pcm_areas_copy_wrap(areas, offset,
257                                                         io->buffer_size,
258                                                         jack->areas, 0, nframes,
259                                                         io->channels, xfer,
260                                                         io->format);
261
262                         hw_ptr += xfer;
263                         if (hw_ptr >= jack->boundary)
264                                 hw_ptr -= jack->boundary;
265                         jack->hw_ptr = hw_ptr;
266                 }
267         }
268
269         /* check if requested frames were copied */
270         if (xfer < nframes) {
271                 /* always fill the not yet written JACK buffer with silence */
272                 if (io->stream == SND_PCM_STREAM_PLAYBACK) {
273                         const snd_pcm_uframes_t frames = nframes - xfer;
274
275                         snd_pcm_areas_silence(jack->areas, xfer, io->channels,
276                                               frames, io->format);
277                 }
278
279                 if (io->state == SND_PCM_STATE_RUNNING ||
280                     io->state == SND_PCM_STATE_DRAINING) {
281                         /* report Xrun to user application */
282                         jack->xrun_detected = true;
283                 }
284         }
285
286         pcm_poll_unblock_check(io); /* unblock socket for polling if needed */
287
288         pthread_mutex_unlock (&jack->running_mutex);
289
290         return 0;
291 }
292
293 static void jack_allocate_and_register_ports(snd_pcm_ioplug_t *io)
294 {
295         snd_pcm_jack_t *jack = io->private_data;
296         unsigned int i;
297
298         jack->ports = calloc(io->channels, sizeof(jack_port_t *));
299
300         for (i = 0; i < io->channels; i++) {
301                 char port_name[32];
302
303                 if (io->stream == SND_PCM_STREAM_PLAYBACK) {
304                         sprintf(port_name, "out_%03d", i);
305                         jack->ports[i] = jack_port_register(jack->client, port_name,
306                                                             JACK_DEFAULT_AUDIO_TYPE,
307                                                             JackPortIsOutput, 0);
308                 } else {
309                         sprintf(port_name, "in_%03d", i);
310                         jack->ports[i] = jack_port_register(jack->client, port_name,
311                                                             JACK_DEFAULT_AUDIO_TYPE,
312                                                             JackPortIsInput, 0);
313                 }
314         }
315 }
316
317 static int snd_pcm_jack_prepare(snd_pcm_ioplug_t *io)
318 {
319         snd_pcm_jack_t *jack = io->private_data;
320         unsigned int i;
321         snd_pcm_sw_params_t *swparams;
322         int err;
323
324         if (io->channels != jack->num_ports) {
325                 SNDERR("Channel count %d not equal to no. of ports %d in JACK",
326                        io->channels, jack->num_ports);
327                 return -EINVAL;
328         }
329
330         jack->hw_ptr = 0;
331         jack->xrun_detected = false;
332
333         jack->min_avail = io->period_size;
334         snd_pcm_sw_params_alloca(&swparams);
335         err = snd_pcm_sw_params_current(io->pcm, swparams);
336         if (err == 0) {
337                 snd_pcm_sw_params_get_avail_min(swparams, &jack->min_avail);
338                 /* get boundary for available calulation */
339                 snd_pcm_sw_params_get_boundary(swparams, &jack->boundary);
340         }
341
342         if (io->stream == SND_PCM_STREAM_PLAYBACK)
343                 pcm_poll_unblock_check(io); /* playback pcm initially accepts writes */
344         else
345                 pcm_poll_block_check(io); /* block capture pcm if that's XRUN recovery */
346
347         if (!jack->ports) {
348                 jack_allocate_and_register_ports(io);
349                 jack_set_process_callback(jack->client,
350                                           (JackProcessCallback)snd_pcm_jack_process_cb, io);
351         }
352
353         if (jack->activated)
354                 return 0;
355
356         if (jack_activate(jack->client))
357                 return -EIO;
358
359         jack->activated = 1;
360
361         for (i = 0; i < io->channels && i < jack->num_ports; i++) {
362                 const char * const own_port = jack_port_name(jack->ports[i]);
363                 snd_pcm_jack_port_list_t *port_elem;
364
365                 for (port_elem = jack->port_names[i]; port_elem != NULL;
366                      port_elem = port_elem->next) {
367                         const char *src, *dst;
368                         if (io->stream == SND_PCM_STREAM_PLAYBACK) {
369                                 src = own_port;
370                                 dst = port_elem->name;
371                         } else {
372                                 src = port_elem->name;
373                                 dst = own_port;
374                         }
375                         if (jack_connect(jack->client, src, dst)) {
376                                 fprintf(stderr, "cannot connect %s to %s\n",
377                                         src, dst);
378                                 return -EIO;
379                         }
380                 }
381         }
382         return 0;
383 }
384
385 static int snd_pcm_jack_start(snd_pcm_ioplug_t *io)
386 {
387         snd_pcm_jack_t *jack = io->private_data;
388         pthread_mutex_lock (&jack->running_mutex);
389         jack->running = 1;
390         pthread_mutex_unlock (&jack->running_mutex);
391         /*
392          * Since the processing of jack_activate() and jack_connect() take a
393          * while longer, snd_pcm_jack_start() was blocked.
394          * Consider a usecase of reading the data from capture device and
395          * writing to a playback device, since the capture device is
396          * already started and the starting of playback device is blocked,
397          * it leads to XRUNs for capture device.
398          * Therefore these calls are moved to snd_pcm_jack_prepare(),
399          * So that the capture and playback devices can be prepared in advance
400          * and starting of the device doesn't take too long.
401          */
402         return 0;
403 }
404
405 static int snd_pcm_jack_stop(snd_pcm_ioplug_t *io)
406 {
407         snd_pcm_jack_t *jack = io->private_data;
408         pthread_mutex_lock (&jack->running_mutex);
409         jack->running = 0;
410         pthread_mutex_unlock (&jack->running_mutex);
411         return 0;
412 }
413
414 static int snd_pcm_jack_hw_free(snd_pcm_ioplug_t *io)
415 {
416         snd_pcm_jack_t *jack = io->private_data;
417
418         if (jack->activated) {
419                 jack_deactivate(jack->client);
420                 jack->activated = 0;
421         }
422 #if 0
423         unsigned i;
424         for (i = 0; i < io->channels; i++) {
425                 if (jack->ports[i]) {
426                         jack_port_unregister(jack->client, jack->ports[i]);
427                         jack->ports[i] = NULL;
428                 }
429         }
430 #endif
431         return 0;
432 }
433
434 static int snd_pcm_jack_sw_params(snd_pcm_ioplug_t *io, snd_pcm_sw_params_t *params)
435 {
436         snd_pcm_jack_t *jack = io->private_data;
437         snd_pcm_sw_params_get_avail_min(params, &jack->min_avail);
438         return 0;
439 }
440
441 static snd_pcm_ioplug_callback_t jack_pcm_callback = {
442         .close = snd_pcm_jack_close,
443         .start = snd_pcm_jack_start,
444         .stop = snd_pcm_jack_stop,
445         .pointer = snd_pcm_jack_pointer,
446         .hw_free = snd_pcm_jack_hw_free,
447         .prepare = snd_pcm_jack_prepare,
448         .poll_revents = snd_pcm_jack_poll_revents,
449         .sw_params = snd_pcm_jack_sw_params,
450 };
451
452 #define ARRAY_SIZE(ary) (sizeof(ary)/sizeof(ary[0]))
453
454 static int jack_set_hw_constraint(snd_pcm_jack_t *jack)
455 {
456         unsigned int access_list[] = {
457                 SND_PCM_ACCESS_MMAP_INTERLEAVED,
458                 SND_PCM_ACCESS_MMAP_NONINTERLEAVED,
459                 SND_PCM_ACCESS_RW_INTERLEAVED,
460                 SND_PCM_ACCESS_RW_NONINTERLEAVED
461         };
462         unsigned int format = SND_PCM_FORMAT_FLOAT;
463         unsigned int rate = jack_get_sample_rate(jack->client);
464         unsigned int psize_list[MAX_PERIODS_MULTIPLE];
465         unsigned int nframes = jack_get_buffer_size(jack->client);
466         unsigned int jack_buffer_bytes = (snd_pcm_format_size(format, nframes) *
467                                           jack->num_ports);
468         unsigned int i;
469         int err;
470
471         if (!jack_buffer_bytes) {
472                 SNDERR("Buffer size is zero");
473                 return -EINVAL;
474         }
475         for (i = 1; i <= ARRAY_SIZE(psize_list); i++)
476                 psize_list[i-1] = jack_buffer_bytes * i;
477
478         jack->sample_bits = snd_pcm_format_physical_width(format);
479         if ((err = snd_pcm_ioplug_set_param_list(&jack->io, SND_PCM_IOPLUG_HW_ACCESS,
480                                                  ARRAY_SIZE(access_list), access_list)) < 0 ||
481             (err = snd_pcm_ioplug_set_param_list(&jack->io, SND_PCM_IOPLUG_HW_FORMAT,
482                                                  1, &format)) < 0 ||
483             (err = snd_pcm_ioplug_set_param_minmax(&jack->io, SND_PCM_IOPLUG_HW_CHANNELS,
484                                                    jack->num_ports, jack->num_ports)) < 0 ||
485             (err = snd_pcm_ioplug_set_param_minmax(&jack->io, SND_PCM_IOPLUG_HW_RATE,
486                                                    rate, rate)) < 0 ||
487             (err = jack->use_period_alignment ?
488                                 snd_pcm_ioplug_set_param_list(&jack->io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, ARRAY_SIZE(psize_list), psize_list) :
489                                 snd_pcm_ioplug_set_param_minmax(&jack->io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, 128, 64*1024) ) < 0 ||
490             (err = snd_pcm_ioplug_set_param_minmax(&jack->io, SND_PCM_IOPLUG_HW_PERIODS,
491                                                    2, 64)) < 0)
492                 return err;
493
494         return 0;
495 }
496
497 static int parse_ports(snd_pcm_jack_t *jack, snd_config_t *conf)
498 {
499         snd_config_iterator_t i, next;
500         snd_pcm_jack_port_list_t **ports = NULL;
501         unsigned int cnt = 0;
502         unsigned int channel;
503
504         if (conf == NULL)
505                 return 0;
506
507         snd_config_for_each(i, next, conf) {
508                 snd_config_t *n = snd_config_iterator_entry(i);
509                 const char *id;
510
511                 if (snd_config_get_id(n, &id) < 0)
512                         continue;
513                 cnt++;
514         }
515         jack->port_names = ports = calloc(cnt, sizeof(jack->port_names[0]));
516         if (ports == NULL)
517                 return -ENOMEM;
518         jack->num_ports = cnt;
519         snd_config_for_each(i, next, conf) {
520                 snd_config_t *n = snd_config_iterator_entry(i);
521                 const char *id;
522                 const char *port;
523                 int err;
524
525                 if (snd_config_get_id(n, &id) < 0)
526                         continue;
527                 channel = atoi(id);
528                 if (snd_config_get_string(n, &port) >= 0) {
529                         err = snd_pcm_jack_port_list_add(jack, channel, port);
530                         if (err < 0)
531                                 return err;
532                 } else if (snd_config_get_type(n) == SND_CONFIG_TYPE_COMPOUND) {
533                         snd_config_iterator_t k, next_k;
534
535                         snd_config_for_each(k, next_k, n) {
536                                 snd_config_t *m = snd_config_iterator_entry(k);
537
538                                 if (snd_config_get_string(m, &port) < 0)
539                                         continue;
540                                 err = snd_pcm_jack_port_list_add(jack, channel,
541                                                                  port);
542                                 if (err < 0)
543                                         return err;
544                         }
545                 } else {
546                         continue;
547                 }
548         }
549
550         return 0;
551 }
552
553 static int make_nonblock(int fd)
554 {
555         int fl;
556
557         if ((fl = fcntl(fd, F_GETFL)) < 0)
558                 return fl;
559
560         if (fl & O_NONBLOCK)
561                 return 0;
562
563         return fcntl(fd, F_SETFL, fl | O_NONBLOCK);
564 }
565
566 static int snd_pcm_jack_open(snd_pcm_t **pcmp, const char *name,
567                              const char *client_name,
568                              snd_config_t *playback_conf,
569                              snd_config_t *capture_conf,
570                              int use_period_alignment,
571                              snd_pcm_stream_t stream, int mode)
572 {
573         snd_pcm_jack_t *jack;
574         int err;
575         int fd[2];
576         static unsigned int num = 0;
577         char jack_client_name[32];
578         
579         assert(pcmp);
580         jack = calloc(1, sizeof(*jack));
581         if (!jack)
582                 return -ENOMEM;
583
584         pthread_mutex_init (&jack->running_mutex, NULL);
585
586         jack->fd = -1;
587         jack->io.poll_fd = -1;
588         jack->use_period_alignment = use_period_alignment;
589
590         err = parse_ports(jack, stream == SND_PCM_STREAM_PLAYBACK ?
591                           playback_conf : capture_conf);
592         if (err) {
593                 snd_pcm_jack_free(jack);
594                 return err;
595         }
596
597         if (jack->num_ports == 0) {
598                 SNDERR("define the %s_ports section",
599                        stream == SND_PCM_STREAM_PLAYBACK ? "playback" : "capture");
600                 snd_pcm_jack_free(jack);
601                 return -EINVAL;
602         }
603
604         if (client_name == NULL) {
605 #if defined(_GNU_SOURCE)
606                 const char *pname = program_invocation_short_name;
607 #else
608                 const char *pname = getprogname();
609 #endif
610                 if (!pname[0]) {
611                         pname = "alsa-jack";
612                 }
613                 err = snprintf(jack_client_name, sizeof(jack_client_name),
614                                "%s.%s.%d.%d", pname,
615                                stream == SND_PCM_STREAM_PLAYBACK ? "P" : "C",
616                                getpid(), num++);
617         } else
618                 err = snprintf(jack_client_name, sizeof(jack_client_name),
619                                "%s", client_name);
620
621         if (err >= (int)sizeof(jack_client_name)) {
622                 fprintf(stderr, "%s: WARNING: JACK client name '%s' truncated to %d characters, might not be unique\n",
623                         __func__, jack_client_name, (int)strlen(jack_client_name));
624         }
625
626         jack->client = jack_client_open(jack_client_name, JackNoStartServer, NULL);
627
628         if (jack->client == 0) {
629                 snd_pcm_jack_free(jack);
630                 return -ENOENT;
631         }
632
633         jack->areas = calloc(jack->num_ports, sizeof(snd_pcm_channel_area_t));
634         if (! jack->areas) {
635                 snd_pcm_jack_free(jack);
636                 return -ENOMEM;
637         }
638
639         socketpair(AF_LOCAL, SOCK_STREAM, 0, fd);
640         
641         make_nonblock(fd[0]);
642         make_nonblock(fd[1]);
643
644         jack->fd = fd[0];
645
646         jack->io.version = SND_PCM_IOPLUG_VERSION;
647         jack->io.name = "ALSA <-> JACK PCM I/O Plugin";
648         jack->io.callback = &jack_pcm_callback;
649         jack->io.private_data = jack;
650         jack->io.poll_fd = fd[1];
651         jack->io.poll_events = POLLIN;
652         jack->io.mmap_rw = 1;
653
654 #ifdef SND_PCM_IOPLUG_FLAG_BOUNDARY_WA
655         jack->io.flags = SND_PCM_IOPLUG_FLAG_BOUNDARY_WA;
656 #else
657 #warning hw_ptr updates of buffer_size will not be recognized by the ALSA library. Consider to update your ALSA library.
658 #endif
659
660         err = snd_pcm_ioplug_create(&jack->io, name, stream, mode);
661         if (err < 0) {
662                 snd_pcm_jack_free(jack);
663                 return err;
664         }
665
666         err = jack_set_hw_constraint(jack);
667         if (err < 0) {
668                 snd_pcm_ioplug_delete(&jack->io);
669                 return err;
670         }
671
672         *pcmp = jack->io.pcm;
673
674         return 0;
675 }
676
677
678 SND_PCM_PLUGIN_DEFINE_FUNC(jack)
679 {
680         snd_config_iterator_t i, next;
681         snd_config_t *playback_conf = NULL;
682         snd_config_t *capture_conf = NULL;
683         const char *client_name = NULL;
684         int err;
685         int align_jack_period = 1; /*by default we allow only JACK aligned period size*/
686         
687         snd_config_for_each(i, next, conf) {
688                 snd_config_t *n = snd_config_iterator_entry(i);
689                 const char *id;
690                 if (snd_config_get_id(n, &id) < 0)
691                         continue;
692                 if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0 || strcmp(id, "hint") == 0)
693                         continue;
694                 if (strcmp(id, "name") == 0) {
695                         snd_config_get_string(n, &client_name);
696                         continue;
697                 }
698                 if (strcmp(id, "playback_ports") == 0) {
699                         if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
700                                 SNDERR("Invalid type for %s", id);
701                                 return -EINVAL;
702                         }
703                         playback_conf = n;
704                         continue;
705                 }
706                 if (strcmp(id, "capture_ports") == 0) {
707                         if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
708                                 SNDERR("Invalid type for %s", id);
709                                 return -EINVAL;
710                         }
711                         capture_conf = n;
712                         continue;
713                 }
714                 if (strcmp(id, "align_psize") == 0) {
715                         err = snd_config_get_bool(n);
716                         if (err < 0)
717                                 return err;
718                         align_jack_period = err ? 1 : 0;
719                         continue;
720                 }
721                 SNDERR("Unknown field %s", id);
722                 return -EINVAL;
723         }
724
725         err = snd_pcm_jack_open(pcmp, name, client_name, playback_conf, capture_conf, align_jack_period, stream, mode);
726
727         return err;
728 }
729
730 SND_PCM_PLUGIN_SYMBOL(jack);