python-aidot-cameras 0.12.12__tar.gz → 0.12.13__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.12/python_aidot_cameras.egg-info → python_aidot_cameras-0.12.13}/PKG-INFO +1 -1
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/client.py +21 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/sdes_open.py +11 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/pyproject.toml +1 -1
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13/python_aidot_cameras.egg-info}/PKG-INFO +1 -1
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/python_aidot_cameras.egg-info/SOURCES.txt +1 -0
- python_aidot_cameras-0.12.13/tests/test_dormant_camera_cleanup.py +65 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_viewer_check_throttle.py +0 -1
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/LICENSE +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/MANIFEST.in +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/README.md +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/__init__.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/__main__.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/__init__.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/__init__.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/clock.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/codecs/__init__.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/codecs/base.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/codecs/g711.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/codecs/g722.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/codecs/h264.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/codecs/opus.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/codecs/vpx.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/contrib/__init__.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/contrib/media.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/contrib/signaling.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/events.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/exceptions.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/jitterbuffer.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/mediastreams.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/rate.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/rtcconfiguration.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/rtcdatachannel.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/rtcdtlstransport.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/rtcicetransport.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/rtcpeerconnection.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/rtcrtpparameters.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/rtcrtpreceiver.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/rtcrtpsender.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/rtcrtptransceiver.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/rtcsctptransport.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/rtcsessiondescription.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/rtp.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/sdp.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/stats.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/utils.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/__init__.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/constants.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/controls.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/go2rtc.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/lan_control.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/models.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/playback.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/protocol.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/sdes.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/tutk.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/webrtc.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/webrtc_open.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/client.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/const.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/credentials.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/crypto.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/device_client.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/discover.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/exceptions.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/g711.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/py.typed +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/python_aidot_cameras.egg-info/dependency_links.txt +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/python_aidot_cameras.egg-info/entry_points.txt +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/python_aidot_cameras.egg-info/requires.txt +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/python_aidot_cameras.egg-info/top_level.txt +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/setup.cfg +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_aioice_compat.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_alarm_event.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_backoff.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_deferred_hardening.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_device_login_guard.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_device_user_info_cache.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_dtls_not_ready_burst.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_dtls_pinning.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_dtls_serve_decode_skip.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_dtls_serve_open_timeout.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_dtls_skip_signaling_wait.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_dtls_slow_probe.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_egress_guard.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_go2rtc.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_go2rtc_cli.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_h264_decode_rate_limit.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_highport_nomination.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_ice_config_cache.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_idle_release_both_loops.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_keepalive_renew.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_key_restart_sdp.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_keyframe_prompter.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_lan_control.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_light_active_color_mode.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_live_stream_param.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_logging_caps.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_motion_poll.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_mqtt_credential_refetch.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_mqtt_credential_self_heal.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_mqtt_password_not_persisted.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_mqtt_session_reconnect.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_narrow_pc_ice.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_no_self_referential_go2rtc.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_no_undefined_names.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_offline_keepalive_pause.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_open_fail_logger.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_open_gate_delay.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_persistent_mqtt.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_persistent_mqtt_robustness.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_playback_tls.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_post_merge_hardening.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_retry_policy.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_sdes_adaptive.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_sdes_bridge_break_gate.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_sdes_echo_wait_timeout.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_sdes_fast_liveplay.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_sdes_ffmpeg_stderr_log.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_sdes_idle_release.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_sdes_open_cleanup.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_sdes_serve_audio.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_sdes_serve_cmd.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_sdes_sprop.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_sdes_talk.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_sdes_teardown_exit_log.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_sdes_watchdog.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_sdp_payload_type_narrowing.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_security_hardening.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_serializable_login_info.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_serve_relay.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_session_stats.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_speak.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_stream_cap.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_stream_drain_ownership.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_stream_idle.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_stream_slot_cap.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_stream_teardown.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_talk.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_terminal_ack.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_token_file_robustness.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_token_refresh.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_upstream_compat.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_viewer_presence.py +0 -0
- {python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_wait_or_event.py +0 -0
{python_aidot_cameras-0.12.12/python_aidot_cameras.egg-info → python_aidot_cameras-0.12.13}/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.13
|
|
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.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/client.py
RENAMED
|
@@ -3155,6 +3155,19 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
|
|
|
3155
3155
|
self._cancel_keepalive_renew()
|
|
3156
3156
|
self._keepalive_rtsp_url = None
|
|
3157
3157
|
self._serve_ready.clear()
|
|
3158
|
+
# Take the stream out of go2rtc too. Leaving it registered
|
|
3159
|
+
# points go2rtc at a source that no longer exists, so a viewer
|
|
3160
|
+
# attaching while the camera is dormant gets a hard refusal
|
|
3161
|
+
# ("connection refused" on the serve port) instead of a clean
|
|
3162
|
+
# "no such stream" - and in push mode that source was never
|
|
3163
|
+
# dialable in the first place. stream_source() re-registers on
|
|
3164
|
+
# the next view.
|
|
3165
|
+
try:
|
|
3166
|
+
await self._deregister_go2rtc()
|
|
3167
|
+
except Exception:
|
|
3168
|
+
_LOGGER.debug("camera %s: swallowed exception in %s",
|
|
3169
|
+
getattr(self, "device_id", "?"),
|
|
3170
|
+
"_deregister_go2rtc", exc_info=True)
|
|
3158
3171
|
_LOGGER.debug(
|
|
3159
3172
|
"SDES serve: %s idle (no viewer) - released until next view",
|
|
3160
3173
|
self.device_id,
|
|
@@ -4116,6 +4129,14 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
|
|
|
4116
4129
|
self._cancel_keepalive_renew()
|
|
4117
4130
|
self._keepalive_rtsp_url = None
|
|
4118
4131
|
self._serve_ready.clear()
|
|
4132
|
+
# Same as the SDES path: do not leave go2rtc holding a stream
|
|
4133
|
+
# whose source no longer exists.
|
|
4134
|
+
try:
|
|
4135
|
+
await self._deregister_go2rtc()
|
|
4136
|
+
except Exception:
|
|
4137
|
+
_LOGGER.debug("camera %s: swallowed exception in %s",
|
|
4138
|
+
getattr(self, "device_id", "?"),
|
|
4139
|
+
"_deregister_go2rtc", exc_info=True)
|
|
4119
4140
|
_LOGGER.debug(
|
|
4120
4141
|
"DTLS serve: %s idle (no viewer) - released until next view",
|
|
4121
4142
|
self.device_id,
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/sdes_open.py
RENAMED
|
@@ -102,6 +102,11 @@ def _sdes_echo_wait_timeout(skip_liveplay: bool) -> float:
|
|
|
102
102
|
return 0.0 if skip_liveplay else 2.0
|
|
103
103
|
|
|
104
104
|
|
|
105
|
+
# ffmpeg returns AVERROR(EPIPE) = -32 when its output consumer disappears, and a
|
|
106
|
+
# process exit status is truncated to an unsigned byte: -32 & 0xFF = 224.
|
|
107
|
+
_FFMPEG_EXIT_EPIPE = 224
|
|
108
|
+
|
|
109
|
+
|
|
105
110
|
def _classify_ffmpeg_exit(rc: int, teardown_requested: bool) -> int:
|
|
106
111
|
"""Log level for the bridge observe loop's "ffmpeg exited" line.
|
|
107
112
|
|
|
@@ -116,6 +121,12 @@ def _classify_ffmpeg_exit(rc: int, teardown_requested: bool) -> int:
|
|
|
116
121
|
"""
|
|
117
122
|
if rc < 0 and teardown_requested:
|
|
118
123
|
return logging.DEBUG
|
|
124
|
+
if rc == _FFMPEG_EXIT_EPIPE:
|
|
125
|
+
# Broken pipe: the consumer went away. That is the NORMAL end of a
|
|
126
|
+
# `-listen 1` serve - go2rtc disconnects and ffmpeg exits - so warning
|
|
127
|
+
# about it trains the reader to ignore real failures. A process exit
|
|
128
|
+
# status is an unsigned byte, so AVERROR(EPIPE) = -32 surfaces as 224.
|
|
129
|
+
return logging.DEBUG
|
|
119
130
|
return logging.WARNING
|
|
120
131
|
|
|
121
132
|
|
|
@@ -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.13"
|
|
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.12 → python_aidot_cameras-0.12.13/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.13
|
|
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
|
|
@@ -72,6 +72,7 @@ tests/test_backoff.py
|
|
|
72
72
|
tests/test_deferred_hardening.py
|
|
73
73
|
tests/test_device_login_guard.py
|
|
74
74
|
tests/test_device_user_info_cache.py
|
|
75
|
+
tests/test_dormant_camera_cleanup.py
|
|
75
76
|
tests/test_dtls_not_ready_burst.py
|
|
76
77
|
tests/test_dtls_pinning.py
|
|
77
78
|
tests/test_dtls_serve_decode_skip.py
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""A dormant camera must not leave a dead stream registered in go2rtc.
|
|
2
|
+
|
|
3
|
+
Idle-release stops the serve but used to leave the go2rtc stream in place,
|
|
4
|
+
pointing at a source that no longer exists. A viewer attaching then gets a hard
|
|
5
|
+
"connection refused" on the serve port rather than a clean miss - and in PUSH mode
|
|
6
|
+
that source was never dialable at all, because the keepalive publishes INTO go2rtc
|
|
7
|
+
rather than serving over HTTP.
|
|
8
|
+
|
|
9
|
+
Observed live: four go2rtc streams registered against serve ports with nothing
|
|
10
|
+
listening, and go2rtc reporting
|
|
11
|
+
`dial tcp 127.0.0.1:18981: connect: connection refused`.
|
|
12
|
+
"""
|
|
13
|
+
import inspect
|
|
14
|
+
|
|
15
|
+
import aidot_cameras.camera.client as cc
|
|
16
|
+
from aidot_cameras.camera.sdes_open import (
|
|
17
|
+
_FFMPEG_EXIT_EPIPE,
|
|
18
|
+
_classify_ffmpeg_exit,
|
|
19
|
+
)
|
|
20
|
+
import logging
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _src(name):
|
|
24
|
+
return inspect.getsource(getattr(cc.CameraMixin, name))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_sdes_idle_release_deregisters_from_go2rtc():
|
|
28
|
+
src = _src("_sdes_keepalive_loop_inner")
|
|
29
|
+
idle = src[src.index("if _idle_release:"):]
|
|
30
|
+
assert "_deregister_go2rtc" in idle
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_dtls_idle_release_deregisters_from_go2rtc():
|
|
34
|
+
src = _src("_dtls_serve_loop_inner")
|
|
35
|
+
idle = src[src.index("if idle_release:"):]
|
|
36
|
+
assert "_deregister_go2rtc" in idle
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_deregistration_failure_cannot_break_the_release():
|
|
40
|
+
# Going dormant must still complete if go2rtc is unreachable.
|
|
41
|
+
for name, marker in (("_sdes_keepalive_loop_inner", "if _idle_release:"),
|
|
42
|
+
("_dtls_serve_loop_inner", "if idle_release:")):
|
|
43
|
+
idle = _src(name)
|
|
44
|
+
idle = idle[idle.index(marker):]
|
|
45
|
+
block = idle[idle.index("_deregister_go2rtc") - 200:
|
|
46
|
+
idle.index("_deregister_go2rtc") + 300]
|
|
47
|
+
assert "try:" in block and "except Exception" in block
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_consumer_disconnect_is_not_logged_as_a_failure():
|
|
51
|
+
# ffmpeg returns AVERROR(EPIPE) = -32 when its consumer goes away, and an exit
|
|
52
|
+
# status is an unsigned byte, so it surfaces as 224. That is the normal end of
|
|
53
|
+
# a `-listen 1` serve, not a fault.
|
|
54
|
+
assert _FFMPEG_EXIT_EPIPE == 224
|
|
55
|
+
assert _classify_ffmpeg_exit(224, teardown_requested=False) == logging.DEBUG
|
|
56
|
+
assert _classify_ffmpeg_exit(224, teardown_requested=True) == logging.DEBUG
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_real_failures_still_warn():
|
|
60
|
+
assert _classify_ffmpeg_exit(1, teardown_requested=False) == logging.WARNING
|
|
61
|
+
assert _classify_ffmpeg_exit(255, teardown_requested=False) == logging.WARNING
|
|
62
|
+
# A signal death with no teardown in flight is still unexpected.
|
|
63
|
+
assert _classify_ffmpeg_exit(-9, teardown_requested=False) == logging.WARNING
|
|
64
|
+
# ...but an expected teardown is quiet.
|
|
65
|
+
assert _classify_ffmpeg_exit(-9, teardown_requested=True) == logging.DEBUG
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/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.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/events.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/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.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/rtp.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/sdp.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/stats.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/_vendor/aiortc/utils.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/__init__.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/constants.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/controls.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/go2rtc.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/lan_control.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/models.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/playback.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/protocol.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/webrtc.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/aidot_cameras/camera/webrtc_open.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/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.12 → python_aidot_cameras-0.12.13}/tests/test_deferred_hardening.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_device_login_guard.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_device_user_info_cache.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_dtls_not_ready_burst.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_dtls_serve_decode_skip.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_dtls_serve_open_timeout.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/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.12 → python_aidot_cameras-0.12.13}/tests/test_h264_decode_rate_limit.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_highport_nomination.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_ice_config_cache.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_idle_release_both_loops.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_keyframe_prompter.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_light_active_color_mode.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_live_stream_param.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_mqtt_credential_refetch.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_mqtt_session_reconnect.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_no_undefined_names.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_offline_keepalive_pause.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/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.12 → python_aidot_cameras-0.12.13}/tests/test_post_merge_hardening.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_sdes_bridge_break_gate.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_sdes_echo_wait_timeout.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_sdes_fast_liveplay.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_sdes_ffmpeg_stderr_log.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_sdes_idle_release.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_sdes_open_cleanup.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_sdes_serve_audio.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_sdes_teardown_exit_log.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/tests/test_security_hardening.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.12.12 → python_aidot_cameras-0.12.13}/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.12 → python_aidot_cameras-0.12.13}/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.12 → python_aidot_cameras-0.12.13}/tests/test_token_file_robustness.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|