[pulseaudio-discuss] Merging soxr
andrey.semashev at gmail.com
Tue Jan 6 06:17:46 PST 2015
On Wednesday 19 November 2014 00:58:04 Alexander E. Patrakov wrote:
> 19.11.2014 00:42, Andrey Semashev wrote:
> > On Tuesday 18 November 2014 21:32:53 Alexander E. Patrakov wrote:
> >> 18.11.2014 19:14, David Henningsson wrote:
> >>> On 2014-11-18 14:46, Alexander E. Patrakov wrote:
> >>>> Add support for libsoxr resampler: David's objection about overriding
> >>>> pa_resampler_request is 100% valid, and the patchset cannot be merged
> >>>> without taking it into account.
> >>> Well, the result will be inoptimal rather than completely not working
> >>> without a working pa_resampler_request (especially given that Andrey
> >>> seems to be satisfied with the current behaviour). If we're given fewer
> >>> samples back than we expected, we'll just go through another round of
> >>> resampling/mixing/etc, which I assume is what happens here.
> >> Well, now I have looked at the code in sink.c and sink-input.c, and I
> >> must say that I don't like it. Namely, there are assertions in
> >> fill_mix_info():
> >> pa_assert(info->chunk.memblock);
> >> pa_assert(info->chunk.length > 0);
> >> At the very least, the first assertion should be moved up, because just
> >> above them, in the conditional statement, info->chunk.memblock is passed
> >> to pa_memblock_is_silence().
> >> Also there are assertions in pa_sink_input_peek() that are very similar
> >> in nature, and I don't see how it is guaranteed that the assertions
> >> never fail.
> >> So the devious sequence of events seems to be (assuming S16 stereo
> >> samples):
> >> pa_sink_input_peek is called with slength == 8 or something like that.
> >> pa_resampler_request() returns 8 or something like that.
> >> i->pop(), when asked to provide 8 bytes, creates a memchunk (tchunk) of
> >> this length.
> >> pa_resampler_run() eats the full tchunk, but produces nothing (an empty
> >> rchunk).
> >> As rchunk is empty, nothing gets pushed onto render_memblockq.
> >> Then pa_memblockq_peek() gets called, and it is asserted that the
> >> returned chunk exists and is not empty. Which looks dubious, and I think
> >> that we can try triggering this with a very-low-latency client
> >> (unpatched wine or maybe qemu?).
> >> So, incorrect results from pa_resampler_request() look dangerous when
> >> the difference results in zero vs non-zero output samples from
> >> pa_resampler_run().
> >> Of course, all of the above is in no way specific to the soxr resampler.
> >> An imprecise pa_resampler_request() is a bug. What bothers me is that
> >> soxr has a higher chance to trigger this bug.
> > So, what will be the resolution of this problem? Should I work towards
> > relaxing the requirement on pa_resampler_request() being precise or is
> > this
> > requirement permanent?
> I think that the temporary resolution would be to add a loop that calls
> pa_resampler_run repeatedly. IOW, the loop that David assumed as
> existing but which actually doesn't exist in pa_sink_input_peek().
I finally got some time to dive into the code, sorry for the delay.
As far as I understand the code, the loop is already there in
pa_sink_input_peek() (see sink-input.c:924, "while (tchunk.length > 0)"). The
outer loop (sink-input.c:893, "while (!pa_memblockq_is_readable(i-
>thread_info.render_memblockq))") will end when either render_memblockq is not
empty or the sink input is drained; in the latter case render_memblockq can be
However, render_memblockq is initialized with a silence chunk in
pa_sink_input_new(), which means that when the queue is empty it should return
silence. This means that pa_memblockq_peek() in sink-input.c:993 and the
following asserts should never fail. Same for the asserts in fill_mix_info(),
the loop should be cut short by pa_memblock_is_silence(). "pa_assert(info-
>chunk.memblock);" could be moved upper though, but it it doesn't matter for
the case in point.
Am I missing something?
More information about the pulseaudio-discuss