* [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