[pulseaudio-discuss] [PATCH v2] pacat: Write to stream in frame-sized chunks

Ahmed S. Darwish darwish.07 at gmail.com
Mon Dec 26 05:31:53 UTC 2016


Hi,

First, wish you all a merry Christmas :-)

On Wed, Dec 21, 2016 at 06:16:36AM +0200, Ahmed S. Darwish wrote:
> On Tue, Dec 20, 2016 at 10:03:22AM +0000, Ahmed S. Darwish wrote:
> > On Tue, Dec 20, 2016 at 03:20:00PM +0530, Arun Raghavan wrote:
> > >
...
> > >
> > > Is that a regression?
> > >
> >
> > Didn't try this on earlier versions of pulse to know for sure;
> > will invesitgate further..
> >
>
> OK, it is a regression introduced after v9.0. I've done some
> bisections; here is the offending commit:
>
> commit 74251f07864c63439ea847d7287024ac54578d64
> Author: Pierre Ossman <ossman at cendio.se>
> Date:   Thu May 19 15:54:08 2016 +0200
>
>     memblockq: remove internal "missing" state variable
>
>     It was a very confusing state variable that required a lot of
>     fiddling. It was also redundant in that it can be computed from
>     the other variables, removing any risk of it getting out of sync.
>     In the same spirit, make sure "requested" also always contains a
>     sane value, even though it may not be used by every caller.
>
> The issue (not receiving any more stream write callback events) can
> be triggered by:
>
>     ./src/pacat -r --latency-msec=4 | ./src/pacat --latency-msec=4
>

OK, the regression is that in the cleanup commit above, the semantics
of memblockq 'missing' length calculations has changed.

Namely, bq->requested is now used as a _cach_ for caclculating the
now removed bq->missing:

size_t pa_memblockq_pop_missing(pa_memblockq *bq) {
  ...

  /* Note that write_index might be before read_index, which means
   * that we should ask for extra data to catch up. This also means
   * that we cannot call pa_memblockq_length() as it doesn't return
   * negative values. */

  length = (bq->write_index - bq->read_index) + bq->requested;
                                                ^^^^^^^^^^^^^^
  if (length > (int64_t)bq->tlength)
    return 0;

  missing = (int64_t)bq->tlength - length;

  ...

  bq->requested += missing;

  ...
  return missing;
}

But bq->requested has different semantics upon write index change
before and after the same commit:

After the cleanup commit:

static void write_index_changed(pa_memblockq *bq, int64_t old_write_index,
                                bool account) {
  int64_t delta;

  delta = bq->write_index - old_write_index;

  if (account) {
    if (delta > (int64_t)bq->requested)
      bq->requested = 0;        <== Here is the trigger; bq 'requested'
                                <== only adjusted in the positive case
    else if (delta > 0)
      bq->requested -= delta;
  }
  ...
}

But before it:

static void write_index_changed(pa_memblockq *bq, int64_t old_write_index,
                                bool account) {
  int64_t delta;

   delta = bq->write_index - old_write_index;

  if (account)
    bq->requested -= delta;       <== bq requested adjusted regardless
                                  <== of sign
  else
    bq->missing -= delta;         <== bq missing is adjusted
                                  <== regardless of 'account'

  ...
}

Restoring the old semantics of bq->requested to allow negative values
upon write index change fixes the issue. It makes
pa_memblockq_pop_missing() reports non-zero values again, and thus
further stream write callback events to be triggered.

Note: this is still a very partial / preliminary understanding. I'm
investigating further for the root cause / right solution ...

regards,

-- 
Darwish
http://darwish.chasingpointers.com


More information about the pulseaudio-discuss mailing list