python-aidot-cameras 0.12.15__tar.gz → 0.12.16__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.12.15/python_aidot_cameras.egg-info → python_aidot_cameras-0.12.16}/PKG-INFO +1 -1
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/client.py +47 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/webrtc_open.py +34 -1
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/pyproject.toml +1 -1
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16/python_aidot_cameras.egg-info}/PKG-INFO +1 -1
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/python_aidot_cameras.egg-info/SOURCES.txt +2 -0
- python_aidot_cameras-0.12.16/tests/test_peerid_reuse.py +69 -0
- python_aidot_cameras-0.12.16/tests/test_sdes_terminal_ack.py +73 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/LICENSE +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/MANIFEST.in +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/README.md +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/__init__.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/__main__.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/__init__.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/__init__.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/clock.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/codecs/__init__.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/codecs/base.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/codecs/g711.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/codecs/g722.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/codecs/h264.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/codecs/opus.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/codecs/vpx.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/contrib/__init__.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/contrib/media.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/contrib/signaling.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/events.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/exceptions.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/jitterbuffer.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/mediastreams.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/rate.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/rtcconfiguration.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/rtcdatachannel.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/rtcdtlstransport.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/rtcicetransport.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/rtcpeerconnection.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/rtcrtpparameters.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/rtcrtpreceiver.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/rtcrtpsender.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/rtcrtptransceiver.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/rtcsctptransport.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/rtcsessiondescription.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/rtp.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/sdp.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/stats.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/utils.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/__init__.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/constants.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/controls.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/go2rtc.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/lan_control.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/models.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/playback.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/protocol.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/sdes.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/sdes_open.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/tutk.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/webrtc.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/client.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/const.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/credentials.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/crypto.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/device_client.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/discover.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/exceptions.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/g711.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/py.typed +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/python_aidot_cameras.egg-info/dependency_links.txt +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/python_aidot_cameras.egg-info/entry_points.txt +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/python_aidot_cameras.egg-info/requires.txt +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/python_aidot_cameras.egg-info/top_level.txt +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/setup.cfg +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_aioice_compat.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_alarm_event.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_backoff.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_battery_skip_turn.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_deferred_hardening.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_device_login_guard.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_device_user_info_cache.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_dormant_camera_cleanup.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_dtls_mux_terminal_write.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_dtls_not_ready_burst.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_dtls_pinning.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_dtls_serve_decode_skip.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_dtls_serve_open_timeout.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_dtls_skip_signaling_wait.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_dtls_slow_probe.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_egress_guard.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_go2rtc.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_go2rtc_cli.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_h264_decode_rate_limit.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_highport_nomination.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_ice_config_cache.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_idle_release_both_loops.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_keepalive_renew.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_key_restart_sdp.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_keyframe_prompter.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_lan_control.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_light_active_color_mode.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_live_stream_param.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_logging_caps.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_motion_poll.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_mqtt_credential_refetch.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_mqtt_credential_self_heal.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_mqtt_password_not_persisted.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_mqtt_session_reconnect.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_narrow_pc_ice.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_no_self_referential_go2rtc.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_no_undefined_names.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_offline_keepalive_pause.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_open_fail_logger.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_open_gate_delay.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_persistent_mqtt.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_persistent_mqtt_robustness.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_playback_tls.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_post_merge_hardening.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_retry_policy.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_sdes_adaptive.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_sdes_bridge_break_gate.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_sdes_echo_wait_timeout.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_sdes_fast_liveplay.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_sdes_ffmpeg_stderr_log.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_sdes_idle_release.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_sdes_open_cleanup.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_sdes_serve_audio.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_sdes_serve_cmd.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_sdes_sprop.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_sdes_talk.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_sdes_teardown_exit_log.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_sdes_watchdog.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_sdp_payload_type_narrowing.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_security_hardening.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_serializable_login_info.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_serve_relay.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_session_stats.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_speak.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_stream_cap.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_stream_drain_ownership.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_stream_idle.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_stream_slot_cap.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_stream_teardown.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_talk.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_terminal_ack.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_token_file_robustness.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_token_refresh.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_upstream_compat.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_viewer_check_throttle.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_viewer_presence.py +0 -0
- {python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_wait_or_event.py +0 -0
{python_aidot_cameras-0.12.15/python_aidot_cameras.egg-info → python_aidot_cameras-0.12.16}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-aidot-cameras
|
|
3
|
-
Version: 0.12.
|
|
3
|
+
Version: 0.12.16
|
|
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.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/client.py
RENAMED
|
@@ -3057,11 +3057,30 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
|
|
|
3057
3057
|
# lifetime; an integration reload / restart re-probes the fast path.
|
|
3058
3058
|
_fast_failed = bool(getattr(self, "_fast_path_unavailable", False))
|
|
3059
3059
|
|
|
3060
|
+
# Reuse ONE peerid across the retries of this loop instead of minting a
|
|
3061
|
+
# fresh one per attempt. A fresh peerid = a new camera-side session, and
|
|
3062
|
+
# the camera frees old ones only slowly, so mint-per-retry stacks up
|
|
3063
|
+
# sessions on a failing battery camera faster than they drain (measured:
|
|
3064
|
+
# this is how the L2 wedged into a wake-then-sleep loop). Mirrors the
|
|
3065
|
+
# official app, which resends within one session. Rotate to a fresh
|
|
3066
|
+
# peerid after a session that actually delivered media (so the next view
|
|
3067
|
+
# is a clean session) or after _PEERID_MAX_REUSE consecutive dead
|
|
3068
|
+
# attempts (so a poisoned peerid can't wedge us permanently).
|
|
3069
|
+
_PEERID_MAX_REUSE = 3
|
|
3070
|
+
_loop_peer_id = self.generate_webrtc_peer_id(live_type=2, stream_id=0,
|
|
3071
|
+
sdes=True)
|
|
3072
|
+
_peer_reuses = 0
|
|
3073
|
+
|
|
3060
3074
|
while self._streaming_active:
|
|
3061
3075
|
if self._serve_relay is not None:
|
|
3062
3076
|
# Clear any stale backend from a prior session; the open below
|
|
3063
3077
|
# points the relay at this session's fresh internal ffmpeg port.
|
|
3064
3078
|
self._serve_relay.set_backend(None)
|
|
3079
|
+
if _peer_reuses >= _PEERID_MAX_REUSE:
|
|
3080
|
+
_loop_peer_id = self.generate_webrtc_peer_id(
|
|
3081
|
+
live_type=2, stream_id=0, sdes=True)
|
|
3082
|
+
_peer_reuses = 0
|
|
3083
|
+
_peer_reuses += 1
|
|
3065
3084
|
_use_fast = self._adaptive_next_fast(_adaptive, _fast_failed)
|
|
3066
3085
|
if _adaptive:
|
|
3067
3086
|
self._fast_attempt_override = _use_fast
|
|
@@ -3069,10 +3088,31 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
|
|
|
3069
3088
|
session = await self.async_open_webrtc_stream(
|
|
3070
3089
|
rtsp_push_url=self._keepalive_rtsp_url,
|
|
3071
3090
|
timeout=(_FAST_OPEN_TIMEOUT if _use_fast else 120.0),
|
|
3091
|
+
reuse_peer_id=_loop_peer_id,
|
|
3072
3092
|
)
|
|
3073
3093
|
except asyncio.CancelledError:
|
|
3074
3094
|
self._fast_attempt_override = None
|
|
3075
3095
|
return
|
|
3096
|
+
except AidotCameraBusy as busy:
|
|
3097
|
+
# The camera itself said it has no free session (-50002 max
|
|
3098
|
+
# concurrent streams / -50015). Each retry mints a NEW peerid and
|
|
3099
|
+
# so registers ANOTHER camera-side session, which the camera only
|
|
3100
|
+
# releases slowly - so retrying on the short backoff makes the
|
|
3101
|
+
# shortage worse and can wedge a battery camera into a
|
|
3102
|
+
# wake-then-sleep loop that serves nothing. Wait out the release
|
|
3103
|
+
# window instead. (The DTLS loops have always done this; the SDES
|
|
3104
|
+
# loop silently did not.)
|
|
3105
|
+
self._fast_attempt_override = None
|
|
3106
|
+
_LOGGER.warning(
|
|
3107
|
+
"SDES keepalive: camera %s refused the stream (%s) - "
|
|
3108
|
+
"backing off %.0fs so its sessions can be released",
|
|
3109
|
+
self.device_id, busy, _MAX_DELAY,
|
|
3110
|
+
)
|
|
3111
|
+
try:
|
|
3112
|
+
await asyncio.sleep(_MAX_DELAY)
|
|
3113
|
+
except asyncio.CancelledError:
|
|
3114
|
+
return
|
|
3115
|
+
continue
|
|
3076
3116
|
except Exception as exc:
|
|
3077
3117
|
self._fast_attempt_override = None
|
|
3078
3118
|
if _use_fast:
|
|
@@ -3197,6 +3237,13 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
|
|
|
3197
3237
|
# Adaptive bookkeeping: a fast attempt that never delivered media
|
|
3198
3238
|
# latches the loop onto the full relay path for its remaining opens.
|
|
3199
3239
|
_healthy = session.last_media_monotonic > 0.0
|
|
3240
|
+
if _healthy:
|
|
3241
|
+
# A session that delivered media is a real, cleanly-used session;
|
|
3242
|
+
# the next open should be a fresh one rather than re-offering on a
|
|
3243
|
+
# peerid the camera has already finished with.
|
|
3244
|
+
_loop_peer_id = self.generate_webrtc_peer_id(
|
|
3245
|
+
live_type=2, stream_id=0, sdes=True)
|
|
3246
|
+
_peer_reuses = 0
|
|
3200
3247
|
if _use_fast and not _healthy and not _fast_failed:
|
|
3201
3248
|
_LOGGER.info(
|
|
3202
3249
|
"SDES adaptive[%s]: fast attempt delivered no media - "
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/webrtc_open.py
RENAMED
|
@@ -159,6 +159,7 @@ class _WebRTCOpenMixin:
|
|
|
159
159
|
rtsp_push_url: Optional[str] = None,
|
|
160
160
|
talk_pcm_provider: "Optional[Callable[[], Optional[bytes]]]" = None,
|
|
161
161
|
talk: bool = False,
|
|
162
|
+
reuse_peer_id: Optional[str] = None,
|
|
162
163
|
) -> "WebRTCSession":
|
|
163
164
|
"""Open a liveType=2 WebRTC stream via MQTT signaling.
|
|
164
165
|
|
|
@@ -497,7 +498,14 @@ class _WebRTCOpenMixin:
|
|
|
497
498
|
_dtls_fallback_ok = str(_cam_props.get("isDTLS", "1")) != "0"
|
|
498
499
|
|
|
499
500
|
device_id = self.device_id
|
|
500
|
-
|
|
501
|
+
# A fresh peerid mints a NEW camera-side session, and the camera releases
|
|
502
|
+
# old ones only slowly (~3-4 min measured), so minting one on every retry
|
|
503
|
+
# of a failing loop stacks up sessions faster than they drain and can wedge
|
|
504
|
+
# a battery camera. The official app instead reuses one peerid and resends
|
|
505
|
+
# the same offer within a single session. ``reuse_peer_id`` lets a caller
|
|
506
|
+
# (the SDES keepalive loop) hold one peerid across retries; None keeps the
|
|
507
|
+
# historical mint-per-attempt behaviour for every other caller.
|
|
508
|
+
peer_id = reuse_peer_id or self.generate_webrtc_peer_id(
|
|
501
509
|
live_type=2, stream_id=stream_id, sdes=use_sdes
|
|
502
510
|
)
|
|
503
511
|
loop = asyncio.get_running_loop()
|
|
@@ -1212,7 +1220,26 @@ class _WebRTCOpenMixin:
|
|
|
1212
1220
|
# Branch: SDES-SRTP cameras use ffmpeg; DTLS cameras use aiortc
|
|
1213
1221
|
# ------------------------------------------------------------------ #
|
|
1214
1222
|
if use_sdes:
|
|
1223
|
+
def _raise_if_camera_refused():
|
|
1224
|
+
"""Surface a terminal webrtcResp ack on the SDES path too.
|
|
1225
|
+
|
|
1226
|
+
GAP D was only wired into the DTLS branch: the shared message
|
|
1227
|
+
handler records -50002 (max concurrent streams) / -50015 into
|
|
1228
|
+
``terminal_error_fut`` for BOTH transports, but only the DTLS
|
|
1229
|
+
connect ever read it. So when a battery camera answered "no
|
|
1230
|
+
free session", the SDES keepalive loop treated it as a generic
|
|
1231
|
+
failure and retried on the short backoff - hammering the very
|
|
1232
|
+
camera that had just said it was full, and registering yet
|
|
1233
|
+
another peerid each time. Raising AidotCameraBusy lets the
|
|
1234
|
+
loop back off for the camera's release window instead.
|
|
1235
|
+
"""
|
|
1236
|
+
if terminal_error_fut.done():
|
|
1237
|
+
_code, _desc = terminal_error_fut.result()
|
|
1238
|
+
_status(f"camera refused the stream (code={_code}) - not retrying")
|
|
1239
|
+
raise AidotCameraBusy(_code, _desc)
|
|
1240
|
+
|
|
1215
1241
|
try:
|
|
1242
|
+
_raise_if_camera_refused()
|
|
1216
1243
|
_sdes_session = await self._open_sdes_stream(
|
|
1217
1244
|
peer_id=peer_id,
|
|
1218
1245
|
user_id=user_id,
|
|
@@ -1248,7 +1275,13 @@ class _WebRTCOpenMixin:
|
|
|
1248
1275
|
# DTLS-fallback path below keeps the slot for its own hand-off.)
|
|
1249
1276
|
self._release_stream_drain_to_session()
|
|
1250
1277
|
return _sdes_session
|
|
1278
|
+
except AidotCameraBusy:
|
|
1279
|
+
raise
|
|
1251
1280
|
except CameraMixin._SdesNoAnswerError:
|
|
1281
|
+
# A terminal refusal that lands while we were waiting surfaces
|
|
1282
|
+
# as a no-answer; check before spending a DTLS fallback on a
|
|
1283
|
+
# camera that has already told us it has no free session.
|
|
1284
|
+
_raise_if_camera_refused()
|
|
1252
1285
|
# Camera reported enableSdes='1' but did not respond to our SDES
|
|
1253
1286
|
# offer. iOS telemetry shows models such as LK.IPC.A001064 can
|
|
1254
1287
|
# have an incorrectly set enableSdes property while actually
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-aidot-cameras"
|
|
7
|
-
version = "0.12.
|
|
7
|
+
version = "0.12.16"
|
|
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.12.15 → python_aidot_cameras-0.12.16/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.12.
|
|
3
|
+
Version: 0.12.16
|
|
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
|
|
@@ -106,6 +106,7 @@ tests/test_no_undefined_names.py
|
|
|
106
106
|
tests/test_offline_keepalive_pause.py
|
|
107
107
|
tests/test_open_fail_logger.py
|
|
108
108
|
tests/test_open_gate_delay.py
|
|
109
|
+
tests/test_peerid_reuse.py
|
|
109
110
|
tests/test_persistent_mqtt.py
|
|
110
111
|
tests/test_persistent_mqtt_robustness.py
|
|
111
112
|
tests/test_playback_tls.py
|
|
@@ -123,6 +124,7 @@ tests/test_sdes_serve_cmd.py
|
|
|
123
124
|
tests/test_sdes_sprop.py
|
|
124
125
|
tests/test_sdes_talk.py
|
|
125
126
|
tests/test_sdes_teardown_exit_log.py
|
|
127
|
+
tests/test_sdes_terminal_ack.py
|
|
126
128
|
tests/test_sdes_watchdog.py
|
|
127
129
|
tests/test_sdp_payload_type_narrowing.py
|
|
128
130
|
tests/test_security_hardening.py
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""The SDES keepalive loop reuses one peerid across retries instead of minting
|
|
2
|
+
a fresh one every attempt.
|
|
3
|
+
|
|
4
|
+
A fresh peerid registers a NEW camera-side session, and the camera releases old
|
|
5
|
+
ones only slowly (~3-4 min measured), so minting one per retry on a failing loop
|
|
6
|
+
stacks up sessions faster than they drain - which is how a battery A001513 gets
|
|
7
|
+
wedged into a wake-then-sleep loop that serves nothing. The official app reuses a
|
|
8
|
+
peerid and resends within one session. This locks:
|
|
9
|
+
- the impl accepts reuse_peer_id and uses it verbatim when given;
|
|
10
|
+
- it still mints a fresh one when not given (unchanged for every other caller);
|
|
11
|
+
- the SDES keepalive loop holds one across retries and rotates it after a
|
|
12
|
+
media-delivering session or a reuse cap.
|
|
13
|
+
"""
|
|
14
|
+
import inspect
|
|
15
|
+
import os
|
|
16
|
+
import sys
|
|
17
|
+
|
|
18
|
+
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
19
|
+
|
|
20
|
+
import aidot_cameras.camera.client as cc
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _impl_signature():
|
|
24
|
+
for cls in vars(cc).values():
|
|
25
|
+
if isinstance(cls, type) and "_async_open_webrtc_stream_impl" in cls.__dict__:
|
|
26
|
+
return inspect.signature(cls.__dict__["_async_open_webrtc_stream_impl"])
|
|
27
|
+
raise AssertionError("impl not found")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _fn_source(qualname):
|
|
31
|
+
for cls in vars(cc).values():
|
|
32
|
+
if isinstance(cls, type) and qualname in cls.__dict__:
|
|
33
|
+
return inspect.getsource(cls.__dict__[qualname])
|
|
34
|
+
raise AssertionError(f"{qualname} not found")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_impl_accepts_reuse_peer_id_defaulting_to_none():
|
|
38
|
+
p = _impl_signature().parameters.get("reuse_peer_id")
|
|
39
|
+
assert p is not None, "impl must accept reuse_peer_id"
|
|
40
|
+
assert p.default is None, "default None preserves mint-per-call for other callers"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_impl_uses_reuse_peer_id_verbatim_when_given():
|
|
44
|
+
src = _fn_source("_async_open_webrtc_stream_impl")
|
|
45
|
+
# peer_id = reuse_peer_id or generate_webrtc_peer_id(...)
|
|
46
|
+
assert "reuse_peer_id or" in src, (
|
|
47
|
+
"when a peerid is supplied it must be used as-is, not regenerated")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_sdes_keepalive_loop_holds_and_rotates_one_peerid():
|
|
51
|
+
src = _fn_source("_sdes_keepalive_loop_inner")
|
|
52
|
+
assert "reuse_peer_id=" in src, "the SDES loop must pass a reused peerid"
|
|
53
|
+
assert "_loop_peer_id" in src
|
|
54
|
+
# rotate after a media-delivering session and after a reuse cap
|
|
55
|
+
assert "_PEERID_MAX_REUSE" in src, "must cap consecutive reuses"
|
|
56
|
+
assert src.count("generate_webrtc_peer_id") >= 2, (
|
|
57
|
+
"must be able to rotate to a fresh peerid (initial + rotation)")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def test_generate_peer_id_is_unique_per_call():
|
|
61
|
+
gen = None
|
|
62
|
+
for cls in vars(cc).values():
|
|
63
|
+
if isinstance(cls, type) and "generate_webrtc_peer_id" in cls.__dict__:
|
|
64
|
+
gen = cls.generate_webrtc_peer_id
|
|
65
|
+
break
|
|
66
|
+
assert gen is not None
|
|
67
|
+
a = gen(live_type=2, stream_id=0, sdes=True)
|
|
68
|
+
b = gen(live_type=2, stream_id=0, sdes=True)
|
|
69
|
+
assert a != b and a.endswith("_2_0_1") and b.endswith("_2_0_1")
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""A terminal webrtcResp ack must be honoured on the SDES path, not just DTLS.
|
|
2
|
+
|
|
3
|
+
The shared message handler records -50002 ("max concurrent streams") and -50015
|
|
4
|
+
into ``terminal_error_fut`` for BOTH transports, but only the DTLS connect ever
|
|
5
|
+
read it. So when a battery camera answered "no free session", the SDES keepalive
|
|
6
|
+
loop saw a generic failure and retried on the short backoff - hammering the very
|
|
7
|
+
camera that had just said it was full, and minting a NEW peerid (= another
|
|
8
|
+
camera-side session, released only slowly) on every attempt. That is how a
|
|
9
|
+
battery A001513 gets wedged into a wake-then-sleep loop that serves nothing.
|
|
10
|
+
|
|
11
|
+
These tests lock the two halves of the fix: the codes are classified as
|
|
12
|
+
terminal, and the SDES keepalive loop treats AidotCameraBusy as "back off for
|
|
13
|
+
the release window" rather than "retry immediately".
|
|
14
|
+
"""
|
|
15
|
+
import inspect
|
|
16
|
+
import os
|
|
17
|
+
import sys
|
|
18
|
+
|
|
19
|
+
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
20
|
+
|
|
21
|
+
from aidot_cameras.camera.protocol import (
|
|
22
|
+
_WEBRTC_TERMINAL_ACK_CODES,
|
|
23
|
+
_terminal_webrtc_ack,
|
|
24
|
+
)
|
|
25
|
+
import aidot_cameras.camera.client as cc
|
|
26
|
+
import aidot_cameras.camera.webrtc_open as wo
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_session_exceed_codes_are_terminal():
|
|
30
|
+
assert -50002 in _WEBRTC_TERMINAL_ACK_CODES
|
|
31
|
+
assert -50015 in _WEBRTC_TERMINAL_ACK_CODES
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_terminal_ack_parses_session_exceed():
|
|
35
|
+
msg = {"method": "webrtcResp", "ack": {"code": -50002, "desc": "SESSION_EXCEED"}}
|
|
36
|
+
got = _terminal_webrtc_ack(msg)
|
|
37
|
+
assert got is not None
|
|
38
|
+
assert got[0] == -50002
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_transient_ack_is_not_terminal():
|
|
42
|
+
# -50019 ("not ready") is benign: mains cameras emit it and recover via ICE.
|
|
43
|
+
msg = {"method": "webrtcResp", "ack": {"code": -50019, "desc": "not ready"}}
|
|
44
|
+
assert _terminal_webrtc_ack(msg) is None
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _fn_source(mod, qualname):
|
|
48
|
+
"""Source of a method by name, without relying on file offsets."""
|
|
49
|
+
for cls in vars(mod).values():
|
|
50
|
+
if isinstance(cls, type):
|
|
51
|
+
fn = cls.__dict__.get(qualname)
|
|
52
|
+
if fn is not None:
|
|
53
|
+
return inspect.getsource(fn)
|
|
54
|
+
raise AssertionError(f"{qualname} not found in {mod.__name__}")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_sdes_open_path_checks_the_terminal_future():
|
|
58
|
+
# The SDES branch must consult terminal_error_fut; before the fix it never did.
|
|
59
|
+
src = _fn_source(wo, "_async_open_webrtc_stream_impl")
|
|
60
|
+
sdes_branch = src[src.rindex("if use_sdes:"):]
|
|
61
|
+
assert "terminal_error_fut" in sdes_branch, (
|
|
62
|
+
"SDES branch must read terminal_error_fut (GAP D was DTLS-only)")
|
|
63
|
+
assert "AidotCameraBusy" in sdes_branch
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_sdes_keepalive_loop_backs_off_on_camera_busy():
|
|
67
|
+
loop_src = _fn_source(cc, "_sdes_keepalive_loop_inner")
|
|
68
|
+
assert "except AidotCameraBusy" in loop_src, (
|
|
69
|
+
"the SDES keepalive loop must honour a camera refusal instead of "
|
|
70
|
+
"retrying on the short backoff")
|
|
71
|
+
busy_at = loop_src.index("except AidotCameraBusy")
|
|
72
|
+
assert "_MAX_DELAY" in loop_src[busy_at:busy_at + 1600], (
|
|
73
|
+
"a camera refusal must wait out the long release window")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/clock.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.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/events.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/rate.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
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/rtp.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/sdp.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/stats.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/_vendor/aiortc/utils.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/__init__.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/constants.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/controls.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/go2rtc.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/lan_control.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/models.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/playback.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/protocol.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/sdes_open.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/camera/webrtc.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/aidot_cameras/device_client.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
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_battery_skip_turn.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_deferred_hardening.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_device_login_guard.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_device_user_info_cache.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_dormant_camera_cleanup.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_dtls_mux_terminal_write.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_dtls_not_ready_burst.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_dtls_serve_decode_skip.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_dtls_serve_open_timeout.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_dtls_skip_signaling_wait.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_h264_decode_rate_limit.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_highport_nomination.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_ice_config_cache.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_idle_release_both_loops.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_keyframe_prompter.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_light_active_color_mode.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_live_stream_param.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_mqtt_credential_refetch.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_mqtt_session_reconnect.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_no_undefined_names.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_offline_keepalive_pause.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/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.12.15 → python_aidot_cameras-0.12.16}/tests/test_post_merge_hardening.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_sdes_bridge_break_gate.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_sdes_echo_wait_timeout.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_sdes_fast_liveplay.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_sdes_ffmpeg_stderr_log.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_sdes_idle_release.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_sdes_open_cleanup.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_sdes_serve_audio.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_sdes_teardown_exit_log.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_security_hardening.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/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.12.15 → python_aidot_cameras-0.12.16}/tests/test_stream_drain_ownership.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_token_file_robustness.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.15 → python_aidot_cameras-0.12.16}/tests/test_viewer_check_throttle.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|