python-aidot-cameras 1.0.0rc66__tar.gz → 1.0.0rc67__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-1.0.0rc66/python_aidot_cameras.egg-info → python_aidot_cameras-1.0.0rc67}/PKG-INFO +1 -1
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/recording.py +8 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/sd_playback.py +67 -3
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/webrtc_open.py +54 -12
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/pyproject.toml +1 -1
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67/python_aidot_cameras.egg-info}/PKG-INFO +1 -1
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sd_playback_dtls.py +101 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/LICENSE +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/MANIFEST.in +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/README.md +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/__init__.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/__main__.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_log_redaction.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_upstream.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/__init__.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/LICENSE +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/__init__.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/clock.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/codecs/__init__.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/codecs/base.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/codecs/g711.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/codecs/g722.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/codecs/h264.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/codecs/opus.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/codecs/vpx.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/contrib/__init__.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/contrib/media.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/contrib/signaling.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/events.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/exceptions.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/jitterbuffer.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/mediastreams.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/rate.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/rtcconfiguration.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/rtcdatachannel.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/rtcdtlstransport.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/rtcicetransport.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/rtcpeerconnection.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/rtcrtpparameters.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/rtcrtpreceiver.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/rtcrtpsender.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/rtcrtptransceiver.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/rtcsctptransport.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/rtcsessiondescription.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/rtp.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/sdp.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/stats.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/aiortc/utils.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/__init__.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/aac_track.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/agc.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/client.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/constants.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/controls.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/go2rtc.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/h264_sps.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/health.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/hls_ts.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/hwaccel.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/lan_control.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/models.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/protocol.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/rtp_h264.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/rtsp_publish.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/sd_events.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/sd_listing.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/sdes.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/sdes_open.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/ts_fanout.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/ts_tee.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/webrtc.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/client.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/cloud_auth.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/const.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/credentials.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/crypto.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/device_client.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/discover.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/exceptions.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/g711.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/lan_retry.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/py.typed +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/settings.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/python_aidot_cameras.egg-info/SOURCES.txt +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/python_aidot_cameras.egg-info/dependency_links.txt +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/python_aidot_cameras.egg-info/entry_points.txt +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/python_aidot_cameras.egg-info/requires.txt +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/python_aidot_cameras.egg-info/top_level.txt +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/setup.cfg +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_aac_track.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_abandoned_attempt_skips_the_doomed_serve.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_abandoned_wait_still_maps_audio.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_aioice_compat.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_alarm_event.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_answer_pt_kinds.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_answer_sdp_video_pt.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_answer_section_selection.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_arrival_timestamps.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_audio_mux_offline.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_auth_error_routing.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_auto_alarm.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_auto_light_settings.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_avio_ctrl_uses_the_session_dseq.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_avio_header_single_layout.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_avio_request.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_avio_response_parse.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_avio_response_router.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_backoff.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_battery_cap_spans_sessions.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_battery_detection.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_battery_evidence_corroboration.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_battery_stale_offer_is_abandoned_early.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_battery_wake_settles_before_the_command.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_ble_gateway_is_gone.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_bridge_state_sentinels.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_busy_backoff.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_camera_properties.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_canary_log_names_the_camera.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_close_mid_ice_leaves_nothing_pending.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_cloud_count.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_cloud_error_log_names_the_exception.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_cloud_error_severity.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_cloud_plan.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_constants_imports_resolve.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_control_verdicts.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_declared_properties.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_deferred_hardening.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_detection_types.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_device_cmd_seq_match.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_device_login_guard.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_device_user_info_cache.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_direct_publish_attaches_negotiated_audio.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_direct_ts_keyframe_signal.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_direct_ts_serve.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_direct_ts_serve_only_for_http.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_dormant_camera_cleanup.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_drain_is_cancellable.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_dtls_mux_terminal_write.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_dtls_not_ready_burst.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_dtls_open_abort_covers_every_exit.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_dtls_pinning.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_dtls_recorder_wiring.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_dtls_refusal_after_the_echo.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_dtls_resolution_ack.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_dtls_serve_decode_skip.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_dtls_serve_ice_wait.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_dtls_serve_open_timeout.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_dtls_skip_signaling_wait.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_dtls_slow_probe.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_dtls_stdout_producer.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_dtls_tap_states_no_reorder.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_dtls_ts_copy_recording.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_dtls_video_presence.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_egress_guard.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_env_seams.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_every_exception_is_exported.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_feature_probe_needs_a_live_session.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_ffmpeg_rx_sdp_single_template.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_ffmpeg_signal_exit_is_not_a_crash.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_first_media_abandon_rules.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_futile_keepalive.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_gate_requires_a_decoded_frame.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_go2rtc.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_go2rtc_cli.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_h264_decode_rate_limit.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_h264_sps.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_health_line.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_health_line_counts_pictures.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_highport_nomination.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_hls_ts_end_to_end.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_hls_ts_wiring.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_hwaccel_probe.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_ice_config_cache.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_ice_credentials_match_the_app.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_ice_peer_reflexive.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_idle_release_both_loops.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_ipc_envelope_single_builder.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_keepalive_renew.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_key_restart_sdp.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_keyframe_prompter.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_lan_control.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_lan_login_accessors.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_lan_retry_reaches_the_storming_devices.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_lan_retry_short_sessions.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_lan_retry_silences_upstream_over_ceiling.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_lan_retry_stops_on_close.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_lan_sweep_only_with_lights.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_late_repeats_are_dropped.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_light_active_color_mode.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_live_session_carries_talk.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_live_stream_param.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_live_validate_policy.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_live_validate_token_refresh.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_live_video_canary.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_liveplay_echo_timeout.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_local_only_controls.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_log_hygiene.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_logging_caps.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_login_connect_deadline.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_login_reconnect_backoff.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_loop_break_ends_the_loop.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_media_counted_only_when_plaintext.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_media_path_is_reported.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_media_socket_rcvbuf.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_media_wait_floor.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_motion_poll.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_mqtt_client_id_is_exact.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_mqtt_credential_refetch.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_mqtt_credential_self_heal.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_mqtt_password_not_persisted.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_mqtt_session_reconnect.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_mqtt_thread_not_orphaned.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_mypy_new_findings.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_nack.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_nack_cannot_add_load_in_a_burst.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_narrow_pc_ice.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_no_key_material_in_logs.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_no_private_notes_on_the_public_surface.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_no_self_referential_go2rtc.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_no_unbounded_hex_dumps.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_no_undefined_names.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_nominates_as_soon_as_the_answer_lands.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_off_subnet_candidate.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_offer_keeps_rtcp_feedback.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_offline_keepalive_pause.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_on_frame_is_an_av_frame.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_open_errors_are_aidot_errors.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_open_fail_logger.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_open_gate_delay.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_peer_id_client_type.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_peerid_reuse.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_persistent_mqtt.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_persistent_mqtt_robustness.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_phase_returns_reach_the_caller.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_phase_state_is_complete.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_plaintext_mqtt_refused.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_post_merge_hardening.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_ptz_probe_reads_what_it_is_told.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_public_signature_matches_impl.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_publish_target_readiness.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_quality_campaign_in_session.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_reboot_action.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_recent_recordings.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_region_allowlist.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_remb.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_remb_goes_out_the_relay_aware_sender.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_removed_keepalive_arguments_are_tolerated.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_resent_frames_are_dropped.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_resolution_persists.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_restart_cycle.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_retry_policy.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_review_lan_retry_and_graces.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_rtp_h264.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_rtsp_publish.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_rtsp_publish_go2rtc.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_scripts_importable.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sctp_init_ack_tsn.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sctp_reassembly.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sctp_sack.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sd_card_presence.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sd_event_decode.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sd_event_probe_payloads.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sd_listing.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sd_playback.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sd_playback_clock.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sd_playback_controls.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sd_playback_entry.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sd_playback_media_hold.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sd_playback_open.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_avio_dispatch.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_bridge_break_gate.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_connection_mode.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_echo_wait_is_not_dead_time.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_fast_liveplay.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_ffmpeg_stderr_log.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_first_media_stall_report.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_ice_teardown.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_idle_release.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_nack_bridge.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_offer_video_pin.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_open_cleanup.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_open_yields_the_loop.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_pinned_codec_retry.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_sctp_abort.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_serve_audio.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_serve_cmd.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_serve_stderr_drain.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_sprop.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_talk.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_teardown_exit_log.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_terminal_ack.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_terminal_ack_latency.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdes_watchdog.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdp_narrowing_properties.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sdp_payload_type_narrowing.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_security_hardening.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_self_peer_is_an_address_not_an_ip.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_serializable_login_info.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_serve_bound_survives_arrival_stamping.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_serve_input_timeout.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_serve_loop_releases_on_error.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_serve_loss_tolerance.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_serve_pt_respects_the_pin.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_serve_relay.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_serve_stderr_keeps_the_reason.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_session_mode_seq.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_session_stats.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_session_stop_twice.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_settings_registry.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_shared_house_seam.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_signalling_is_attributable_to_a_camera.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_skip_guard.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_snapshot_cancellation.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_speak.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sprop_capture_gate.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sprop_staleness.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sprop_unstable_public.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sprop_write_is_reported_truthfully.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_srtp_rx_rekey.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_srtp_tx_key_note.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_stable_terminal_id.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_stall_nudge_policy.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_stall_report_says_what_the_answer_carried.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_stall_report_says_whether_the_trigger_was_answered.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_stall_report_separates_silence_from_undecryptable.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_stall_report_survives_a_caller_giving_up.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_stall_reports_reach_the_artifact.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_status_and_trace_channels.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_stream_cap.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_stream_drain_ownership.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_stream_idle.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_stream_slot_cap.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_stream_teardown.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_stun_attr_single_builder.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_swallowed_exception_names.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_talk.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_talk_reports_a_speaker_that_never_opened.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_tap_to_mux_end_to_end.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_terminal_ack.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_tmmbr.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_token_file_robustness.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_token_refresh.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_transport_failure_reporting.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_ts_fanout.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_ts_tee.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_turn_create_permission.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_turn_target_shared.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_unbuildable_summary_repeats_at_debug.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_unreachable_nominee_is_abandoned_early.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_upstream_compat.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_upstream_seam_adapter.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_upstream_secrets_redacted.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_validator_shares_one_token.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_vendored_aiortc_integrity.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_video_presence_needs_a_keyframe.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_video_profile_log.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_video_pts_dts.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_video_ts_unwrap.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_viewer_check_throttle.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_viewer_presence.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_viewer_present_push_mode.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_wait_or_event.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_wake_gate_camera_evidence.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_wake_readiness_retry.py +0 -0
- {python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_webrtc_answer_race.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-aidot-cameras
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.0rc67
|
|
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-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/recording.py
RENAMED
|
@@ -68,6 +68,9 @@ class TsCopyRecorder:
|
|
|
68
68
|
self._thread: Optional[threading.Thread] = None
|
|
69
69
|
self._state: dict = {}
|
|
70
70
|
self._stopped = False
|
|
71
|
+
# Called first thing in stop(), for whoever still holds packets for
|
|
72
|
+
# this recording (the SD playback tap's reorder buffer).
|
|
73
|
+
self.on_stop: "list" = []
|
|
71
74
|
# Opened before the session connects, so an unwritable path fails
|
|
72
75
|
# while there is nothing to clean up: by the caller in an executor
|
|
73
76
|
# (``file``; an open() on an event loop blocks it), or here. Held open
|
|
@@ -96,6 +99,11 @@ class TsCopyRecorder:
|
|
|
96
99
|
if self._stopped:
|
|
97
100
|
return
|
|
98
101
|
self._stopped = True
|
|
102
|
+
for _cb in self.on_stop:
|
|
103
|
+
try:
|
|
104
|
+
_cb()
|
|
105
|
+
except Exception:
|
|
106
|
+
_LOGGER.debug("recording stop callback failed", exc_info=True)
|
|
99
107
|
if self._thread is None:
|
|
100
108
|
self._close()
|
|
101
109
|
return
|
|
@@ -597,6 +597,59 @@ def answer_h265_parameter_sets(sdp: str, pt: Optional[int]) -> "list[bytes]":
|
|
|
597
597
|
return out
|
|
598
598
|
|
|
599
599
|
|
|
600
|
+
class SeqReorder:
|
|
601
|
+
"""Puts one RTP stream back in sequence order, waiting a little for gaps.
|
|
602
|
+
|
|
603
|
+
A packet the camera resends after a NACK arrives after the ones that
|
|
604
|
+
followed it; the access-unit assembler takes packets in order, so they
|
|
605
|
+
are held here until the gap fills or ``max_wait_s`` passes, then handed
|
|
606
|
+
on in order (a gap given up on reaches the assembler as a gap, and its
|
|
607
|
+
unit is handed on damaged). ``push`` returns what is ready; ``flush``
|
|
608
|
+
returns the rest at the end.
|
|
609
|
+
"""
|
|
610
|
+
|
|
611
|
+
#: Most packets held; past this the oldest gap is given up at once.
|
|
612
|
+
MAX_HELD = 1500
|
|
613
|
+
|
|
614
|
+
def __init__(self, max_wait_s: float = 0.3) -> None:
|
|
615
|
+
self.max_wait_s = max_wait_s
|
|
616
|
+
self._next: "Optional[int]" = None
|
|
617
|
+
self._held: "dict[int, tuple[float, Any]]" = {}
|
|
618
|
+
self.late = 0 # arrived after its gap was given up
|
|
619
|
+
|
|
620
|
+
def push(self, seq: int, item: Any, now: float) -> "list":
|
|
621
|
+
if self._next is None:
|
|
622
|
+
self._next = seq
|
|
623
|
+
if (seq - self._next) & 0x8000: # before the next expected one
|
|
624
|
+
self.late += 1
|
|
625
|
+
return []
|
|
626
|
+
self._held.setdefault(seq, (now, item))
|
|
627
|
+
return self._release(now)
|
|
628
|
+
|
|
629
|
+
def _release(self, now: float) -> "list":
|
|
630
|
+
out = []
|
|
631
|
+
while True:
|
|
632
|
+
while self._next in self._held:
|
|
633
|
+
out.append(self._held.pop(self._next)[1])
|
|
634
|
+
self._next = (self._next + 1) & 0xFFFF
|
|
635
|
+
if not self._held:
|
|
636
|
+
return out
|
|
637
|
+
oldest = min(t for t, _ in self._held.values())
|
|
638
|
+
if now - oldest < self.max_wait_s and len(self._held) < self.MAX_HELD:
|
|
639
|
+
return out
|
|
640
|
+
# Give up on the gap: carry on from the earliest packet held.
|
|
641
|
+
self._next = min(self._held, key=lambda s: (s - self._next) & 0xFFFF)
|
|
642
|
+
|
|
643
|
+
def flush(self) -> "list":
|
|
644
|
+
out = []
|
|
645
|
+
while self._held:
|
|
646
|
+
if self._next not in self._held:
|
|
647
|
+
self._next = min(self._held, key=lambda s: (s - self._next) & 0xFFFF)
|
|
648
|
+
out.append(self._held.pop(self._next)[1])
|
|
649
|
+
self._next = (self._next + 1) & 0xFFFF
|
|
650
|
+
return out
|
|
651
|
+
|
|
652
|
+
|
|
600
653
|
class H265AccessUnits:
|
|
601
654
|
"""RTP payloads (RFC 7798) in, Annex B access units out.
|
|
602
655
|
|
|
@@ -627,6 +680,12 @@ class H265AccessUnits:
|
|
|
627
680
|
self._broken = False
|
|
628
681
|
self.dropped = 0
|
|
629
682
|
self.damaged = 0
|
|
683
|
+
# The camera sends a recording's last frame twice, under a new
|
|
684
|
+
# timestamp (A000088, 2026-10-30): a decoder then sees the same picture
|
|
685
|
+
# order count twice. A unit identical to the one before is not handed
|
|
686
|
+
# on (``repeats`` counts them).
|
|
687
|
+
self.repeats = 0
|
|
688
|
+
self._last_unit: "Optional[bytes]" = None
|
|
630
689
|
|
|
631
690
|
def _emit(self) -> "list[tuple[bytes, int, bool]]":
|
|
632
691
|
out = []
|
|
@@ -641,9 +700,14 @@ class H265AccessUnits:
|
|
|
641
700
|
nals = self._nals
|
|
642
701
|
if kf and 32 not in types and self.parameter_sets:
|
|
643
702
|
nals = self.parameter_sets + nals
|
|
644
|
-
|
|
645
|
-
if self.
|
|
646
|
-
self.
|
|
703
|
+
unit = b"".join(_NAL_SC + n for n in nals)
|
|
704
|
+
if unit == self._last_unit:
|
|
705
|
+
self.repeats += 1
|
|
706
|
+
else:
|
|
707
|
+
out.append((unit, self._ts, kf))
|
|
708
|
+
self._last_unit = unit
|
|
709
|
+
if self._broken:
|
|
710
|
+
self.damaged += 1
|
|
647
711
|
elif self._nals or self._broken:
|
|
648
712
|
self.dropped += 1
|
|
649
713
|
self._nals, self._fu, self._broken = [], None, False
|
|
@@ -295,7 +295,8 @@ def _install_sd_h265_tap(pc, h265, status) -> int:
|
|
|
295
295
|
PCMU by number, but its answer's audio was PCMA alone, so nothing else
|
|
296
296
|
claims it. Returns the routers tapped.
|
|
297
297
|
"""
|
|
298
|
-
from .
|
|
298
|
+
from .._vendor.aiortc.rtcrtpreceiver import NackGenerator
|
|
299
|
+
from .sd_playback import SeqReorder, starts_h265_stream
|
|
299
300
|
|
|
300
301
|
if h265 is None:
|
|
301
302
|
return 0
|
|
@@ -308,17 +309,21 @@ def _install_sd_h265_tap(pc, h265, status) -> int:
|
|
|
308
309
|
routers.append(router)
|
|
309
310
|
|
|
310
311
|
def _make(router):
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
312
|
+
# A video receiver on this transport sends the NACKs: aiortc only
|
|
313
|
+
# asks for resends on streams it routes, and this one it does not.
|
|
314
|
+
rx = None
|
|
315
|
+
for t in pc.getTransceivers():
|
|
316
|
+
r = t.receiver
|
|
317
|
+
if getattr(getattr(r, "transport", None), "_rtp_router", None) is router:
|
|
318
|
+
if rx is None or getattr(t, "kind", None) == "video":
|
|
319
|
+
rx = r
|
|
320
|
+
reorder = SeqReorder()
|
|
321
|
+
nack_gen = NackGenerator()
|
|
322
|
+
# The loop holds tasks weakly: a NACK not referenced here can be
|
|
323
|
+
# collected before it is sent.
|
|
324
|
+
nack_tasks: "set" = set()
|
|
325
|
+
|
|
326
|
+
def _feed(packet) -> None:
|
|
322
327
|
units = h265["units"]
|
|
323
328
|
lost_before = units.dropped
|
|
324
329
|
damaged_before = units.damaged
|
|
@@ -342,6 +347,43 @@ def _install_sd_h265_tap(pc, h265, status) -> int:
|
|
|
342
347
|
" damaged (the decoder conceals it)"
|
|
343
348
|
)
|
|
344
349
|
|
|
350
|
+
def _flush() -> None:
|
|
351
|
+
for held in reorder.flush():
|
|
352
|
+
_feed(held)
|
|
353
|
+
|
|
354
|
+
on_stop = getattr(h265["recorder"], "on_stop", None)
|
|
355
|
+
if on_stop is not None:
|
|
356
|
+
on_stop.append(_flush)
|
|
357
|
+
|
|
358
|
+
def _tap(packet) -> None:
|
|
359
|
+
pt = h265["pt"]
|
|
360
|
+
if pt is None:
|
|
361
|
+
if packet.payload_type in router.payload_type_table or not (
|
|
362
|
+
starts_h265_stream(packet.payload)
|
|
363
|
+
):
|
|
364
|
+
return
|
|
365
|
+
h265["pt"] = pt = packet.payload_type
|
|
366
|
+
status(f"SD playback: taking pt={pt} as the recording's H265")
|
|
367
|
+
if packet.payload_type != pt:
|
|
368
|
+
return
|
|
369
|
+
# Ask for what never arrived; the resend is put back in place
|
|
370
|
+
# by the reorder buffer before the assembler sees it.
|
|
371
|
+
if nack_gen.add(packet) and rx is not None and nack_gen.missing:
|
|
372
|
+
h265["nacks"] = h265.get("nacks", 0) + 1
|
|
373
|
+
if h265["nacks"] == 1:
|
|
374
|
+
status("SD playback: asking the camera to resend lost H265 (NACK)")
|
|
375
|
+
try:
|
|
376
|
+
task = asyncio.get_running_loop().create_task(
|
|
377
|
+
rx._send_rtcp_nack(packet.ssrc, sorted(nack_gen.missing))
|
|
378
|
+
)
|
|
379
|
+
except RuntimeError:
|
|
380
|
+
pass # no loop: nothing to send on
|
|
381
|
+
else:
|
|
382
|
+
nack_tasks.add(task)
|
|
383
|
+
task.add_done_callback(nack_tasks.discard)
|
|
384
|
+
for ready in reorder.push(packet.sequence_number, packet, time.monotonic()):
|
|
385
|
+
_feed(ready)
|
|
386
|
+
|
|
345
387
|
return _tap
|
|
346
388
|
|
|
347
389
|
for router in routers:
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-aidot-cameras"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.0rc67"
|
|
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"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-aidot-cameras
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.0rc67
|
|
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-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_sd_playback_dtls.py
RENAMED
|
@@ -474,3 +474,104 @@ def test_by_default_a_damaged_unit_is_handed_on_and_counted():
|
|
|
474
474
|
assert units.damaged == 1 and units.dropped == 0
|
|
475
475
|
assert got[0][2] is True # still marked a keyframe
|
|
476
476
|
assert got[1:] and [_nals(d) for d, _, _ in got[1:]] == [_nals(a) for a in aus[1:]]
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
def test_a_unit_sent_twice_is_handed_on_once():
|
|
480
|
+
# The A000088 sent a recording's last frame twice under a new timestamp
|
|
481
|
+
# (2026-10-30); the decoder then reported a duplicate picture order count.
|
|
482
|
+
aus = _hevc_access_units(3)
|
|
483
|
+
units = H265AccessUnits()
|
|
484
|
+
got, seq = [], 10
|
|
485
|
+
for i, au in enumerate([*aus, aus[-1]]):
|
|
486
|
+
pkts = _packetize(au, i * 6000, seq)
|
|
487
|
+
seq += len(pkts)
|
|
488
|
+
for p in pkts:
|
|
489
|
+
got += units.feed(*p)
|
|
490
|
+
assert [ts for _, ts, _ in got] == [0, 6000, 12000]
|
|
491
|
+
assert units.repeats == 1
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
def test_a_resent_packet_is_put_back_in_place():
|
|
495
|
+
from aidot_cameras.camera.sd_playback import SeqReorder
|
|
496
|
+
|
|
497
|
+
r = SeqReorder(max_wait_s=0.3)
|
|
498
|
+
assert r.push(10, "a", 0.0) == ["a"]
|
|
499
|
+
assert r.push(12, "c", 0.01) == [] # 11 missing: hold 12
|
|
500
|
+
assert r.push(13, "d", 0.02) == []
|
|
501
|
+
assert r.push(11, "b", 0.1) == ["b", "c", "d"] # the resend fills it
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
def test_a_gap_that_never_fills_is_given_up_in_time():
|
|
505
|
+
from aidot_cameras.camera.sd_playback import SeqReorder
|
|
506
|
+
|
|
507
|
+
r = SeqReorder(max_wait_s=0.3)
|
|
508
|
+
r.push(65534, "a", 0.0)
|
|
509
|
+
assert r.push(1, "d", 0.01) == [] # 65535 and 0 missing, across the wrap
|
|
510
|
+
assert r.push(2, "e", 0.35) == ["d", "e"] # past the wait: carry on
|
|
511
|
+
assert r.push(0, "late", 0.4) == [] and r.late == 1
|
|
512
|
+
r.push(5, "h", 0.5)
|
|
513
|
+
assert r.flush() == ["h"]
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
def test_the_tap_asks_for_a_lost_packet_and_puts_the_resend_in_place():
|
|
517
|
+
# The A000088 resends what a NACK names (2026-10-30: three plays, no
|
|
518
|
+
# frame damaged or dropped, 0 decode errors, against 147 error lines
|
|
519
|
+
# from one dropped frame before). aiortc does not NACK this stream, as it
|
|
520
|
+
# does not route it; the tap asks, and holds packets until the resend.
|
|
521
|
+
import asyncio
|
|
522
|
+
|
|
523
|
+
from aidot_cameras.camera.webrtc_open import _install_sd_h265_tap
|
|
524
|
+
|
|
525
|
+
sent = []
|
|
526
|
+
|
|
527
|
+
class _Rx:
|
|
528
|
+
def __init__(self, router):
|
|
529
|
+
self.transport = type("T", (), {"_rtp_router": router})()
|
|
530
|
+
|
|
531
|
+
async def _send_rtcp_nack(self, ssrc, lost):
|
|
532
|
+
sent.append((ssrc, list(lost)))
|
|
533
|
+
|
|
534
|
+
class _PcNack:
|
|
535
|
+
def __init__(self, router):
|
|
536
|
+
self._t = [type("Tr", (), {"receiver": _Rx(router), "kind": "video"})()]
|
|
537
|
+
|
|
538
|
+
def getTransceivers(self):
|
|
539
|
+
return self._t
|
|
540
|
+
|
|
541
|
+
def _p(seq, ts, marker, payload):
|
|
542
|
+
p = _pkt(98, seq, ts, marker, payload)
|
|
543
|
+
p.ssrc = 0x1234
|
|
544
|
+
return p
|
|
545
|
+
|
|
546
|
+
rec = type("Rec", (), {"vq": queue.Queue(), "on_stop": []})()
|
|
547
|
+
state = {"pt": 98, "units": H265AccessUnits(), "recorder": rec, "dropped": 0}
|
|
548
|
+
router = _Router()
|
|
549
|
+
|
|
550
|
+
# One IDR in three fragments, and the next unit.
|
|
551
|
+
idr = bytes([19 << 1, 1]) + bytes(range(60))
|
|
552
|
+
fu_ind = bytes([(idr[0] & 0x81) | (49 << 1), idr[1]])
|
|
553
|
+
body = idr[2:]
|
|
554
|
+
frags = [
|
|
555
|
+
fu_ind + bytes([19 | 0x80]) + body[:20],
|
|
556
|
+
fu_ind + bytes([19]) + body[20:40],
|
|
557
|
+
fu_ind + bytes([19 | 0x40]) + body[40:],
|
|
558
|
+
]
|
|
559
|
+
trail = bytes([1 << 1, 1, 0xBB])
|
|
560
|
+
|
|
561
|
+
async def main():
|
|
562
|
+
assert _install_sd_h265_tap(_PcNack(router), state, lambda m: None) == 1
|
|
563
|
+
router.raw_tap(_p(100, 3000, False, frags[0]))
|
|
564
|
+
router.raw_tap(_p(102, 3000, True, frags[2])) # 101 lost
|
|
565
|
+
router.raw_tap(_p(103, 9000, True, trail))
|
|
566
|
+
await asyncio.sleep(0)
|
|
567
|
+
assert sent == [(0x1234, [101])]
|
|
568
|
+
assert rec.vq.empty() # held for the resend
|
|
569
|
+
router.raw_tap(_p(101, 3000, False, frags[1])) # the resend
|
|
570
|
+
await asyncio.sleep(0)
|
|
571
|
+
|
|
572
|
+
asyncio.run(main())
|
|
573
|
+
first = rec.vq.get_nowait()
|
|
574
|
+
assert first == (b"\x00\x00\x00\x01" + idr, 3000, True, "hevc")
|
|
575
|
+
assert state["units"].damaged == 0 and state["units"].dropped == 0
|
|
576
|
+
assert rec.vq.get_nowait()[1] == 9000
|
|
577
|
+
assert rec.on_stop # the tap flushes what it holds when the recording stops
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_log_redaction.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_upstream.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/_vendor/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/__init__.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/aac_track.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/agc.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/client.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/constants.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/controls.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/go2rtc.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/h264_sps.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/health.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/hls_ts.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/hwaccel.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/models.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/protocol.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/rtp_h264.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/sd_events.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/sd_listing.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/sdes.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/sdes_open.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/ts_fanout.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/ts_tee.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/camera/webrtc.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/cloud_auth.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/credentials.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/device_client.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/exceptions.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/aidot_cameras/lan_retry.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-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_aioice_compat.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_answer_pt_kinds.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_answer_sdp_video_pt.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_arrival_timestamps.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_audio_mux_offline.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_auth_error_routing.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_auto_light_settings.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_avio_request.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_avio_response_parse.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_avio_response_router.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_battery_detection.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_ble_gateway_is_gone.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_busy_backoff.py
RENAMED
|
File without changes
|
{python_aidot_cameras-1.0.0rc66 → python_aidot_cameras-1.0.0rc67}/tests/test_camera_properties.py
RENAMED
|
File without changes
|