Add web mixer with native input volume and output selection

This commit is contained in:
jsahn
2026-10-12 18:45:43 +09:00
parent ceef64dfed
commit 5fbece12bb
19 changed files with 696 additions and 34 deletions
+25 -1
View File
@@ -40,7 +40,7 @@ class ManagerTests(unittest.TestCase):
self.assertIn('"radxa_mix"',f['/etc/shairport-sync.conf'])
self.assertIn('--pcm=radxa_mix',f['/etc/systemd/system/bluealsa-aplay.service.d/10-radxa-mixer.conf'])
self.assertNotIn('--single-audio', ''.join(f.values()))
self.assertIn('ttable { 0.0 0.5 1.1 0.5 }',f['/etc/asound.conf'])
self.assertIn('ttable { 0.0 0.707945784 1.1 0.707945784 }',f['/etc/asound.conf'])
self.assertIn('rate 44100',f['/etc/asound.conf'])
def test_output_device_is_not_hardcoded(self):
@@ -51,6 +51,8 @@ class ManagerTests(unittest.TestCase):
self.assertNotIn('E4:58',unit)
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)
def test_name_quotes_are_escaped(self):
f=m.templates(self.config(name='Desk "Two"'))
@@ -64,6 +66,28 @@ class ManagerTests(unittest.TestCase):
self.assertFalse(any('pair' in call.args for call in run.call_args_list))
self.assertTrue(any('trust' in call.args for call in run.call_args_list))
def test_bond_request_must_not_report_temporary_pair_as_success(self):
def fake(*args, **kwargs):
return subprocess.CompletedProcess(args,0,stdout='Paired: yes\nBonded: no')
with patch.object(m,'root'),patch.object(m,'run',side_effect=fake) as run:
with self.assertRaises(ValueError):m.pair('AA:BB:CC:DD:EE:FF',output=True,bond=True)
self.assertFalse(any('trust' in call.args for call in run.call_args_list))
def test_bond_request_keeps_existing_bond(self):
def fake(*args, **kwargs):
return subprocess.CompletedProcess(args,0,stdout='Paired: yes\nBonded: yes')
with patch.object(m,'root'),patch.object(m,'run',side_effect=fake) as run:
m.pair('AA:BB:CC:DD:EE:FF',bond=True)
self.assertFalse(any('pair' in call.args for call in run.call_args_list))
def test_reconfigure_does_not_require_headphone_to_be_on(self):
c=self.config(output='bluetooth',bluetooth_device='AA:BB:CC:DD:EE:FF')
with patch.object(m,'root'), patch.object(m,'run') as run, patch.object(m,'load',return_value=c), \
patch.object(m,'snapshot',return_value=Path('/mock')), patch.object(m,'save'), \
patch.object(m,'active',return_value=True),patch.object(m,'enabled',return_value=True):
m.apply(c,reconfigure=True)
self.assertFalse(any('connect' in call.args for call in run.call_args_list))
def test_failed_service_restores_configuration(self):
c=self.config()
with patch.object(m, 'root'), patch.object(m, 'run') as run, \