python-aidot-cameras 0.7.34__tar.gz → 0.7.35__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 (64) hide show
  1. {python_aidot_cameras-0.7.34/src/python_aidot_cameras.egg-info → python_aidot_cameras-0.7.35}/PKG-INFO +1 -1
  2. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/pyproject.toml +1 -1
  3. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/camera/client.py +18 -7
  4. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35/src/python_aidot_cameras.egg-info}/PKG-INFO +1 -1
  5. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_sdes_serve_audio.py +22 -0
  6. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/LICENSE +0 -0
  7. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/MANIFEST.in +0 -0
  8. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/README.md +0 -0
  9. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/setup.cfg +0 -0
  10. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/__init__.py +0 -0
  11. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/aes_utils.py +0 -0
  12. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/camera/__init__.py +0 -0
  13. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/camera/constants.py +0 -0
  14. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/camera/controls.py +0 -0
  15. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/camera/go2rtc.py +0 -0
  16. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/camera/lan_control.py +0 -0
  17. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/camera/models.py +0 -0
  18. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/camera/playback.py +0 -0
  19. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/camera/protocol.py +0 -0
  20. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/camera/sdes.py +0 -0
  21. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/camera/tutk.py +0 -0
  22. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/camera/webrtc.py +0 -0
  23. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/client.py +0 -0
  24. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/const.py +0 -0
  25. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/credentials.py +0 -0
  26. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/device_client.py +0 -0
  27. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/discover.py +0 -0
  28. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/exceptions.py +0 -0
  29. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/g711.py +0 -0
  30. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/login_const.py +0 -0
  31. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/models/__init__.py +0 -0
  32. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/models/device_client_model.py +0 -0
  33. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/models/device_model.py +0 -0
  34. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/models/discover_model.py +0 -0
  35. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/aidot/py.typed +0 -0
  36. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/python_aidot_cameras.egg-info/SOURCES.txt +0 -0
  37. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/python_aidot_cameras.egg-info/dependency_links.txt +0 -0
  38. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/python_aidot_cameras.egg-info/requires.txt +0 -0
  39. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/src/python_aidot_cameras.egg-info/top_level.txt +0 -0
  40. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_alarm_event.py +0 -0
  41. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_backoff.py +0 -0
  42. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_device_login_guard.py +0 -0
  43. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_go2rtc.py +0 -0
  44. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_highport_nomination.py +0 -0
  45. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_lan_control.py +0 -0
  46. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_live_stream_param.py +0 -0
  47. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_motion_poll.py +0 -0
  48. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_no_undefined_names.py +0 -0
  49. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_persistent_mqtt.py +0 -0
  50. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_post_merge_hardening.py +0 -0
  51. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_sdes_adaptive.py +0 -0
  52. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_sdes_fast_liveplay.py +0 -0
  53. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_sdes_idle_release.py +0 -0
  54. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_sdes_serve_cmd.py +0 -0
  55. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_sdes_sprop.py +0 -0
  56. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_sdes_talk.py +0 -0
  57. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_sdes_watchdog.py +0 -0
  58. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_serve_relay.py +0 -0
  59. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_speak.py +0 -0
  60. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_stream_cap.py +0 -0
  61. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_stream_idle.py +0 -0
  62. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_talk.py +0 -0
  63. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_terminal_ack.py +0 -0
  64. {python_aidot_cameras-0.7.34 → python_aidot_cameras-0.7.35}/tests/test_token_refresh.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-aidot-cameras
3
- Version: 0.7.34
3
+ Version: 0.7.35
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "python-aidot-cameras"
7
- version = "0.7.34"
7
+ version = "0.7.35"
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"
@@ -2071,6 +2071,7 @@ class CameraMixin(_CameraControlsMixin):
2071
2071
  sdes_fast_liveplay: Optional[bool] = None,
2072
2072
  sdes_skip_turn: Optional[bool] = None,
2073
2073
  sdes_adaptive: Optional[bool] = None,
2074
+ sdes_audio_gain_db: Optional[float] = None,
2074
2075
  ) -> None:
2075
2076
  """Start a persistent stream that keeps the camera session alive.
2076
2077
 
@@ -2113,6 +2114,8 @@ class CameraMixin(_CameraControlsMixin):
2113
2114
  self._fast_connect_opt = fast_connect
2114
2115
  if sdes_audio is not None:
2115
2116
  self._sdes_audio_opt = sdes_audio
2117
+ if sdes_audio_gain_db is not None:
2118
+ self._sdes_audio_gain_opt = sdes_audio_gain_db
2116
2119
  if live_stream_param is not None:
2117
2120
  self._live_stream_param_opt = live_stream_param
2118
2121
  if serve_relay is not None:
@@ -2734,6 +2737,19 @@ class CameraMixin(_CameraControlsMixin):
2734
2737
  return os.environ.get("AIDOT_SDES_SERVE_AUDIO", "").strip().lower() not in (
2735
2738
  "0", "false", "no", "off")
2736
2739
 
2740
+ def _resolve_sdes_audio_gain_db(self) -> float:
2741
+ """Gain (dB) applied to the served SDES audio (the camera mic runs hot).
2742
+
2743
+ Per-camera ``sdes_audio_gain_db`` (via ``start_keepalive``) wins; else the
2744
+ ``AIDOT_SDES_AUDIO_GAIN_DB`` env; else ``-8``. A bad value falls back to
2745
+ the default rather than raising."""
2746
+ opt = getattr(self, "_sdes_audio_gain_opt", None)
2747
+ src = opt if opt is not None else os.environ.get("AIDOT_SDES_AUDIO_GAIN_DB", "-8")
2748
+ try:
2749
+ return float(src)
2750
+ except (ValueError, TypeError):
2751
+ return -8.0
2752
+
2737
2753
  def _resolve_sdes_skip_turn(self) -> bool:
2738
2754
  """EXPERIMENTAL (opt-in, default off): skip the blocking SDES TURN relay
2739
2755
  pre-allocation, for cameras reachable LAN-direct.
@@ -10052,18 +10068,13 @@ class CameraMixin(_CameraControlsMixin):
10052
10068
  if out_dir:
10053
10069
  os.makedirs(out_dir, exist_ok=True)
10054
10070
  # Build the ffmpeg command (single source of truth: _build_sdes_serve_cmd).
10055
- _sdes_audio = self._resolve_sdes_serve_audio()
10056
- try:
10057
- _sdes_gain_db = float(os.environ.get("AIDOT_SDES_AUDIO_GAIN_DB", "-8"))
10058
- except (ValueError, TypeError):
10059
- _sdes_gain_db = -8.0
10060
10071
  cmd = _build_sdes_serve_cmd(
10061
10072
  sdp_path=sdp_path,
10062
10073
  rtsp_push_url=rtsp_push_url,
10063
10074
  output_path=output_path,
10064
10075
  max_seconds=max_seconds,
10065
- sdes_audio=bool(_sdes_audio),
10066
- audio_gain_db=_sdes_gain_db,
10076
+ sdes_audio=self._resolve_sdes_serve_audio(),
10077
+ audio_gain_db=self._resolve_sdes_audio_gain_db(),
10067
10078
  )
10068
10079
  # --- H.265 fix: narrow the ffmpeg SDP to the camera's actual codec ----
10069
10080
  # The camera streams H.264 (pt=96) OR H.265 (pt=97), varying per session.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-aidot-cameras
3
- Version: 0.7.34
3
+ Version: 0.7.35
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
@@ -48,6 +48,28 @@ def test_kwarg_option_wins_over_env(monkeypatch):
48
48
  assert cam2._resolve_sdes_serve_audio() is True
49
49
 
50
50
 
51
+ def test_gain_default(monkeypatch):
52
+ monkeypatch.delenv("AIDOT_SDES_AUDIO_GAIN_DB", raising=False)
53
+ assert _cam()._resolve_sdes_audio_gain_db() == -8.0
54
+
55
+
56
+ def test_gain_env(monkeypatch):
57
+ monkeypatch.setenv("AIDOT_SDES_AUDIO_GAIN_DB", "-3.5")
58
+ assert _cam()._resolve_sdes_audio_gain_db() == -3.5
59
+
60
+
61
+ def test_gain_opt_wins(monkeypatch):
62
+ monkeypatch.setenv("AIDOT_SDES_AUDIO_GAIN_DB", "-3")
63
+ cam = _cam()
64
+ cam._sdes_audio_gain_opt = 2.0
65
+ assert cam._resolve_sdes_audio_gain_db() == 2.0
66
+
67
+
68
+ def test_gain_bad_value_falls_back(monkeypatch):
69
+ monkeypatch.setenv("AIDOT_SDES_AUDIO_GAIN_DB", "loud")
70
+ assert _cam()._resolve_sdes_audio_gain_db() == -8.0
71
+
72
+
51
73
  if __name__ == "__main__":
52
74
  import traceback
53
75