* [PATCH] alsa-plugins: fix polling and recovering in alsa-jack plugin @ 2014-05-02 18:46 Sergey 2014-05-05 15:56 ` Takashi Iwai 0 siblings, 1 reply; 5+ messages in thread From: Sergey @ 2014-05-02 18:46 UTC (permalink / raw) To: alsa-devel Hello. This patch fixes polling in alsa-to-jack plugin. It makes poll()+_poll_revents() return correct values whenever there's something to read/write. Additionally jack_deactivate() code makes it survive snd_pcm_recover(). It works for the code example I posted before, aplay, arecord, mozilla, etc. Comments and suggestions are welcome. --- diff --git a/jack/pcm_jack.c b/jack/pcm_jack.c index 7a8b24d..a39fea5 100644 --- a/jack/pcm_jack.c +++ b/jack/pcm_jack.c @@ -42,6 +42,7 @@ typedef struct { unsigned int num_ports; unsigned int hw_ptr; unsigned int sample_bits; + snd_pcm_uframes_t min_avail; unsigned int channels; snd_pcm_channel_area_t *areas; @@ -50,6 +51,41 @@ typedef struct { jack_client_t *client; } snd_pcm_jack_t; +static inline int poll_blocked(snd_pcm_ioplug_t *io) +{ + static char buf[65536]; + snd_pcm_sframes_t avail; + snd_pcm_jack_t *jack = io->private_data; + + if (io->state == SND_PCM_STATE_RUNNING) + { + avail = snd_pcm_avail_update(io->pcm); + if (avail >= 0 && avail < jack->min_avail) + { + read(io->poll_fd, &buf, sizeof buf); + return 1; + } + } + + return 0; +} + +static inline int poll_unblocked(snd_pcm_ioplug_t *io) +{ + static char buf[1]; + snd_pcm_sframes_t avail; + snd_pcm_jack_t *jack = io->private_data; + + avail = snd_pcm_avail_update(io->pcm); + if (avail < 0 || avail >= jack->min_avail) + { + write(jack->fd, &buf, 1); + return 1; + } + + return 0; +} + static void snd_pcm_jack_free(snd_pcm_jack_t *jack) { if (jack) { @@ -81,14 +117,10 @@ static int snd_pcm_jack_poll_revents(snd_pcm_ioplug_t *io, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) { - static char buf[1]; - assert(pfds && nfds == 1 && revents); - read(pfds[0].fd, buf, 1); - *revents = pfds[0].revents & ~(POLLIN | POLLOUT); - if (pfds[0].revents & POLLIN) + if (pfds[0].revents & POLLIN && !poll_blocked(io)) *revents |= (io->stream == SND_PCM_STREAM_PLAYBACK) ? POLLOUT : POLLIN; return 0; } @@ -105,7 +137,6 @@ snd_pcm_jack_process_cb(jack_nframes_t nframes, snd_pcm_ioplug_t *io) snd_pcm_jack_t *jack = io->private_data; const snd_pcm_channel_area_t *areas; snd_pcm_uframes_t xfer = 0; - static char buf[1]; unsigned int channel; for (channel = 0; channel < io->channels; channel++) { @@ -145,7 +176,7 @@ snd_pcm_jack_process_cb(jack_nframes_t nframes, snd_pcm_ioplug_t *io) xfer += frames; } - write(jack->fd, buf, 1); /* for polling */ + poll_unblocked(io); /* unblock socket for polling if needed */ return 0; } @@ -154,9 +185,25 @@ static int snd_pcm_jack_prepare(snd_pcm_ioplug_t *io) { snd_pcm_jack_t *jack = io->private_data; unsigned int i; + snd_pcm_sw_params_t *swparams; + int err; jack->hw_ptr = 0; + jack->min_avail = io->period_size; + snd_pcm_sw_params_alloca(&swparams); + err = snd_pcm_sw_params_current(io->pcm, swparams); + if (err == 0) { + snd_pcm_sw_params_get_avail_min(swparams, &jack->min_avail); + } + + poll_unblocked(io); /* unblock socket for initial polling if needed */ + + if (jack->activated) { + jack_deactivate(jack->client); + jack->activated = 0; + } + if (jack->ports) return 0; -- ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH] alsa-plugins: fix polling and recovering in alsa-jack plugin 2014-05-02 18:46 [PATCH] alsa-plugins: fix polling and recovering in alsa-jack plugin Sergey @ 2014-05-05 15:56 ` Takashi Iwai 2014-05-09 0:00 ` Sergey 0 siblings, 1 reply; 5+ messages in thread From: Takashi Iwai @ 2014-05-05 15:56 UTC (permalink / raw) To: Sergey; +Cc: alsa-devel At Fri, 02 May 2014 22:46:33 +0400, Sergey wrote: > > Hello. > > This patch fixes polling in alsa-to-jack plugin. > It makes poll()+_poll_revents() return correct values > whenever there's something to read/write. > > Additionally jack_deactivate() code makes it survive snd_pcm_recover(). > > It works for the code example I posted before, aplay, arecord, mozilla, etc. > > Comments and suggestions are welcome. Thanks for the patch. The basic idea looks good, but some suggestions below. > > --- > diff --git a/jack/pcm_jack.c b/jack/pcm_jack.c > index 7a8b24d..a39fea5 100644 > --- a/jack/pcm_jack.c > +++ b/jack/pcm_jack.c > @@ -42,6 +42,7 @@ typedef struct { > unsigned int num_ports; > unsigned int hw_ptr; > unsigned int sample_bits; > + snd_pcm_uframes_t min_avail; > > unsigned int channels; > snd_pcm_channel_area_t *areas; > @@ -50,6 +51,41 @@ typedef struct { > jack_client_t *client; > } snd_pcm_jack_t; > > +static inline int poll_blocked(snd_pcm_ioplug_t *io) You don't need inline in general. Compilers should be smart enough nowadays. > +{ > + static char buf[65536]; > + snd_pcm_sframes_t avail; > + snd_pcm_jack_t *jack = io->private_data; > + > + if (io->state == SND_PCM_STATE_RUNNING) > + { Please follow the coding style in that file. The brace is placed in the same line as if (). > + avail = snd_pcm_avail_update(io->pcm); > + if (avail >= 0 && avail < jack->min_avail) > + { > + read(io->poll_fd, &buf, sizeof buf); So, it's intended to clear all pending writes, right? If so, do reads in loop. Then you don't have to use such a big buffer. The size of 32 or such should be enough. > + return 1; > + } > + } > + > + return 0; > +} > + > +static inline int poll_unblocked(snd_pcm_ioplug_t *io) The function names are a bit too ambiguous and hard to understand what they are really doing only from the names. > +{ > + static char buf[1]; > + snd_pcm_sframes_t avail; > + snd_pcm_jack_t *jack = io->private_data; > + > + avail = snd_pcm_avail_update(io->pcm); > + if (avail < 0 || avail >= jack->min_avail) > + { > + write(jack->fd, &buf, 1); > + return 1; > + } > + > + return 0; > +} > + > static void snd_pcm_jack_free(snd_pcm_jack_t *jack) > { > if (jack) { > @@ -81,14 +117,10 @@ static int snd_pcm_jack_poll_revents(snd_pcm_ioplug_t *io, > struct pollfd *pfds, unsigned int nfds, > unsigned short *revents) > { > - static char buf[1]; > - > assert(pfds && nfds == 1 && revents); > > - read(pfds[0].fd, buf, 1); > - > *revents = pfds[0].revents & ~(POLLIN | POLLOUT); > - if (pfds[0].revents & POLLIN) > + if (pfds[0].revents & POLLIN && !poll_blocked(io)) > *revents |= (io->stream == SND_PCM_STREAM_PLAYBACK) ? POLLOUT : POLLIN; > return 0; > } > @@ -105,7 +137,6 @@ snd_pcm_jack_process_cb(jack_nframes_t nframes, snd_pcm_ioplug_t *io) > snd_pcm_jack_t *jack = io->private_data; > const snd_pcm_channel_area_t *areas; > snd_pcm_uframes_t xfer = 0; > - static char buf[1]; > unsigned int channel; > > for (channel = 0; channel < io->channels; channel++) { > @@ -145,7 +176,7 @@ snd_pcm_jack_process_cb(jack_nframes_t nframes, snd_pcm_ioplug_t *io) > xfer += frames; > } > > - write(jack->fd, buf, 1); /* for polling */ > + poll_unblocked(io); /* unblock socket for polling if needed */ > > return 0; > } > @@ -154,9 +185,25 @@ static int snd_pcm_jack_prepare(snd_pcm_ioplug_t *io) > { > snd_pcm_jack_t *jack = io->private_data; > unsigned int i; > + snd_pcm_sw_params_t *swparams; > + int err; > > jack->hw_ptr = 0; > > + jack->min_avail = io->period_size; > + snd_pcm_sw_params_alloca(&swparams); > + err = snd_pcm_sw_params_current(io->pcm, swparams); > + if (err == 0) { > + snd_pcm_sw_params_get_avail_min(swparams, &jack->min_avail); > + } > + > + poll_unblocked(io); /* unblock socket for initial polling if needed */ Is this really needed? > + > + if (jack->activated) { > + jack_deactivate(jack->client); > + jack->activated = 0; > + } This is same as just calling snd_pcm_jack_stop(). thanks, Takashi ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] alsa-plugins: fix polling and recovering in alsa-jack plugin 2014-05-05 15:56 ` Takashi Iwai @ 2014-05-09 0:00 ` Sergey 2014-05-09 5:34 ` Takashi Iwai 0 siblings, 1 reply; 5+ messages in thread From: Sergey @ 2014-05-09 0:00 UTC (permalink / raw) To: alsa-devel At Mon 05 May 2014 Takashi Iwai wrote: >> This patch fixes polling in alsa-to-jack plugin. >> It makes poll()+_poll_revents() return correct values >> whenever there's something to read/write. >> >> Additionally jack_deactivate() code makes it survive snd_pcm_recover(). >> >> It works for the code example I posted before, aplay, arecord, mozilla, etc. >> >> Comments and suggestions are welcome. > > Thanks for the patch. The basic idea looks good, but some suggestions > below. Thank you for your response and comments. > You don't need inline in general. Compilers should be smart enough > nowadays. Uninlined. > Please follow the coding style in that file. The brace is placed in > the same line as if (). Missed that, sorry. Fixed. > So, it's intended to clear all pending writes, right? > If so, do reads in loop. Then you don't have to use such a big > buffer. The size of 32 or such should be enough. Done. > The function names are a bit too ambiguous and hard to understand what > they are really doing only from the names. How about pcm_poll_block() and pcm_poll_unblock()? >> + poll_unblocked(io); /* unblock socket for initial polling if needed */ > > Is this really needed? Playback pcm accepts writes since _prepare(), so poll() is unblocked there. Without it playback pcm gets poll() blocked by default and a code like: _open(); _set_params(); while (still_playing) { if (poll() > 0 && _revents() == 0 && revents&POLLOUT) _write(); } never starts writing. >> + >> + if (jack->activated) { >> + jack_deactivate(jack->client); >> + jack->activated = 0; >> + } > > This is same as just calling snd_pcm_jack_stop(). Right. To put snd_pcm_jack_stop() call in snd_pcm_jack_prepare() I have to move snd_pcm_jack_prepare() below snd_pcm_jack_stop(), that makes patch larger. Patch updated and ready for more comments. --- diff --git a/jack/pcm_jack.c b/jack/pcm_jack.c index 7a8b24d..837e15c 100644 --- a/jack/pcm_jack.c +++ b/jack/pcm_jack.c @@ -42,6 +42,7 @@ typedef struct { unsigned int num_ports; unsigned int hw_ptr; unsigned int sample_bits; + snd_pcm_uframes_t min_avail; unsigned int channels; snd_pcm_channel_area_t *areas; @@ -50,6 +51,38 @@ typedef struct { jack_client_t *client; } snd_pcm_jack_t; +static int pcm_poll_block(snd_pcm_ioplug_t *io) +{ + static char buf[32]; + snd_pcm_sframes_t avail; + snd_pcm_jack_t *jack = io->private_data; + + if (io->state == SND_PCM_STATE_RUNNING) { + avail = snd_pcm_avail_update(io->pcm); + if (avail >= 0 && avail < jack->min_avail) { + while (read(io->poll_fd, &buf, sizeof(buf)) == sizeof(buf)); + return 1; + } + } + + return 0; +} + +static int pcm_poll_unblock(snd_pcm_ioplug_t *io) +{ + static char buf[1]; + snd_pcm_sframes_t avail; + snd_pcm_jack_t *jack = io->private_data; + + avail = snd_pcm_avail_update(io->pcm); + if (avail < 0 || avail >= jack->min_avail) { + write(jack->fd, &buf, 1); + return 1; + } + + return 0; +} + static void snd_pcm_jack_free(snd_pcm_jack_t *jack) { if (jack) { @@ -81,14 +114,10 @@ static int snd_pcm_jack_poll_revents(snd_pcm_ioplug_t *io, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) { - static char buf[1]; - assert(pfds && nfds == 1 && revents); - read(pfds[0].fd, buf, 1); - *revents = pfds[0].revents & ~(POLLIN | POLLOUT); - if (pfds[0].revents & POLLIN) + if (pfds[0].revents & POLLIN && !pcm_poll_block(io)) *revents |= (io->stream == SND_PCM_STREAM_PLAYBACK) ? POLLOUT : POLLIN; return 0; } @@ -105,7 +134,6 @@ snd_pcm_jack_process_cb(jack_nframes_t nframes, snd_pcm_ioplug_t *io) snd_pcm_jack_t *jack = io->private_data; const snd_pcm_channel_area_t *areas; snd_pcm_uframes_t xfer = 0; - static char buf[1]; unsigned int channel; for (channel = 0; channel < io->channels; channel++) { @@ -145,44 +173,11 @@ snd_pcm_jack_process_cb(jack_nframes_t nframes, snd_pcm_ioplug_t *io) xfer += frames; } - write(jack->fd, buf, 1); /* for polling */ + pcm_poll_unblock(io); /* unblock socket for polling if needed */ return 0; } -static int snd_pcm_jack_prepare(snd_pcm_ioplug_t *io) -{ - snd_pcm_jack_t *jack = io->private_data; - unsigned int i; - - jack->hw_ptr = 0; - - if (jack->ports) - return 0; - - jack->ports = calloc(io->channels, sizeof(jack_port_t*)); - - for (i = 0; i < io->channels; i++) { - char port_name[32]; - if (io->stream == SND_PCM_STREAM_PLAYBACK) { - - sprintf(port_name, "out_%03d", i); - jack->ports[i] = jack_port_register(jack->client, port_name, - JACK_DEFAULT_AUDIO_TYPE, - JackPortIsOutput, 0); - } else { - sprintf(port_name, "in_%03d", i); - jack->ports[i] = jack_port_register(jack->client, port_name, - JACK_DEFAULT_AUDIO_TYPE, - JackPortIsInput, 0); - } - } - - jack_set_process_callback(jack->client, - (JackProcessCallback)snd_pcm_jack_process_cb, io); - return 0; -} - static int snd_pcm_jack_start(snd_pcm_ioplug_t *io) { snd_pcm_jack_t *jack = io->private_data; @@ -233,6 +228,54 @@ static int snd_pcm_jack_stop(snd_pcm_ioplug_t *io) return 0; } +static int snd_pcm_jack_prepare(snd_pcm_ioplug_t *io) +{ + snd_pcm_jack_t *jack = io->private_data; + unsigned int i; + snd_pcm_sw_params_t *swparams; + int err; + + jack->hw_ptr = 0; + + jack->min_avail = io->period_size; + snd_pcm_sw_params_alloca(&swparams); + err = snd_pcm_sw_params_current(io->pcm, swparams); + if (err == 0) { + snd_pcm_sw_params_get_avail_min(swparams, &jack->min_avail); + } + + /* deactivate jack connections if this is XRUN recovery */ + snd_pcm_jack_stop(io); + + /* playback pcm initially accepts writes, poll must be unblocked */ + pcm_poll_unblock(io); + + if (jack->ports) + return 0; + + jack->ports = calloc(io->channels, sizeof(jack_port_t*)); + + for (i = 0; i < io->channels; i++) { + char port_name[32]; + if (io->stream == SND_PCM_STREAM_PLAYBACK) { + + sprintf(port_name, "out_%03d", i); + jack->ports[i] = jack_port_register(jack->client, port_name, + JACK_DEFAULT_AUDIO_TYPE, + JackPortIsOutput, 0); + } else { + sprintf(port_name, "in_%03d", i); + jack->ports[i] = jack_port_register(jack->client, port_name, + JACK_DEFAULT_AUDIO_TYPE, + JackPortIsInput, 0); + } + } + + jack_set_process_callback(jack->client, + (JackProcessCallback)snd_pcm_jack_process_cb, io); + return 0; +} + static snd_pcm_ioplug_callback_t jack_pcm_callback = { .close = snd_pcm_jack_close, .start = snd_pcm_jack_start, -- ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH] alsa-plugins: fix polling and recovering in alsa-jack plugin 2014-05-09 0:00 ` Sergey @ 2014-05-09 5:34 ` Takashi Iwai 2014-05-12 23:20 ` Sergey 0 siblings, 1 reply; 5+ messages in thread From: Takashi Iwai @ 2014-05-09 5:34 UTC (permalink / raw) To: Sergey; +Cc: alsa-devel At Fri, 09 May 2014 04:00:50 +0400, Sergey wrote: > > At Mon 05 May 2014 Takashi Iwai wrote: > > >> This patch fixes polling in alsa-to-jack plugin. > >> It makes poll()+_poll_revents() return correct values > >> whenever there's something to read/write. > >> > >> Additionally jack_deactivate() code makes it survive snd_pcm_recover(). > >> > >> It works for the code example I posted before, aplay, arecord, mozilla, etc. > >> > >> Comments and suggestions are welcome. > > > > Thanks for the patch. The basic idea looks good, but some suggestions > > below. > > Thank you for your response and comments. > > > You don't need inline in general. Compilers should be smart enough > > nowadays. > > Uninlined. > > > Please follow the coding style in that file. The brace is placed in > > the same line as if (). > > Missed that, sorry. Fixed. > > > So, it's intended to clear all pending writes, right? > > If so, do reads in loop. Then you don't have to use such a big > > buffer. The size of 32 or such should be enough. > > Done. > > > The function names are a bit too ambiguous and hard to understand what > > they are really doing only from the names. > > How about pcm_poll_block() and pcm_poll_unblock()? A bit better, but not really. You can give a comment to each function to explain what they do. Then you might find better names while explaining functionality to yourself. > >> + poll_unblocked(io); /* unblock socket for initial polling if needed */ > > > > Is this really needed? > > Playback pcm accepts writes since _prepare(), so poll() is unblocked there. > Without it playback pcm gets poll() blocked by default and a code like: > _open(); > _set_params(); > while (still_playing) { > if (poll() > 0 && _revents() == 0 && revents&POLLOUT) > _write(); > } > never starts writing. Then do it only for the playback. For capture, the poll shouldn't return at prepare state. > >> + > >> + if (jack->activated) { > >> + jack_deactivate(jack->client); > >> + jack->activated = 0; > >> + } > > > > This is same as just calling snd_pcm_jack_stop(). > > Right. To put snd_pcm_jack_stop() call in snd_pcm_jack_prepare() > I have to move snd_pcm_jack_prepare() below snd_pcm_jack_stop(), > that makes patch larger. You can declare a function. thanks, Takashi > > Patch updated and ready for more comments. > > --- > diff --git a/jack/pcm_jack.c b/jack/pcm_jack.c > index 7a8b24d..837e15c 100644 > --- a/jack/pcm_jack.c > +++ b/jack/pcm_jack.c > @@ -42,6 +42,7 @@ typedef struct { > unsigned int num_ports; > unsigned int hw_ptr; > unsigned int sample_bits; > + snd_pcm_uframes_t min_avail; > > unsigned int channels; > snd_pcm_channel_area_t *areas; > @@ -50,6 +51,38 @@ typedef struct { > jack_client_t *client; > } snd_pcm_jack_t; > > +static int pcm_poll_block(snd_pcm_ioplug_t *io) > +{ > + static char buf[32]; > + snd_pcm_sframes_t avail; > + snd_pcm_jack_t *jack = io->private_data; > + > + if (io->state == SND_PCM_STATE_RUNNING) { > + avail = snd_pcm_avail_update(io->pcm); > + if (avail >= 0 && avail < jack->min_avail) { > + while (read(io->poll_fd, &buf, sizeof(buf)) == sizeof(buf)); > + return 1; > + } > + } > + > + return 0; > +} > + > +static int pcm_poll_unblock(snd_pcm_ioplug_t *io) > +{ > + static char buf[1]; > + snd_pcm_sframes_t avail; > + snd_pcm_jack_t *jack = io->private_data; > + > + avail = snd_pcm_avail_update(io->pcm); > + if (avail < 0 || avail >= jack->min_avail) { > + write(jack->fd, &buf, 1); > + return 1; > + } > + > + return 0; > +} > + > static void snd_pcm_jack_free(snd_pcm_jack_t *jack) > { > if (jack) { > @@ -81,14 +114,10 @@ static int snd_pcm_jack_poll_revents(snd_pcm_ioplug_t *io, > struct pollfd *pfds, unsigned int nfds, > unsigned short *revents) > { > - static char buf[1]; > - > assert(pfds && nfds == 1 && revents); > > - read(pfds[0].fd, buf, 1); > - > *revents = pfds[0].revents & ~(POLLIN | POLLOUT); > - if (pfds[0].revents & POLLIN) > + if (pfds[0].revents & POLLIN && !pcm_poll_block(io)) > *revents |= (io->stream == SND_PCM_STREAM_PLAYBACK) ? POLLOUT : POLLIN; > return 0; > } > @@ -105,7 +134,6 @@ snd_pcm_jack_process_cb(jack_nframes_t nframes, snd_pcm_ioplug_t *io) > snd_pcm_jack_t *jack = io->private_data; > const snd_pcm_channel_area_t *areas; > snd_pcm_uframes_t xfer = 0; > - static char buf[1]; > unsigned int channel; > > for (channel = 0; channel < io->channels; channel++) { > @@ -145,44 +173,11 @@ snd_pcm_jack_process_cb(jack_nframes_t nframes, snd_pcm_ioplug_t *io) > xfer += frames; > } > > - write(jack->fd, buf, 1); /* for polling */ > + pcm_poll_unblock(io); /* unblock socket for polling if needed */ > > return 0; > } > > -static int snd_pcm_jack_prepare(snd_pcm_ioplug_t *io) > -{ > - snd_pcm_jack_t *jack = io->private_data; > - unsigned int i; > - > - jack->hw_ptr = 0; > - > - if (jack->ports) > - return 0; > - > - jack->ports = calloc(io->channels, sizeof(jack_port_t*)); > - > - for (i = 0; i < io->channels; i++) { > - char port_name[32]; > - if (io->stream == SND_PCM_STREAM_PLAYBACK) { > - > - sprintf(port_name, "out_%03d", i); > - jack->ports[i] = jack_port_register(jack->client, port_name, > - JACK_DEFAULT_AUDIO_TYPE, > - JackPortIsOutput, 0); > - } else { > - sprintf(port_name, "in_%03d", i); > - jack->ports[i] = jack_port_register(jack->client, port_name, > - JACK_DEFAULT_AUDIO_TYPE, > - JackPortIsInput, 0); > - } > - } > - > - jack_set_process_callback(jack->client, > - (JackProcessCallback)snd_pcm_jack_process_cb, io); > - return 0; > -} > - > static int snd_pcm_jack_start(snd_pcm_ioplug_t *io) > { > snd_pcm_jack_t *jack = io->private_data; > @@ -233,6 +228,54 @@ static int snd_pcm_jack_stop(snd_pcm_ioplug_t *io) > return 0; > } > > +static int snd_pcm_jack_prepare(snd_pcm_ioplug_t *io) > +{ > + snd_pcm_jack_t *jack = io->private_data; > + unsigned int i; > + snd_pcm_sw_params_t *swparams; > + int err; > + > + jack->hw_ptr = 0; > + > + jack->min_avail = io->period_size; > + snd_pcm_sw_params_alloca(&swparams); > + err = snd_pcm_sw_params_current(io->pcm, swparams); > + if (err == 0) { > + snd_pcm_sw_params_get_avail_min(swparams, &jack->min_avail); > + } > + > + /* deactivate jack connections if this is XRUN recovery */ > + snd_pcm_jack_stop(io); > + > + /* playback pcm initially accepts writes, poll must be unblocked */ > + pcm_poll_unblock(io); > + > + if (jack->ports) > + return 0; > + > + jack->ports = calloc(io->channels, sizeof(jack_port_t*)); > + > + for (i = 0; i < io->channels; i++) { > + char port_name[32]; > + if (io->stream == SND_PCM_STREAM_PLAYBACK) { > + > + sprintf(port_name, "out_%03d", i); > + jack->ports[i] = jack_port_register(jack->client, port_name, > + JACK_DEFAULT_AUDIO_TYPE, > + JackPortIsOutput, 0); > + } else { > + sprintf(port_name, "in_%03d", i); > + jack->ports[i] = jack_port_register(jack->client, port_name, > + JACK_DEFAULT_AUDIO_TYPE, > + JackPortIsInput, 0); > + } > + } > + > + jack_set_process_callback(jack->client, > + (JackProcessCallback)snd_pcm_jack_process_cb, io); > + return 0; > +} > + > static snd_pcm_ioplug_callback_t jack_pcm_callback = { > .close = snd_pcm_jack_close, > .start = snd_pcm_jack_start, > -- > _______________________________________________ > Alsa-devel mailing list > Alsa-devel@alsa-project.org > http://mailman.alsa-project.org/mailman/listinfo/alsa-devel > ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] alsa-plugins: fix polling and recovering in alsa-jack plugin 2014-05-09 5:34 ` Takashi Iwai @ 2014-05-12 23:20 ` Sergey 0 siblings, 0 replies; 5+ messages in thread From: Sergey @ 2014-05-12 23:20 UTC (permalink / raw) To: alsa-devel Fri 09 May 2014 Takashi Iwai wrote: >>>> This patch fixes polling in alsa-to-jack plugin. >>>> It makes poll()+_poll_revents() return correct values >>>> whenever there's something to read/write. >>>> >>>> Additionally jack_deactivate() code makes it survive snd_pcm_recover(). >>>> >>>> It works for the code example I posted before, aplay, arecord, mozilla, etc. >>>> >>>> Comments and suggestions are welcome. >>> The function names are a bit too ambiguous and hard to understand what >>> they are really doing only from the names. >> >> How about pcm_poll_block() and pcm_poll_unblock()? > > A bit better, but not really. You can give a comment to each function > to explain what they do. Then you might find better names while > explaining functionality to yourself. pcm_poll_block() function blocks pcm polling if pcm is not ready to send data (capture pcm) or receive data (playback pcm). And pcm_poll_unblock() unblocks poll() if pcm is ready to send/receive data. But block_poll_if_pcm_not_ready() looks too cumbersome. Maybe pcm_poll_block_check() and pcm_poll_unblock_check()? >> Playback pcm accepts writes since _prepare(), so poll() is unblocked there. > > Then do it only for the playback. For capture, the poll shouldn't > return at prepare state. I thought that socket is created empty, so poll() is blocked by default. But you're right, I forgot about XRUN recovery, when _prepare() can be called with unblocked poll. It could be blocked by the next _poll_revents(), but it's probably better to have it explicitly blocked in _prepare(). I modified _block function and added its call to _prepare(). >> Right. To put snd_pcm_jack_stop() call in snd_pcm_jack_prepare() >> I have to move snd_pcm_jack_prepare() below snd_pcm_jack_stop(), >> that makes patch larger. > > You can declare a function. Done. Patch updated. --- diff --git a/jack/pcm_jack.c b/jack/pcm_jack.c index 7a8b24d..36fbdc9 100644 --- a/jack/pcm_jack.c +++ b/jack/pcm_jack.c @@ -42,6 +42,7 @@ typedef struct { unsigned int num_ports; unsigned int hw_ptr; unsigned int sample_bits; + snd_pcm_uframes_t min_avail; unsigned int channels; snd_pcm_channel_area_t *areas; @@ -50,6 +51,41 @@ typedef struct { jack_client_t *client; } snd_pcm_jack_t; +static int snd_pcm_jack_stop(snd_pcm_ioplug_t *io); + +static int pcm_poll_block_check(snd_pcm_ioplug_t *io) +{ + static char buf[32]; + snd_pcm_sframes_t avail; + snd_pcm_jack_t *jack = io->private_data; + + if (io->state == SND_PCM_STATE_RUNNING || + (io->state == SND_PCM_STATE_PREPARED && io->stream == SND_PCM_STREAM_CAPTURE)) { + avail = snd_pcm_avail_update(io->pcm); + if (avail >= 0 && avail < jack->min_avail) { + while (read(io->poll_fd, &buf, sizeof(buf)) == sizeof(buf)); + return 1; + } + } + + return 0; +} + +static int pcm_poll_unblock_check(snd_pcm_ioplug_t *io) +{ + static char buf[1]; + snd_pcm_sframes_t avail; + snd_pcm_jack_t *jack = io->private_data; + + avail = snd_pcm_avail_update(io->pcm); + if (avail < 0 || avail >= jack->min_avail) { + write(jack->fd, &buf, 1); + return 1; + } + + return 0; +} + static void snd_pcm_jack_free(snd_pcm_jack_t *jack) { if (jack) { @@ -81,14 +117,10 @@ static int snd_pcm_jack_poll_revents(snd_pcm_ioplug_t *io, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) { - static char buf[1]; - assert(pfds && nfds == 1 && revents); - read(pfds[0].fd, buf, 1); - *revents = pfds[0].revents & ~(POLLIN | POLLOUT); - if (pfds[0].revents & POLLIN) + if (pfds[0].revents & POLLIN && !pcm_poll_block_check(io)) *revents |= (io->stream == SND_PCM_STREAM_PLAYBACK) ? POLLOUT : POLLIN; return 0; } @@ -105,7 +137,6 @@ snd_pcm_jack_process_cb(jack_nframes_t nframes, snd_pcm_ioplug_t *io) snd_pcm_jack_t *jack = io->private_data; const snd_pcm_channel_area_t *areas; snd_pcm_uframes_t xfer = 0; - static char buf[1]; unsigned int channel; for (channel = 0; channel < io->channels; channel++) { @@ -145,7 +176,7 @@ snd_pcm_jack_process_cb(jack_nframes_t nframes, snd_pcm_ioplug_t *io) xfer += frames; } - write(jack->fd, buf, 1); /* for polling */ + pcm_poll_unblock_check(io); /* unblock socket for polling if needed */ return 0; } @@ -154,9 +185,26 @@ static int snd_pcm_jack_prepare(snd_pcm_ioplug_t *io) { snd_pcm_jack_t *jack = io->private_data; unsigned int i; + snd_pcm_sw_params_t *swparams; + int err; jack->hw_ptr = 0; + jack->min_avail = io->period_size; + snd_pcm_sw_params_alloca(&swparams); + err = snd_pcm_sw_params_current(io->pcm, swparams); + if (err == 0) { + snd_pcm_sw_params_get_avail_min(swparams, &jack->min_avail); + } + + /* deactivate jack connections if this is XRUN recovery */ + snd_pcm_jack_stop(io); + + if (io->stream == SND_PCM_STREAM_PLAYBACK) + pcm_poll_unblock_check(io); /* playback pcm initially accepts writes */ + else + pcm_poll_block_check(io); /* block capture pcm if that's XRUN recovery */ + if (jack->ports) return 0; -- ^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2014-05-12 23:20 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2014-05-02 18:46 [PATCH] alsa-plugins: fix polling and recovering in alsa-jack plugin Sergey 2014-05-05 15:56 ` Takashi Iwai 2014-05-09 0:00 ` Sergey 2014-05-09 5:34 ` Takashi Iwai 2014-05-12 23:20 ` Sergey
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox