infinicode 2.8.90 → 2.8.91
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -455,6 +455,9 @@ class PreviewAgent:
|
|
|
455
455
|
self._vision_session_id: Optional[str] = None
|
|
456
456
|
self._vision_trigger_in_flight = False
|
|
457
457
|
self._speaker_test_in_flight = False
|
|
458
|
+
# The USB adapter is an exclusive ALSA endpoint. Keep operator tests
|
|
459
|
+
# and motion cues from racing each other while LiveKit is paused.
|
|
460
|
+
self._speaker_operation_lock = asyncio.Lock()
|
|
458
461
|
self._vision_hard_deadline: float = 0.0
|
|
459
462
|
self._vision_last_activity: float = 0.0
|
|
460
463
|
self.production_mode = False
|
|
@@ -896,18 +899,20 @@ class PreviewAgent:
|
|
|
896
899
|
return
|
|
897
900
|
self._speaker_test_in_flight = True
|
|
898
901
|
from robot_supervisor import _speaker_roundtrip_test
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
902
|
+
async with self._speaker_operation_lock:
|
|
903
|
+
# LiveKit owns the USB microphone and speaker continuously.
|
|
904
|
+
# Pause it while holding the same lock as the motion cue so
|
|
905
|
+
# nothing can reopen ALSA before the explicit test starts.
|
|
906
|
+
restore_state = self._current_state if self._publisher else None
|
|
907
|
+
if restore_state:
|
|
908
|
+
await self._stop_publisher()
|
|
909
|
+
await asyncio.sleep(1.0)
|
|
910
|
+
try:
|
|
911
|
+
result = await asyncio.to_thread(_speaker_roundtrip_test, request.get("params") or {})
|
|
912
|
+
result["media_owner_paused"] = bool(restore_state)
|
|
913
|
+
finally:
|
|
914
|
+
if restore_state and restore_state.active:
|
|
915
|
+
await self._start_publisher(restore_state)
|
|
911
916
|
result_response = await self._session.post(
|
|
912
917
|
f"{self.scheduler_url.rstrip('/')}/api/devices/{self.device_id}/supervisor-output",
|
|
913
918
|
json={"kind": "speaker_test", "service": None, "payload": result,
|
|
@@ -1066,7 +1071,8 @@ class PreviewAgent:
|
|
|
1066
1071
|
# The cue and TTS share one physical ALSA output. Finish and release
|
|
1067
1072
|
# the cue before LiveKit can deliver the greeting; background playback
|
|
1068
1073
|
# races aplay and makes greeting delivery intermittently fail busy.
|
|
1069
|
-
|
|
1074
|
+
async with self._speaker_operation_lock:
|
|
1075
|
+
await asyncio.to_thread(_play_audio_effect, self.audio_playback_device, "motion")
|
|
1070
1076
|
try:
|
|
1071
1077
|
r = await self._session.post(
|
|
1072
1078
|
f"{self.scheduler_url.rstrip('/')}/api/devices/{self.device_id}/request-session",
|
|
@@ -1317,6 +1323,11 @@ class LiveKitPublisher:
|
|
|
1317
1323
|
process.wait(timeout=2)
|
|
1318
1324
|
except subprocess.TimeoutExpired:
|
|
1319
1325
|
process.terminate()
|
|
1326
|
+
try:
|
|
1327
|
+
process.wait(timeout=1)
|
|
1328
|
+
except subprocess.TimeoutExpired:
|
|
1329
|
+
process.kill()
|
|
1330
|
+
process.wait(timeout=1)
|
|
1320
1331
|
|
|
1321
1332
|
def close(self) -> None:
|
|
1322
1333
|
return
|
|
@@ -1493,16 +1504,24 @@ class LiveKitPublisher:
|
|
|
1493
1504
|
else:
|
|
1494
1505
|
data = b"".join(raw[i:i + 2] * OUT_CHANNELS for i in range(0, len(raw), 2))
|
|
1495
1506
|
write_queue.put(data)
|
|
1496
|
-
except Exception as e:
|
|
1497
|
-
logger.warning(f"audio out stream error: {e}")
|
|
1498
|
-
finally:
|
|
1499
|
-
|
|
1500
|
-
|
|
1507
|
+
except Exception as e:
|
|
1508
|
+
logger.warning(f"audio out stream error: {e}")
|
|
1509
|
+
finally:
|
|
1510
|
+
cancelling = bool(asyncio.current_task() and asyncio.current_task().cancelling())
|
|
1511
|
+
if cancelling:
|
|
1512
|
+
# On publisher teardown, close ALSA first. Waiting for the
|
|
1513
|
+
# writer while aplay still owns the device leaves hw:X,Y busy
|
|
1514
|
+
# long enough for the queued dashboard test to fail.
|
|
1515
|
+
stream_failed.set()
|
|
1516
|
+
out.stop_stream()
|
|
1517
|
+
write_queue.put(None)
|
|
1518
|
+
writer_thread.join(timeout=2.0)
|
|
1501
1519
|
logger.info(
|
|
1502
1520
|
f"audio out: {sid} received {frame_count} frames, "
|
|
1503
1521
|
f"writer wrote {written_frames[0]} chunks, queue backlog at close={write_queue.qsize()}"
|
|
1504
1522
|
)
|
|
1505
|
-
|
|
1523
|
+
if not cancelling:
|
|
1524
|
+
out.stop_stream()
|
|
1506
1525
|
out.close()
|
|
1507
1526
|
if pa is not None:
|
|
1508
1527
|
pa.terminate()
|