alsa-plugin: improve alsa plugin delay precision if alsa period is not align with the quantum

Method on_stream_process can be called multiple times with the same
pwt.delay and pwt.now values. Its a case, when snd_pcm_pipewire_process
returns less then b->requested frames. For example, if requested is 2048
and alsa period size is 512, then on_stream_process is called 4 times
in a row with the same pwt.delay and pwt.now values.
Store number of transferred frames for this "session" in separate variable
so its incremented each time the on_stream_process is called. Number
of transferred frames is cleared when a new "session" starts.

Introduce also number of buffered frames, which is number of frames
read from alsa but not sent to pipewire yet. This is the case
when period is not align with the quantum size. For example alsa period is
480, but quantum is 512. on_stream_process is called 2 times for the first
quantum, 512 frames is sent to pipewire and 448 frames are cached for the
next round. These 448 frames needs to be included in delay computation
in the next on_stream_process.

Signed-off-by: Martin Geier <martin.geier@streamunlimited.com>
This commit is contained in:
Martin Geier 2022-10-18 14:50:51 +02:00 committed by Wim Taymans
parent 1a4c2ce624
commit f5f4be5109

View file

@ -123,6 +123,8 @@ typedef struct {
struct spa_hook stream_listener;
int64_t delay;
int64_t transfered;
int64_t buffered;
uint64_t now;
uintptr_t seq;
@ -262,7 +264,7 @@ static int snd_pcm_pipewire_delay(snd_pcm_ioplug_t *io, snd_pcm_sframes_t *delay
do {
seq1 = SEQ_READ(pw->seq);
delay = pw->delay;
delay = pw->delay + pw->transfered;
now = pw->now;
if (io->stream == SND_PCM_STREAM_PLAYBACK)
avail = snd_pcm_ioplug_hw_avail(io, pw->hw_ptr, io->appl_ptr);
@ -463,12 +465,20 @@ static void on_stream_process(void *data)
SEQ_WRITE(pw->seq);
if (pw->now != pwt.now) {
pw->transfered = pw->buffered;
pw->buffered = 0;
}
xfer = snd_pcm_pipewire_process(pw, b, &hw_avail, want);
pw->delay = delay;
/* the buffer is now queued in the stream and consumed */
if (io->stream == SND_PCM_STREAM_PLAYBACK)
pw->delay += xfer;
pw->transfered += xfer;
/* more then requested data transfered, use them in next iteration */
pw->buffered = pw->transfered < b->requested ? 0 : (pw->transfered % b->requested);
pw->now = pwt.now;
SEQ_WRITE(pw->seq);