python-aidot-cameras 0.11.10__tar.gz → 0.11.11__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.11.10/python_aidot_cameras.egg-info → python_aidot_cameras-0.11.11}/PKG-INFO +1 -1
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/camera/protocol.py +38 -8
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/camera/webrtc_open.py +5 -2
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/pyproject.toml +1 -1
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11/python_aidot_cameras.egg-info}/PKG-INFO +1 -1
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_mqtt_session_reconnect.py +50 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/LICENSE +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/MANIFEST.in +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/README.md +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/__init__.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/__main__.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/__init__.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/__init__.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/clock.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/codecs/__init__.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/codecs/base.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/codecs/g711.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/codecs/g722.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/codecs/h264.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/codecs/opus.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/codecs/vpx.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/contrib/__init__.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/contrib/media.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/contrib/signaling.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/events.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/exceptions.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/jitterbuffer.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/mediastreams.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/rate.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/rtcconfiguration.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/rtcdatachannel.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/rtcdtlstransport.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/rtcicetransport.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/rtcpeerconnection.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/rtcrtpparameters.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/rtcrtpreceiver.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/rtcrtpsender.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/rtcrtptransceiver.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/rtcsctptransport.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/rtcsessiondescription.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/rtp.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/sdp.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/stats.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/utils.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/aes_utils.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/camera/__init__.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/camera/client.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/camera/constants.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/camera/controls.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/camera/go2rtc.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/camera/lan_control.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/camera/models.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/camera/playback.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/camera/sdes.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/camera/sdes_open.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/camera/tutk.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/camera/webrtc.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/client.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/const.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/credentials.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/device_client.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/discover.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/exceptions.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/g711.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/login_const.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/models/__init__.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/models/device_client_model.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/models/device_model.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/models/discover_model.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/py.typed +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/python_aidot_cameras.egg-info/SOURCES.txt +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/python_aidot_cameras.egg-info/dependency_links.txt +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/python_aidot_cameras.egg-info/entry_points.txt +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/python_aidot_cameras.egg-info/requires.txt +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/python_aidot_cameras.egg-info/top_level.txt +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/setup.cfg +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_aioice_compat.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_alarm_event.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_backoff.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_deferred_hardening.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_device_login_guard.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_device_user_info_cache.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_dtls_not_ready_burst.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_dtls_pinning.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_dtls_skip_signaling_wait.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_egress_guard.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_go2rtc.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_go2rtc_cli.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_highport_nomination.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_ice_config_cache.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_keepalive_renew.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_keyframe_prompter.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_lan_control.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_live_stream_param.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_logging_caps.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_motion_poll.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_narrow_pc_ice.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_no_undefined_names.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_offline_keepalive_pause.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_open_fail_logger.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_open_gate_delay.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_persistent_mqtt.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_persistent_mqtt_robustness.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_playback_tls.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_post_merge_hardening.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_retry_policy.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_sdes_adaptive.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_sdes_echo_wait_timeout.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_sdes_fast_liveplay.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_sdes_ffmpeg_stderr_log.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_sdes_idle_release.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_sdes_open_cleanup.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_sdes_serve_audio.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_sdes_serve_cmd.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_sdes_sprop.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_sdes_talk.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_sdes_watchdog.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_security_hardening.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_serializable_login_info.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_serve_relay.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_session_stats.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_speak.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_stream_cap.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_stream_drain_ownership.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_stream_idle.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_stream_teardown.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_talk.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_terminal_ack.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_token_file_robustness.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_token_refresh.py +0 -0
- {python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_wait_or_event.py +0 -0
{python_aidot_cameras-0.11.10/python_aidot_cameras.egg-info → python_aidot_cameras-0.11.11}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-aidot-cameras
|
|
3
|
-
Version: 0.11.
|
|
3
|
+
Version: 0.11.11
|
|
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
|
|
@@ -79,6 +79,13 @@ def _build_stun_binding_success_response(
|
|
|
79
79
|
|
|
80
80
|
_WEBRTC_TERMINAL_ACK_CODES = (-50002, -50015)
|
|
81
81
|
|
|
82
|
+
# If a post-connect MQTT drop stays disconnected longer than this (seconds) with
|
|
83
|
+
# no successful paho reconnect, the receive loop ends the session rather than
|
|
84
|
+
# polling a dead socket until the full duration deadline. Long enough to ride
|
|
85
|
+
# out an ordinary network blip + paho's auto-reconnect, short enough that a
|
|
86
|
+
# terminal drop (session taken over, revoked creds, broker gone) fails fast.
|
|
87
|
+
_MQTT_RECONNECT_GRACE = 20.0
|
|
88
|
+
|
|
82
89
|
|
|
83
90
|
def _terminal_webrtc_ack(msg: dict):
|
|
84
91
|
"""Return ``(code, desc)`` if ``msg`` is a webrtcResp carrying a TERMINAL ack
|
|
@@ -1188,7 +1195,8 @@ def _mqtt_session_sync(
|
|
|
1188
1195
|
|
|
1189
1196
|
msg_q = _queue.Queue()
|
|
1190
1197
|
conn_ev = threading.Event()
|
|
1191
|
-
status = {"connected": False, "rc": None, "rc_str": "", "error": None,
|
|
1198
|
+
status = {"connected": False, "rc": None, "rc_str": "", "error": None,
|
|
1199
|
+
"log": [], "disconnected_since": None}
|
|
1192
1200
|
|
|
1193
1201
|
# Build client - handle paho >=2.0 (VERSION2) and <2.0
|
|
1194
1202
|
try:
|
|
@@ -1217,6 +1225,9 @@ def _mqtt_session_sync(
|
|
|
1217
1225
|
status["rc"] = rc
|
|
1218
1226
|
status["rc_str"] = str(reason_code)
|
|
1219
1227
|
if rc == 0:
|
|
1228
|
+
# Successful (re)connect: a prior drop (if any) has recovered, so the
|
|
1229
|
+
# receive loop must not fail it fast - clear the disconnect marker.
|
|
1230
|
+
status["disconnected_since"] = None
|
|
1220
1231
|
# (Re)subscribe on EVERY successful connect. paho's loop_start
|
|
1221
1232
|
# auto-reconnects after a transient drop, but with clean_session the
|
|
1222
1233
|
# broker retains no subscriptions, so a reconnected client would be
|
|
@@ -1250,14 +1261,21 @@ def _mqtt_session_sync(
|
|
|
1250
1261
|
conn_ev.set()
|
|
1251
1262
|
msg_q.put(None) # sentinel: end the receive loop
|
|
1252
1263
|
return
|
|
1253
|
-
# Already connected once: this is a transient drop. paho's
|
|
1254
|
-
# auto-reconnects and _on_connect re-subscribes
|
|
1255
|
-
#
|
|
1256
|
-
# signaling (the non-persistent transport runs one session for
|
|
1257
|
-
# stream).
|
|
1258
|
-
#
|
|
1264
|
+
# Already connected once: this is (so far) a transient drop. paho's
|
|
1265
|
+
# loop_start auto-reconnects and _on_connect re-subscribes AND clears
|
|
1266
|
+
# disconnected_since, so a brief blip must NOT tear down a long-lived
|
|
1267
|
+
# stream's signaling (the non-persistent transport runs one session for
|
|
1268
|
+
# the whole stream). But a drop that never recovers - session taken over
|
|
1269
|
+
# (rc=142) when the account's persistent client reclaims the clientId,
|
|
1270
|
+
# revoked creds, broker gone - would otherwise leave the receive loop
|
|
1271
|
+
# polling a dead socket until the full duration deadline. Record when the
|
|
1272
|
+
# drop began; the loop ends the session once it has persisted past
|
|
1273
|
+
# _MQTT_RECONNECT_GRACE. (dict single-key set/get is atomic under the GIL,
|
|
1274
|
+
# so no lock is needed across the paho thread and the receive loop.)
|
|
1275
|
+
if status.get("disconnected_since") is None:
|
|
1276
|
+
status["disconnected_since"] = time.monotonic()
|
|
1259
1277
|
_LOGGER.debug(
|
|
1260
|
-
"_mqtt_session:
|
|
1278
|
+
"_mqtt_session: disconnect rc=%s (awaiting paho reconnect)",
|
|
1261
1279
|
reason_code,
|
|
1262
1280
|
)
|
|
1263
1281
|
|
|
@@ -1327,6 +1345,18 @@ def _mqtt_session_sync(
|
|
|
1327
1345
|
remaining = deadline - _time.monotonic()
|
|
1328
1346
|
if remaining <= 0:
|
|
1329
1347
|
break
|
|
1348
|
+
# End the session if a post-connect drop never recovered: a terminal
|
|
1349
|
+
# disconnect delivers no further messages, so without this the loop would
|
|
1350
|
+
# poll a dead socket (and the caller's camera signaling would silently
|
|
1351
|
+
# stall) until the full duration deadline.
|
|
1352
|
+
_ds = status.get("disconnected_since")
|
|
1353
|
+
if _ds is not None and (_time.monotonic() - _ds) > _MQTT_RECONNECT_GRACE:
|
|
1354
|
+
_LOGGER.warning(
|
|
1355
|
+
"_mqtt_session: MQTT disconnected >%.0fs with no reconnect "
|
|
1356
|
+
"(rc=%s) - ending session; camera signaling can no longer arrive",
|
|
1357
|
+
_MQTT_RECONNECT_GRACE, status.get("rc_str"),
|
|
1358
|
+
)
|
|
1359
|
+
break
|
|
1330
1360
|
try:
|
|
1331
1361
|
item = msg_q.get(timeout=min(remaining, 0.1))
|
|
1332
1362
|
except _queue.Empty:
|
|
@@ -1284,8 +1284,11 @@ class _WebRTCOpenMixin:
|
|
|
1284
1284
|
# ------------------------------------------------------------------ #
|
|
1285
1285
|
# aiortc peer connection (DTLS-SRTP path)
|
|
1286
1286
|
# ------------------------------------------------------------------ #
|
|
1287
|
-
|
|
1288
|
-
|
|
1287
|
+
# NOTE: do NOT force aioice to DEBUG here. It floods the log on every DTLS
|
|
1288
|
+
# open, and the package-init cap (aidot/__init__.py) holds aioice.ice /
|
|
1289
|
+
# aioice.turn at INFO anyway, so forcing DEBUG was both self-defeating and
|
|
1290
|
+
# noisy. To debug ICE, set the aioice logger level explicitly (that
|
|
1291
|
+
# overrides the NOTSET-guarded cap).
|
|
1289
1292
|
from aidot._vendor.aiortc import RTCConfiguration, RTCIceServer
|
|
1290
1293
|
|
|
1291
1294
|
def _sanitize_ice_uris(uris):
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-aidot-cameras"
|
|
7
|
-
version = "0.11.
|
|
7
|
+
version = "0.11.11"
|
|
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"
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11/python_aidot_cameras.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-aidot-cameras
|
|
3
|
-
Version: 0.11.
|
|
3
|
+
Version: 0.11.11
|
|
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
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_mqtt_session_reconnect.py
RENAMED
|
@@ -82,3 +82,53 @@ def test_disconnect_before_connect_ends_session(monkeypatch):
|
|
|
82
82
|
)
|
|
83
83
|
assert messages == []
|
|
84
84
|
assert status["connected"] is False
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def test_terminal_disconnect_ends_session_before_deadline(monkeypatch):
|
|
88
|
+
"""A post-connect drop that never reconnects must end the session via the
|
|
89
|
+
reconnect grace, not poll a dead socket until the full duration deadline."""
|
|
90
|
+
monkeypatch.setattr(proto, "_MQTT_RECONNECT_GRACE", 0.15)
|
|
91
|
+
|
|
92
|
+
def driver(c):
|
|
93
|
+
c.on_connect(c, None, {}, 0) # connected
|
|
94
|
+
c.on_message(c, None, _FakeMsg("t/before", b"x")) # delivered pre-drop
|
|
95
|
+
time.sleep(0.02)
|
|
96
|
+
c.on_disconnect(c, None, 142) # terminal drop; NO reconnect
|
|
97
|
+
|
|
98
|
+
_install_fake_client(monkeypatch, driver)
|
|
99
|
+
|
|
100
|
+
t0 = time.monotonic()
|
|
101
|
+
messages, status = proto._mqtt_session_sync(
|
|
102
|
+
"wss://broker.example/mqtt", "u", "p", "cid",
|
|
103
|
+
["t/a"], [], 30.0, # 30s duration - must NOT wait this long
|
|
104
|
+
)
|
|
105
|
+
elapsed = time.monotonic() - t0
|
|
106
|
+
|
|
107
|
+
assert elapsed < 5.0, f"terminal disconnect should end fast, took {elapsed:.1f}s"
|
|
108
|
+
assert ("t/before", "x") in messages # pre-drop message still collected
|
|
109
|
+
assert status["disconnected_since"] is not None # the drop was recorded
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def test_reconnect_within_grace_keeps_session(monkeypatch):
|
|
113
|
+
"""A drop that reconnects within the grace clears disconnected_since, so the
|
|
114
|
+
receive loop must NOT fail the session fast (guards the transient path)."""
|
|
115
|
+
monkeypatch.setattr(proto, "_MQTT_RECONNECT_GRACE", 0.5)
|
|
116
|
+
outgoing = queue.Queue()
|
|
117
|
+
|
|
118
|
+
def driver(c):
|
|
119
|
+
c.on_connect(c, None, {}, 0)
|
|
120
|
+
c.on_disconnect(c, None, 7) # blip
|
|
121
|
+
time.sleep(0.05) # < grace
|
|
122
|
+
c.on_connect(c, None, {}, 0) # recovered
|
|
123
|
+
c.on_message(c, None, _FakeMsg("t/after", b"live"))
|
|
124
|
+
time.sleep(0.05)
|
|
125
|
+
outgoing.put_nowait(None) # clean stop
|
|
126
|
+
|
|
127
|
+
_install_fake_client(monkeypatch, driver)
|
|
128
|
+
|
|
129
|
+
messages, status = proto._mqtt_session_sync(
|
|
130
|
+
"wss://broker.example/mqtt", "u", "p", "cid",
|
|
131
|
+
["t/a"], [], 30.0, outgoing_queue=outgoing,
|
|
132
|
+
)
|
|
133
|
+
assert ("t/after", "live") in messages # survived the blip
|
|
134
|
+
assert status["disconnected_since"] is None # cleared on reconnect
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/codecs/base.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/codecs/g711.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/codecs/g722.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/codecs/h264.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/codecs/opus.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/codecs/vpx.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/contrib/media.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/events.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/exceptions.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/jitterbuffer.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/mediastreams.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/rtcdatachannel.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/rtcrtpreceiver.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/aidot/_vendor/aiortc/rtcrtpsender.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
|
|
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.11.10 → python_aidot_cameras-0.11.11}/aidot/models/device_client_model.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_deferred_hardening.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_device_login_guard.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_device_user_info_cache.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_dtls_not_ready_burst.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_dtls_skip_signaling_wait.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_highport_nomination.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_ice_config_cache.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_keyframe_prompter.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_live_stream_param.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_no_undefined_names.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_offline_keepalive_pause.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_open_fail_logger.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_post_merge_hardening.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_sdes_echo_wait_timeout.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_sdes_fast_liveplay.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_sdes_ffmpeg_stderr_log.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_sdes_idle_release.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_sdes_open_cleanup.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_sdes_serve_audio.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_security_hardening.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_serializable_login_info.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_stream_drain_ownership.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.11.10 → python_aidot_cameras-0.11.11}/tests/test_token_file_robustness.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|