From 7ac8cd1dbb79e1209a2c6a3dff00b6e169c60856 Mon Sep 17 00:00:00 2001 From: jsahn Date: Mon, 12 Oct 2026 19:07:34 +0900 Subject: [PATCH] Reduce mixer and Bluetooth buffers from 500 ms to 200 ms SBC medium, not the larger buffer, removed the headphone relay dropouts, so cut dmix, bluealsa-aplay and alsaloop buffers to 200 ms and the Shairport backend buffer to 0.15 s. Verified by listening (iPhone -> headphones, with AirPlay mixed in) with no RTP loss or underruns. Co-Authored-By: Claude Opus 5.5 --- README.md | 2 +- TROUBLESHOOTING.md | 5 ++++- VALIDATION.md | 12 +++++++++++- reference/CURRENT-BOARD.md | 2 +- scripts/radxa-audio.py | 8 ++++---- tests/test_manager.py | 2 +- 6 files changed, 22 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 4f2bbed..19f8062 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Mac/iPhone의 AirPlay 2 ── Shairport Sync ─┐ - Bluetooth: Debian의 BlueALSA 패키지. 기준 보드 버전 **4.3.1**. - 수신과 송신은 A2DP 음악 프로필을 사용합니다. 기준 보드에서는 SBC로 연결됐습니다. - SBC 송신 품질은 medium입니다. 기준 보드에서 high로 동시 수신·송신 시 끊겨 - 전송량을 줄였습니다. 송신 버퍼는 500 ms이며, 이 조합에서 끊김 없는 청취를 확인했습니다. + 전송량을 줄였습니다. 믹서·입력·송신 버퍼는 각 200 ms이며, 이 조합에서 끊김 없는 청취를 확인했습니다. - DAC 출력은 44.1 kHz / 스테레오 / 16비트, 블루투스용 가상 믹서는 48 kHz입니다. - 각 입력을 3 dB 낮춥니다. 여러 입력의 큰 소리가 겹쳐 찢어지면 입력 볼륨을 낮추세요. 지연 없는 실시간 녹음/악기 모니터링용 구성은 아닙니다. - 각 송신 기기의 볼륨으로 믹스 비율을 바꿉니다. diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md index 15e5feb..462c9f2 100644 --- a/TROUBLESHOOTING.md +++ b/TROUBLESHOOTING.md @@ -112,7 +112,10 @@ sudo journalctl -u radxa-mixer-web -n 40 --no-pager 기준 보드에서는 버퍼만 500 ms로 늘려서는 끊김이 남았고, 송신 SBC 품질을 high에서 medium으로 낮춘 뒤(`bluealsa --sbc-quality=medium`) 해결됐습니다. 같은 컨트롤러로 수신과 송신을 동시에 하므로 송신 전송량이 수신 손실에 영향을 줍니다. -현재 송신 버퍼는 500 ms이며 그만큼 지연이 추가됩니다. +SBC medium 적용 후에는 500 ms 버퍼가 필요 없어 믹서(dmix), Bluetooth 입력 +(`bluealsa-aplay`), 헤드폰 송신(`alsaloop`) 버퍼를 각각 200 ms로 줄였습니다. +버퍼를 다시 늘리면 지연이 그만큼 늘어나므로, 끊김이 생기면 먼저 로그로 +수신 손실인지 버퍼 오류인지 구분하세요. 청취 확인 시에는 `bluealsa-aplay -l`의 PLAYBACK 목록에 헤드폰이 있는지 먼저 봅니다. 없으면 헤드폰이 휴대폰에 직접 연결돼 Radxa를 거치지 않은 소리일 수 있습니다. diff --git a/VALIDATION.md b/VALIDATION.md index 9bea725..77c8aca 100644 --- a/VALIDATION.md +++ b/VALIDATION.md @@ -55,13 +55,23 @@ SBC 품질 변경으로 컨트롤러 오류가 해결됐다고 보지는 않습 로그에서 `Missing RTP packets`, underrun/overrun, HCI 시간 초과는 없었습니다. 따라서 SBC medium + 500 ms 버퍼 조합으로 끊김이 해소된 것으로 판단합니다. 장시간 재생 안정성은 아직 확인하지 않았습니다. + +### 지연 축소 + +500 ms 버퍼는 끊김 해결에 기여하지 않았으므로 지연을 줄였습니다. +1단계로 헤드폰 송신(`alsaloop -t`)을 200 ms로 줄여 사용자가 끊김 없음을 확인했습니다. +2단계로 dmix 버퍼 500 → 200 ms, `bluealsa-aplay --pcm-buffer-time` 500 → 200 ms, +Shairport 출력 버퍼 0.5 → 0.15 s로 줄였습니다. iPhone Bluetooth → 보스 청취에서 +사용자가 끊김 없음을 확인했고, `Missing RTP packets`·underrun은 0건이었습니다. +같은 구간의 AirPlay 동시 재생 통계에서도 Missing/Late 프레임은 0이었습니다. +경로 전체 지연은 측정하지 않았으며, 버퍼 합계 기준 약 0.6 s 줄었습니다. 이미 영구 등록된 휴대폰 등록은 재부팅 후 유지됐습니다. ## 실제 청취로 확인한 범위 사용자가 AirPlay 재생, AirPlay + 아이폰 Bluetooth 입력의 DAC 믹스 재생을 정상 청취했다고 확인했습니다. iPhone Bluetooth 입력 → 보스 헤드폰 출력도 -SBC medium / 500 ms 버퍼 설정에서 끊김 없이 청취했다고 확인했습니다. +SBC medium / 200 ms 버퍼 설정에서 끊김 없이 청취했다고 확인했습니다. ## 아직 검증하지 않은 범위 diff --git a/reference/CURRENT-BOARD.md b/reference/CURRENT-BOARD.md index f5fbbd7..c699dfd 100644 --- a/reference/CURRENT-BOARD.md +++ b/reference/CURRENT-BOARD.md @@ -18,7 +18,7 @@ 사용자가 정상 청취를 확인했습니다. Bose 헤드폰은 페어링/신뢰 등록 및 A2DP SBC 48 kHz 출력 연결과 가상 믹서 전송까지 확인했습니다. 사용자는 이후 iPhone → 보스 경로의 소리 끊김을 보고했습니다. 수신 패킷 손실과 -버퍼 오류를 확인했습니다. 500 ms 버퍼와 SBC medium 송신 설정을 적용하고 +버퍼 오류를 확인했습니다. SBC medium 송신 설정과 200 ms 버퍼(지연 축소)를 적용하고 보스를 영구 등록한 뒤, iPhone → Radxa → 보스 경로의 정상 청취를 확인했습니다. 기존 설정 백업은 보드의 `/root/audio-mixer-backup-20261012-162401/`와 diff --git a/scripts/radxa-audio.py b/scripts/radxa-audio.py index 04695d1..cff9300 100755 --- a/scripts/radxa-audio.py +++ b/scripts/radxa-audio.py @@ -80,7 +80,7 @@ pcm.radxa_dmix {{ channels 2 period_time 0 period_size {rate // 100} - buffer_size {rate // 2} + buffer_size {rate // 5} }} bindings {{ 0 0 1 1 }} }} @@ -105,7 +105,7 @@ def templates(c): name = {json.dumps(c['name'], ensure_ascii=False)}; service_type = "airplay2"; output_backend = "alsa"; - audio_backend_buffer_desired_length_in_seconds = 0.5; + audio_backend_buffer_desired_length_in_seconds = 0.15; }}; alsa = {{ output_device = "radxa_mix"; @@ -126,7 +126,7 @@ Group=audio PrivateUsers=false RemoveIPC=false ExecStart= -ExecStart=/usr/bin/bluealsa-aplay -S --pcm=radxa_mix --volume=software --pcm-period-time=10000 --pcm-buffer-time=500000 +ExecStart=/usr/bin/bluealsa-aplay -S --pcm=radxa_mix --volume=software --pcm-period-time=10000 --pcm-buffer-time=200000 ''', '/etc/modules-load.d/radxa-audio-loopback.conf': 'snd-aloop\n', '/etc/modprobe.d/radxa-audio-loopback.conf': 'options snd-aloop pcm_substreams=1\n', @@ -143,7 +143,7 @@ StartLimitIntervalSec=0 User=shairport-sync Group=audio ExecStartPre=-/usr/bin/bluetoothctl --timeout 8 connect {addr} a2dp-sink -ExecStart=/usr/bin/alsaloop -C hw:Loopback,1,0 -P bluealsa:DEV={addr},PROFILE=a2dp -c 2 -r 48000 -f S16_LE -t 500000 -S 4 -A 2 +ExecStart=/usr/bin/alsaloop -C hw:Loopback,1,0 -P bluealsa:DEV={addr},PROFILE=a2dp -c 2 -r 48000 -f S16_LE -t 200000 -S 4 -A 2 Restart=always RestartSec=5 TimeoutStartSec=30 diff --git a/tests/test_manager.py b/tests/test_manager.py index 2eada4b..2ac93f5 100644 --- a/tests/test_manager.py +++ b/tests/test_manager.py @@ -52,7 +52,7 @@ class ManagerTests(unittest.TestCase): self.assertIn('Loopback', f['/etc/asound.conf']) self.assertIn('rate 48000',f['/etc/asound.conf']) self.assertIn('--sbc-quality=medium',f['/etc/systemd/system/bluealsa.service.d/10-radxa-sink.conf']) - self.assertIn('-t 500000',unit) + self.assertIn('-t 200000',unit) def test_name_quotes_are_escaped(self): f=m.templates(self.config(name='Desk "Two"'))