mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-10-04 13:24:13 +08:00
Bind dedicated Bluetooth PCM directly instead of late-overridden ALSA defaults
This commit is contained in:
@@ -6,6 +6,8 @@ import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
PCM_NAME = 'roadscore_bluetooth'
|
||||
|
||||
ADDRESS = re.compile(r'^(?:[0-9A-F]{2}:){5}[0-9A-F]{2}$')
|
||||
|
||||
|
||||
@@ -43,14 +45,15 @@ def prepare_output(directory, *, env=None, reader=real_selection,
|
||||
raise ValueError('A valid system ALSA configuration file is required')
|
||||
path=Path(directory).resolve()/'roadscore-bluealsa.conf'
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
config=f'<{base}>\n\ndefaults.bluealsa.!device "{address}"\ndefaults.bluealsa.!profile "a2dp"\n'
|
||||
config=(f'<{base}>\n\npcm.{PCM_NAME} {{\n type bluealsa\n device "{address}"\n'
|
||||
' profile "a2dp"\n hint { show on description "RoadScore selected Bluetooth speaker" }\n}\n')
|
||||
# Exclusive creation protects existing configuration and keeps the change process-local.
|
||||
with path.open('x') as handle:
|
||||
os.chmod(path, 0o600)
|
||||
handle.write(config)
|
||||
env['ALSA_CONFIG_PATH']=str(path)
|
||||
return {'bluetooth_selected':True, 'address':address, 'output_identity':f'bluealsa:{address}',
|
||||
'profile':'a2dp', 'sample_rate':48000, 'channels':2, 'alsa_config':str(path),
|
||||
'profile':'a2dp', 'pcm_name':PCM_NAME, 'sample_rate':48000, 'channels':2, 'alsa_config':str(path),
|
||||
'timing_source':'PortAudio host/backend estimate; not measured acoustic Bluetooth latency',
|
||||
'physical_latency_ms':None}
|
||||
|
||||
@@ -59,8 +62,8 @@ def select_device(devices, metadata):
|
||||
if not metadata.get('bluetooth_selected'):
|
||||
return None
|
||||
matches=[index for index, device in enumerate(devices)
|
||||
if str(device.get('name', '')).strip().lower()=='bluealsa'
|
||||
if str(device.get('name', '')).strip().lower()==metadata.get('pcm_name', PCM_NAME)
|
||||
and device.get('max_output_channels', 0)>=2]
|
||||
if len(matches)!=1:
|
||||
raise RuntimeError('Selected Bluetooth speaker requires one stereo BlueALSA output; no speaker fallback')
|
||||
raise RuntimeError('Selected Bluetooth speaker requires one selected RoadScore Bluetooth PCM; no speaker fallback')
|
||||
return matches[0]
|
||||
|
||||
@@ -13,13 +13,15 @@ class BluetoothOutputTests(unittest.TestCase):
|
||||
meta=prepare_output(Path(d)/'run',env=env,reader=lambda _:dict(enabled=True,address='aa:bb:cc:dd:ee:ff'),alsa_base=base,loaded_modules={})
|
||||
text=Path(env['ALSA_CONFIG_PATH']).read_text()
|
||||
self.assertIn(f'<{base}>',text)
|
||||
self.assertIn('defaults.bluealsa.!device "AA:BB:CC:DD:EE:FF"',text)
|
||||
self.assertIn('pcm.roadscore_bluetooth {',text)
|
||||
self.assertIn('device "AA:BB:CC:DD:EE:FF"',text)
|
||||
self.assertNotIn('defaults.bluealsa',text)
|
||||
self.assertEqual(base.read_text(),'system config')
|
||||
self.assertEqual(env['OPENPILOT_PREFIX'],'replay')
|
||||
self.assertIsNone(meta['physical_latency_ms'])
|
||||
self.assertEqual(select_device([{'name':'default','max_output_channels':2},{'name':'bluealsa','max_output_channels':128}],meta),1)
|
||||
self.assertEqual(select_device([{'name':'default','max_output_channels':2},{'name':'roadscore_bluetooth','max_output_channels':128}],meta),1)
|
||||
def test_missing_or_ambiguous_bluetooth_does_not_fallback(self):
|
||||
for devices in [[],[{'name':'default','max_output_channels':2}], [{'name':'bluealsa','max_output_channels':1}], [{'name':'bluealsa','max_output_channels':2}]*2]:
|
||||
for devices in [[],[{'name':'default','max_output_channels':2}], [{'name':'bluealsa','max_output_channels':128}], [{'name':'roadscore_bluetooth','max_output_channels':1}], [{'name':'roadscore_bluetooth','max_output_channels':2}]*2]:
|
||||
with self.assertRaises(RuntimeError):select_device(devices,{'bluetooth_selected':True})
|
||||
def test_disabled_does_not_touch_configuration(self):
|
||||
env={};self.assertEqual(prepare_output('/unused',env=env,reader=lambda _:dict(enabled=False)),{'bluetooth_selected':False});self.assertEqual(env,{})
|
||||
|
||||
Reference in New Issue
Block a user