python-aidot-cameras 0.15.7__tar.gz → 0.15.8__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.15.7/python_aidot_cameras.egg-info → python_aidot_cameras-0.15.8}/PKG-INFO +1 -1
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/client.py +30 -1
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/pyproject.toml +1 -1
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8/python_aidot_cameras.egg-info}/PKG-INFO +1 -1
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/python_aidot_cameras.egg-info/SOURCES.txt +1 -0
- python_aidot_cameras-0.15.8/tests/test_serve_loss_tolerance.py +70 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/LICENSE +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/MANIFEST.in +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/README.md +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/__init__.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/__main__.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_upstream.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/__init__.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/__init__.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/clock.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/codecs/__init__.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/codecs/base.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/codecs/g711.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/codecs/g722.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/codecs/h264.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/codecs/opus.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/codecs/vpx.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/contrib/__init__.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/contrib/media.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/contrib/signaling.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/events.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/exceptions.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/jitterbuffer.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/mediastreams.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/rate.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/rtcconfiguration.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/rtcdatachannel.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/rtcdtlstransport.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/rtcicetransport.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/rtcpeerconnection.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/rtcrtpparameters.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/rtcrtpreceiver.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/rtcrtpsender.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/rtcrtptransceiver.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/rtcsctptransport.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/rtcsessiondescription.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/rtp.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/sdp.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/stats.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/utils.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/ble_gateway.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/__init__.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/constants.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/controls.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/go2rtc.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/hwaccel.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/lan_control.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/models.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/playback.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/protocol.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/sdes.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/sdes_open.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/tutk.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/webrtc.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/webrtc_open.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/client.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/const.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/credentials.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/crypto.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/device_client.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/discover.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/exceptions.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/g711.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/py.typed +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/python_aidot_cameras.egg-info/dependency_links.txt +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/python_aidot_cameras.egg-info/entry_points.txt +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/python_aidot_cameras.egg-info/requires.txt +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/python_aidot_cameras.egg-info/top_level.txt +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/setup.cfg +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_aioice_compat.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_alarm_event.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_answer_sdp_video_pt.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_audio_mux_offline.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_backoff.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_battery_detection.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_battery_evidence_corroboration.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_battery_skip_turn.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_ble_gateway.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_bridge_state_sentinels.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_constants_imports_resolve.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_deferred_hardening.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_device_login_guard.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_device_user_info_cache.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_dormant_camera_cleanup.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_dtls_mux_terminal_write.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_dtls_not_ready_burst.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_dtls_pinning.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_dtls_serve_decode_skip.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_dtls_serve_open_timeout.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_dtls_skip_signaling_wait.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_dtls_slow_probe.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_dtls_stdout_producer.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_egress_guard.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_env_seams.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_go2rtc.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_go2rtc_cli.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_h264_decode_rate_limit.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_highport_nomination.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_hwaccel_probe.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_ice_config_cache.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_ice_peer_reflexive.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_idle_release_both_loops.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_keepalive_renew.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_key_restart_sdp.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_keyframe_prompter.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_lan_control.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_light_active_color_mode.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_live_stream_param.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_live_validate_policy.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_logging_caps.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_media_socket_rcvbuf.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_media_wait_floor.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_motion_poll.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_mqtt_credential_refetch.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_mqtt_credential_self_heal.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_mqtt_password_not_persisted.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_mqtt_session_reconnect.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_narrow_pc_ice.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_no_self_referential_go2rtc.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_no_undefined_names.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_offline_keepalive_pause.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_open_fail_logger.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_open_gate_delay.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_peerid_reuse.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_persistent_mqtt.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_persistent_mqtt_robustness.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_playback_tls.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_post_merge_hardening.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_resolution_persists.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_restart_cycle.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_retry_policy.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_scripts_importable.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_adaptive.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_bridge_break_gate.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_echo_wait_timeout.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_fast_liveplay.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_ffmpeg_stderr_log.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_idle_release.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_open_cleanup.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_serve_audio.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_serve_cmd.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_serve_stderr_drain.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_sprop.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_talk.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_teardown_exit_log.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_terminal_ack.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_terminal_ack_latency.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_watchdog.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdp_narrowing_properties.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdp_payload_type_narrowing.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_security_hardening.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_serializable_login_info.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_serve_relay.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_session_stats.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_shared_house_seam.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_speak.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sprop_staleness.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_stream_cap.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_stream_drain_ownership.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_stream_idle.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_stream_slot_cap.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_stream_teardown.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_talk.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_terminal_ack.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_token_file_robustness.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_token_refresh.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_turn_create_permission.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_upstream_compat.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_viewer_check_throttle.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_viewer_presence.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_viewer_present_push_mode.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_wait_or_event.py +0 -0
- {python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_wake_readiness_retry.py +0 -0
{python_aidot_cameras-0.15.7/python_aidot_cameras.egg-info → python_aidot_cameras-0.15.8}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-aidot-cameras
|
|
3
|
-
Version: 0.15.
|
|
3
|
+
Version: 0.15.8
|
|
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
|
|
@@ -365,6 +365,18 @@ def _is_self_referential_source(source: str, stream_name: str) -> bool:
|
|
|
365
365
|
return path == stream_name
|
|
366
366
|
|
|
367
367
|
|
|
368
|
+
#: Packets the serve's demuxer may hold while it waits for a gap to fill. A
|
|
369
|
+
#: keyframe on an A001064 is 146-190 KB - roughly 130 packets - so anything
|
|
370
|
+
#: smaller than a few hundred cannot ride out a burst that arrives out of order.
|
|
371
|
+
#: Env-overridable because the right value depends on the link, not on us.
|
|
372
|
+
_SERVE_REORDER_QUEUE = int(os.environ.get("AIDOT_SERVE_REORDER_QUEUE", "500"))
|
|
373
|
+
|
|
374
|
+
#: How long (microseconds) the demuxer waits for a missing packet before moving
|
|
375
|
+
#: on. Bounded on purpose: waiting forever turns loss into a stall, which is the
|
|
376
|
+
#: failure this is meant to prevent.
|
|
377
|
+
_SERVE_MAX_DELAY_US = int(os.environ.get("AIDOT_SERVE_MAX_DELAY_US", "500000"))
|
|
378
|
+
|
|
379
|
+
|
|
368
380
|
def _build_sdes_serve_cmd(
|
|
369
381
|
*,
|
|
370
382
|
sdp_path: str,
|
|
@@ -470,9 +482,26 @@ def _build_sdes_serve_cmd(
|
|
|
470
482
|
# 2 s analyzeduration: the camera sends SPS+PPS+IDR in the first burst;
|
|
471
483
|
# 15 s consumed nearly all packets during analysis. PLI re-arms an IDR
|
|
472
484
|
# every 5 s so parameters always re-arrive.
|
|
473
|
-
|
|
485
|
+
#
|
|
486
|
+
# ``discardcorrupt`` is the loss half of this: both ends of this path are
|
|
487
|
+
# wireless (the camera, and typically the host), so RTP arrives with real
|
|
488
|
+
# gaps. Measured on the reference install: `RTP: missed N packets` with
|
|
489
|
+
# ZERO drops on every socket in the path, which means the packets were
|
|
490
|
+
# lost before they ever reached the box. Without this ffmpeg passes the
|
|
491
|
+
# damaged frame downstream and then backs its input queue up behind the
|
|
492
|
+
# reordering it thinks it needs - "max delay reached. need to consume
|
|
493
|
+
# packet" - and the serve eventually dies, taking every viewer with it.
|
|
494
|
+
# A brief artefact is a far better outcome than a dropped stream.
|
|
495
|
+
"-fflags", "+nobuffer+genpts+discardcorrupt",
|
|
474
496
|
"-analyzeduration", "2000000",
|
|
475
497
|
"-probesize", "500000",
|
|
498
|
+
# Reordering headroom. The default (-1) leaves the demuxer with almost
|
|
499
|
+
# none, so a burst that arrives out of order reads as loss. A keyframe
|
|
500
|
+
# here is 146-190 KB - about 130 packets - so the queue has to be able to
|
|
501
|
+
# hold more than one of them, and max_delay bounds how long it will wait
|
|
502
|
+
# before giving up on a gap rather than stalling the pipeline.
|
|
503
|
+
"-reorder_queue_size", str(_SERVE_REORDER_QUEUE),
|
|
504
|
+
"-max_delay", str(_SERVE_MAX_DELAY_US),
|
|
476
505
|
"-i", sdp_path,
|
|
477
506
|
*dest_args,
|
|
478
507
|
]
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-aidot-cameras"
|
|
7
|
-
version = "0.15.
|
|
7
|
+
version = "0.15.8"
|
|
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.15.7 → python_aidot_cameras-0.15.8/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.15.
|
|
3
|
+
Version: 0.15.8
|
|
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
|
|
@@ -152,6 +152,7 @@ tests/test_sdp_narrowing_properties.py
|
|
|
152
152
|
tests/test_sdp_payload_type_narrowing.py
|
|
153
153
|
tests/test_security_hardening.py
|
|
154
154
|
tests/test_serializable_login_info.py
|
|
155
|
+
tests/test_serve_loss_tolerance.py
|
|
155
156
|
tests/test_serve_relay.py
|
|
156
157
|
tests/test_session_stats.py
|
|
157
158
|
tests/test_shared_house_seam.py
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""The serve must ride out real packet loss instead of dying on it.
|
|
2
|
+
|
|
3
|
+
Both ends of this path are usually wireless - the camera, and the Home Assistant
|
|
4
|
+
host - so RTP genuinely arrives with gaps. Measured on the reference install:
|
|
5
|
+
ffmpeg logged `RTP: missed N packets` while every socket in the path showed ZERO
|
|
6
|
+
kernel drops, which means those packets were lost before they ever reached the
|
|
7
|
+
box. Nothing in the code can recover them.
|
|
8
|
+
|
|
9
|
+
What the code controls is what happens next. Without reordering headroom the
|
|
10
|
+
demuxer treats a burst that arrives out of order as loss; without a bounded
|
|
11
|
+
max_delay it stalls waiting ("max delay reached. need to consume packet") and
|
|
12
|
+
backs its input queue up until the serve dies, dropping every attached viewer.
|
|
13
|
+
A brief artefact is a far better outcome than a dropped stream.
|
|
14
|
+
"""
|
|
15
|
+
import pytest
|
|
16
|
+
|
|
17
|
+
from aidot_cameras.camera.client import (
|
|
18
|
+
_SERVE_MAX_DELAY_US,
|
|
19
|
+
_SERVE_REORDER_QUEUE,
|
|
20
|
+
_build_sdes_serve_cmd,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
_DESTINATIONS = [
|
|
24
|
+
pytest.param({"rtsp_push_url": "rtsp://127.0.0.1:8554/cam"}, id="push"),
|
|
25
|
+
pytest.param({"rtsp_push_url": "http://127.0.0.1:18981/cam.ts"}, id="http-listen"),
|
|
26
|
+
pytest.param({"output_path": "/tmp/cam.ts"}, id="file"),
|
|
27
|
+
pytest.param({}, id="null-drain"),
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _cmd(**kwargs):
|
|
32
|
+
return _build_sdes_serve_cmd(sdp_path="/tmp/x.sdp", **kwargs)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@pytest.mark.parametrize("dest", _DESTINATIONS)
|
|
36
|
+
def test_every_destination_gets_the_loss_tolerance_args(dest):
|
|
37
|
+
"""The input side is shared, so loss tolerance must not depend on the sink."""
|
|
38
|
+
cmd = _cmd(**dest)
|
|
39
|
+
assert "-reorder_queue_size" in cmd
|
|
40
|
+
assert cmd[cmd.index("-reorder_queue_size") + 1] == str(_SERVE_REORDER_QUEUE)
|
|
41
|
+
assert "-max_delay" in cmd
|
|
42
|
+
assert cmd[cmd.index("-max_delay") + 1] == str(_SERVE_MAX_DELAY_US)
|
|
43
|
+
fflags = cmd[cmd.index("-fflags") + 1]
|
|
44
|
+
assert "discardcorrupt" in fflags, fflags
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_the_reorder_queue_clears_a_keyframe():
|
|
48
|
+
# 146-190 KB of keyframe is ~130 packets at MTU. A queue that cannot hold
|
|
49
|
+
# more than one keyframe's worth reads an out-of-order burst as loss.
|
|
50
|
+
assert _SERVE_REORDER_QUEUE >= 260
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_max_delay_is_bounded():
|
|
54
|
+
"""Unbounded waiting turns loss into the stall this is meant to prevent."""
|
|
55
|
+
assert 0 < _SERVE_MAX_DELAY_US <= 2_000_000
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@pytest.mark.parametrize("dest", _DESTINATIONS)
|
|
59
|
+
def test_the_low_latency_flags_survive(dest):
|
|
60
|
+
"""Tolerance must not be bought by silently reintroducing buffering."""
|
|
61
|
+
fflags = _cmd(**dest)[_cmd(**dest).index("-fflags") + 1]
|
|
62
|
+
assert "nobuffer" in fflags and "genpts" in fflags, fflags
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_the_args_sit_before_the_input():
|
|
66
|
+
"""Demuxer options after -i apply to the output and are silently ignored."""
|
|
67
|
+
cmd = _cmd(rtsp_push_url="rtsp://127.0.0.1:8554/cam")
|
|
68
|
+
i = cmd.index("-i")
|
|
69
|
+
for opt in ("-reorder_queue_size", "-max_delay", "-fflags"):
|
|
70
|
+
assert cmd.index(opt) < i, f"{opt} must precede -i to affect the input"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/__init__.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/__init__.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/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.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/events.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/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.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/rtp.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/sdp.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/stats.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/_vendor/aiortc/utils.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/__init__.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/constants.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/controls.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/lan_control.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/playback.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/protocol.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/sdes_open.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/aidot_cameras/camera/webrtc_open.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
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_answer_sdp_video_pt.py
RENAMED
|
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.15.7 → python_aidot_cameras-0.15.8}/tests/test_bridge_state_sentinels.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_constants_imports_resolve.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_deferred_hardening.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_device_login_guard.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_device_user_info_cache.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_dormant_camera_cleanup.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_dtls_mux_terminal_write.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_dtls_not_ready_burst.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_dtls_serve_decode_skip.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_dtls_serve_open_timeout.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_dtls_skip_signaling_wait.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_dtls_stdout_producer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_h264_decode_rate_limit.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_highport_nomination.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_ice_peer_reflexive.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_idle_release_both_loops.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_light_active_color_mode.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_live_validate_policy.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_media_socket_rcvbuf.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_mqtt_credential_refetch.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_mqtt_credential_self_heal.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_mqtt_session_reconnect.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_no_self_referential_go2rtc.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_no_undefined_names.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_offline_keepalive_pause.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_persistent_mqtt_robustness.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_post_merge_hardening.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_resolution_persists.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_scripts_importable.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_bridge_break_gate.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_echo_wait_timeout.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_fast_liveplay.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_ffmpeg_stderr_log.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_serve_stderr_drain.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_teardown_exit_log.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdes_terminal_ack_latency.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdp_narrowing_properties.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_sdp_payload_type_narrowing.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_security_hardening.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_serializable_login_info.py
RENAMED
|
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.15.7 → python_aidot_cameras-0.15.8}/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.15.7 → python_aidot_cameras-0.15.8}/tests/test_token_file_robustness.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_turn_create_permission.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_viewer_check_throttle.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_viewer_present_push_mode.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.15.7 → python_aidot_cameras-0.15.8}/tests/test_wake_readiness_retry.py
RENAMED
|
File without changes
|