From ba4a1bb103f8693843e5e37bb6422f92fd602960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=27=C3=A9lectron=20rare?= <108685187+electron-rare@users.noreply.github.com> Date: Thu, 2 Jul 2026 14:13:52 +0200 Subject: [PATCH] perf(pose): 30hz gesture loop under iphone-usb iphone-usb path: camera decode + ARKit conversion is cheap (no MediaPipe inference on Mac). Frame-based gesture calibrations (debounce/hold/grace/persist) assume 30 Hz. Keep 18 Hz for the webcam MediaPipe path (M5 CPU protection). Tests: period formula + MultiWorker.__init__ signature check. --- data_only_viz/main.py | 8 +++++++- data_only_viz/tests/test_config.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/data_only_viz/main.py b/data_only_viz/main.py index 8b338b4..96b1646 100644 --- a/data_only_viz/main.py +++ b/data_only_viz/main.py @@ -390,9 +390,15 @@ class AppDelegate(NSObject): if _cfg.av_live_mediapipe: try: from .multi import MultiWorker + _iphone_usb = getattr(self._opts, "iphone_usb", False) + # iphone-usb path: camera decode + ARKit conversion is cheap + # (no MediaPipe inference on the Mac). Frame-based gesture + # calibrations (debounce/hold/grace/persist) assume 30 Hz. + # Keep 18 Hz for the webcam MediaPipe path (M5 CPU protection). self._pose_worker = MultiWorker( self._state, num_persons=4, - iphone_usb=getattr(self._opts, "iphone_usb", False)) + iphone_usb=_iphone_usb, + target_fps=30.0 if _iphone_usb else 18.0) self._pose_worker.start() LOG.info("worker: MediaPipe Multi (Pose+Face+Hand × 4)") return diff --git a/data_only_viz/tests/test_config.py b/data_only_viz/tests/test_config.py index 2978cdb..4393002 100644 --- a/data_only_viz/tests/test_config.py +++ b/data_only_viz/tests/test_config.py @@ -365,3 +365,33 @@ def test_iphone_usb_skips_ensure_model(): def test_bool_ne0_mesh_rig(val, expected): cfg = VizConfig.from_env({"MESH_RIG": val}) assert cfg.mesh_rig is expected + + +# --------------------------------------------------------------------------- +# Item 2: MultiWorker runs at 30 Hz under iphone-usb +# --------------------------------------------------------------------------- + +def test_multiworker_period_formula_for_iphone_usb(): + """MultiWorker stores period = 1 / max(1, target_fps). + + Frame-based gesture calibrations (debounce/hold/grace/persist) assume + 30 Hz. When --iphone-usb is active (camera decode + ARKit conversion, + no MediaPipe on the Mac), target_fps=30 is passed; webcam keeps 18. + This test verifies the __init__ period arithmetic directly, sidestepping + heavy ML/AppKit imports that are unavailable in CI. + """ + from data_only_viz.multi import MultiWorker + import math + # Verify the formula for both paths + for target_fps, expected in [(30.0, 1.0 / 30.0), (18.0, 1.0 / 18.0)]: + # Same expression as MultiWorker.__init__: self.period = 1.0 / max(1.0, target_fps) + period = 1.0 / max(1.0, target_fps) + assert math.isclose(period, expected, rel_tol=1e-6), ( + f"target_fps={target_fps}: expected period {expected:.6f}, got {period:.6f}" + ) + # Verify the constructor signature accepts the kwarg (compilation check) + import inspect + sig = inspect.signature(MultiWorker.__init__) + assert "target_fps" in sig.parameters, ( + "MultiWorker.__init__ must accept target_fps kwarg" + )