python-aidot-cameras 0.7.25__tar.gz → 0.7.26__tar.gz

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.
Files changed (59) hide show
  1. {python_aidot_cameras-0.7.25/src/python_aidot_cameras.egg-info → python_aidot_cameras-0.7.26}/PKG-INFO +4 -1
  2. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/README.md +3 -0
  3. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/pyproject.toml +1 -1
  4. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/camera/client.py +43 -1
  5. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26/src/python_aidot_cameras.egg-info}/PKG-INFO +4 -1
  6. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/LICENSE +0 -0
  7. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/MANIFEST.in +0 -0
  8. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/setup.cfg +0 -0
  9. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/__init__.py +0 -0
  10. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/aes_utils.py +0 -0
  11. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/camera/__init__.py +0 -0
  12. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/camera/constants.py +0 -0
  13. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/camera/controls.py +0 -0
  14. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/camera/go2rtc.py +0 -0
  15. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/camera/lan_control.py +0 -0
  16. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/camera/models.py +0 -0
  17. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/camera/playback.py +0 -0
  18. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/camera/protocol.py +0 -0
  19. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/camera/sdes.py +0 -0
  20. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/camera/tutk.py +0 -0
  21. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/camera/webrtc.py +0 -0
  22. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/client.py +0 -0
  23. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/const.py +0 -0
  24. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/credentials.py +0 -0
  25. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/device_client.py +0 -0
  26. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/discover.py +0 -0
  27. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/exceptions.py +0 -0
  28. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/g711.py +0 -0
  29. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/login_const.py +0 -0
  30. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/models/__init__.py +0 -0
  31. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/models/device_client_model.py +0 -0
  32. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/models/device_model.py +0 -0
  33. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/models/discover_model.py +0 -0
  34. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/aidot/py.typed +0 -0
  35. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/python_aidot_cameras.egg-info/SOURCES.txt +0 -0
  36. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/python_aidot_cameras.egg-info/dependency_links.txt +0 -0
  37. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/python_aidot_cameras.egg-info/requires.txt +0 -0
  38. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/src/python_aidot_cameras.egg-info/top_level.txt +0 -0
  39. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/tests/test_alarm_event.py +0 -0
  40. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/tests/test_backoff.py +0 -0
  41. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/tests/test_go2rtc.py +0 -0
  42. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/tests/test_highport_nomination.py +0 -0
  43. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/tests/test_lan_control.py +0 -0
  44. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/tests/test_live_stream_param.py +0 -0
  45. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/tests/test_motion_poll.py +0 -0
  46. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/tests/test_no_undefined_names.py +0 -0
  47. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/tests/test_post_merge_hardening.py +0 -0
  48. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/tests/test_sdes_fast_liveplay.py +0 -0
  49. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/tests/test_sdes_idle_release.py +0 -0
  50. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/tests/test_sdes_sprop.py +0 -0
  51. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/tests/test_sdes_talk.py +0 -0
  52. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/tests/test_sdes_watchdog.py +0 -0
  53. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/tests/test_serve_relay.py +0 -0
  54. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/tests/test_speak.py +0 -0
  55. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/tests/test_stream_cap.py +0 -0
  56. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/tests/test_stream_idle.py +0 -0
  57. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/tests/test_talk.py +0 -0
  58. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/tests/test_terminal_ack.py +0 -0
  59. {python_aidot_cameras-0.7.25 → python_aidot_cameras-0.7.26}/tests/test_token_refresh.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-aidot-cameras
3
- Version: 0.7.25
3
+ Version: 0.7.26
4
4
  Summary: Control AiDot/Leedarson WiFi lights and cameras (WebRTC streaming, two-way audio, PTZ, controls)
5
5
  Author-email: cbrightly <chris.brightly@gmail.com>
6
6
  License-Expression: MIT
@@ -122,6 +122,8 @@ chosen to work out of the box; override only when tuning.
122
122
  | `AIDOT_SPROP_DIR` | Directory where captured SPS/PPS (sprop) parameter sets are cached. Set this to a writable path (e.g. for Home Assistant) if the default location is read-only. | `<package dir>` |
123
123
  | `AIDOT_DISABLE_HIGHPORT_FIX` | If set (any value), disables the DTLS high-port `USE-CANDIDATE` nomination fix and falls back to upstream aioice behavior (used to measure the baseline connect rate). | unset (fix enabled) |
124
124
  | `AIDOT_FAST_CONNECT` | Enables LAN-direct "fast connect" mode (STUN-only, skips several cloud signaling waits) when set to a truthy value. | unset (off) |
125
+ | `AIDOT_SDES_FAST_LIVEPLAY` | Truthy value skips the `livePlayResp` blocking wait for eligible SDES cameras (~4.5 s faster cold start), while keeping the full ICE/SCTP handshake. Role-reversal models (A001064 PTZ) are always excluded. Soak-validated; opt-in. | unset (off) |
126
+ | `AIDOT_SERVE_RELAY` | Holds the public stream port via an internal relay that proxies to ffmpeg, so the first (cold) view connects instead of failing while ffmpeg can't pre-bind the port. Set to `0` to serve ffmpeg directly. | `1` (enabled) |
125
127
  | `AIDOT_MAX_CONCURRENT_OPENS` | Caps how many stream opens run concurrently. | `2` |
126
128
  | `AIDOT_MAX_CONCURRENT_STREAMS` | Caps how many cameras stream at once. | `3` |
127
129
  | `AIDOT_STREAM_IDLE_S` | Seconds of stream idle before an idle release. | `120` |
@@ -131,6 +133,7 @@ chosen to work out of the box; override only when tuning.
131
133
  | `AIDOT_BUSY_RETRY_S` | Delay, in seconds, before retrying when a camera reports busy. | `45` |
132
134
  | `AIDOT_LIVESTREAM_PARAM` | Set to `0` to skip the cloud `liveStreamParam` pre-connect that provisions battery cameras' live-stream sessions before signaling (without it, battery cameras like the L2 models reject streaming with `-50019`). | `1` (enabled) |
133
135
  | `AIDOT_GOP_PLI_S` | Interval, in seconds, between PLI (keyframe) requests. | `2.0` |
136
+ | `AIDOT_SDES_PLI_GAPS` | Comma-separated second offsets for the early PLI (keyframe-request) burst on SDES cameras, to pull the first keyframe in faster on cold start. | `0,1.5,2,3` |
134
137
  | `AIDOT_AUDIO_TARGET_DBFS` | Target loudness (dBFS) for two-way audio normalization. | `-15` |
135
138
  | `AIDOT_AUDIO_MAXGAIN_DB` | Maximum gain (dB) applied by the audio normalizer. | `30` |
136
139
  | `AIDOT_AUDIO_MINGAIN_DB` | Minimum gain (dB) applied by the audio normalizer. | `-12` |
@@ -95,6 +95,8 @@ chosen to work out of the box; override only when tuning.
95
95
  | `AIDOT_SPROP_DIR` | Directory where captured SPS/PPS (sprop) parameter sets are cached. Set this to a writable path (e.g. for Home Assistant) if the default location is read-only. | `<package dir>` |
96
96
  | `AIDOT_DISABLE_HIGHPORT_FIX` | If set (any value), disables the DTLS high-port `USE-CANDIDATE` nomination fix and falls back to upstream aioice behavior (used to measure the baseline connect rate). | unset (fix enabled) |
97
97
  | `AIDOT_FAST_CONNECT` | Enables LAN-direct "fast connect" mode (STUN-only, skips several cloud signaling waits) when set to a truthy value. | unset (off) |
98
+ | `AIDOT_SDES_FAST_LIVEPLAY` | Truthy value skips the `livePlayResp` blocking wait for eligible SDES cameras (~4.5 s faster cold start), while keeping the full ICE/SCTP handshake. Role-reversal models (A001064 PTZ) are always excluded. Soak-validated; opt-in. | unset (off) |
99
+ | `AIDOT_SERVE_RELAY` | Holds the public stream port via an internal relay that proxies to ffmpeg, so the first (cold) view connects instead of failing while ffmpeg can't pre-bind the port. Set to `0` to serve ffmpeg directly. | `1` (enabled) |
98
100
  | `AIDOT_MAX_CONCURRENT_OPENS` | Caps how many stream opens run concurrently. | `2` |
99
101
  | `AIDOT_MAX_CONCURRENT_STREAMS` | Caps how many cameras stream at once. | `3` |
100
102
  | `AIDOT_STREAM_IDLE_S` | Seconds of stream idle before an idle release. | `120` |
@@ -104,6 +106,7 @@ chosen to work out of the box; override only when tuning.
104
106
  | `AIDOT_BUSY_RETRY_S` | Delay, in seconds, before retrying when a camera reports busy. | `45` |
105
107
  | `AIDOT_LIVESTREAM_PARAM` | Set to `0` to skip the cloud `liveStreamParam` pre-connect that provisions battery cameras' live-stream sessions before signaling (without it, battery cameras like the L2 models reject streaming with `-50019`). | `1` (enabled) |
106
108
  | `AIDOT_GOP_PLI_S` | Interval, in seconds, between PLI (keyframe) requests. | `2.0` |
109
+ | `AIDOT_SDES_PLI_GAPS` | Comma-separated second offsets for the early PLI (keyframe-request) burst on SDES cameras, to pull the first keyframe in faster on cold start. | `0,1.5,2,3` |
107
110
  | `AIDOT_AUDIO_TARGET_DBFS` | Target loudness (dBFS) for two-way audio normalization. | `-15` |
108
111
  | `AIDOT_AUDIO_MAXGAIN_DB` | Maximum gain (dB) applied by the audio normalizer. | `30` |
109
112
  | `AIDOT_AUDIO_MINGAIN_DB` | Minimum gain (dB) applied by the audio normalizer. | `-12` |
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "python-aidot-cameras"
7
- version = "0.7.25"
7
+ version = "0.7.26"
8
8
  description = "Control AiDot/Leedarson WiFi lights and cameras (WebRTC streaming, two-way audio, PTZ, controls)"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -2559,6 +2559,30 @@ class CameraMixin(_CameraControlsMixin):
2559
2559
  return os.environ.get("AIDOT_SDES_FAST_LIVEPLAY", "").strip().lower() in (
2560
2560
  "1", "true", "yes", "on")
2561
2561
 
2562
+ def _resolve_sdes_skip_turn(self) -> bool:
2563
+ """EXPERIMENTAL (opt-in, default off): skip the blocking SDES TURN relay
2564
+ pre-allocation, for cameras reachable LAN-direct.
2565
+
2566
+ Before building the offer the SDES path does two synchronous RFC-5766
2567
+ Allocate round-trips (audio + video) to the cloud TURN server so the
2568
+ offer's c=/m= can carry a relay address - ~2-3 s of pure cold-start
2569
+ latency. On a LAN the camera's host candidate wins and that relay is
2570
+ never used, so skipping it shaves the latency - at the cost of no relay
2571
+ fallback for a camera on a different segment / behind strict NAT (the
2572
+ same trade-off ``AIDOT_FAST_CONNECT`` already makes for DTLS, and which
2573
+ is force-disabled for SDES because it *also* skips the SCTP-arming
2574
+ waits; this flag skips ONLY the relay pre-allocation, leaving the rest
2575
+ of the SDES handshake intact).
2576
+
2577
+ Per-camera ``sdes_skip_turn`` (set via start_keepalive) wins; else the
2578
+ ``AIDOT_SDES_SKIP_TURN_PREALLOC`` env (truthy = 1/true/yes/on), default
2579
+ off. Only consulted for SDES cameras."""
2580
+ opt = getattr(self, "_sdes_skip_turn_opt", None)
2581
+ if opt is not None:
2582
+ return bool(opt)
2583
+ return os.environ.get("AIDOT_SDES_SKIP_TURN_PREALLOC", "").strip().lower() in (
2584
+ "1", "true", "yes", "on")
2585
+
2562
2586
  def _maybe_start_serve_relay(self, serve_url: Optional[str]) -> "Optional[_ServeRelay]":
2563
2587
  """Hold the public serve port via a _ServeRelay so an eager go2rtc pull
2564
2588
  connects-and-waits instead of hitting ECONNREFUSED during the ~16-25s
@@ -6818,7 +6842,15 @@ class CameraMixin(_CameraControlsMixin):
6818
6842
  # AIDOT_FAST_CONNECT skips this blocking pre-allocation (LAN-direct mode):
6819
6843
  # the offer goes out immediately with host/srflx candidates and the LAN
6820
6844
  # path connects without waiting on a cloud TURN Allocate round-trip.
6821
- if _sdes_turn_entries and not _fast_connect:
6845
+ # AIDOT_SDES_SKIP_TURN_PREALLOC (experimental, opt-in) does the same skip
6846
+ # for SDES specifically, where _fast_connect is force-off (see
6847
+ # _resolve_sdes_skip_turn). Either way the cost is instrumented below so
6848
+ # the saving is measurable: grep ``signaling-wait[`` for sdes-turn-prealloc.
6849
+ _skip_turn_prealloc = self._resolve_sdes_skip_turn()
6850
+ _turn_t0 = time.monotonic()
6851
+ _turn_did = False
6852
+ if _sdes_turn_entries and not _fast_connect and not _skip_turn_prealloc:
6853
+ _turn_did = True
6822
6854
  try:
6823
6855
  import re as _re_pre
6824
6856
  import hashlib as _hlk_pre
@@ -6855,6 +6887,16 @@ class CameraMixin(_CameraControlsMixin):
6855
6887
  )
6856
6888
  except Exception as _pre_exc:
6857
6889
  _LOGGER.warning("TURN pre-allocation error: %s", _pre_exc)
6890
+ if _skip_turn_prealloc and _sdes_turn_entries:
6891
+ _status(
6892
+ "AIDOT_SDES_SKIP_TURN_PREALLOC: skipping TURN relay"
6893
+ " pre-allocation (~2-3s) - host/srflx candidates only, LAN-direct"
6894
+ )
6895
+ _LOGGER.info(
6896
+ "signaling-wait[%s] sdes-turn-prealloc elapsed=%dms allocated=%d skipped=%s",
6897
+ self.device_id,
6898
+ int((time.monotonic() - _turn_t0) * 1000),
6899
+ len(_relay_addrs), bool(_skip_turn_prealloc))
6858
6900
 
6859
6901
  # --- DTLS certificate for m=application probe ----------------------- #
6860
6902
  # PreCon cameras (sptPreconn=1) need SESSION_MODE_REQ via SCTP datachannel.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-aidot-cameras
3
- Version: 0.7.25
3
+ Version: 0.7.26
4
4
  Summary: Control AiDot/Leedarson WiFi lights and cameras (WebRTC streaming, two-way audio, PTZ, controls)
5
5
  Author-email: cbrightly <chris.brightly@gmail.com>
6
6
  License-Expression: MIT
@@ -122,6 +122,8 @@ chosen to work out of the box; override only when tuning.
122
122
  | `AIDOT_SPROP_DIR` | Directory where captured SPS/PPS (sprop) parameter sets are cached. Set this to a writable path (e.g. for Home Assistant) if the default location is read-only. | `<package dir>` |
123
123
  | `AIDOT_DISABLE_HIGHPORT_FIX` | If set (any value), disables the DTLS high-port `USE-CANDIDATE` nomination fix and falls back to upstream aioice behavior (used to measure the baseline connect rate). | unset (fix enabled) |
124
124
  | `AIDOT_FAST_CONNECT` | Enables LAN-direct "fast connect" mode (STUN-only, skips several cloud signaling waits) when set to a truthy value. | unset (off) |
125
+ | `AIDOT_SDES_FAST_LIVEPLAY` | Truthy value skips the `livePlayResp` blocking wait for eligible SDES cameras (~4.5 s faster cold start), while keeping the full ICE/SCTP handshake. Role-reversal models (A001064 PTZ) are always excluded. Soak-validated; opt-in. | unset (off) |
126
+ | `AIDOT_SERVE_RELAY` | Holds the public stream port via an internal relay that proxies to ffmpeg, so the first (cold) view connects instead of failing while ffmpeg can't pre-bind the port. Set to `0` to serve ffmpeg directly. | `1` (enabled) |
125
127
  | `AIDOT_MAX_CONCURRENT_OPENS` | Caps how many stream opens run concurrently. | `2` |
126
128
  | `AIDOT_MAX_CONCURRENT_STREAMS` | Caps how many cameras stream at once. | `3` |
127
129
  | `AIDOT_STREAM_IDLE_S` | Seconds of stream idle before an idle release. | `120` |
@@ -131,6 +133,7 @@ chosen to work out of the box; override only when tuning.
131
133
  | `AIDOT_BUSY_RETRY_S` | Delay, in seconds, before retrying when a camera reports busy. | `45` |
132
134
  | `AIDOT_LIVESTREAM_PARAM` | Set to `0` to skip the cloud `liveStreamParam` pre-connect that provisions battery cameras' live-stream sessions before signaling (without it, battery cameras like the L2 models reject streaming with `-50019`). | `1` (enabled) |
133
135
  | `AIDOT_GOP_PLI_S` | Interval, in seconds, between PLI (keyframe) requests. | `2.0` |
136
+ | `AIDOT_SDES_PLI_GAPS` | Comma-separated second offsets for the early PLI (keyframe-request) burst on SDES cameras, to pull the first keyframe in faster on cold start. | `0,1.5,2,3` |
134
137
  | `AIDOT_AUDIO_TARGET_DBFS` | Target loudness (dBFS) for two-way audio normalization. | `-15` |
135
138
  | `AIDOT_AUDIO_MAXGAIN_DB` | Maximum gain (dB) applied by the audio normalizer. | `30` |
136
139
  | `AIDOT_AUDIO_MINGAIN_DB` | Minimum gain (dB) applied by the audio normalizer. | `-12` |