Feature request: keep the ALSA output running briefly between streams (--keep-output-alive <s>)
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 42/100
- Loại issue
- Tính năng
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- cpp
- Lĩnh vực
- audio-video-rtc
Hướng nghiên cứu
Start with alsa_sink.h and alsa_sink.cpp, then trace the existing fixed-volume option through CLI parsing, configuration, and sendspin-cli.conf.example. Use the attached patch and the modeled parse/config tests as references, and run the build-armv6 container with SENDSPIN_CLI_WERROR=ON. Done means the ALSA keep-alive behavior, timeout, CLI/config bounds, and no-op behavior for other backends are implemented and all 122 tests pass.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Problem
With an HDMI (or S/PDIF) receiver behind the player, the start of every stream is cut off.
At each stream end and start, AlsaAudioSink stops the PCM:
clear()callssnd_pcm_drop()+snd_pcm_prepare()configure()does the same when the next stream has the same format
The PCM then sits in PREPARED (or in XRUN, if the ring runs dry before clear() arrives)
until the next stream writes. While it does, no audio packets go out over HDMI, so the receiver
drops the input and has to re-lock when audio comes back. That takes about 2-3 s on an Onkyo
TX-NR626. For Music Assistant announcements (TTS) this is a real problem: MA ends the music
stream, plays the announcement as its own stream and then resumes the music, so the receiver
re-locks twice, and most of a short announcement is lost. A pre-announce chime is too short
to cover the re-lock.
Setup: Raspberry Pi Zero W, sendspin-cli 0.4.0 (linux-armv6), Music Assistant 2.10.8.
Output is onkyo_hdmi, a copy of the hdmi:CARD=vc4hdmi,DEV=0 chain in asound.conf with the
hw rate pinned to 48 kHz, plus audio-format = flac:48000:24:2,pcm:48000:24:2, so the format
never changes between streams and only the same-format path below is involved.
Measured by polling /proc/asound/card0/pcm0p/sub0/status every 250 ms during
radio -> TTS -> radio:
RUNNING (radio)
PREPARED ~1 s <- stream end, clear()
RUNNING (TTS, ~6 s)
XRUN ~0.3 s <- ring ran dry before the stream-end message
PREPARED ~2 s
RUNNING (radio)
Workarounds that do not work
Both try to keep the device busy from outside the player. Each puts a layer between the player
and the device that reports snd_pcm_delay() too coarsely or too jittery for the 5 ms
HARD_SYNC_THRESHOLD_US. The result is a constant Lost sync / hard-sync loop, which you hear
as choppy audio:
snd-aloop+alsaloopfeeding HDMI. The loopback pointer moves in jiffies, and the Pi
kernel runsHZ=100. Result:Lost sync (~90 ms off)about every second, with any
alsalooplatency or sync mode.- System-mode PulseAudio with
module-suspend-on-idleunloaded (-o pulse). The same
Lost syncstorm, see #32, plus 100 % CPU on a Pi Zero.
So this has to happen inside the sink, where the delay reported to the sync task comes straight
from the device.
Proposal
An opt-in option --keep-output-alive <seconds> (config key keep-output-alive), 0-3600,
default 0 (off), ALSA backend only. Other backends get a no-op AudioSink::set_keep_alive().
The goal is only to bridge the switch from one stream to the next, not to keep the receiver
awake forever: a few seconds (e.g. keep-output-alive = 10) are enough.
When enabled:
clear()and the same-format path inconfigure()no longer drop the PCM. If it is
running, they rewind the queued audio withsnd_pcm_rewind(), keeping one period in front
of the hardware pointer as a DMA safety margin. Then they write a short run of silence right
away. If the rewind fails, the queued tail simply plays out.poll()(main loop, ~10 ms) tops the ring up with silence to about 2 periods oncewrite()
has not delivered real audio for 60 ms. It usestry_lockondevice_mutex_: awrite()
blocked insnd_pcm_wait()holds the mutex, so a stream that is running is never touched
and the main loop never stalls. The same path re-prepares anXRUN(e.g. the ring ran dry
at the end of a stream beforeclear()), so the signal does not drop there either.- Time limit. Every real
write()and every same-formatconfigure()(re)starts a window
of<seconds>; aclear()restarts it while it is still open. When it runs out, the PCM is
dropped and prepared exactly as without the option, so the receiver sees the signal end and
its auto standby still works. After that,clear()behaves as without the option, and the
next stream starts the PCM again and opens a new window. - Sync is not touched: the keep-alive silence is just queued frames, and the next real
write()measures it throughsnd_pcm_delay()as usual.
Results
A patch against v0.4.0 (about 170 added lines in alsa_sink.{h,cpp}, plus option plumbing, help
text, sendspin-cli.conf.example and parse/config tests modeled on --fixed-volume) is
attached. It builds with SENDSPIN_CLI_WERROR=ON in the build-armv6 container, and all
122 tests pass. clear() and configure() are unchanged on current main, so it should apply
there with little or no change.
On the Pi Zero W above, with keep-output-alive = 10:
- HDMI PCM
RUNNINGwithout a break through radio -> TTS -> radio (polled every 250 ms) - the receiver no longer re-locks, and TTS announcements play from the first word
- no
Lost syncduring the switches; CPU the same as without the option (~75 % idle) - after a pause the PCM went from
RUNNINGtoPREPAREDexactly 10 s after the last audio
(so the receiver can go to standby), and the next stream started normally
Open questions
- Name and unit: is
keep-output-alive <seconds>fine, or would you prefer milliseconds or an
output-level setting? - Is a hard cap (3600 s) sensible, or should there be a "forever" value for setups that want
it? I left that out on purpose so that receivers can always go to standby. - PortAudio, Pulse and PipeWire are left out on purpose. Pulse and PipeWire already have their
own idle/suspend handling.
- Ngôn ngữ chính
- C++
- Star
- 18
- Fork
- 7
- Merge trung bình
- 1 ngày 12 giờ
- Pull request đã merge (30 ngày)
- 26
Chuẩn bị môi trường
Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của Sendspin/sendspin-cpp-cli
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
Sendspin/sendspin-cpp-cli#111 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 35/100
Sendspin/sendspin-cpp-cli#108 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 62/100
Sendspin/sendspin-cpp-cli#106 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 35/100
Sendspin/sendspin-cpp-cli#97 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Idle CPU: a fixed 10 ms main loop, and a PulseAudio stream that stays open after the stream endsĐang mở
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 42/100
Sendspin/sendspin-cpp-cli#92 ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của Sendspin/sendspin-cpp-cli
Issue tương tự
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 65/100
-
error not reported I/O low priority rt_lib
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 67/100
Maintainer thường phản hồi trong vòng 1 ngày
-
[XLA] hlo/pass/README.md says passes implement Run; since the NVI change they implement RunImplĐang mở
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 91/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
NVIDIA-RTX/NRI#312 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 67/100
Maintainer thường phản hồi trong vòng 9 ngày