Fix Bluetooth bonding and record verified headphone relay fix

One-shot bluetoothctl pairing exited before SSP finished, leaving the
headphone paired but not bonded, so it was lost on reboot. Pair inside a
single bluetoothctl session with a persistent agent, and clear temporary
pairings first. Document that SBC medium + 500 ms buffer removed the
iPhone -> Radxa -> headphone dropouts, verified by listening and logs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
jsahn
2026-10-12 19:01:36 +09:00
co-authored by Claude Opus 5.5
parent 5fbece12bb
commit 432eca1755
6 changed files with 59 additions and 14 deletions
+27 -3
View File
@@ -269,12 +269,13 @@ def pair(addr, output=False, bond=False):
raise ValueError('장비 주소 형식이 잘못됐습니다.')
info = run('bluetoothctl', 'info', addr, check=False, capture=True).stdout
if 'Paired: yes' not in info or (bond and 'Bonded: yes' not in info):
# Outgoing pairing agent lives only for this operation.
controller = run('bluetoothctl', 'show', capture=True).stdout
was_pairable = 'Pairable: yes' in controller
run('bluetoothctl', 'pairable', 'on')
if 'Paired: yes' in info:
# A temporary (unbonded) pairing blocks a new link key; start clean.
run('bluetoothctl', 'remove', addr, check=False, capture=True)
try:
run('bluetoothctl', '--agent', 'NoInputNoOutput', '--timeout', '25', 'pair', addr, check=False)
agent_pair(addr)
finally:
if not was_pairable:
run('bluetoothctl', 'pairable', 'off', check=False)
@@ -294,6 +295,29 @@ def pair(addr, output=False, bond=False):
print('페어링/신뢰 등록 완료:', addr)
def agent_pair(addr, scan_seconds=12, pair_seconds=20):
"""Pair inside one bluetoothctl session so the agent stays registered.
A one-shot `bluetoothctl --agent ... pair` can exit before Secure Simple
Pairing finishes, which leaves the device paired but not bonded.
"""
import time
proc = subprocess.Popen(['bluetoothctl'], stdin=subprocess.PIPE, text=True)
steps = [('agent NoInputNoOutput', 1), ('default-agent', 1), ('pairable on', 1),
('scan on', scan_seconds), ('scan off', 1), ('pair ' + addr, pair_seconds)]
try:
for command, wait in steps:
proc.stdin.write(command + '\n')
proc.stdin.flush()
time.sleep(wait)
proc.stdin.write('quit\n')
proc.stdin.flush()
proc.wait(timeout=10)
except (OSError, subprocess.TimeoutExpired):
proc.kill()
proc.wait()
def main():
p = argparse.ArgumentParser(description='Radxa AirPlay + Bluetooth 믹서 관리')
sub = p.add_subparsers(dest='cmd', required=True)