python-aidot-cameras 0.12.10__tar.gz → 0.12.11__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 (143) hide show
  1. {python_aidot_cameras-0.12.10/python_aidot_cameras.egg-info → python_aidot_cameras-0.12.11}/PKG-INFO +1 -1
  2. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/camera/client.py +29 -0
  3. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/pyproject.toml +1 -1
  4. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11/python_aidot_cameras.egg-info}/PKG-INFO +1 -1
  5. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/python_aidot_cameras.egg-info/SOURCES.txt +1 -0
  6. python_aidot_cameras-0.12.11/tests/test_no_self_referential_go2rtc.py +47 -0
  7. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/LICENSE +0 -0
  8. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/MANIFEST.in +0 -0
  9. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/README.md +0 -0
  10. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/__init__.py +0 -0
  11. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/__main__.py +0 -0
  12. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/__init__.py +0 -0
  13. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/__init__.py +0 -0
  14. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/clock.py +0 -0
  15. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/codecs/__init__.py +0 -0
  16. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/codecs/base.py +0 -0
  17. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/codecs/g711.py +0 -0
  18. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/codecs/g722.py +0 -0
  19. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/codecs/h264.py +0 -0
  20. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/codecs/opus.py +0 -0
  21. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/codecs/vpx.py +0 -0
  22. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/contrib/__init__.py +0 -0
  23. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/contrib/media.py +0 -0
  24. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/contrib/signaling.py +0 -0
  25. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/events.py +0 -0
  26. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/exceptions.py +0 -0
  27. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/jitterbuffer.py +0 -0
  28. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/mediastreams.py +0 -0
  29. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/rate.py +0 -0
  30. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/rtcconfiguration.py +0 -0
  31. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/rtcdatachannel.py +0 -0
  32. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/rtcdtlstransport.py +0 -0
  33. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/rtcicetransport.py +0 -0
  34. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/rtcpeerconnection.py +0 -0
  35. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/rtcrtpparameters.py +0 -0
  36. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/rtcrtpreceiver.py +0 -0
  37. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/rtcrtpsender.py +0 -0
  38. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/rtcrtptransceiver.py +0 -0
  39. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/rtcsctptransport.py +0 -0
  40. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/rtcsessiondescription.py +0 -0
  41. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/rtp.py +0 -0
  42. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/sdp.py +0 -0
  43. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/stats.py +0 -0
  44. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/_vendor/aiortc/utils.py +0 -0
  45. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/camera/__init__.py +0 -0
  46. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/camera/constants.py +0 -0
  47. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/camera/controls.py +0 -0
  48. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/camera/go2rtc.py +0 -0
  49. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/camera/lan_control.py +0 -0
  50. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/camera/models.py +0 -0
  51. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/camera/playback.py +0 -0
  52. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/camera/protocol.py +0 -0
  53. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/camera/sdes.py +0 -0
  54. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/camera/sdes_open.py +0 -0
  55. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/camera/tutk.py +0 -0
  56. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/camera/webrtc.py +0 -0
  57. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/camera/webrtc_open.py +0 -0
  58. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/client.py +0 -0
  59. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/const.py +0 -0
  60. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/credentials.py +0 -0
  61. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/crypto.py +0 -0
  62. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/device_client.py +0 -0
  63. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/discover.py +0 -0
  64. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/exceptions.py +0 -0
  65. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/g711.py +0 -0
  66. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/aidot_cameras/py.typed +0 -0
  67. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/python_aidot_cameras.egg-info/dependency_links.txt +0 -0
  68. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/python_aidot_cameras.egg-info/entry_points.txt +0 -0
  69. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/python_aidot_cameras.egg-info/requires.txt +0 -0
  70. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/python_aidot_cameras.egg-info/top_level.txt +0 -0
  71. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/setup.cfg +0 -0
  72. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_aioice_compat.py +0 -0
  73. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_alarm_event.py +0 -0
  74. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_backoff.py +0 -0
  75. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_deferred_hardening.py +0 -0
  76. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_device_login_guard.py +0 -0
  77. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_device_user_info_cache.py +0 -0
  78. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_dtls_not_ready_burst.py +0 -0
  79. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_dtls_pinning.py +0 -0
  80. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_dtls_serve_decode_skip.py +0 -0
  81. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_dtls_serve_open_timeout.py +0 -0
  82. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_dtls_skip_signaling_wait.py +0 -0
  83. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_dtls_slow_probe.py +0 -0
  84. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_egress_guard.py +0 -0
  85. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_go2rtc.py +0 -0
  86. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_go2rtc_cli.py +0 -0
  87. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_h264_decode_rate_limit.py +0 -0
  88. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_highport_nomination.py +0 -0
  89. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_ice_config_cache.py +0 -0
  90. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_idle_release_both_loops.py +0 -0
  91. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_keepalive_renew.py +0 -0
  92. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_key_restart_sdp.py +0 -0
  93. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_keyframe_prompter.py +0 -0
  94. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_lan_control.py +0 -0
  95. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_light_active_color_mode.py +0 -0
  96. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_live_stream_param.py +0 -0
  97. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_logging_caps.py +0 -0
  98. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_motion_poll.py +0 -0
  99. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_mqtt_credential_refetch.py +0 -0
  100. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_mqtt_credential_self_heal.py +0 -0
  101. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_mqtt_password_not_persisted.py +0 -0
  102. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_mqtt_session_reconnect.py +0 -0
  103. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_narrow_pc_ice.py +0 -0
  104. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_no_undefined_names.py +0 -0
  105. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_offline_keepalive_pause.py +0 -0
  106. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_open_fail_logger.py +0 -0
  107. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_open_gate_delay.py +0 -0
  108. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_persistent_mqtt.py +0 -0
  109. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_persistent_mqtt_robustness.py +0 -0
  110. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_playback_tls.py +0 -0
  111. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_post_merge_hardening.py +0 -0
  112. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_retry_policy.py +0 -0
  113. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_sdes_adaptive.py +0 -0
  114. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_sdes_bridge_break_gate.py +0 -0
  115. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_sdes_echo_wait_timeout.py +0 -0
  116. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_sdes_fast_liveplay.py +0 -0
  117. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_sdes_ffmpeg_stderr_log.py +0 -0
  118. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_sdes_idle_release.py +0 -0
  119. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_sdes_open_cleanup.py +0 -0
  120. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_sdes_serve_audio.py +0 -0
  121. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_sdes_serve_cmd.py +0 -0
  122. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_sdes_sprop.py +0 -0
  123. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_sdes_talk.py +0 -0
  124. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_sdes_teardown_exit_log.py +0 -0
  125. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_sdes_watchdog.py +0 -0
  126. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_sdp_payload_type_narrowing.py +0 -0
  127. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_security_hardening.py +0 -0
  128. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_serializable_login_info.py +0 -0
  129. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_serve_relay.py +0 -0
  130. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_session_stats.py +0 -0
  131. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_speak.py +0 -0
  132. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_stream_cap.py +0 -0
  133. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_stream_drain_ownership.py +0 -0
  134. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_stream_idle.py +0 -0
  135. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_stream_slot_cap.py +0 -0
  136. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_stream_teardown.py +0 -0
  137. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_talk.py +0 -0
  138. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_terminal_ack.py +0 -0
  139. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_token_file_robustness.py +0 -0
  140. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_token_refresh.py +0 -0
  141. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_upstream_compat.py +0 -0
  142. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_viewer_presence.py +0 -0
  143. {python_aidot_cameras-0.12.10 → python_aidot_cameras-0.12.11}/tests/test_wait_or_event.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-aidot-cameras
3
- Version: 0.12.10
3
+ Version: 0.12.11
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
@@ -2,6 +2,7 @@
2
2
 
3
3
  import json
4
4
  import logging
5
+ from urllib.parse import urlparse
5
6
  import os
6
7
  import random
7
8
  import time
@@ -337,6 +338,22 @@ def _save_frame_as_jpeg(image_data: Any, output_path: str) -> bool:
337
338
  return False
338
339
 
339
340
 
341
+ def _is_self_referential_source(source: str, stream_name: str) -> bool:
342
+ """True when registering ``source`` under ``stream_name`` would loop.
343
+
344
+ A go2rtc stream whose source is its own RTSP address becomes its own
345
+ producer: the stream lists a producer, nothing feeds it, and every consumer
346
+ gets a connection with no media. That is exactly the shape of a PUSH URL,
347
+ ``rtsp://host:8554/<stream name>`` - the address the keepalive publishes to.
348
+ """
349
+ if not source or not stream_name:
350
+ return False
351
+ if not source.lower().startswith(("rtsp://", "rtsps://")):
352
+ return False
353
+ path = urlparse(source).path.strip("/")
354
+ return path == stream_name
355
+
356
+
340
357
  def _build_sdes_serve_cmd(
341
358
  *,
342
359
  sdp_path: str,
@@ -2763,6 +2780,18 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
2763
2780
  if not (self._streaming_active and self._go2rtc_url and self._keepalive_rtsp_url):
2764
2781
  return
2765
2782
  name = self._go2rtc_stream_name()
2783
+ if _is_self_referential_source(self._keepalive_rtsp_url, name):
2784
+ # PUSH mode: the keepalive publishes INTO go2rtc, so this URL is
2785
+ # go2rtc's own address for this very stream. Registering it as the
2786
+ # stream's source makes go2rtc its own producer - a loop that yields
2787
+ # a stream with a producer attached and no media coming out of it.
2788
+ # In push mode the publisher already feeds the stream; there is
2789
+ # nothing to register.
2790
+ _LOGGER.debug(
2791
+ "camera %s: not registering %s with go2rtc - the push URL is that "
2792
+ "stream's own address", self.device_id, name,
2793
+ )
2794
+ return
2766
2795
  try:
2767
2796
  async with aiohttp.ClientSession() as _s2:
2768
2797
  url = await prefer_go2rtc(
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "python-aidot-cameras"
7
- version = "0.12.10"
7
+ version = "0.12.11"
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: 0.12.10
3
+ Version: 0.12.11
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
@@ -98,6 +98,7 @@ tests/test_mqtt_credential_self_heal.py
98
98
  tests/test_mqtt_password_not_persisted.py
99
99
  tests/test_mqtt_session_reconnect.py
100
100
  tests/test_narrow_pc_ice.py
101
+ tests/test_no_self_referential_go2rtc.py
101
102
  tests/test_no_undefined_names.py
102
103
  tests/test_offline_keepalive_pause.py
103
104
  tests/test_open_fail_logger.py
@@ -0,0 +1,47 @@
1
+ """A go2rtc stream must never be registered as its own source.
2
+
3
+ In PUSH mode the keepalive publishes INTO go2rtc, so the "keepalive rtsp url" is
4
+ go2rtc's own address for that stream. Registering it as the stream's source makes
5
+ go2rtc its own producer: the stream lists a producer, nothing feeds it, and every
6
+ consumer gets a connection with no media.
7
+
8
+ Seen live after the integration began passing go2rtc_url: one camera's stream had
9
+ two producers, one of them `rtsp://127.0.0.1:8554/aidot_12b144cb12da` - its own
10
+ address - and go2rtc returned HTTP 200 with a zero-byte frame for it.
11
+ """
12
+ from aidot_cameras.camera.client import _is_self_referential_source as loops
13
+
14
+
15
+ def test_push_url_for_the_same_stream_is_self_referential():
16
+ assert loops("rtsp://127.0.0.1:8554/aidot_12b144cb12da",
17
+ "aidot_12b144cb12da") is True
18
+
19
+
20
+ def test_push_url_for_a_different_stream_is_fine():
21
+ # Publishing camera A into stream B is odd but not a loop.
22
+ assert loops("rtsp://127.0.0.1:8554/aidot_other", "aidot_12b144cb12da") is False
23
+
24
+
25
+ def test_the_http_serve_url_is_a_real_source():
26
+ # PULL mode: go2rtc fetches from the library's own serve. Must still register.
27
+ assert loops("http://127.0.0.1:18931/ecf4937b640c4c96a102ffdc9b51c2a0.ts",
28
+ "aidot_ecf4937b640c") is False
29
+
30
+
31
+ def test_rtsps_is_covered_too():
32
+ assert loops("rtsps://127.0.0.1:8554/aidot_x", "aidot_x") is True
33
+
34
+
35
+ def test_trailing_slash_and_case_do_not_hide_it():
36
+ assert loops("RTSP://127.0.0.1:8554/aidot_x/", "aidot_x") is True
37
+
38
+
39
+ def test_missing_values_are_not_self_referential():
40
+ assert loops("", "aidot_x") is False
41
+ assert loops("rtsp://127.0.0.1:8554/aidot_x", "") is False
42
+
43
+
44
+ def test_a_remote_go2rtc_push_url_still_counts():
45
+ # The host does not matter; publishing into the stream you are registering is
46
+ # a loop wherever go2rtc lives.
47
+ assert loops("rtsp://go2rtc.lan:8554/aidot_x", "aidot_x") is True