python-aidot-cameras 0.7.21__tar.gz → 0.7.23__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.
- {python_aidot_cameras-0.7.21/src/python_aidot_cameras.egg-info → python_aidot_cameras-0.7.23}/PKG-INFO +1 -1
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/pyproject.toml +1 -1
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/camera/client.py +77 -28
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23/src/python_aidot_cameras.egg-info}/PKG-INFO +1 -1
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/python_aidot_cameras.egg-info/SOURCES.txt +1 -0
- python_aidot_cameras-0.7.23/tests/test_sdes_fast_liveplay.py +70 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/LICENSE +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/MANIFEST.in +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/README.md +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/setup.cfg +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/__init__.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/aes_utils.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/camera/__init__.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/camera/constants.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/camera/controls.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/camera/go2rtc.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/camera/lan_control.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/camera/models.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/camera/playback.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/camera/protocol.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/camera/sdes.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/camera/tutk.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/camera/webrtc.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/client.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/const.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/credentials.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/device_client.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/discover.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/exceptions.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/g711.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/login_const.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/models/__init__.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/models/device_client_model.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/models/device_model.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/models/discover_model.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/py.typed +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/python_aidot_cameras.egg-info/dependency_links.txt +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/python_aidot_cameras.egg-info/requires.txt +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/python_aidot_cameras.egg-info/top_level.txt +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/tests/test_alarm_event.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/tests/test_backoff.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/tests/test_go2rtc.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/tests/test_highport_nomination.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/tests/test_lan_control.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/tests/test_live_stream_param.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/tests/test_motion_poll.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/tests/test_no_undefined_names.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/tests/test_post_merge_hardening.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/tests/test_sdes_idle_release.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/tests/test_sdes_sprop.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/tests/test_sdes_talk.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/tests/test_sdes_watchdog.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/tests/test_serve_relay.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/tests/test_speak.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/tests/test_stream_cap.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/tests/test_stream_idle.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/tests/test_talk.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/tests/test_terminal_ack.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/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.
|
|
3
|
+
Version: 0.7.23
|
|
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
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-aidot-cameras"
|
|
7
|
-
version = "0.7.
|
|
7
|
+
version = "0.7.23"
|
|
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"
|
|
@@ -2531,6 +2531,19 @@ class CameraMixin(_CameraControlsMixin):
|
|
|
2531
2531
|
except (TypeError, ValueError):
|
|
2532
2532
|
return 120.0
|
|
2533
2533
|
|
|
2534
|
+
def _resolve_sdes_fast_liveplay(self) -> bool:
|
|
2535
|
+
"""Whether to use SDES fast-liveplay (shorten the always-timing-out
|
|
2536
|
+
echo/livePlayResp signaling) - validated in soak, opt-in, default off.
|
|
2537
|
+
|
|
2538
|
+
Per-camera ``sdes_fast_liveplay`` (set via start_keepalive) wins; else the
|
|
2539
|
+
``AIDOT_SDES_FAST_LIVEPLAY`` env (truthy = 1/true/yes/on), default off.
|
|
2540
|
+
Only consulted for SDES cameras (the caller gates on is_sdes_camera)."""
|
|
2541
|
+
opt = getattr(self, "_sdes_fast_liveplay_opt", None)
|
|
2542
|
+
if opt is not None:
|
|
2543
|
+
return bool(opt)
|
|
2544
|
+
return os.environ.get("AIDOT_SDES_FAST_LIVEPLAY", "").strip().lower() in (
|
|
2545
|
+
"1", "true", "yes", "on")
|
|
2546
|
+
|
|
2534
2547
|
def _maybe_start_serve_relay(self, serve_url: Optional[str]) -> "Optional[_ServeRelay]":
|
|
2535
2548
|
"""Hold the public serve port via a _ServeRelay so an eager go2rtc pull
|
|
2536
2549
|
connects-and-waits instead of hitting ECONNREFUSED during the ~16-25s
|
|
@@ -3347,16 +3360,9 @@ class CameraMixin(_CameraControlsMixin):
|
|
|
3347
3360
|
# the livePlayResp ack, which is purely a camera accept/reject we don't
|
|
3348
3361
|
# need to block on (the official app never waits for it). So this targeted
|
|
3349
3362
|
# skip is expected to be SCTP-safe and shave ~2 s off the SDES cold start.
|
|
3350
|
-
# Off by default, pending live
|
|
3363
|
+
# Off by default, pending live validation. Applied in _open_sdes_stream
|
|
3364
|
+
# (the SDES path has its own livePlayResp wait); start_keepalive(
|
|
3351
3365
|
# sdes_fast_liveplay=...) wins, else AIDOT_SDES_FAST_LIVEPLAY env.
|
|
3352
|
-
_sdes_skip_lp = False
|
|
3353
|
-
if self.is_sdes_camera:
|
|
3354
|
-
_sl = getattr(self, "_sdes_fast_liveplay_opt", None)
|
|
3355
|
-
if _sl is None:
|
|
3356
|
-
_sl = os.environ.get(
|
|
3357
|
-
"AIDOT_SDES_FAST_LIVEPLAY", "").strip().lower() in (
|
|
3358
|
-
"1", "true", "yes", "on")
|
|
3359
|
-
_sdes_skip_lp = bool(_sl)
|
|
3360
3366
|
|
|
3361
3367
|
# Wake battery cameras via the cloud HTTP low-power endpoint before the
|
|
3362
3368
|
# handshake (matches the app, which fires the HTTP wake so a sleeping camera
|
|
@@ -4145,20 +4151,24 @@ class CameraMixin(_CameraControlsMixin):
|
|
|
4145
4151
|
# SDP/ICE immediately - losing fast-fail on rejection (rare; ICE then
|
|
4146
4152
|
# fails instead) in exchange for ~2 s off every LAN connect.
|
|
4147
4153
|
if _fast_connect:
|
|
4154
|
+
_LOGGER.info(
|
|
4155
|
+
"signaling-wait[%s] livePlayResp skipped (fast_connect)",
|
|
4156
|
+
self.device_id)
|
|
4148
4157
|
_status(
|
|
4149
4158
|
"AIDOT_FAST_CONNECT: skipping livePlayResp wait (~2s) -"
|
|
4150
4159
|
" proceeding to SDP/ICE (app-parity, no fast-fail on reject)"
|
|
4151
4160
|
)
|
|
4152
|
-
elif _sdes_skip_lp:
|
|
4153
|
-
_status(
|
|
4154
|
-
"AIDOT_SDES_FAST_LIVEPLAY: skipping livePlayResp wait (~2s)"
|
|
4155
|
-
" for SDES - full ICE/TURN/SCTP handshake retained (experiment)"
|
|
4156
|
-
)
|
|
4157
4161
|
else:
|
|
4162
|
+
# Instrumented: how long this wait actually costs (it returns as
|
|
4163
|
+
# soon as livePlayResp arrives; the 2s is only paid on timeout).
|
|
4164
|
+
# This is exactly the cost the sdes_fast_liveplay experiment skips.
|
|
4165
|
+
_lp_t0 = time.monotonic()
|
|
4166
|
+
_lp_arrived = False
|
|
4158
4167
|
try:
|
|
4159
4168
|
_lp_resp = await asyncio.wait_for(
|
|
4160
4169
|
asyncio.shield(liveplay_resp_fut), timeout=2.0
|
|
4161
4170
|
)
|
|
4171
|
+
_lp_arrived = True
|
|
4162
4172
|
_lp_code = int(_lp_resp.get("code", 200))
|
|
4163
4173
|
_lp_on = int(_lp_resp.get("livePlay", 1))
|
|
4164
4174
|
if _lp_code not in (0, 200) or _lp_on == 0:
|
|
@@ -4167,6 +4177,10 @@ class CameraMixin(_CameraControlsMixin):
|
|
|
4167
4177
|
)
|
|
4168
4178
|
except TimeoutError:
|
|
4169
4179
|
pass
|
|
4180
|
+
_LOGGER.info(
|
|
4181
|
+
"signaling-wait[%s] livePlayResp elapsed=%dms arrived=%s",
|
|
4182
|
+
self.device_id,
|
|
4183
|
+
int((time.monotonic() - _lp_t0) * 1000), _lp_arrived)
|
|
4170
4184
|
# Short extra wait for getIceConfigResp - the server may only respond
|
|
4171
4185
|
# once a live camera session is active (i.e. after livePlayReq).
|
|
4172
4186
|
# Waiting here ensures TURN credentials arrive before RTCPeerConnection
|
|
@@ -4178,11 +4192,18 @@ class CameraMixin(_CameraControlsMixin):
|
|
|
4178
4192
|
# per-session TURN relay credentials, which LAN-direct doesn't need;
|
|
4179
4193
|
# remote/strict-NAT cameras do, hence this is opt-in (see flag above).
|
|
4180
4194
|
if not ice_config_fut.done() and not _fast_connect:
|
|
4195
|
+
_ic_t0 = time.monotonic()
|
|
4196
|
+
_ic_arrived = False
|
|
4181
4197
|
try:
|
|
4182
4198
|
await asyncio.wait_for(asyncio.shield(ice_config_fut), timeout=3.0)
|
|
4199
|
+
_ic_arrived = True
|
|
4183
4200
|
_status("getIceConfigResp received (post-livePlayReq)")
|
|
4184
4201
|
except TimeoutError:
|
|
4185
4202
|
pass # proceed without TURN; synthetic candidates are fallback
|
|
4203
|
+
_LOGGER.info(
|
|
4204
|
+
"signaling-wait[%s] getIceConfigResp elapsed=%dms arrived=%s",
|
|
4205
|
+
self.device_id,
|
|
4206
|
+
int((time.monotonic() - _ic_t0) * 1000), _ic_arrived)
|
|
4186
4207
|
elif _fast_connect:
|
|
4187
4208
|
_status(
|
|
4188
4209
|
"AIDOT_FAST_CONNECT: skipping getIceConfigResp wait"
|
|
@@ -7027,24 +7048,52 @@ class CameraMixin(_CameraControlsMixin):
|
|
|
7027
7048
|
# webrtcReq. The echo confirms the MQTT pipeline to this device is live
|
|
7028
7049
|
# and the broker session is registered. Fall through after 5 s if it
|
|
7029
7050
|
# never arrives (same safety as the old fixed 0.5 s sleep, but adaptive).
|
|
7051
|
+
# SDES fast-liveplay (opt-in via sdes_fast_liveplay): instrumentation showed
|
|
7052
|
+
# the echo and livePlayResp waits BOTH always time out for the SDES cameras
|
|
7053
|
+
# measured (echo/resp never arrive) yet streaming succeeds - i.e. ~6 s of
|
|
7054
|
+
# dead padding. When the flag is on, cap the echo wait short and skip the
|
|
7055
|
+
# livePlayResp wait; the full ICE/TURN/SCTP handshake is untouched. This
|
|
7056
|
+
# is the SDES path's OWN livePlay waits (the DTLS gate above never runs for
|
|
7057
|
+
# SDES: use_sdes is True there). VALIDATED in a 3 h live soak (15 SDES
|
|
7058
|
+
# opens across battery cameras, flag engaged on all, 0 churn / 0 fail,
|
|
7059
|
+
# ~4.5 s signaling saved); kept off by default pending broader multi-day
|
|
7060
|
+
# use (per-open + near-term stability proven, long-haul not yet).
|
|
7061
|
+
_skip_lp = self._resolve_sdes_fast_liveplay()
|
|
7062
|
+
_echo_timeout = 1.5 if _skip_lp else 5.0
|
|
7063
|
+
_echo_t0 = time.monotonic()
|
|
7030
7064
|
try:
|
|
7031
|
-
await _asyncio.wait_for(liveplay_echo_ev.wait(), timeout=
|
|
7065
|
+
await _asyncio.wait_for(liveplay_echo_ev.wait(), timeout=_echo_timeout)
|
|
7032
7066
|
_status("livePlayReq echo received - sending webrtcReq, ICE, then launching ffmpeg")
|
|
7033
7067
|
except TimeoutError:
|
|
7034
|
-
_status("no livePlayReq echo in
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
|
|
7068
|
+
_status(f"no livePlayReq echo in {_echo_timeout:.1f}s - sending webrtcReq,"
|
|
7069
|
+
" ICE, then launching ffmpeg anyway")
|
|
7070
|
+
_LOGGER.info(
|
|
7071
|
+
"signaling-wait[%s] livePlayReq-echo elapsed=%dms (timeout=%.1fs)",
|
|
7072
|
+
self.device_id, int((time.monotonic() - _echo_t0) * 1000), _echo_timeout)
|
|
7073
|
+
# livePlayResp: explicit camera accept/reject before SDP/ICE.
|
|
7074
|
+
if _skip_lp:
|
|
7075
|
+
_LOGGER.info(
|
|
7076
|
+
"signaling-wait[%s] livePlayResp skipped (sdes_fast_liveplay)",
|
|
7077
|
+
self.device_id)
|
|
7078
|
+
else:
|
|
7079
|
+
_lp_t0 = time.monotonic()
|
|
7080
|
+
_lp_arrived = False
|
|
7081
|
+
try:
|
|
7082
|
+
_lp_resp_sdes = await _asyncio.wait_for(
|
|
7083
|
+
_asyncio.shield(liveplay_resp_fut), timeout=1.0
|
|
7045
7084
|
)
|
|
7046
|
-
|
|
7047
|
-
|
|
7085
|
+
_lp_arrived = True
|
|
7086
|
+
_lp_code_sdes = int(_lp_resp_sdes.get("code", 200))
|
|
7087
|
+
_lp_on_sdes = int(_lp_resp_sdes.get("livePlay", 1))
|
|
7088
|
+
if _lp_code_sdes not in (0, 200) or _lp_on_sdes == 0:
|
|
7089
|
+
raise RuntimeError(
|
|
7090
|
+
f"livePlay rejected by camera (code={_lp_code_sdes}, livePlay={_lp_on_sdes})"
|
|
7091
|
+
)
|
|
7092
|
+
except TimeoutError:
|
|
7093
|
+
pass
|
|
7094
|
+
_LOGGER.info(
|
|
7095
|
+
"signaling-wait[%s] livePlayResp elapsed=%dms arrived=%s",
|
|
7096
|
+
self.device_id, int((time.monotonic() - _lp_t0) * 1000), _lp_arrived)
|
|
7048
7097
|
|
|
7049
7098
|
# --- Build local-receiver SDP for ffmpeg ----------------------------- #
|
|
7050
7099
|
# Built BEFORE sending webrtcReq so ffmpeg is already listening on the
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-aidot-cameras
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.23
|
|
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
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Unit tests for _resolve_sdes_fast_liveplay - the P5 flag (EXPERIMENTAL).
|
|
2
|
+
|
|
3
|
+
P5 skips only the ~2s livePlayResp wait for SDES cameras. This locks the
|
|
4
|
+
opt/env precedence (per-camera kwarg wins over AIDOT_SDES_FAST_LIVEPLAY env,
|
|
5
|
+
default off) so the wiring is verifiable without a camera. The actual stability
|
|
6
|
+
effect is validated by real-world soak (see scripts/sdes_soak_monitor.py), not
|
|
7
|
+
here.
|
|
8
|
+
"""
|
|
9
|
+
import os
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "src"))
|
|
13
|
+
|
|
14
|
+
import aidot.camera.client as cc
|
|
15
|
+
|
|
16
|
+
_CAM = next(v for v in vars(cc).values()
|
|
17
|
+
if isinstance(v, type) and "_resolve_sdes_fast_liveplay" in v.__dict__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _cam():
|
|
21
|
+
return _CAM.__new__(_CAM)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_default_off(monkeypatch):
|
|
25
|
+
monkeypatch.delenv("AIDOT_SDES_FAST_LIVEPLAY", raising=False)
|
|
26
|
+
assert _cam()._resolve_sdes_fast_liveplay() is False
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_env_truthy_values(monkeypatch):
|
|
30
|
+
for val in ("1", "true", "TRUE", "yes", "on", " On "):
|
|
31
|
+
monkeypatch.setenv("AIDOT_SDES_FAST_LIVEPLAY", val)
|
|
32
|
+
assert _cam()._resolve_sdes_fast_liveplay() is True, val
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_env_falsey_values(monkeypatch):
|
|
36
|
+
for val in ("0", "false", "no", "off", ""):
|
|
37
|
+
monkeypatch.setenv("AIDOT_SDES_FAST_LIVEPLAY", val)
|
|
38
|
+
assert _cam()._resolve_sdes_fast_liveplay() is False, val
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_kwarg_option_wins_over_env(monkeypatch):
|
|
42
|
+
monkeypatch.setenv("AIDOT_SDES_FAST_LIVEPLAY", "1")
|
|
43
|
+
cam = _cam()
|
|
44
|
+
cam._sdes_fast_liveplay_opt = False # start_keepalive(sdes_fast_liveplay=False)
|
|
45
|
+
assert cam._resolve_sdes_fast_liveplay() is False
|
|
46
|
+
|
|
47
|
+
cam2 = _cam()
|
|
48
|
+
monkeypatch.delenv("AIDOT_SDES_FAST_LIVEPLAY", raising=False)
|
|
49
|
+
cam2._sdes_fast_liveplay_opt = True
|
|
50
|
+
assert cam2._resolve_sdes_fast_liveplay() is True
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
if __name__ == "__main__":
|
|
54
|
+
import traceback
|
|
55
|
+
|
|
56
|
+
class _MP:
|
|
57
|
+
def setenv(self, k, v): os.environ[k] = v
|
|
58
|
+
def delenv(self, k, raising=False): os.environ.pop(k, None)
|
|
59
|
+
|
|
60
|
+
_fail = 0
|
|
61
|
+
for _k, _v in sorted(globals().items()):
|
|
62
|
+
if _k.startswith("test_"):
|
|
63
|
+
try:
|
|
64
|
+
_v(_MP()) if _v.__code__.co_argcount else _v()
|
|
65
|
+
print(f"PASS {_k}")
|
|
66
|
+
except Exception:
|
|
67
|
+
_fail += 1
|
|
68
|
+
print(f"FAIL {_k}")
|
|
69
|
+
traceback.print_exc()
|
|
70
|
+
raise SystemExit(1 if _fail else 0)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/models/device_client_model.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/models/device_model.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/src/aidot/models/discover_model.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/tests/test_highport_nomination.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/tests/test_no_undefined_names.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.23}/tests/test_post_merge_hardening.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|