From 6c58c9634ceda0158a9636aaac6d0270ab83ba12 Mon Sep 17 00:00:00 2001 From: Pieter Palmers Date: Wed, 14 Feb 2018 21:12:31 +0100 Subject: [PATCH 1/3] use realtime priority for audio thread --- src/apulse-threaded-mainloop.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/apulse-threaded-mainloop.c b/src/apulse-threaded-mainloop.c index 38a7c39..de3ffb7 100644 --- a/src/apulse-threaded-mainloop.c +++ b/src/apulse-threaded-mainloop.c @@ -129,15 +129,30 @@ pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept) pthread_cond_signal(&m->cond); } +#define AUDIO_THREAD_RT_PRIORITY 60 + APULSE_EXPORT int pa_threaded_mainloop_start(pa_threaded_mainloop *m) { + struct sched_param rtparam; + int err; trace_info_f("F %s m=%p\n", __func__, m); if (m->running) return 1; pthread_create(&m->t, NULL, mainloop_thread, m); + + memset(&rtparam, 0, sizeof(rtparam)); + rtparam.sched_priority = AUDIO_THREAD_RT_PRIORITY; + + if ((err = pthread_setschedparam(m->t, SCHED_FIFO, &rtparam)) != 0) { + trace_warning( + "cannot use real-time scheduling (FIFO at priority %d) " + "for audio thread (%d: %s)", + rtparam.sched_priority, err, strerror(err)); + } + m->running = 1; return 0; } From b5142a51301e76e31d3b7dda4fa816d4041811ab Mon Sep 17 00:00:00 2001 From: Pieter Palmers Date: Wed, 14 Feb 2018 21:13:01 +0100 Subject: [PATCH 2/3] add alsa error handling --- src/apulse-stream.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/apulse-stream.c b/src/apulse-stream.c index f36e93d..2a3838c 100644 --- a/src/apulse-stream.c +++ b/src/apulse-stream.c @@ -58,6 +58,7 @@ deh_stream_first_readwrite_callback(pa_mainloop_api *api, pa_defer_event *de, vo pa_stream_unref(s); } +static int xruns=0; static void data_available_for_stream(pa_mainloop_api *a, pa_io_event *ioe, int fd, pa_io_event_flags_t events, @@ -167,11 +168,13 @@ data_available_for_stream(pa_mainloop_api *a, pa_io_event *ioe, int fd, pa_io_ev } if (events & PA_IO_EVENT_OUTPUT) { + int r; + if (paused) { // client stream is corked. Pass silence to ALSA size_t bytecnt = MIN(buf_size, frame_count * frame_size); memset(buf, 0, bytecnt); - snd_pcm_writei(s->ph, buf, bytecnt / frame_size); + r= snd_pcm_writei(s->ph, buf, bytecnt / frame_size); } else { size_t writable_size = pa_stream_writable_size(s); @@ -188,9 +191,29 @@ data_available_for_stream(pa_mainloop_api *a, pa_io_event *ioe, int fd, pa_io_ev // application is not ready yet, play silence bytecnt = MIN(buf_size, frame_count * frame_size); memset(buf, 0, bytecnt); + trace_warning("application not ready\n"); } - snd_pcm_writei(s->ph, buf, bytecnt / frame_size); + r = snd_pcm_writei(s->ph, buf, bytecnt / frame_size); } + + if (r < 0) { + switch (r) { + case -EAGAIN: // non-blocking I/O, no need to do anything + break; + case -EBADFD: // FD in wrong state + trace_warning("ALSA badfd: rv=%d\n", r); + snd_pcm_prepare(s->ph); + break; + case -EPIPE: // XRUN + xruns++; + trace_warning("ALSA xrun: rv=%d, xruns=%d\n", r, xruns); + snd_pcm_recover(s->ph, r, 1); + break; + default: + trace_warning("ALSA error: rv=%d\n", r); + snd_pcm_recover(s->ph, r, 1); + } + } } if (events & PA_IO_EVENT_INPUT) { From caa6f1c38461f15eed2447174c4136d86b8f8366 Mon Sep 17 00:00:00 2001 From: Pieter Palmers Date: Wed, 14 Feb 2018 21:13:31 +0100 Subject: [PATCH 3/3] request as much data as we can in each callback, instead of just the minimum --- src/apulse-stream.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/apulse-stream.c b/src/apulse-stream.c index 2a3838c..7bfdb74 100644 --- a/src/apulse-stream.c +++ b/src/apulse-stream.c @@ -179,8 +179,9 @@ data_available_for_stream(pa_mainloop_api *a, pa_io_event *ioe, int fd, pa_io_ev size_t writable_size = pa_stream_writable_size(s); // Ask client for data, but only if we are ready for at least |minreq| bytes. - if (s->write_cb && writable_size >= s->buffer_attr.minreq) - s->write_cb(s, s->buffer_attr.minreq, s->write_cb_userdata); + if (s->write_cb && writable_size >= s->buffer_attr.minreq) { + s->write_cb(s, writable_size, s->write_cb_userdata); + } size_t bytecnt = MIN(buf_size, frame_count * frame_size); bytecnt = ringbuffer_read(s->rb, buf, bytecnt);