Attempt to decrease dectalk lag. Hoping you don't have to send settings over every time you want it to say something.
This commit is contained in:
@@ -27,6 +27,7 @@ class driver(dectalkDriver.driver):
|
||||
def initialize(self, environment):
|
||||
self.env = environment
|
||||
self._is_initialized = False
|
||||
self._reset_setting_cache()
|
||||
self.usb_device = None
|
||||
self.usb_core = None
|
||||
self.usb_util = None
|
||||
@@ -187,7 +188,7 @@ class driver(dectalkDriver.driver):
|
||||
def _write_bytes(self, data, description="data", cancel_generation=None):
|
||||
if description == "speech" and cancel_generation is None:
|
||||
cancel_generation = self._get_speech_cancel_generation()
|
||||
self._write_endpoint(
|
||||
return self._write_endpoint(
|
||||
self.speech_endpoint,
|
||||
data,
|
||||
description,
|
||||
@@ -203,12 +204,12 @@ class driver(dectalkDriver.driver):
|
||||
cancel_generation=None,
|
||||
):
|
||||
if not data:
|
||||
return
|
||||
return False
|
||||
if write_lock is None:
|
||||
write_lock = self.lock
|
||||
with write_lock:
|
||||
if self.usb_device is None:
|
||||
return
|
||||
return False
|
||||
try:
|
||||
total_written = 0
|
||||
while total_written < len(data):
|
||||
@@ -220,7 +221,7 @@ class driver(dectalkDriver.driver):
|
||||
debug.DebugLevel.INFO,
|
||||
on_any_level=True,
|
||||
)
|
||||
return
|
||||
return False
|
||||
chunk = data[
|
||||
total_written : total_written + self.packet_size
|
||||
]
|
||||
@@ -243,12 +244,14 @@ class driver(dectalkDriver.driver):
|
||||
debug.DebugLevel.INFO,
|
||||
on_any_level=True,
|
||||
)
|
||||
return True
|
||||
except (self.usb_core.USBError, OSError) as error:
|
||||
self._debug(
|
||||
f"DECtalk USB write failed: {error}",
|
||||
debug.DebugLevel.ERROR,
|
||||
on_any_level=True,
|
||||
)
|
||||
return False
|
||||
|
||||
def _advance_speech_cancel_generation(self):
|
||||
with self._speech_cancel_lock:
|
||||
|
||||
@@ -38,10 +38,12 @@ class hardware_serial_driver(speech_driver):
|
||||
self.lock = threading.Lock()
|
||||
self.worker_thread = None
|
||||
self._stop_worker = False
|
||||
self._setting_cache = {}
|
||||
|
||||
def initialize(self, environment):
|
||||
self.env = environment
|
||||
self._is_initialized = False
|
||||
self._reset_setting_cache()
|
||||
settings_manager = self.env["runtime"]["SettingsManager"]
|
||||
self.device = self._clean_device_setting(
|
||||
settings_manager.get_setting("speech", "hardware_device")
|
||||
@@ -115,21 +117,30 @@ class hardware_serial_driver(speech_driver):
|
||||
return
|
||||
if not isinstance(rate, float):
|
||||
return
|
||||
self._write_bytes(self._rate_command(rate), "rate")
|
||||
self._write_setting_command("rate", self._rate_command(rate))
|
||||
|
||||
def set_pitch(self, pitch):
|
||||
if not self._is_initialized:
|
||||
return
|
||||
if not isinstance(pitch, float):
|
||||
return
|
||||
self._write_bytes(self._pitch_command(pitch), "pitch")
|
||||
self._write_setting_command("pitch", self._pitch_command(pitch))
|
||||
|
||||
def set_volume(self, volume):
|
||||
if not self._is_initialized:
|
||||
return
|
||||
if not isinstance(volume, float):
|
||||
return
|
||||
self._write_bytes(self._volume_command(volume), "volume")
|
||||
self._write_setting_command("volume", self._volume_command(volume))
|
||||
|
||||
def _reset_setting_cache(self):
|
||||
self._setting_cache = {}
|
||||
|
||||
def _write_setting_command(self, setting, command):
|
||||
if self._setting_cache.get(setting) == command:
|
||||
return
|
||||
if self._write_bytes(command, setting):
|
||||
self._setting_cache[setting] = command
|
||||
|
||||
def _worker(self):
|
||||
while not self._stop_worker:
|
||||
@@ -223,10 +234,10 @@ class hardware_serial_driver(speech_driver):
|
||||
|
||||
def _write_bytes(self, data, description="data"):
|
||||
if not data:
|
||||
return
|
||||
return False
|
||||
with self.lock:
|
||||
if self.serial_port is None:
|
||||
return
|
||||
return False
|
||||
try:
|
||||
total_written = 0
|
||||
while total_written < len(data):
|
||||
@@ -243,12 +254,14 @@ class hardware_serial_driver(speech_driver):
|
||||
debug.DebugLevel.INFO,
|
||||
on_any_level=True,
|
||||
)
|
||||
return True
|
||||
except OSError as error:
|
||||
self._debug(
|
||||
f"Hardware speech write failed: {error}",
|
||||
debug.DebugLevel.ERROR,
|
||||
on_any_level=True,
|
||||
)
|
||||
return False
|
||||
|
||||
def _termios_baud_rate(self, baud_rate):
|
||||
baud_name = f"B{baud_rate}"
|
||||
|
||||
@@ -161,6 +161,25 @@ def test_dectalk_usb_driver_writes_commands_and_speech(monkeypatch):
|
||||
speech_driver.shutdown()
|
||||
|
||||
|
||||
def test_dectalk_usb_driver_skips_redundant_setting_writes(monkeypatch):
|
||||
speech_driver, device, _, _ = initialized_driver(monkeypatch)
|
||||
try:
|
||||
speech_driver.set_rate(0.5)
|
||||
speech_driver.set_pitch(0.5)
|
||||
speech_driver.set_volume(1.0)
|
||||
speech_driver.set_rate(0.5)
|
||||
speech_driver.set_pitch(0.5)
|
||||
speech_driver.set_volume(1.0)
|
||||
|
||||
assert device.writes == [
|
||||
(0x02, b"[:ra 180]", 1000),
|
||||
(0x02, b"[:dv ap 122]", 1000),
|
||||
(0x02, b"[:dv g5 86]", 1000),
|
||||
]
|
||||
finally:
|
||||
speech_driver.shutdown()
|
||||
|
||||
|
||||
def test_dectalk_usb_driver_chunks_normal_writes(monkeypatch):
|
||||
speech_driver, device, _, _ = initialized_driver(monkeypatch)
|
||||
try:
|
||||
|
||||
@@ -95,6 +95,22 @@ def test_dectalk_driver_writes_settings_and_cancel(serial_pair):
|
||||
speech_driver.shutdown()
|
||||
|
||||
|
||||
def test_dectalk_driver_skips_redundant_setting_commands(serial_pair):
|
||||
speech_driver, master_fd = initialized_driver(dectalkDriver, serial_pair)
|
||||
try:
|
||||
speech_driver.set_rate(0.5)
|
||||
speech_driver.set_pitch(0.5)
|
||||
speech_driver.set_volume(1.0)
|
||||
speech_driver.set_rate(0.5)
|
||||
speech_driver.set_pitch(0.5)
|
||||
speech_driver.set_volume(1.0)
|
||||
expected = b"[:ra 180][:dv ap 122][:dv g5 86]"
|
||||
assert read_available(master_fd, len(expected)) == expected
|
||||
assert read_available(master_fd, 1, timeout=0.2) == b""
|
||||
finally:
|
||||
speech_driver.shutdown()
|
||||
|
||||
|
||||
def test_dectalk_driver_uses_native_defaults_at_fenrir_midpoint(serial_pair):
|
||||
speech_driver, master_fd = initialized_driver(dectalkDriver, serial_pair)
|
||||
try:
|
||||
@@ -199,6 +215,27 @@ def test_hardware_driver_retries_partial_serial_writes(monkeypatch):
|
||||
assert written_chunks == [b"ab", b"cd", b"ef"]
|
||||
|
||||
|
||||
def test_hardware_driver_retries_setting_after_failed_write(monkeypatch):
|
||||
speech_driver = dectalkDriver.driver()
|
||||
speech_driver._is_initialized = True
|
||||
write_results = [False, True]
|
||||
written_commands = []
|
||||
|
||||
def fake_write(data, description):
|
||||
written_commands.append((data, description))
|
||||
return write_results.pop(0)
|
||||
|
||||
monkeypatch.setattr(speech_driver, "_write_bytes", fake_write)
|
||||
|
||||
speech_driver.set_rate(0.5)
|
||||
speech_driver.set_rate(0.5)
|
||||
|
||||
assert written_commands == [
|
||||
(b"[:ra 180]", "rate"),
|
||||
(b"[:ra 180]", "rate"),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("driver_class", [doubletalkDriver, tripletalkDriver])
|
||||
def test_litetalk_compatible_alias_drivers(driver_class, serial_pair):
|
||||
speech_driver, master_fd = initialized_driver(driver_class, serial_pair)
|
||||
|
||||
Reference in New Issue
Block a user