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 <noreply@anthropic.com>
This commit is contained in:
jsahn
2026-10-12 19:07:34 +09:00
co-authored by Claude Opus 5.5
parent 432eca1755
commit 7ac8cd1dbb
6 changed files with 22 additions and 9 deletions
+1 -1
View File
@@ -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 낮춥니다. 여러 입력의 큰 소리가 겹쳐 찢어지면 입력 볼륨을 낮추세요. 지연 없는 실시간 녹음/악기 모니터링용 구성은 아닙니다.
- 각 송신 기기의 볼륨으로 믹스 비율을 바꿉니다.
+4 -1
View File
@@ -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를 거치지 않은 소리일 수 있습니다.
+11 -1
View File
@@ -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 버퍼 설정에서 끊김 없이 청취했다고 확인했습니다.
## 아직 검증하지 않은 범위
+1 -1
View File
@@ -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/`와
+4 -4
View File
@@ -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
+1 -1
View File
@@ -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"'))