You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A capture stream whose reader thread gives up goes on looking healthy to whoever owns it. The
device stops producing, an error is logged, and nothing else changes: the stream reports no
failure, and stopping it succeeds. So a MicrophoneSource believes it holds a working
microphone that has merely gone quiet, and an application built on it has no way to notice, retry,
or fail. The seam needs a way to say "this stream is dead" in code, not only in a log line.
To the best of our current knowledge, on the ALSA arm the reader ends early on three paths — a
long run of waits that produced nothing, an unrecoverable refusal while reading device status,
and a recovery that could not restart the device. Each logs at error! and returns. Afterwards
the delivery handle is still present (a finished thread handle is indistinguishable from a
running one), the stream still believes its device is running, and stopping it joins the dead
thread and reports success.
Design
Nothing here is settled; the shape is the work. The plan decides the audio device seam exists — AudioDeviceBackend opening AudioCaptureStream and AudioPlaybackStream
(docs/plan/ARCHITECTURE.md §Media I/O [audio-subsystem]) — but does not fix its method list,
so choosing the surface is pattern choice inside this ticket rather than a plan change. It does
not need /align.
Three shapes were named when this was surfaced; the first two are live, the third is not:
An error hand-off beside the sample hand-off — the backend calls it once when the stream
dies. The caller learns when it happens. Costs a second callback on the seam, and the same
"must not block, must not re-enter" contract the sample hand-off already carries.
A pollable failure — something like capture_failure() -> Option<Error> the owner reads on
its own schedule. Cheaper surface; the caller only learns when it next looks.
Whichever lands applies to all three arms — PipeWire, ALSA and the silent-null backend all
implement the trait — and the null backend's answer ("never dies") is part of the design, not an
afterthought.
Done means
An owner of a stream can learn in code that its device stopped serving it, without reading
logs — capture and playback alike, since both directions shipped onto this seam before the
shape did.
The answer is the same shape on every arm of the backend chain, including the null backend.
A stream that was stopped deliberately is not reported as a failure.
Validation shape
A unit-level test that drives a stream whose reader — or writer — ends for each reason it can end
for, and asserts the owner observes the failure — the arms' reader-exit paths are reachable without
hardware if the failure is injectable at the seam rather than only at a real device. Alongside
it, an audio-tier check that a healthy stream reports no failure across an ordinary run, so the
signal cannot be wired to fire always. The existing tier assertions that a stopped stream is
silent and that a restart replaces the hand-off must keep passing unchanged.
Needs the physical rig?
audio
Non-derivable notes
Surfaced by review of #2010 (closing #1991), which shipped the ALSA arm; it is a property of the
seam, not of that arm, and the PipeWire arm has it too.
Deferred from #1991 on scope rather than on architecture. An earlier reading called it an
architecture question and that was wrong — the plan fixes the seam's existence, not its methods.
Sequencing: #1992 shipped first (PR #2013), so AudioPlaybackStream is already on this seam and
the retrofit this ticket anticipated for that order is the one that has to happen — the shape
lands across both stream types rather than one, which is still answering the question once. The
ALSA writer thread ends early on the same three paths its reader does
(alsa_audio_device_backend.rs:1085,1096 and an unrecoverable snd_pcm_writei), and the
PipeWire shim already records PW_STREAM_STATE_ERROR into stream_failed / stream_failure_text for either direction — nothing reads it once the stream is open.
What & why
A capture stream whose reader thread gives up goes on looking healthy to whoever owns it. The
device stops producing, an error is logged, and nothing else changes: the stream reports no
failure, and stopping it succeeds. So a
MicrophoneSourcebelieves it holds a workingmicrophone that has merely gone quiet, and an application built on it has no way to notice, retry,
or fail. The seam needs a way to say "this stream is dead" in code, not only in a log line.
To the best of our current knowledge, on the ALSA arm the reader ends early on three paths — a
long run of waits that produced nothing, an unrecoverable refusal while reading device status,
and a recovery that could not restart the device. Each logs at
error!and returns. Afterwardsthe delivery handle is still present (a finished thread handle is indistinguishable from a
running one), the stream still believes its device is running, and stopping it joins the dead
thread and reports success.
Design
Nothing here is settled; the shape is the work. The plan decides the audio device seam exists —
AudioDeviceBackendopeningAudioCaptureStreamandAudioPlaybackStream(
docs/plan/ARCHITECTURE.md§Media I/O[audio-subsystem]) — but does not fix its method list,so choosing the surface is pattern choice inside this ticket rather than a plan change. It does
not need
/align.Three shapes were named when this was surfaced; the first two are live, the third is not:
dies. The caller learns when it happens. Costs a second callback on the seam, and the same
"must not block, must not re-enter" contract the sample hand-off already carries.
capture_failure() -> Option<Error>the owner reads onits own schedule. Cheaper surface; the caller only learns when it next looks.
stop_delivering— rejected once already, during review offeat(engine): the ALSA arm — dlopen'd libasound with monotonic timestamps, and the chain demotes in order #2010. It tells you at teardown, which is the one moment the answer no longer matters: capture
has been dead since the reader returned and the owner had no way to know. Recorded here so it
is not re-proposed as new.
Whichever lands applies to all three arms — PipeWire, ALSA and the silent-null backend all
implement the trait — and the null backend's answer ("never dies") is part of the design, not an
afterthought.
Done means
logs — capture and playback alike, since both directions shipped onto this seam before the
shape did.
Validation shape
A unit-level test that drives a stream whose reader — or writer — ends for each reason it can end
for, and asserts the owner observes the failure — the arms' reader-exit paths are reachable without
hardware if the failure is injectable at the seam rather than only at a real device. Alongside
it, an audio-tier check that a healthy stream reports no failure across an ordinary run, so the
signal cannot be wired to fire always. The existing tier assertions that a stopped stream is
silent and that a restart replaces the hand-off must keep passing unchanged.
Needs the physical rig?
Non-derivable notes
Surfaced by review of #2010 (closing #1991), which shipped the ALSA arm; it is a property of the
seam, not of that arm, and the PipeWire arm has it too.
Deferred from #1991 on scope rather than on architecture. An earlier reading called it an
architecture question and that was wrong — the plan fixes the seam's existence, not its methods.
Sequencing: #1992 shipped first (PR #2013), so
AudioPlaybackStreamis already on this seam andthe retrofit this ticket anticipated for that order is the one that has to happen — the shape
lands across both stream types rather than one, which is still answering the question once. The
ALSA writer thread ends early on the same three paths its reader does
(
alsa_audio_device_backend.rs:1085,1096and an unrecoverablesnd_pcm_writei), and thePipeWire shim already records
PW_STREAM_STATE_ERRORintostream_failed/stream_failure_textfor either direction — nothing reads it once the stream is open.