[pulseaudio-discuss] Async API - need some help

Tanu Kaskinen tanuk at iki.fi
Sun Jun 19 03:18:46 PDT 2011


On Sun, 2011-06-19 at 11:53 +0200, Zeno Endemann wrote:
> On 2011-06-19 10:48, Tanu Kaskinen wrote:
> > On Sun, 2011-06-19 at 11:28 +0300, Tanu Kaskinen wrote:
> >> Btw, pa_buffer_attr.tlength is given in microseconds, but you pass the
> >> number in the UI without converting it, and since the ui doesn't let me
> >> choose bigger numbers than 2000, the maximum tlength is 8000
> >> microseconds... (Why do you multiply the number with 4, btw?)
> > 
> > Uh, I'm talking nonsense here. tlength is given in bytes. Your
> > conversion is broken still, though. What I said about the effective
> > tlength not being what was requested is not true - pulseaudio does seem
> > to work correctly here (the effective tlength is less than what is
> > requested, but I'd guess that the sink latency is getting substracted
> > from the requested length). Latency reporting is still broken.
> > 
> 
> Thanks for the help! The correct formula for tlength should be
> latency * 2 * sspec.channels * sspec.rate / 1000, right?

Yes, I believe that's correct. But please use pa_usec_to_bytes(), it's
easier to read :)

> Should I file a bug report for the latency thing?

Yes, please.

> >> 1. The following code fragment works (audio is played):
> >>     int16_t *buf = (int16_t *)malloc(nbytes);
> >>     writeToneToBuffer(buf, nbytes/4, ...);
> >>     pa_stream_write(p, buf, (nbytes/4)*4, 0, 0, PA_SEEK_RELATIVE );
> >>     free(buf);
> >> whereas this does not:
> >>     int16_t *buf = 0;
> >>     pa_stream_begin_write(p, (void **)&buf, &nbytes);
> >>     writeToneToBuffer(buf, nbytes/4, ...);
> >>     pa_stream_write(p, buf, (nbytes/4)*4, 0, 0, PA_SEEK_RELATIVE );
> >> There is no error reported, just no audio is played. Do I need to do
> >> something else?
> > 
> > It seems to work fine if I set the latency to some low value. With
> > higher latencies the problem is that pa_stream_begin_write() returns a
> > buffer that is much smaller than the original request size, and it's not
> > enough to fill the buffer to the prebuf limit. Since the prebuffering
> > never ends, the stream never starts playing. You should make multiple
> > writes until the buffer is full (ie. pa_stream_writable_size returns 0).
> 
> Hm, the following code seems to work, did you mean it like this:
>     while( pa_stream_writable_size(p) > 0) {
>         pa_stream_begin_write(p, (void **)&buf, &nbytes);
>         if( ! buf )
>             break;
>         writeToneToBuffer(buf, nbytes/4, cs);
>         pa_stream_write(p, buf, (nbytes/4)*4, 0, 0, PA_SEEK_RELATIVE );
>     }

That probably works fine, but I'd keep track of what was the original
nbytes value and substract from it after calling pa_stream_write().

The if (!buf) check should be redundant. pa_stream_begin_write() never
returns a null buffer unless you have made a mistake (see the checks at
<http://cgit.freedesktop.org/pulseaudio/pulseaudio/tree/src/pulse/stream.c#n1384>) - if you don't trust yourself, you can break if pa_stream_begin_write() returns an error, or use an assertion.

> >> 2. I figure it should be possible to react fast to user input even when
> >> the playback buffers are big by overwriting already written buffers with
> >> pa_stream_write(..., buf, ..., offset, PA_SEEK_RELATIVE_ON_READ). But
> >> how big can/should buf and offset be? So far I haven't been able to get
> >> good results with this (either underruns are reported or the latency
> >> remains quite bad).
> > 
> > I don't have any advice for the offset, sorry. It would be good to have
> > some example code for doing rewrites... For buf size, I'd guess pretty
> > large buffers would be good. If you can use
> > pa_stream_begin_write(nbytes=-1), use it and fill the whole buffer it
> > gives you, or if you use a small buffer, you'll probably want to limit
> > the amount you write to tlength + offset (offset being a negative
> > number).
> 
> I tried using pa_stream_begin_write, but it always returns a nullpointer
> there...

It shouldn't return a null pointer. Check the error code.

> and wouldn't a neagtive offset mean that I loose some samples,
> because they are written before the read position?

For some reason it's not documented how the offset is interpreted, or at
least I didn't find where it's said. I checked the code and it seemed
that a negative offset would mean that the samples would be written
after the read position, but I'm not 100% sure.

-- 
Tanu



More information about the pulseaudio-discuss mailing list