Skip to content

Pulse, PortAudio and PipeWire sinks leave outage frames in the playback clock #58

Description

@chrisuthe

#55 fixes this for the ALSA sink (#54). The other three device-backed sinks have the same gap.

When the stream is gone, each sink's write() accepts audio so the sync task does not spin:

  • src/pulse_sink.cpp:452
  • src/portaudio_sink.cpp:532
  • src/pipewire_sink.cpp:437

The sync task adds those bytes to buffered_frames, but no on_frames_played report ever retires them. After the stream recovers, the first real progress report computes finish_timestamp + frames_to_us(buffered_frames), so the playhead jumps ahead by the whole outage. The result is sync-loss cycling until the next stream resets the count.

Port the ALSA approach from #55:

  • Count discarded frames in SinkRecovery (discard_frames()), under the sink's lock.
  • Do not report the gap from the recovery path. Take it with the first report that has a device timestamp, and retire it in that same on_frames_played call, saturating at UINT32_MAX.
  • Count frames written just before a loss (the stream closed mid-write) as discarded too.
  • Drop the gap in clear() and at the top of configure() with forget_discarded_frames(), without refilling the budget.

Only Pulse reports progress from write() (pulse_sink.cpp:581), so it can follow ALSA directly. PortAudio (portaudio_sink.cpp:1010) and PipeWire (pipewire_sink.cpp:711) report from their audio callbacks, so the gap has to be taken there, under whatever guards the count on that thread.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions