python-aidot-cameras 0.17.3b2__tar.gz → 1.0.0b3__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.
Files changed (216) hide show
  1. {python_aidot_cameras-0.17.3b2/python_aidot_cameras.egg-info → python_aidot_cameras-1.0.0b3}/PKG-INFO +3 -1
  2. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/README.md +2 -0
  3. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/camera/client.py +29 -4
  4. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/camera/protocol.py +12 -4
  5. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/camera/sdes.py +28 -8
  6. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/camera/sdes_open.py +432 -25
  7. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/pyproject.toml +1 -1
  8. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3/python_aidot_cameras.egg-info}/PKG-INFO +3 -1
  9. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/python_aidot_cameras.egg-info/SOURCES.txt +11 -0
  10. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_control_verdicts.py +12 -2
  11. python_aidot_cameras-1.0.0b3/tests/test_dtls_resolution_ack.py +238 -0
  12. python_aidot_cameras-1.0.0b3/tests/test_feature_probe_needs_a_live_session.py +132 -0
  13. python_aidot_cameras-1.0.0b3/tests/test_gate_requires_a_decoded_frame.py +101 -0
  14. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_ice_peer_reflexive.py +7 -3
  15. python_aidot_cameras-1.0.0b3/tests/test_live_session_carries_talk.py +113 -0
  16. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_live_validate_policy.py +182 -0
  17. python_aidot_cameras-1.0.0b3/tests/test_no_key_material_in_logs.py +269 -0
  18. python_aidot_cameras-1.0.0b3/tests/test_ptz_probe_reads_what_it_is_told.py +88 -0
  19. python_aidot_cameras-1.0.0b3/tests/test_sdes_first_media_stall_report.py +344 -0
  20. python_aidot_cameras-1.0.0b3/tests/test_sdes_offer_video_order.py +263 -0
  21. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sdes_talk.py +16 -0
  22. python_aidot_cameras-1.0.0b3/tests/test_self_peer_is_an_address_not_an_ip.py +101 -0
  23. python_aidot_cameras-1.0.0b3/tests/test_sprop_write_is_reported_truthfully.py +102 -0
  24. python_aidot_cameras-1.0.0b3/tests/test_talk_reports_a_speaker_that_never_opened.py +170 -0
  25. python_aidot_cameras-1.0.0b3/tests/test_tutk_path_is_out_of_reach.py +78 -0
  26. python_aidot_cameras-0.17.3b2/tests/test_no_key_material_in_logs.py +0 -140
  27. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/LICENSE +0 -0
  28. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/MANIFEST.in +0 -0
  29. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/__init__.py +0 -0
  30. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/__main__.py +0 -0
  31. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_upstream.py +0 -0
  32. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/__init__.py +0 -0
  33. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/__init__.py +0 -0
  34. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/clock.py +0 -0
  35. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/codecs/__init__.py +0 -0
  36. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/codecs/base.py +0 -0
  37. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/codecs/g711.py +0 -0
  38. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/codecs/g722.py +0 -0
  39. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/codecs/h264.py +0 -0
  40. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/codecs/opus.py +0 -0
  41. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/codecs/vpx.py +0 -0
  42. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/contrib/__init__.py +0 -0
  43. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/contrib/media.py +0 -0
  44. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/contrib/signaling.py +0 -0
  45. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/events.py +0 -0
  46. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/exceptions.py +0 -0
  47. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/jitterbuffer.py +0 -0
  48. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/mediastreams.py +0 -0
  49. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/rate.py +0 -0
  50. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/rtcconfiguration.py +0 -0
  51. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/rtcdatachannel.py +0 -0
  52. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/rtcdtlstransport.py +0 -0
  53. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/rtcicetransport.py +0 -0
  54. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/rtcpeerconnection.py +0 -0
  55. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/rtcrtpparameters.py +0 -0
  56. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/rtcrtpreceiver.py +0 -0
  57. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/rtcrtpsender.py +0 -0
  58. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/rtcrtptransceiver.py +0 -0
  59. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/rtcsctptransport.py +0 -0
  60. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/rtcsessiondescription.py +0 -0
  61. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/rtp.py +0 -0
  62. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/sdp.py +0 -0
  63. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/stats.py +0 -0
  64. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/_vendor/aiortc/utils.py +0 -0
  65. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/ble_gateway.py +0 -0
  66. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/camera/__init__.py +0 -0
  67. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/camera/constants.py +0 -0
  68. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/camera/controls.py +0 -0
  69. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/camera/go2rtc.py +0 -0
  70. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/camera/hwaccel.py +0 -0
  71. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/camera/lan_control.py +0 -0
  72. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/camera/models.py +0 -0
  73. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/camera/playback.py +0 -0
  74. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/camera/tutk.py +0 -0
  75. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/camera/webrtc.py +0 -0
  76. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/camera/webrtc_open.py +0 -0
  77. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/client.py +0 -0
  78. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/const.py +0 -0
  79. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/credentials.py +0 -0
  80. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/crypto.py +0 -0
  81. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/device_client.py +0 -0
  82. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/discover.py +0 -0
  83. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/exceptions.py +0 -0
  84. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/g711.py +0 -0
  85. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/lan_retry.py +0 -0
  86. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/aidot_cameras/py.typed +0 -0
  87. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/python_aidot_cameras.egg-info/dependency_links.txt +0 -0
  88. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/python_aidot_cameras.egg-info/entry_points.txt +0 -0
  89. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/python_aidot_cameras.egg-info/requires.txt +0 -0
  90. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/python_aidot_cameras.egg-info/top_level.txt +0 -0
  91. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/setup.cfg +0 -0
  92. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_aioice_compat.py +0 -0
  93. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_alarm_event.py +0 -0
  94. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_answer_sdp_video_pt.py +0 -0
  95. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_audio_mux_offline.py +0 -0
  96. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_avio_request.py +0 -0
  97. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_avio_response_parse.py +0 -0
  98. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_avio_response_router.py +0 -0
  99. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_backoff.py +0 -0
  100. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_battery_detection.py +0 -0
  101. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_battery_evidence_corroboration.py +0 -0
  102. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_battery_skip_turn.py +0 -0
  103. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_ble_gateway.py +0 -0
  104. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_bridge_state_sentinels.py +0 -0
  105. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_busy_backoff.py +0 -0
  106. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_constants_imports_resolve.py +0 -0
  107. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_deferred_hardening.py +0 -0
  108. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_device_cmd_seq_match.py +0 -0
  109. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_device_login_guard.py +0 -0
  110. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_device_user_info_cache.py +0 -0
  111. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_dormant_camera_cleanup.py +0 -0
  112. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_dtls_mux_terminal_write.py +0 -0
  113. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_dtls_not_ready_burst.py +0 -0
  114. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_dtls_pinning.py +0 -0
  115. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_dtls_serve_decode_skip.py +0 -0
  116. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_dtls_serve_open_timeout.py +0 -0
  117. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_dtls_skip_signaling_wait.py +0 -0
  118. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_dtls_slow_probe.py +0 -0
  119. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_dtls_stdout_producer.py +0 -0
  120. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_egress_guard.py +0 -0
  121. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_env_seams.py +0 -0
  122. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_futile_keepalive.py +0 -0
  123. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_go2rtc.py +0 -0
  124. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_go2rtc_cli.py +0 -0
  125. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_h264_decode_rate_limit.py +0 -0
  126. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_highport_nomination.py +0 -0
  127. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_hwaccel_probe.py +0 -0
  128. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_ice_config_cache.py +0 -0
  129. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_idle_release_both_loops.py +0 -0
  130. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_keepalive_renew.py +0 -0
  131. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_key_restart_sdp.py +0 -0
  132. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_keyframe_prompter.py +0 -0
  133. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_lan_control.py +0 -0
  134. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_lan_retry_reaches_the_storming_devices.py +0 -0
  135. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_light_active_color_mode.py +0 -0
  136. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_live_stream_param.py +0 -0
  137. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_logging_caps.py +0 -0
  138. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_login_connect_deadline.py +0 -0
  139. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_login_reconnect_backoff.py +0 -0
  140. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_media_counted_only_when_plaintext.py +0 -0
  141. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_media_socket_rcvbuf.py +0 -0
  142. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_media_wait_floor.py +0 -0
  143. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_motion_poll.py +0 -0
  144. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_mqtt_credential_refetch.py +0 -0
  145. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_mqtt_credential_self_heal.py +0 -0
  146. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_mqtt_password_not_persisted.py +0 -0
  147. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_mqtt_session_reconnect.py +0 -0
  148. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_narrow_pc_ice.py +0 -0
  149. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_no_self_referential_go2rtc.py +0 -0
  150. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_no_undefined_names.py +0 -0
  151. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_offer_keeps_rtcp_feedback.py +0 -0
  152. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_offline_keepalive_pause.py +0 -0
  153. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_open_fail_logger.py +0 -0
  154. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_open_gate_delay.py +0 -0
  155. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_peerid_reuse.py +0 -0
  156. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_persistent_mqtt.py +0 -0
  157. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_persistent_mqtt_robustness.py +0 -0
  158. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_playback_tls.py +0 -0
  159. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_post_merge_hardening.py +0 -0
  160. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_remb.py +0 -0
  161. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_resolution_persists.py +0 -0
  162. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_restart_cycle.py +0 -0
  163. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_retry_policy.py +0 -0
  164. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_scripts_importable.py +0 -0
  165. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sctp_init_ack_tsn.py +0 -0
  166. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sdes_adaptive.py +0 -0
  167. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sdes_avio_dispatch.py +0 -0
  168. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sdes_bridge_break_gate.py +0 -0
  169. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sdes_echo_wait_timeout.py +0 -0
  170. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sdes_fast_liveplay.py +0 -0
  171. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sdes_ffmpeg_stderr_log.py +0 -0
  172. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sdes_idle_release.py +0 -0
  173. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sdes_offer_video_pin.py +0 -0
  174. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sdes_open_cleanup.py +0 -0
  175. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sdes_sctp_abort.py +0 -0
  176. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sdes_serve_audio.py +0 -0
  177. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sdes_serve_cmd.py +0 -0
  178. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sdes_serve_stderr_drain.py +0 -0
  179. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sdes_sprop.py +0 -0
  180. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sdes_teardown_exit_log.py +0 -0
  181. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sdes_terminal_ack.py +0 -0
  182. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sdes_terminal_ack_latency.py +0 -0
  183. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sdes_watchdog.py +0 -0
  184. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sdp_narrowing_properties.py +0 -0
  185. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sdp_payload_type_narrowing.py +0 -0
  186. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_security_hardening.py +0 -0
  187. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_serializable_login_info.py +0 -0
  188. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_serve_loss_tolerance.py +0 -0
  189. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_serve_relay.py +0 -0
  190. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_session_stats.py +0 -0
  191. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_shared_house_seam.py +0 -0
  192. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_snapshot_cancellation.py +0 -0
  193. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_speak.py +0 -0
  194. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sprop_capture_gate.py +0 -0
  195. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_sprop_staleness.py +0 -0
  196. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_srtp_rx_rekey.py +0 -0
  197. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_srtp_tx_key_note.py +0 -0
  198. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_stream_cap.py +0 -0
  199. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_stream_drain_ownership.py +0 -0
  200. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_stream_idle.py +0 -0
  201. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_stream_slot_cap.py +0 -0
  202. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_stream_teardown.py +0 -0
  203. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_talk.py +0 -0
  204. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_terminal_ack.py +0 -0
  205. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_token_file_robustness.py +0 -0
  206. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_token_refresh.py +0 -0
  207. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_turn_create_permission.py +0 -0
  208. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_upstream_compat.py +0 -0
  209. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_video_profile_log.py +0 -0
  210. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_viewer_check_throttle.py +0 -0
  211. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_viewer_presence.py +0 -0
  212. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_viewer_present_push_mode.py +0 -0
  213. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_wait_or_event.py +0 -0
  214. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_wake_gate_camera_evidence.py +0 -0
  215. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/tests/test_wake_readiness_retry.py +0 -0
  216. {python_aidot_cameras-0.17.3b2 → python_aidot_cameras-1.0.0b3}/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: 0.17.3b2
3
+ Version: 1.0.0b3
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
@@ -209,6 +209,8 @@ audio, idle release, the sprop cache path) are documented in
209
209
  | `AIDOT_SDES_SKIP_TURN_PREALLOC` | Skip the SDES TURN relay pre-allocation (~2-3 s of cold-start latency) so signaling goes straight out with the host candidate. Faster on a LAN, at the cost of no relay fallback for a camera on a different segment / behind strict NAT. Experimental, opt-in (truthy = `1`/`true`/`yes`/`on`). | unset (off) |
210
210
  | `AIDOT_SDES_ADAPTIVE` | Adaptive fast-with-fallback for the SDES keepalive loop: try the fast path first and fall back to the full relay path if a fast attempt delivers no media. A per-device cache skips the fast attempt on later views once it has failed. Truthy value enables. Ignored for battery cameras, where the fast path cannot win and its short grace truncates the cold start. | unset (off) |
211
211
  | `AIDOT_SDES_FAST_LIVEPLAY` | Don't block on the `livePlayResp` wait for eligible SDES cameras (~4.5 s faster cold start). Role-reversal models (A001064 PTZ) always excluded for correctness. **On by default**; set to `0`/`false`/`no`/`off` to disable. | enabled (on) |
212
+ | `AIDOT_SDES_VIDEO_PT` | Pin the SDES offer to ONE video codec by payload type, so the camera cannot choose. The offer advertises 96 (H264) and 97 (H265) and the camera decides which to send; on an A001064 that means the same request comes back h264 1280x720 most sessions and hevc 2560x1440 occasionally, at a third of the bitrate. Set to `96` for H264 only (measured h264 720p in 4 of 4 sessions). **Do not set it to `97`** - an H265-only offer returned no video at all in 3 of 3 rounds; narrowing to H265 removes the option rather than selecting it. | unset (both offered) |
213
+ | `AIDOT_SDES_VIDEO_PT_ORDER` | Reorder the SDES offer's video codec list without narrowing it, as a comma-separated preference list (`97,96`). RFC 3264 makes the `m=video` payload-type list a preference list, most-preferred first, and ours has always read `96 97` - not by decision, it has simply never been varied. Whatever is named leads and the rest is appended, so this can express a preference and can never produce a narrowed or empty video m-line. **Experimental and untested on hardware:** whether the camera acts on the order is the open question, so the default is deliberately unchanged. | unset (`96 97`) |
212
214
  | `AIDOT_DTLS_FAST_LIVEPLAY` | The DTLS (A000088) analogue: skip the `livePlayReq`-echo and `livePlayResp` waits (the dominant LAN cold-start cost) while keeping the full ICE/TURN/DTLS handshake, so remote/relay viewing is unaffected. **On by default**; set to `0`/`false`/`no`/`off` to disable. | enabled (on) |
213
215
  | `AIDOT_PERSISTENT_MQTT` | Reuse ONE account-level persistent MQTT connection for commands, attribute fetches, and stream-open signaling (matching the official app) instead of connecting per operation. **On by default** (live soaks cut SDES NO_MEDIA from ~57% to ~11-19%); set to `0`/`false`/`no`/`off` to disable. | enabled (on) |
214
216
  | `AIDOT_SERVE_RELAY` | Hold the public stream port via an internal relay that proxies to ffmpeg, so the first (cold) view connects instead of failing while ffmpeg can't pre-bind the port. Set to `0` to serve ffmpeg directly. | `1` (enabled) |
@@ -178,6 +178,8 @@ audio, idle release, the sprop cache path) are documented in
178
178
  | `AIDOT_SDES_SKIP_TURN_PREALLOC` | Skip the SDES TURN relay pre-allocation (~2-3 s of cold-start latency) so signaling goes straight out with the host candidate. Faster on a LAN, at the cost of no relay fallback for a camera on a different segment / behind strict NAT. Experimental, opt-in (truthy = `1`/`true`/`yes`/`on`). | unset (off) |
179
179
  | `AIDOT_SDES_ADAPTIVE` | Adaptive fast-with-fallback for the SDES keepalive loop: try the fast path first and fall back to the full relay path if a fast attempt delivers no media. A per-device cache skips the fast attempt on later views once it has failed. Truthy value enables. Ignored for battery cameras, where the fast path cannot win and its short grace truncates the cold start. | unset (off) |
180
180
  | `AIDOT_SDES_FAST_LIVEPLAY` | Don't block on the `livePlayResp` wait for eligible SDES cameras (~4.5 s faster cold start). Role-reversal models (A001064 PTZ) always excluded for correctness. **On by default**; set to `0`/`false`/`no`/`off` to disable. | enabled (on) |
181
+ | `AIDOT_SDES_VIDEO_PT` | Pin the SDES offer to ONE video codec by payload type, so the camera cannot choose. The offer advertises 96 (H264) and 97 (H265) and the camera decides which to send; on an A001064 that means the same request comes back h264 1280x720 most sessions and hevc 2560x1440 occasionally, at a third of the bitrate. Set to `96` for H264 only (measured h264 720p in 4 of 4 sessions). **Do not set it to `97`** - an H265-only offer returned no video at all in 3 of 3 rounds; narrowing to H265 removes the option rather than selecting it. | unset (both offered) |
182
+ | `AIDOT_SDES_VIDEO_PT_ORDER` | Reorder the SDES offer's video codec list without narrowing it, as a comma-separated preference list (`97,96`). RFC 3264 makes the `m=video` payload-type list a preference list, most-preferred first, and ours has always read `96 97` - not by decision, it has simply never been varied. Whatever is named leads and the rest is appended, so this can express a preference and can never produce a narrowed or empty video m-line. **Experimental and untested on hardware:** whether the camera acts on the order is the open question, so the default is deliberately unchanged. | unset (`96 97`) |
181
183
  | `AIDOT_DTLS_FAST_LIVEPLAY` | The DTLS (A000088) analogue: skip the `livePlayReq`-echo and `livePlayResp` waits (the dominant LAN cold-start cost) while keeping the full ICE/TURN/DTLS handshake, so remote/relay viewing is unaffected. **On by default**; set to `0`/`false`/`no`/`off` to disable. | enabled (on) |
182
184
  | `AIDOT_PERSISTENT_MQTT` | Reuse ONE account-level persistent MQTT connection for commands, attribute fetches, and stream-open signaling (matching the official app) instead of connecting per operation. **On by default** (live soaks cut SDES NO_MEDIA from ~57% to ~11-19%); set to `0`/`false`/`no`/`off` to disable. | enabled (on) |
183
185
  | `AIDOT_SERVE_RELAY` | Hold the public stream port via an internal relay that proxies to ffmpeg, so the first (cold) view connects instead of failing while ffmpeg can't pre-bind the port. Set to `0` to serve ffmpeg directly. | `1` (enabled) |
@@ -1823,13 +1823,22 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
1823
1823
  self.device_id, len(data))
1824
1824
  elif isinstance(body, dict):
1825
1825
  data = body.get("data") or {}
1826
+ # Keys, never values: this response can carry the per-device
1827
+ # streaming credentials (tutkAccount / tutkPassword - see
1828
+ # docs/DEFERRED_FEATURES.md), and the warning below is logged
1829
+ # at default level, so a whole-body dump lands in every user's
1830
+ # home-assistant.log. The matched-device log further down
1831
+ # already prints keys only; these two did not.
1826
1832
  if data:
1827
- _LOGGER.debug("batchGetDeviceUserInfo response for %s (status=%d): %s",
1828
- self.device_id, status, body)
1833
+ _LOGGER.debug(
1834
+ "batchGetDeviceUserInfo response for %s (status=%d):"
1835
+ " keys=%s, %d item(s)",
1836
+ self.device_id, status, sorted(body.keys()), len(data),
1837
+ )
1829
1838
  else:
1830
1839
  _LOGGER.warning(
1831
- "batchGetDeviceUserInfo no data for %s (status=%d): %s",
1832
- self.device_id, status, body,
1840
+ "batchGetDeviceUserInfo no data for %s (status=%d): keys=%s",
1841
+ self.device_id, status, sorted(body.keys()),
1833
1842
  )
1834
1843
  else:
1835
1844
  data = {}
@@ -3468,6 +3477,22 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
3468
3477
  rtsp_push_url=self._keepalive_rtsp_url,
3469
3478
  timeout=(_FAST_OPEN_TIMEOUT if _use_fast else 120.0),
3470
3479
  reuse_peer_id=_loop_peer_id,
3480
+ # Ask for talk so THIS session can carry it. async_speak
3481
+ # reuses _stream_session only when it is talk-capable, and
3482
+ # an SDES session that did not ask never gets a return audio
3483
+ # track - so without this every press-to-talk opened a
3484
+ # second camera session alongside the live view, and the
3485
+ # camera holds a viewer slot for about 120 s after one ends.
3486
+ #
3487
+ # This changes the SDP offer on the path every SDES live
3488
+ # view takes, which is the kind of change that has caused
3489
+ # fleet-wide blackouts here, so it rests on evidence rather
3490
+ # than reasoning: the release harness has opened all seven
3491
+ # cameras talk-capable across three fleet runs with no
3492
+ # streaming regression. The flag reaches only the offer
3493
+ # (audio sendrecv + a=ssrc) and the shared talk state; it
3494
+ # does not touch the rtsp_push branch this loop uses.
3495
+ talk=True,
3471
3496
  )
3472
3497
  except asyncio.CancelledError:
3473
3498
  self._fast_attempt_override = None
@@ -662,8 +662,14 @@ def _load_sprop(devid: str) -> "Optional[str]":
662
662
  return None
663
663
 
664
664
 
665
- def _save_sprop(devid: str, sprop: str) -> None:
666
- """Persist the ``sprop-parameter-sets`` string for ``devid`` (best-effort).
665
+ def _save_sprop(devid: str, sprop: str) -> bool:
666
+ """Persist the ``sprop-parameter-sets`` for ``devid``. True if it wrote.
667
+
668
+ Returns whether anything was actually cached, because two of the three
669
+ outcomes here write nothing and the caller announces the write in the only
670
+ log line this feature has. An unconditional announcement claims a cache
671
+ that an unstable camera provably does not have, which is the observable an
672
+ investigation reads first.
667
673
 
668
674
  If a DIFFERENT value was already cached, this camera does not keep its
669
675
  parameter sets stable: mark it and drop the cache, so nothing is injected
@@ -672,7 +678,7 @@ def _save_sprop(devid: str, sprop: str) -> None:
672
678
  loses nothing by the injection being skipped.
673
679
  """
674
680
  if _sprop_is_unstable(devid):
675
- return # already known unstable; nothing to cache for this camera
681
+ return False # already known unstable; nothing to cache for this camera
676
682
  try:
677
683
  prev = _load_sprop(devid)
678
684
  if prev is not None and prev != sprop:
@@ -689,17 +695,19 @@ def _save_sprop(devid: str, sprop: str) -> None:
689
695
  os.remove(_sprop_cache_path(devid))
690
696
  except OSError:
691
697
  pass
692
- return
698
+ return False
693
699
  os.makedirs(_SPROP_DIR, exist_ok=True)
694
700
  tmp = _sprop_cache_path(devid) + ".tmp"
695
701
  with open(tmp, "w") as fh:
696
702
  fh.write(sprop)
697
703
  os.replace(tmp, _sprop_cache_path(devid))
704
+ return True
698
705
  except OSError as exc:
699
706
  # Surface (don't swallow): if the cache dir isn't writable the whole
700
707
  # sprop feature is silently inert. AIDOT_SPROP_DIR can redirect it.
701
708
  _LOGGER.warning("sprop cache write failed (%s): %s - set AIDOT_SPROP_DIR "
702
709
  "to a writable path", _SPROP_DIR, exc)
710
+ return False
703
711
 
704
712
 
705
713
  def _inject_sprop(sdp: str, devid: str) -> str:
@@ -133,12 +133,19 @@ class SdesSession(AvioRequestMixin):
133
133
  def talk_supported(self) -> bool:
134
134
  """True if two-way audio can be used on this SDES session.
135
135
 
136
- Requires a talk-capable open (offer advertised sendrecv + a=ssrc). The
137
- camera audio address is filled in by the bridge on first inbound audio;
138
- async_start_talk tolerates being called before that - the pump waits for
139
- the address before emitting.
136
+ Requires a talk-capable open (offer advertised sendrecv + a=ssrc) AND a
137
+ session that is still running. The camera audio address is filled in by
138
+ the bridge on first inbound audio; async_start_talk tolerates being
139
+ called before that - the pump waits for the address before emitting.
140
+
141
+ Liveness is part of the answer because the talk state is a plain dict
142
+ that outlives ffmpeg, while everything that acts on it - the bridge
143
+ thread that sends SPEAKERSTART, the socket the pump writes to - dies
144
+ with ffmpeg. ``async_speak`` reuses the warm session whenever this is
145
+ true, so answering from the dict alone routed talk into a session that
146
+ could no longer carry it instead of opening a fresh one.
140
147
  """
141
- return bool(self._talk_state)
148
+ return bool(self._talk_state) and self.is_alive
142
149
 
143
150
  async def async_start_talk(
144
151
  self, pcm_provider: "Callable[[], Optional[bytes]]"
@@ -170,10 +177,23 @@ class SdesSession(AvioRequestMixin):
170
177
  target=_run_sdes_talk_pump, args=(self._talk_state,), daemon=True
171
178
  )
172
179
  self._talk_thread.start()
173
- if await _speaker_ack_accepted(waiter, SDES_SPEAKER_ACK_TIMEOUT_S):
180
+ accepted = await _speaker_ack_accepted(waiter, SDES_SPEAKER_ACK_TIMEOUT_S)
181
+ # _speaker_ack_accepted is generous by design: it treats an unfamiliar or
182
+ # absent ack as acceptance, because no genuine refusal has ever been
183
+ # identified and guessing at one would break working cameras. That
184
+ # generosity is about INTERPRETING the camera's answer, and it has
185
+ # nothing to say about the case where the question was never asked.
186
+ # `speaker_on` is set on exactly one line - immediately after the bridge
187
+ # thread dispatches SPEAKERSTART(848) - so a falsy flag here means our
188
+ # own bridge never sent the command, which happens whenever ffmpeg (and
189
+ # with it that thread) has already exited. The ack budget above already
190
+ # covers SDES_SPEAKERSTART_DELAY, so a live bridge has always set it by
191
+ # now and this cannot race a working session.
192
+ if accepted and self._talk_state.get("speaker_on"):
174
193
  return True
175
- # The camera refused. Stop the microphone rather than stream viewer
176
- # audio at a speaker that never opened.
194
+ # Either the camera refused, or the speaker command never left this
195
+ # process. Stop the microphone rather than stream viewer audio at a
196
+ # speaker that never opened.
177
197
  self._talk_state["want_speaker"] = False
178
198
  self._talk_state["provider"] = None
179
199
  return False