alsa-plugins: fix polling and recovering in alsa-jack plugin
PATCH 1/1 alsa-plugins: fix polling and recovering in alsa-jack plugin
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.
---
jack/pcm_jack.c +54 -7
@@ -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 ;
At Fri, 02 May 2014 22:46:33 +0400,
Quoted 7 lines · Sergey
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.
Quoted 5 lines
Additionally
jack_deactivate()code makes it survivesnd_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.
Quoted 15 lines
---
jack/pcm_jack.c +1
-0@@ -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;
jack/pcm_jack.c typedef struct { · line 54
Quoted 4 lines
jack/pcm_jack.c +1
-0@@ -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.
jack/pcm_jack.c typedef struct { · line 61
Quoted 7 lines
jack/pcm_jack.c +7
-0+{ +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 ().
jack/pcm_jack.c typedef struct { · line 65
Quoted 4 lines
jack/pcm_jack.c +4
-0+ 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.
jack/pcm_jack.c typedef struct { · line 73
Quoted 8 lines
jack/pcm_jack.c +8
-0+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.
Quoted 58 lines
jack/pcm_jack.c +19
-7+{ +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/pcm_jack.c static int snd_pcm_jack_prepare(snd_pcm_ioplug_t *io) · line 200
Quoted 10 lines
jack/pcm_jack.c +8
-0jack->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?
jack/pcm_jack.c static int snd_pcm_jack_prepare(snd_pcm_ioplug_t *io) · line 205
Quoted 5 lines
jack/pcm_jack.c +5
-0+ +if (jack->activated) { +jack_deactivate (jack->client); + jack->activated =0 ; + }
This is same as just calling snd_pcm_jack_stop().
thanks,
Takashi
Quoted 4 lines · At Mon 05 May 2014 Takashi Iwai wrote:
Quoted 4 lines
This patch fixes polling in alsa-to-jack plugin. It makes poll()+_poll_revents() return correct values whenever there's something to read/write.
Quoted 8 lines
Quoted 5 lines
Additionally
jack_deactivate()code makes it survivesnd_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.
Quoted 2 lines
You don't need inline in general. Compilers should be smart enough nowadays.
Uninlined.
Quoted 2 lines
Please follow the coding style in that file. The brace is placed in the same line as if ().
Missed that, sorry. Fixed.
Quoted 3 lines
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.
Quoted 2 lines
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()?
Quoted 3 lines
Quoted 1 line
+
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.
Quoted 7 lines
Review
Quoted 5 lines
(quoted diff) +5
-0+ + 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.
---
jack/pcm_jack.c +83 -40
@@ -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,
At Fri, 09 May 2014 04:00:50 +0400,
Quoted 32 lines · Sergey
Quoted 4 lines · At Mon 05 May 2014 Takashi Iwai wrote:
Quoted 4 lines
This patch fixes polling in alsa-to-jack plugin. It makes poll()+_poll_revents() return correct values whenever there's something to read/write.
Quoted 8 lines
Quoted 5 lines
Additionally
jack_deactivate()code makes it survivesnd_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.
Quoted 2 lines
You don't need inline in general. Compilers should be smart enough nowadays.
Uninlined.
Quoted 2 lines
Please follow the coding style in that file. The brace is placed in the same line as if ().
Missed that, sorry. Fixed.
Quoted 3 lines
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.
Quoted 6 lines
Done.
Quoted 2 lines
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()andpcm_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.
Quoted 8 lines
Quoted 3 lines
Quoted 1 line
+
poll_unblocked(io); /* unblock socket for initial polling if needed */Is this really needed?
Playback pcm accepts writes since
_prepare(), sopoll()is unblocked there. Without it playback pcm getspoll()blocked by default and a code like:
_open();
_set_params();
Quoted 5 lines
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.
Quoted 11 lines
Quoted 7 lines
Review
Quoted 5 lines
(quoted diff) +5
-0+ + 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 insnd_pcm_jack_prepare()I have to movesnd_pcm_jack_prepare()belowsnd_pcm_jack_stop(), that makes patch larger.
You can declare a function.
thanks,
Takashi
Quoted 186 lines
Patch updated and ready for more comments.
---
jack/pcm_jack.c +83
-40@@ -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,Signature · 4 lines
_______________________________________________ Alsa-devel mailing list [email protected] http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
Quoted 10 lines · Fri 09 May 2014 Takashi Iwai wrote:
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
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 survivesnd_pcm_recover().It works for the code example I posted before, aplay, arecord, mozilla, etc.
Comments and suggestions are welcome.
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
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()andpcm_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()?
Quoted 4 lines
Quoted 1 line
Playback pcm accepts writes since
_prepare(), sopoll()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().
Quoted 5 lines
Quoted 3 lines
Right. To put
snd_pcm_jack_stop()call insnd_pcm_jack_prepare()I have to movesnd_pcm_jack_prepare()belowsnd_pcm_jack_stop(), that makes patch larger.You can declare a function.
Done.
Patch updated.
---
jack/pcm_jack.c +55 -7
@@ -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 ;