python-aidot-cameras 0.9.0__tar.gz → 0.9.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_aidot_cameras-0.9.0/src/python_aidot_cameras.egg-info → python_aidot_cameras-0.9.1}/PKG-INFO +5 -5
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/pyproject.toml +10 -5
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/camera/client.py +19 -19
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/camera/models.py +3 -3
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/camera/playback.py +2 -2
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/camera/protocol.py +16 -16
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/camera/sdes.py +7 -7
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/camera/sdes_open.py +43 -43
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/camera/tutk.py +2 -2
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/camera/webrtc.py +4 -4
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/camera/webrtc_open.py +9 -9
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1/src/python_aidot_cameras.egg-info}/PKG-INFO +5 -5
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/python_aidot_cameras.egg-info/requires.txt +4 -4
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/LICENSE +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/MANIFEST.in +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/README.md +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/setup.cfg +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/__init__.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/aes_utils.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/camera/__init__.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/camera/constants.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/camera/controls.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/camera/go2rtc.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/camera/lan_control.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/client.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/const.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/credentials.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/device_client.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/discover.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/exceptions.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/g711.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/login_const.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/models/__init__.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/models/device_client_model.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/models/device_model.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/models/discover_model.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/py.typed +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/python_aidot_cameras.egg-info/SOURCES.txt +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/python_aidot_cameras.egg-info/dependency_links.txt +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/python_aidot_cameras.egg-info/top_level.txt +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_aioice_compat.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_alarm_event.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_backoff.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_device_login_guard.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_go2rtc.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_highport_nomination.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_ice_config_cache.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_lan_control.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_live_stream_param.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_motion_poll.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_no_undefined_names.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_persistent_mqtt.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_persistent_mqtt_robustness.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_post_merge_hardening.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_sdes_adaptive.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_sdes_fast_liveplay.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_sdes_idle_release.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_sdes_serve_audio.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_sdes_serve_cmd.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_sdes_sprop.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_sdes_talk.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_sdes_watchdog.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_serve_relay.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_session_stats.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_speak.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_stream_cap.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_stream_idle.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_stream_teardown.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_talk.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_terminal_ack.py +0 -0
- {python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_token_refresh.py +0 -0
{python_aidot_cameras-0.9.0/src/python_aidot_cameras.egg-info → python_aidot_cameras-0.9.1}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-aidot-cameras
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.1
|
|
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
|
|
@@ -11,11 +11,11 @@ Classifier: Operating System :: OS Independent
|
|
|
11
11
|
Requires-Python: >=3.11
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
|
-
Requires-Dist: aiohttp
|
|
14
|
+
Requires-Dist: aiohttp>=3.9
|
|
15
15
|
Requires-Dist: paho-mqtt>=2.0
|
|
16
|
-
Requires-Dist: cryptography
|
|
17
|
-
Requires-Dist: pycryptodome
|
|
18
|
-
Requires-Dist: dacite
|
|
16
|
+
Requires-Dist: cryptography>=42.0
|
|
17
|
+
Requires-Dist: pycryptodome>=3.20
|
|
18
|
+
Requires-Dist: dacite>=1.8
|
|
19
19
|
Provides-Extra: webrtc
|
|
20
20
|
Requires-Dist: aiortc>=1.9.0; extra == "webrtc"
|
|
21
21
|
Requires-Dist: aioice<0.12,>=0.9.0; extra == "webrtc"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-aidot-cameras"
|
|
7
|
-
version = "0.9.
|
|
7
|
+
version = "0.9.1"
|
|
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"
|
|
@@ -15,12 +15,17 @@ classifiers = [
|
|
|
15
15
|
"Programming Language :: Python :: 3",
|
|
16
16
|
"Operating System :: OS Independent",
|
|
17
17
|
]
|
|
18
|
+
# Conservative lower bounds only - no upper caps. When installed under Home
|
|
19
|
+
# Assistant, HA core pins aiohttp/cryptography itself; an upper cap here would
|
|
20
|
+
# fight HA's resolver on the box. Floors just exclude ancient releases while
|
|
21
|
+
# leaving the consumer (or HA) free to use a newer version. Bump a floor only
|
|
22
|
+
# after re-validating against it.
|
|
18
23
|
dependencies = [
|
|
19
|
-
"aiohttp",
|
|
24
|
+
"aiohttp>=3.9",
|
|
20
25
|
"paho-mqtt>=2.0",
|
|
21
|
-
"cryptography",
|
|
22
|
-
"pycryptodome",
|
|
23
|
-
"dacite",
|
|
26
|
+
"cryptography>=42.0",
|
|
27
|
+
"pycryptodome>=3.20",
|
|
28
|
+
"dacite>=1.8",
|
|
24
29
|
]
|
|
25
30
|
|
|
26
31
|
[project.optional-dependencies]
|
|
@@ -1467,7 +1467,7 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
|
|
|
1467
1467
|
try:
|
|
1468
1468
|
self.status.update_from_camera_attributes({attr: value})
|
|
1469
1469
|
except Exception:
|
|
1470
|
-
_LOGGER.debug("camera %s: swallowed exception", 'async_set_device_attribute', exc_info=True)
|
|
1470
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), 'async_set_device_attribute', exc_info=True)
|
|
1471
1471
|
return ok
|
|
1472
1472
|
|
|
1473
1473
|
async def async_trigger_device_action(
|
|
@@ -1542,7 +1542,7 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
|
|
|
1542
1542
|
try:
|
|
1543
1543
|
await self.async_wake_camera()
|
|
1544
1544
|
except Exception:
|
|
1545
|
-
_LOGGER.debug("camera %s: swallowed exception", 'async_get_camera_attributes', exc_info=True)
|
|
1545
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), 'async_get_camera_attributes', exc_info=True)
|
|
1546
1546
|
|
|
1547
1547
|
smarthome_auth = await self._async_get_smarthome_auth()
|
|
1548
1548
|
mqtt_user = (smarthome_auth or {}).get("mqttUser") or str(self.user_id)
|
|
@@ -1929,7 +1929,7 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
|
|
|
1929
1929
|
try:
|
|
1930
1930
|
_os.unlink(_tmp_ts)
|
|
1931
1931
|
except Exception:
|
|
1932
|
-
_LOGGER.debug("camera %s: swallowed exception", 'async_snapshot', exc_info=True)
|
|
1932
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), 'async_snapshot', exc_info=True)
|
|
1933
1933
|
|
|
1934
1934
|
# ── DTLS path: on_frame callback delivers frames from aiortc ─────── #
|
|
1935
1935
|
frame_event = _asyncio.Event()
|
|
@@ -2002,21 +2002,21 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
|
|
|
2002
2002
|
try:
|
|
2003
2003
|
await g_task
|
|
2004
2004
|
except (asyncio.CancelledError, Exception):
|
|
2005
|
-
_LOGGER.debug("camera %s: swallowed exception", 'async_stop_streaming', exc_info=True)
|
|
2005
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), 'async_stop_streaming', exc_info=True)
|
|
2006
2006
|
await self._deregister_go2rtc()
|
|
2007
2007
|
session, self._stream_session = self._stream_session, None
|
|
2008
2008
|
if session is not None:
|
|
2009
2009
|
try:
|
|
2010
2010
|
await session.stop()
|
|
2011
2011
|
except Exception:
|
|
2012
|
-
_LOGGER.debug("camera %s: swallowed exception", 'async_stop_streaming', exc_info=True)
|
|
2012
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), 'async_stop_streaming', exc_info=True)
|
|
2013
2013
|
task, self._stream_task = self._stream_task, None
|
|
2014
2014
|
if task is not None and not task.done():
|
|
2015
2015
|
task.cancel()
|
|
2016
2016
|
try:
|
|
2017
2017
|
await task
|
|
2018
2018
|
except (asyncio.CancelledError, Exception):
|
|
2019
|
-
_LOGGER.debug("camera %s: swallowed exception", 'async_stop_streaming', exc_info=True)
|
|
2019
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), 'async_stop_streaming', exc_info=True)
|
|
2020
2020
|
# Reap a persistent-MQTT stream drain that no session stopped (e.g. an
|
|
2021
2021
|
# open cancelled mid-handshake) so its handler is removed from the shared
|
|
2022
2022
|
# connection and its blocked executor thread is released.
|
|
@@ -2041,13 +2041,13 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
|
|
|
2041
2041
|
try:
|
|
2042
2042
|
outq.put_nowait(None) # release the executor thread in outgoing_q.get
|
|
2043
2043
|
except Exception:
|
|
2044
|
-
_LOGGER.debug("camera %s: swallowed exception", '_reap_stream_drain', exc_info=True)
|
|
2044
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_reap_stream_drain', exc_info=True)
|
|
2045
2045
|
if not drain.done():
|
|
2046
2046
|
drain.cancel()
|
|
2047
2047
|
try:
|
|
2048
2048
|
await drain
|
|
2049
2049
|
except (asyncio.CancelledError, Exception):
|
|
2050
|
-
_LOGGER.debug("camera %s: swallowed exception", '_reap_stream_drain', exc_info=True)
|
|
2050
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_reap_stream_drain', exc_info=True)
|
|
2051
2051
|
|
|
2052
2052
|
async def async_start_motion_polling(
|
|
2053
2053
|
self, callback: Callable, interval: float = 30.0, lookback_s: int = 600,
|
|
@@ -2087,7 +2087,7 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
|
|
|
2087
2087
|
try:
|
|
2088
2088
|
await task
|
|
2089
2089
|
except (asyncio.CancelledError, Exception):
|
|
2090
|
-
_LOGGER.debug("camera %s: swallowed exception", 'async_stop_motion_polling', exc_info=True)
|
|
2090
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), 'async_stop_motion_polling', exc_info=True)
|
|
2091
2091
|
|
|
2092
2092
|
async def _motion_poll_loop(self, lookback_s: int) -> None:
|
|
2093
2093
|
"""Background: poll the cloud event list; fire callback on newly-recorded events."""
|
|
@@ -2241,7 +2241,7 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
|
|
|
2241
2241
|
try:
|
|
2242
2242
|
await self.async_wait_serve_ready(timeout=40.0)
|
|
2243
2243
|
except Exception:
|
|
2244
|
-
_LOGGER.debug("camera %s: swallowed exception", '_register_with_go2rtc', exc_info=True)
|
|
2244
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_register_with_go2rtc', exc_info=True)
|
|
2245
2245
|
if not (self._streaming_active and self._go2rtc_url and self._keepalive_rtsp_url):
|
|
2246
2246
|
return
|
|
2247
2247
|
name = f"aidot_{self.device_id[:12]}"
|
|
@@ -2254,7 +2254,7 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
|
|
|
2254
2254
|
_LOGGER.info(
|
|
2255
2255
|
"camera %s: preferring go2rtc stream -> %s", self.device_id, url)
|
|
2256
2256
|
except Exception:
|
|
2257
|
-
_LOGGER.debug("camera %s: swallowed exception", '_register_with_go2rtc', exc_info=True)
|
|
2257
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_register_with_go2rtc', exc_info=True)
|
|
2258
2258
|
|
|
2259
2259
|
async def _deregister_go2rtc(self) -> None:
|
|
2260
2260
|
"""Remove this camera's stream from go2rtc (best-effort)."""
|
|
@@ -2269,7 +2269,7 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
|
|
|
2269
2269
|
async with aiohttp.ClientSession() as _s2:
|
|
2270
2270
|
await Go2rtcClient(_s2, base).remove_stream(name)
|
|
2271
2271
|
except Exception:
|
|
2272
|
-
_LOGGER.debug("camera %s: swallowed exception", '_deregister_go2rtc', exc_info=True)
|
|
2272
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_deregister_go2rtc', exc_info=True)
|
|
2273
2273
|
|
|
2274
2274
|
async def async_wait_serve_ready(self, timeout: float = 20.0) -> bool:
|
|
2275
2275
|
"""Wait until the DTLS serve is bound + serving (or ``timeout``).
|
|
@@ -2520,7 +2520,7 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
|
|
|
2520
2520
|
try:
|
|
2521
2521
|
await session.stop()
|
|
2522
2522
|
except Exception:
|
|
2523
|
-
_LOGGER.debug("camera %s: swallowed exception", '_sdes_keepalive_loop', exc_info=True)
|
|
2523
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_sdes_keepalive_loop', exc_info=True)
|
|
2524
2524
|
self._streaming_active = False
|
|
2525
2525
|
self._keepalive_rtsp_url = None
|
|
2526
2526
|
self._serve_ready.clear()
|
|
@@ -2540,7 +2540,7 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
|
|
|
2540
2540
|
try:
|
|
2541
2541
|
await session.stop()
|
|
2542
2542
|
except Exception:
|
|
2543
|
-
_LOGGER.debug("camera %s: swallowed exception", '_sdes_keepalive_loop', exc_info=True)
|
|
2543
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_sdes_keepalive_loop', exc_info=True)
|
|
2544
2544
|
|
|
2545
2545
|
# Adaptive bookkeeping: a fast attempt that never delivered media
|
|
2546
2546
|
# latches the loop onto the full relay path for its remaining opens.
|
|
@@ -2651,7 +2651,7 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
|
|
|
2651
2651
|
try:
|
|
2652
2652
|
await session.stop()
|
|
2653
2653
|
except Exception:
|
|
2654
|
-
_LOGGER.debug("camera %s: swallowed exception", '_on_frame', exc_info=True)
|
|
2654
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_on_frame', exc_info=True)
|
|
2655
2655
|
|
|
2656
2656
|
if self._streaming_active:
|
|
2657
2657
|
# Reset backoff if this session produced frames (a normal drop
|
|
@@ -2707,7 +2707,7 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
|
|
|
2707
2707
|
except Exception:
|
|
2708
2708
|
pass # full -> drop (PLI re-arms a GOP)
|
|
2709
2709
|
except Exception:
|
|
2710
|
-
_LOGGER.debug("
|
|
2710
|
+
_LOGGER.debug("swallowed exception in %s", '_tap_put', exc_info=True)
|
|
2711
2711
|
return _orig_put(task, *a, **k)
|
|
2712
2712
|
|
|
2713
2713
|
_qd.put = _tap_put
|
|
@@ -3229,7 +3229,7 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
|
|
|
3229
3229
|
try:
|
|
3230
3230
|
wfile.close()
|
|
3231
3231
|
except Exception:
|
|
3232
|
-
_LOGGER.debug("camera %s: swallowed exception", '_pc_dead', exc_info=True)
|
|
3232
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_pc_dead', exc_info=True)
|
|
3233
3233
|
wfile = None
|
|
3234
3234
|
mux_thread.join(timeout=2.0)
|
|
3235
3235
|
mux_thread = stop_flag = None
|
|
@@ -3248,7 +3248,7 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
|
|
|
3248
3248
|
try:
|
|
3249
3249
|
wfile.close()
|
|
3250
3250
|
except Exception:
|
|
3251
|
-
_LOGGER.debug("camera %s: swallowed exception", '_pc_dead', exc_info=True)
|
|
3251
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_pc_dead', exc_info=True)
|
|
3252
3252
|
if mux_thread is not None:
|
|
3253
3253
|
mux_thread.join(timeout=2.0)
|
|
3254
3254
|
_terminate_proc(proc) # never orphan ffmpeg on teardown
|
|
@@ -3256,7 +3256,7 @@ class CameraMixin(_CameraControlsMixin, _WebRTCOpenMixin, _SdesOpenMixin):
|
|
|
3256
3256
|
try:
|
|
3257
3257
|
await session.stop()
|
|
3258
3258
|
except Exception:
|
|
3259
|
-
_LOGGER.debug("camera %s: swallowed exception", '_pc_dead', exc_info=True)
|
|
3259
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_pc_dead', exc_info=True)
|
|
3260
3260
|
|
|
3261
3261
|
if cancelled:
|
|
3262
3262
|
return
|
|
@@ -102,7 +102,7 @@ class CameraStatusData(DeviceStatusData):
|
|
|
102
102
|
try:
|
|
103
103
|
self.battery_remaining = int(v)
|
|
104
104
|
except (ValueError, TypeError):
|
|
105
|
-
_LOGGER.debug("
|
|
105
|
+
_LOGGER.debug("swallowed exception in %s", 'update', exc_info=True)
|
|
106
106
|
if (v := attr.get("Occupancy")) is not None:
|
|
107
107
|
self.occupancy = bool(int(v))
|
|
108
108
|
if (v := attr.get("SDcardStatus")) is not None:
|
|
@@ -111,7 +111,7 @@ class CameraStatusData(DeviceStatusData):
|
|
|
111
111
|
try:
|
|
112
112
|
self.wifi_rssi = int(v)
|
|
113
113
|
except (ValueError, TypeError):
|
|
114
|
-
_LOGGER.debug("
|
|
114
|
+
_LOGGER.debug("swallowed exception in %s", 'update', exc_info=True)
|
|
115
115
|
|
|
116
116
|
# Cloud "properties" keys that belong to lights, not cameras. A camera's
|
|
117
117
|
# image "Dimming" must not be read as a light brightness (and could TypeError
|
|
@@ -163,7 +163,7 @@ class CameraDeviceInformation(DeviceInformation):
|
|
|
163
163
|
if isinstance(codes, list):
|
|
164
164
|
self.ptz_directions = [int(c) for c in codes]
|
|
165
165
|
except Exception:
|
|
166
|
-
_LOGGER.debug("
|
|
166
|
+
_LOGGER.debug("swallowed exception in %s", '__init__', exc_info=True)
|
|
167
167
|
|
|
168
168
|
|
|
169
169
|
@dataclass
|
|
@@ -291,7 +291,7 @@ class CloudPlaybackSession:
|
|
|
291
291
|
self._writer.close()
|
|
292
292
|
await self._writer.wait_closed()
|
|
293
293
|
except Exception:
|
|
294
|
-
_LOGGER.debug("
|
|
294
|
+
_LOGGER.debug("swallowed exception in %s", 'stop', exc_info=True)
|
|
295
295
|
self._writer = None
|
|
296
296
|
self._reader = None
|
|
297
297
|
|
|
@@ -480,6 +480,6 @@ class LiveStreamSession:
|
|
|
480
480
|
self._writer.close()
|
|
481
481
|
await self._writer.wait_closed()
|
|
482
482
|
except Exception:
|
|
483
|
-
_LOGGER.debug("
|
|
483
|
+
_LOGGER.debug("swallowed exception in %s", '_cleanup', exc_info=True)
|
|
484
484
|
self._writer = None
|
|
485
485
|
self._reader = None
|
|
@@ -302,13 +302,13 @@ def _compress_sdp_for_camera(sdp: str) -> str:
|
|
|
302
302
|
try:
|
|
303
303
|
seen["H264/90000_pt"] = ln.split(":")[1].split(" ")[0]
|
|
304
304
|
except Exception:
|
|
305
|
-
_LOGGER.debug("
|
|
305
|
+
_LOGGER.debug("swallowed exception in %s", 'keep', exc_info=True)
|
|
306
306
|
elif "H265/90000" in ln and seen.get("H265/90000") is None:
|
|
307
307
|
keep(ln, "H265/90000")
|
|
308
308
|
try:
|
|
309
309
|
seen["H265/90000_pt"] = ln.split(":")[1].split(" ")[0]
|
|
310
310
|
except Exception:
|
|
311
|
-
_LOGGER.debug("
|
|
311
|
+
_LOGGER.debug("swallowed exception in %s", 'keep', exc_info=True)
|
|
312
312
|
elif "apt=" in ln:
|
|
313
313
|
try:
|
|
314
314
|
apt = ln.split("apt=")[1].strip()
|
|
@@ -499,7 +499,7 @@ def _terminate_proc(proc) -> None:
|
|
|
499
499
|
if proc.returncode is None:
|
|
500
500
|
proc.terminate()
|
|
501
501
|
except Exception:
|
|
502
|
-
_LOGGER.debug("
|
|
502
|
+
_LOGGER.debug("swallowed exception in %s", '_terminate_proc', exc_info=True)
|
|
503
503
|
|
|
504
504
|
|
|
505
505
|
_XDG_CONFIG_HOME = os.environ.get("XDG_CONFIG_HOME") or os.path.join(
|
|
@@ -918,7 +918,7 @@ def _dtls_av_mux_run(vq, aq, out_fileobj, progress, stop_flag) -> None:
|
|
|
918
918
|
out.mux(pkt)
|
|
919
919
|
progress[0] = _t.monotonic()
|
|
920
920
|
except Exception:
|
|
921
|
-
_LOGGER.debug("
|
|
921
|
+
_LOGGER.debug("swallowed exception in %s", '_flush_video', exc_info=True)
|
|
922
922
|
|
|
923
923
|
def _flush_audio(drain=False):
|
|
924
924
|
if not have_audio:
|
|
@@ -961,11 +961,11 @@ def _dtls_av_mux_run(vq, aq, out_fileobj, progress, stop_flag) -> None:
|
|
|
961
961
|
_g.sample_rate = 8000
|
|
962
962
|
fr = _g
|
|
963
963
|
except Exception:
|
|
964
|
-
_LOGGER.debug("
|
|
964
|
+
_LOGGER.debug("swallowed exception in %s", '_flush_audio', exc_info=True)
|
|
965
965
|
for rfr in resampler.resample(fr): # 8k PCMA -> 48k fltp
|
|
966
966
|
fifo.write(rfr)
|
|
967
967
|
except Exception:
|
|
968
|
-
_LOGGER.debug("
|
|
968
|
+
_LOGGER.debug("swallowed exception in %s", '_flush_audio', exc_info=True)
|
|
969
969
|
while True:
|
|
970
970
|
fr = fifo.read(1024) # AAC wants 1024-sample frames
|
|
971
971
|
if fr is None:
|
|
@@ -1009,7 +1009,7 @@ def _dtls_av_mux_run(vq, aq, out_fileobj, progress, stop_flag) -> None:
|
|
|
1009
1009
|
out.mux(opkt)
|
|
1010
1010
|
progress[0] = _t.monotonic()
|
|
1011
1011
|
except Exception:
|
|
1012
|
-
_LOGGER.debug("
|
|
1012
|
+
_LOGGER.debug("swallowed exception in %s", '_flush_audio', exc_info=True)
|
|
1013
1013
|
|
|
1014
1014
|
while not stop_flag.is_set():
|
|
1015
1015
|
_flush_video()
|
|
@@ -1022,11 +1022,11 @@ def _dtls_av_mux_run(vq, aq, out_fileobj, progress, stop_flag) -> None:
|
|
|
1022
1022
|
for opkt in aenc.encode(None): # flush
|
|
1023
1023
|
out.mux(opkt)
|
|
1024
1024
|
except Exception:
|
|
1025
|
-
_LOGGER.debug("
|
|
1025
|
+
_LOGGER.debug("swallowed exception in %s", '_dtls_av_mux_run', exc_info=True)
|
|
1026
1026
|
try:
|
|
1027
1027
|
out.close()
|
|
1028
1028
|
except Exception:
|
|
1029
|
-
_LOGGER.debug("
|
|
1029
|
+
_LOGGER.debug("swallowed exception in %s", '_dtls_av_mux_run', exc_info=True)
|
|
1030
1030
|
|
|
1031
1031
|
|
|
1032
1032
|
def _h264_has_keyframe(data: bytes) -> bool:
|
|
@@ -1170,7 +1170,7 @@ def _mqtt_session_sync(
|
|
|
1170
1170
|
try:
|
|
1171
1171
|
client.disconnect()
|
|
1172
1172
|
except Exception:
|
|
1173
|
-
_LOGGER.debug("
|
|
1173
|
+
_LOGGER.debug("swallowed exception in %s", '_on_log', exc_info=True)
|
|
1174
1174
|
return [], status
|
|
1175
1175
|
|
|
1176
1176
|
if not status["connected"]:
|
|
@@ -1182,7 +1182,7 @@ def _mqtt_session_sync(
|
|
|
1182
1182
|
try:
|
|
1183
1183
|
client.disconnect()
|
|
1184
1184
|
except Exception:
|
|
1185
|
-
_LOGGER.debug("
|
|
1185
|
+
_LOGGER.debug("swallowed exception in %s", '_on_log', exc_info=True)
|
|
1186
1186
|
return [], status
|
|
1187
1187
|
|
|
1188
1188
|
_LOGGER.info("_mqtt_session: connected to %s:%d clientId=%s", hostname, port, client_id)
|
|
@@ -1199,7 +1199,7 @@ def _mqtt_session_sync(
|
|
|
1199
1199
|
try:
|
|
1200
1200
|
on_ready(status)
|
|
1201
1201
|
except Exception:
|
|
1202
|
-
_LOGGER.debug("
|
|
1202
|
+
_LOGGER.debug("swallowed exception in %s", '_on_log', exc_info=True)
|
|
1203
1203
|
|
|
1204
1204
|
collected = []
|
|
1205
1205
|
deadline = _time.monotonic() + duration
|
|
@@ -1222,7 +1222,7 @@ def _mqtt_session_sync(
|
|
|
1222
1222
|
try:
|
|
1223
1223
|
client.disconnect()
|
|
1224
1224
|
except Exception:
|
|
1225
|
-
_LOGGER.debug("
|
|
1225
|
+
_LOGGER.debug("swallowed exception in %s", '_on_log', exc_info=True)
|
|
1226
1226
|
return collected, status
|
|
1227
1227
|
pub_topic, pub_payload = out
|
|
1228
1228
|
client.publish(pub_topic, pub_payload)
|
|
@@ -1235,13 +1235,13 @@ def _mqtt_session_sync(
|
|
|
1235
1235
|
try:
|
|
1236
1236
|
on_message(*item)
|
|
1237
1237
|
except Exception:
|
|
1238
|
-
_LOGGER.debug("
|
|
1238
|
+
_LOGGER.debug("swallowed exception in %s", '_on_log', exc_info=True)
|
|
1239
1239
|
|
|
1240
1240
|
client.loop_stop()
|
|
1241
1241
|
try:
|
|
1242
1242
|
client.disconnect()
|
|
1243
1243
|
except Exception:
|
|
1244
|
-
_LOGGER.debug("
|
|
1244
|
+
_LOGGER.debug("swallowed exception in %s", '_mqtt_session_sync', exc_info=True)
|
|
1245
1245
|
return collected, status
|
|
1246
1246
|
|
|
1247
1247
|
|
|
@@ -1566,7 +1566,7 @@ async def _mqtt_get_playback_server_info(
|
|
|
1566
1566
|
pl["serverIP"] = pl.get("serverIP") or pl.get("serverIp")
|
|
1567
1567
|
result_holder.append(pl)
|
|
1568
1568
|
except Exception:
|
|
1569
|
-
_LOGGER.debug("
|
|
1569
|
+
_LOGGER.debug("swallowed exception in %s", '_check', exc_info=True)
|
|
1570
1570
|
|
|
1571
1571
|
await _mqtt_session(
|
|
1572
1572
|
mqtt_url, mqtt_user, mqtt_pwd, client_id,
|
|
@@ -192,7 +192,7 @@ class SdesSession:
|
|
|
192
192
|
try:
|
|
193
193
|
await _stop_loop.run_in_executor(None, lambda: self._proc.wait(5))
|
|
194
194
|
except Exception:
|
|
195
|
-
_LOGGER.debug("
|
|
195
|
+
_LOGGER.debug("swallowed exception in %s", 'stop', exc_info=True)
|
|
196
196
|
# Read drained stderr in the executor with a hard timeout: proc.stderr.read()
|
|
197
197
|
# blocks until EOF, which never arrives if the killed process is still a
|
|
198
198
|
# zombie / stuck in uninterruptible I/O - doing it inline would hang the
|
|
@@ -205,32 +205,32 @@ class SdesSession:
|
|
|
205
205
|
timeout=2.0,
|
|
206
206
|
)
|
|
207
207
|
except Exception: # incl. asyncio.TimeoutError - never let teardown hang here
|
|
208
|
-
_LOGGER.debug("
|
|
208
|
+
_LOGGER.debug("swallowed exception in %s", 'stop', exc_info=True)
|
|
209
209
|
# On timeout the executor thread is still blocked in stderr.read() on
|
|
210
210
|
# a wedged ffmpeg; close the pipe so that read returns instead of
|
|
211
211
|
# pinning a default-pool thread for the life of the process.
|
|
212
212
|
try:
|
|
213
213
|
self._proc.stderr.close()
|
|
214
214
|
except Exception:
|
|
215
|
-
_LOGGER.debug("
|
|
215
|
+
_LOGGER.debug("swallowed exception in %s", 'stop', exc_info=True)
|
|
216
216
|
if stderr_bytes:
|
|
217
217
|
_LOGGER.warning("ffmpeg SDES stderr:\n%s", stderr_bytes.decode(errors="replace"))
|
|
218
218
|
import os
|
|
219
219
|
try:
|
|
220
220
|
os.unlink(self._sdp_path)
|
|
221
221
|
except Exception:
|
|
222
|
-
_LOGGER.debug("
|
|
222
|
+
_LOGGER.debug("swallowed exception in %s", 'stop', exc_info=True)
|
|
223
223
|
for _sock in (self._audio_sock, self._video_sock):
|
|
224
224
|
if _sock is not None:
|
|
225
225
|
try:
|
|
226
226
|
_sock.close()
|
|
227
227
|
except Exception:
|
|
228
|
-
_LOGGER.debug("
|
|
228
|
+
_LOGGER.debug("swallowed exception in %s", 'stop', exc_info=True)
|
|
229
229
|
self._outgoing_q.put_nowait(None)
|
|
230
230
|
try:
|
|
231
231
|
await asyncio.wait_for(self._mqtt_fut, timeout=5.0)
|
|
232
232
|
except Exception:
|
|
233
|
-
_LOGGER.debug("
|
|
233
|
+
_LOGGER.debug("swallowed exception in %s", 'stop', exc_info=True)
|
|
234
234
|
|
|
235
235
|
|
|
236
236
|
def _run_sdes_talk_pump(state: dict) -> None:
|
|
@@ -297,7 +297,7 @@ def _run_sdes_talk_pump(state: dict) -> None:
|
|
|
297
297
|
try:
|
|
298
298
|
_sock.sendto(_tx.protect(_hdr + _alaw), _src)
|
|
299
299
|
except Exception:
|
|
300
|
-
_LOGGER.debug("
|
|
300
|
+
_LOGGER.debug("swallowed exception in %s", '_run_sdes_talk_pump', exc_info=True)
|
|
301
301
|
_seq = (_seq + 1) & 0xFFFF
|
|
302
302
|
_ts = (_ts + len(_alaw)) & 0xFFFFFFFF
|
|
303
303
|
# Active talk: hold 20 ms pacing for the audio cadence.
|
|
@@ -151,7 +151,7 @@ class _SdesOpenMixin:
|
|
|
151
151
|
if len(_p) == 4 and all(x.isdigit() and 0 <= int(x) <= 255 for x in _p):
|
|
152
152
|
_public_ip = _cand_pub
|
|
153
153
|
except Exception:
|
|
154
|
-
_LOGGER.debug("camera %s: swallowed exception", '_open_sdes_stream', exc_info=True)
|
|
154
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_open_sdes_stream', exc_info=True)
|
|
155
155
|
|
|
156
156
|
# Build TURN server list for _sdes_ice_server_list from ice_config if
|
|
157
157
|
# available. The camera's ICE agent uses these to gather its own relay
|
|
@@ -192,7 +192,7 @@ class _SdesOpenMixin:
|
|
|
192
192
|
"Password": _entry.get("credential") or "",
|
|
193
193
|
})
|
|
194
194
|
except Exception:
|
|
195
|
-
_LOGGER.debug("camera %s: swallowed exception", '_open_sdes_stream', exc_info=True)
|
|
195
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_open_sdes_stream', exc_info=True)
|
|
196
196
|
|
|
197
197
|
# --- TURN relay allocation helper ------------------------------------ #
|
|
198
198
|
# Defined BEFORE the offer so relay IP/port can be embedded in the
|
|
@@ -781,13 +781,13 @@ class _SdesOpenMixin:
|
|
|
781
781
|
try:
|
|
782
782
|
_seen["H264/90000_pt"] = _ln.split(":")[1].split(" ")[0]
|
|
783
783
|
except Exception:
|
|
784
|
-
_LOGGER.debug("camera %s: swallowed exception", '_k', exc_info=True)
|
|
784
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_k', exc_info=True)
|
|
785
785
|
elif "H265/90000" in _ln and _seen.get("H265/90000") is None:
|
|
786
786
|
_k(_ln, "H265/90000")
|
|
787
787
|
try:
|
|
788
788
|
_seen["H265/90000_pt"] = _ln.split(":")[1].split(" ")[0]
|
|
789
789
|
except Exception:
|
|
790
|
-
_LOGGER.debug("camera %s: swallowed exception", '_k', exc_info=True)
|
|
790
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_k', exc_info=True)
|
|
791
791
|
elif "apt=" in _ln:
|
|
792
792
|
try:
|
|
793
793
|
_apt = _ln.split("apt=")[1].strip()
|
|
@@ -878,7 +878,7 @@ class _SdesOpenMixin:
|
|
|
878
878
|
"Password": str(_e.get("Password") or ""),
|
|
879
879
|
})
|
|
880
880
|
except Exception:
|
|
881
|
-
_LOGGER.debug("camera %s: swallowed exception", '_k', exc_info=True)
|
|
881
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_k', exc_info=True)
|
|
882
882
|
# Allocate TURN relay if not already done before offer build.
|
|
883
883
|
# When ice_config provided TURN entries, pre-allocation already ran
|
|
884
884
|
# and _relay_addrs is populated - skip to avoid double-allocation.
|
|
@@ -1193,13 +1193,13 @@ class _SdesOpenMixin:
|
|
|
1193
1193
|
_hp_host = _m_hp.group(1)
|
|
1194
1194
|
_hp_port = int(_m_hp.group(2) or 3478)
|
|
1195
1195
|
except Exception:
|
|
1196
|
-
_LOGGER.debug("camera %s: swallowed exception", '_open_sdes_stream', exc_info=True)
|
|
1196
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_open_sdes_stream', exc_info=True)
|
|
1197
1197
|
_hp_stun = b'\x00\x01\x00\x00\x21\x12\xa4\x42' + os.urandom(12)
|
|
1198
1198
|
for _hp_sock in (_audio_sock, _video_sock):
|
|
1199
1199
|
try:
|
|
1200
1200
|
_hp_sock.sendto(_hp_stun, (_hp_host, _hp_port))
|
|
1201
1201
|
except Exception:
|
|
1202
|
-
_LOGGER.debug("camera %s: swallowed exception", '_send_sdes_ice_cand', exc_info=True)
|
|
1202
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_send_sdes_ice_cand', exc_info=True)
|
|
1203
1203
|
# Punch to TURN allocation port (5349) as well so port-restricted NAT
|
|
1204
1204
|
# allows traffic from either TURN port (3478 STUN or 5349 allocation).
|
|
1205
1205
|
_hp_port2 = 5349
|
|
@@ -1208,7 +1208,7 @@ class _SdesOpenMixin:
|
|
|
1208
1208
|
try:
|
|
1209
1209
|
_hp_sock.sendto(_hp_stun, (_hp_host, _hp_port2))
|
|
1210
1210
|
except Exception:
|
|
1211
|
-
_LOGGER.debug("camera %s: swallowed exception", '_send_sdes_ice_cand', exc_info=True)
|
|
1211
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_send_sdes_ice_cand', exc_info=True)
|
|
1212
1212
|
_status(
|
|
1213
1213
|
f"NAT hole-punch: sent from audio={audio_port}"
|
|
1214
1214
|
f" video={video_port} → {_hp_host}:{_hp_port}"
|
|
@@ -1260,7 +1260,7 @@ class _SdesOpenMixin:
|
|
|
1260
1260
|
try:
|
|
1261
1261
|
_rsock.setblocking(False)
|
|
1262
1262
|
except Exception:
|
|
1263
|
-
_LOGGER.debug("camera %s: swallowed exception", '_is_self_peer_ip', exc_info=True)
|
|
1263
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_is_self_peer_ip', exc_info=True)
|
|
1264
1264
|
while time.monotonic() < _stun_deadline:
|
|
1265
1265
|
# Idle-exit: threshold depends on whether we've seen any STUN yet
|
|
1266
1266
|
idle = time.monotonic() - _last_pkt_t
|
|
@@ -1398,7 +1398,7 @@ class _SdesOpenMixin:
|
|
|
1398
1398
|
_sock.sendto(_resp, _src)
|
|
1399
1399
|
_stun_count += 1
|
|
1400
1400
|
except Exception:
|
|
1401
|
-
_LOGGER.debug("camera %s: swallowed exception", '_is_self_peer_ip', exc_info=True)
|
|
1401
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_is_self_peer_ip', exc_info=True)
|
|
1402
1402
|
else:
|
|
1403
1403
|
# Non-STUN packet = SRTP arriving - ICE is done, hand off to ffmpeg now
|
|
1404
1404
|
_srtp_detected = True
|
|
@@ -1409,7 +1409,7 @@ class _SdesOpenMixin:
|
|
|
1409
1409
|
try:
|
|
1410
1410
|
_rsock.setblocking(True)
|
|
1411
1411
|
except Exception:
|
|
1412
|
-
_LOGGER.debug("camera %s: swallowed exception", '_is_self_peer_ip', exc_info=True)
|
|
1412
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_is_self_peer_ip', exc_info=True)
|
|
1413
1413
|
if _stun_count:
|
|
1414
1414
|
_status(f"ICE: responded to {_stun_count} STUN binding request(s)")
|
|
1415
1415
|
elif not _srtp_detected:
|
|
@@ -1479,7 +1479,7 @@ class _SdesOpenMixin:
|
|
|
1479
1479
|
try:
|
|
1480
1480
|
_hp_sock_r.sendto(_hp_stun, (_hp_host, _hp_port))
|
|
1481
1481
|
except Exception:
|
|
1482
|
-
_LOGGER.debug("camera %s: swallowed exception", '_is_self_peer_ip', exc_info=True)
|
|
1482
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_is_self_peer_ip', exc_info=True)
|
|
1483
1483
|
# Retry STUN window (8 s)
|
|
1484
1484
|
_stun_deadline = time.monotonic() + 8.0
|
|
1485
1485
|
_last_pkt_t = time.monotonic()
|
|
@@ -1518,7 +1518,7 @@ class _SdesOpenMixin:
|
|
|
1518
1518
|
_sk_r.sendto(_resp_r, _src_r)
|
|
1519
1519
|
_stun_count += 1
|
|
1520
1520
|
except Exception:
|
|
1521
|
-
_LOGGER.debug("camera %s: swallowed exception", '_is_self_peer_ip', exc_info=True)
|
|
1521
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_is_self_peer_ip', exc_info=True)
|
|
1522
1522
|
else:
|
|
1523
1523
|
_srtp_detected = True
|
|
1524
1524
|
break
|
|
@@ -1554,7 +1554,7 @@ class _SdesOpenMixin:
|
|
|
1554
1554
|
_pre_ans = answer_fut.result()
|
|
1555
1555
|
_pre_launch_answer_sdp = (_pre_ans or {}).get("sdp", "")
|
|
1556
1556
|
except Exception:
|
|
1557
|
-
_LOGGER.debug("camera %s: swallowed exception", '_is_self_peer_ip', exc_info=True)
|
|
1557
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_is_self_peer_ip', exc_info=True)
|
|
1558
1558
|
if _pre_launch_answer_sdp:
|
|
1559
1559
|
_LOGGER.debug(
|
|
1560
1560
|
"_open_sdes_stream: camera webrtcResp answer SDP (len=%d)",
|
|
@@ -1873,7 +1873,7 @@ class _SdesOpenMixin:
|
|
|
1873
1873
|
try:
|
|
1874
1874
|
sock.sendto(_req, cam_addr)
|
|
1875
1875
|
except Exception:
|
|
1876
|
-
_LOGGER.debug("camera %s: swallowed exception", '_send_use_candidate', exc_info=True)
|
|
1876
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_send_use_candidate', exc_info=True)
|
|
1877
1877
|
|
|
1878
1878
|
if _cam_ice_ufrag and _cam_ice_pwd and _cam_ice_cands:
|
|
1879
1879
|
for _c_ip, _c_port in _cam_ice_cands:
|
|
@@ -2100,14 +2100,14 @@ class _SdesOpenMixin:
|
|
|
2100
2100
|
_talk_state["speaker_on"] = True
|
|
2101
2101
|
_status("SDES talk: sent SPEAKERSTART(848) (bridge thread)")
|
|
2102
2102
|
except Exception:
|
|
2103
|
-
_LOGGER.debug("camera %s: swallowed exception", '_bridge_fn', exc_info=True)
|
|
2103
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_bridge_fn', exc_info=True)
|
|
2104
2104
|
elif _talk_state.get("speaker_on") and not _talk_state.get("want_speaker"):
|
|
2105
2105
|
try:
|
|
2106
2106
|
_cmd_chan[0](849, b'\x00' * 8) # SPEAKERSTOP
|
|
2107
2107
|
_talk_state["speaker_on"] = False
|
|
2108
2108
|
_status("SDES talk: sent SPEAKERSTOP(849) (bridge thread)")
|
|
2109
2109
|
except Exception:
|
|
2110
|
-
_LOGGER.debug("camera %s: swallowed exception", '_bridge_fn', exc_info=True)
|
|
2110
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_bridge_fn', exc_info=True)
|
|
2111
2111
|
|
|
2112
2112
|
# RTCP PLI (Picture Loss Indication) - forces camera to
|
|
2113
2113
|
# resend IDR + VPS/SPS/PPS so ffmpeg gets codec params.
|
|
@@ -2177,13 +2177,13 @@ class _SdesOpenMixin:
|
|
|
2177
2177
|
)
|
|
2178
2178
|
_pli_sent = True
|
|
2179
2179
|
except Exception:
|
|
2180
|
-
_LOGGER.debug("camera %s: swallowed exception", '_bridge_fn', exc_info=True)
|
|
2180
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_bridge_fn', exc_info=True)
|
|
2181
2181
|
if not _pli_sent:
|
|
2182
2182
|
try:
|
|
2183
2183
|
_bridge_fn._cam_srtp_sock.sendto(
|
|
2184
2184
|
_pli_raw, _bridge_fn._cam_srtp_src)
|
|
2185
2185
|
except Exception:
|
|
2186
|
-
_LOGGER.debug("camera %s: swallowed exception", '_bridge_fn', exc_info=True)
|
|
2186
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_bridge_fn', exc_info=True)
|
|
2187
2187
|
_bridge_fn._last_pli_ts = _time_br.time()
|
|
2188
2188
|
_pli_n = getattr(_bridge_fn, '_pli_count', 0) + 1
|
|
2189
2189
|
_bridge_fn._pli_count = _pli_n
|
|
@@ -2245,7 +2245,7 @@ class _SdesOpenMixin:
|
|
|
2245
2245
|
_csrc,
|
|
2246
2246
|
)
|
|
2247
2247
|
except Exception:
|
|
2248
|
-
_LOGGER.debug("camera %s: swallowed exception", '_persistent_sdes_cmd', exc_info=True)
|
|
2248
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_persistent_sdes_cmd', exc_info=True)
|
|
2249
2249
|
|
|
2250
2250
|
_cmd_chan[0] = _persistent_sdes_cmd
|
|
2251
2251
|
except Exception as _dw_e:
|
|
@@ -2275,7 +2275,7 @@ class _SdesOpenMixin:
|
|
|
2275
2275
|
_re_key, _AES_re2.MODE_CBC, _re_iv
|
|
2276
2276
|
).encrypt(_pad_re2(_re_plain, 16))
|
|
2277
2277
|
except Exception:
|
|
2278
|
-
_LOGGER.debug("camera %s: swallowed exception", '_bridge_fn', exc_info=True)
|
|
2278
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_bridge_fn', exc_info=True)
|
|
2279
2279
|
for _rp in [_re_enc, _re_plain]:
|
|
2280
2280
|
if _rp is None:
|
|
2281
2281
|
continue
|
|
@@ -2286,7 +2286,7 @@ class _SdesOpenMixin:
|
|
|
2286
2286
|
_trigger_bsrc,
|
|
2287
2287
|
)
|
|
2288
2288
|
except Exception:
|
|
2289
|
-
_LOGGER.debug("camera %s: swallowed exception", '_bridge_fn', exc_info=True)
|
|
2289
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_bridge_fn', exc_info=True)
|
|
2290
2290
|
_last_trigger_ts = _time_br.time()
|
|
2291
2291
|
|
|
2292
2292
|
for _bs in _rl:
|
|
@@ -2439,14 +2439,14 @@ class _SdesOpenMixin:
|
|
|
2439
2439
|
(_br_ci, _br_cp),
|
|
2440
2440
|
)
|
|
2441
2441
|
except Exception:
|
|
2442
|
-
_LOGGER.debug("camera %s: swallowed exception", '_bridge_fn', exc_info=True)
|
|
2442
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_bridge_fn', exc_info=True)
|
|
2443
2443
|
_status(
|
|
2444
2444
|
f"bridge: late USE-CANDIDATE sent (audio+video) to"
|
|
2445
2445
|
f" {len(_bridge_uc_info['cands'])} camera candidate(s)"
|
|
2446
2446
|
" (answer arrived after bridge started)"
|
|
2447
2447
|
)
|
|
2448
2448
|
except Exception:
|
|
2449
|
-
_LOGGER.debug("camera %s: swallowed exception", '_bridge_fn', exc_info=True)
|
|
2449
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_bridge_fn', exc_info=True)
|
|
2450
2450
|
elif len(_bpkt) >= 20 and _bpkt[4:8] == _STUN_MAGIC_BR:
|
|
2451
2451
|
# STUN BindingSuccess (0x0101) from camera: ICE complete.
|
|
2452
2452
|
# Send AES-128-CBC encrypted SESSION_MODE_REQ (AVIO LIVING).
|
|
@@ -2503,7 +2503,7 @@ class _SdesOpenMixin:
|
|
|
2503
2503
|
f" → {_bsrc[0]}:{_bsrc[1]}"
|
|
2504
2504
|
)
|
|
2505
2505
|
except Exception:
|
|
2506
|
-
_LOGGER.debug("camera %s: swallowed exception", '_persistent_sdes_cmd', exc_info=True)
|
|
2506
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_persistent_sdes_cmd', exc_info=True)
|
|
2507
2507
|
_avio_living_sent = True
|
|
2508
2508
|
_last_trigger_ts = _time_br.time()
|
|
2509
2509
|
_trigger_bs = _bs
|
|
@@ -2880,12 +2880,12 @@ class _SdesOpenMixin:
|
|
|
2880
2880
|
_bs.sendto(_rr_sess.protect_rtcp(_rr_pkt), _bsrc)
|
|
2881
2881
|
_rtcp_sent = True
|
|
2882
2882
|
except Exception:
|
|
2883
|
-
_LOGGER.debug("camera %s: swallowed exception", '_persistent_sdes_cmd', exc_info=True)
|
|
2883
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_persistent_sdes_cmd', exc_info=True)
|
|
2884
2884
|
if not _rtcp_sent:
|
|
2885
2885
|
try:
|
|
2886
2886
|
_bs.sendto(_rr_pkt, _bsrc)
|
|
2887
2887
|
except Exception:
|
|
2888
|
-
_LOGGER.debug("camera %s: swallowed exception", '_enc_c8_sctp', exc_info=True)
|
|
2888
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_enc_c8_sctp', exc_info=True)
|
|
2889
2889
|
if _bridge_fn._tutk_count == 1:
|
|
2890
2890
|
_status(
|
|
2891
2891
|
f"SDES: sent RTCP RR to camera"
|
|
@@ -2917,7 +2917,7 @@ class _SdesOpenMixin:
|
|
|
2917
2917
|
f" ({len(_pd_plain)}B PCMA)"
|
|
2918
2918
|
)
|
|
2919
2919
|
except Exception:
|
|
2920
|
-
_LOGGER.debug("camera %s: swallowed exception", '_enc_c8_sctp', exc_info=True)
|
|
2920
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_enc_c8_sctp', exc_info=True)
|
|
2921
2921
|
continue
|
|
2922
2922
|
|
|
2923
2923
|
# Standard SRTP/SRTCP demux by RTP payload type.
|
|
@@ -2955,11 +2955,11 @@ class _SdesOpenMixin:
|
|
|
2955
2955
|
try:
|
|
2956
2956
|
_lo_a.sendto(_bpkt, ('127.0.0.1', _lo_audio_port))
|
|
2957
2957
|
except Exception:
|
|
2958
|
-
_LOGGER.debug("camera %s: swallowed exception", '_bridge_fn', exc_info=True)
|
|
2958
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_bridge_fn', exc_info=True)
|
|
2959
2959
|
try:
|
|
2960
2960
|
_lo_v.sendto(_bpkt, ('127.0.0.1', _lo_video_port))
|
|
2961
2961
|
except Exception:
|
|
2962
|
-
_LOGGER.debug("camera %s: swallowed exception", '_bridge_fn', exc_info=True)
|
|
2962
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_bridge_fn', exc_info=True)
|
|
2963
2963
|
continue
|
|
2964
2964
|
_pt = _pt_byte & 0x7F
|
|
2965
2965
|
if _pt in (96, 97, 98):
|
|
@@ -3138,7 +3138,7 @@ class _SdesOpenMixin:
|
|
|
3138
3138
|
)
|
|
3139
3139
|
_media_progress[0] = _time_br.monotonic()
|
|
3140
3140
|
except Exception:
|
|
3141
|
-
_LOGGER.debug("camera %s: swallowed exception", '_bridge_fn', exc_info=True)
|
|
3141
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_bridge_fn', exc_info=True)
|
|
3142
3142
|
# Periodic ICE controlling check: re-send USE-CANDIDATE every 2.5 s.
|
|
3143
3143
|
# Keeps the camera in ICE "Completed" state and satisfies consent
|
|
3144
3144
|
# refresh (RFC 7675). Also handles the case where the initial
|
|
@@ -3159,11 +3159,11 @@ class _SdesOpenMixin:
|
|
|
3159
3159
|
try:
|
|
3160
3160
|
_lo_a.close()
|
|
3161
3161
|
except Exception:
|
|
3162
|
-
_LOGGER.debug("camera %s: swallowed exception", '_bridge_fn', exc_info=True)
|
|
3162
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_bridge_fn', exc_info=True)
|
|
3163
3163
|
try:
|
|
3164
3164
|
_lo_v.close()
|
|
3165
3165
|
except Exception:
|
|
3166
|
-
_LOGGER.debug("camera %s: swallowed exception", '_bridge_fn', exc_info=True)
|
|
3166
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_bridge_fn', exc_info=True)
|
|
3167
3167
|
|
|
3168
3168
|
_br_first_di_logged = False
|
|
3169
3169
|
_br_first_srtp_logged = False
|
|
@@ -3222,11 +3222,11 @@ class _SdesOpenMixin:
|
|
|
3222
3222
|
try:
|
|
3223
3223
|
_rsock.close()
|
|
3224
3224
|
except Exception:
|
|
3225
|
-
_LOGGER.debug("camera %s: swallowed exception", '_bridge_fn', exc_info=True)
|
|
3225
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_bridge_fn', exc_info=True)
|
|
3226
3226
|
try:
|
|
3227
3227
|
os.unlink(sdp_path)
|
|
3228
3228
|
except Exception:
|
|
3229
|
-
_LOGGER.debug("camera %s: swallowed exception", '_bridge_fn', exc_info=True)
|
|
3229
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_bridge_fn', exc_info=True)
|
|
3230
3230
|
outgoing_q.put_nowait(None) # stop MQTT thread
|
|
3231
3231
|
raise CameraMixin._SdesNoAnswerError()
|
|
3232
3232
|
elif (_cam_echo_received
|
|
@@ -3309,7 +3309,7 @@ class _SdesOpenMixin:
|
|
|
3309
3309
|
f"SDES: narrowed ffmpeg SDP to video pt={_vpt}"
|
|
3310
3310
|
f" ({'H265' if int(_vpt) == 97 else 'H264'})")
|
|
3311
3311
|
except Exception:
|
|
3312
|
-
_LOGGER.debug("camera %s: swallowed exception", '_open_sdes_stream', exc_info=True)
|
|
3312
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_open_sdes_stream', exc_info=True)
|
|
3313
3313
|
_LOGGER.info("SDES ffmpeg cmd: %s", " ".join(cmd))
|
|
3314
3314
|
if _ffmpeg_path() is None:
|
|
3315
3315
|
# ffmpeg is not installed - clean up and surface a clear error
|
|
@@ -3318,11 +3318,11 @@ class _SdesOpenMixin:
|
|
|
3318
3318
|
try:
|
|
3319
3319
|
_rsock.close()
|
|
3320
3320
|
except Exception:
|
|
3321
|
-
_LOGGER.debug("camera %s: swallowed exception", '_bridge_fn', exc_info=True)
|
|
3321
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_bridge_fn', exc_info=True)
|
|
3322
3322
|
try:
|
|
3323
3323
|
os.unlink(sdp_path)
|
|
3324
3324
|
except Exception:
|
|
3325
|
-
_LOGGER.debug("camera %s: swallowed exception", '_bridge_fn', exc_info=True)
|
|
3325
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_bridge_fn', exc_info=True)
|
|
3326
3326
|
outgoing_q.put_nowait(None) # stop MQTT thread
|
|
3327
3327
|
raise RuntimeError(
|
|
3328
3328
|
"ffmpeg not found - install ffmpeg to stream SDES-SRTP cameras.\n"
|
|
@@ -3343,11 +3343,11 @@ class _SdesOpenMixin:
|
|
|
3343
3343
|
try:
|
|
3344
3344
|
_rsock.close()
|
|
3345
3345
|
except Exception:
|
|
3346
|
-
_LOGGER.debug("camera %s: swallowed exception", '_bridge_fn', exc_info=True)
|
|
3346
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_bridge_fn', exc_info=True)
|
|
3347
3347
|
try:
|
|
3348
3348
|
os.unlink(sdp_path)
|
|
3349
3349
|
except Exception:
|
|
3350
|
-
_LOGGER.debug("camera %s: swallowed exception", '_bridge_fn', exc_info=True)
|
|
3350
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_bridge_fn', exc_info=True)
|
|
3351
3351
|
outgoing_q.put_nowait(None) # stop MQTT thread
|
|
3352
3352
|
raise RuntimeError(
|
|
3353
3353
|
"ffmpeg not found - install ffmpeg to stream SDES-SRTP cameras.\n"
|
|
@@ -3591,11 +3591,11 @@ class _SdesOpenMixin:
|
|
|
3591
3591
|
try:
|
|
3592
3592
|
_rsock.close()
|
|
3593
3593
|
except Exception:
|
|
3594
|
-
_LOGGER.debug("camera %s: swallowed exception", '_udp_port_bound', exc_info=True)
|
|
3594
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_udp_port_bound', exc_info=True)
|
|
3595
3595
|
try:
|
|
3596
3596
|
os.unlink(sdp_path)
|
|
3597
3597
|
except Exception:
|
|
3598
|
-
_LOGGER.debug("camera %s: swallowed exception", '_udp_port_bound', exc_info=True)
|
|
3598
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_udp_port_bound', exc_info=True)
|
|
3599
3599
|
outgoing_q.put_nowait(None) # signal MQTT thread to exit
|
|
3600
3600
|
raise CameraMixin._SdesNoAnswerError()
|
|
3601
3601
|
else:
|
|
@@ -3654,7 +3654,7 @@ class _SdesOpenMixin:
|
|
|
3654
3654
|
+ (" [m=app]" if _dc_answer_has_app else "")
|
|
3655
3655
|
)
|
|
3656
3656
|
except Exception:
|
|
3657
|
-
_LOGGER.debug("camera %s: swallowed exception", '_late_second_answer_task', exc_info=True)
|
|
3657
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_late_second_answer_task', exc_info=True)
|
|
3658
3658
|
_spawn_bg(_late_second_answer_task())
|
|
3659
3659
|
|
|
3660
3660
|
return SdesSession(
|
|
@@ -249,12 +249,12 @@ class TutkStreamSession:
|
|
|
249
249
|
try:
|
|
250
250
|
av.avClientStop(self._av_index)
|
|
251
251
|
except Exception:
|
|
252
|
-
_LOGGER.debug("
|
|
252
|
+
_LOGGER.debug("swallowed exception in %s", '_recv_loop', exc_info=True)
|
|
253
253
|
if self._sid >= 0:
|
|
254
254
|
try:
|
|
255
255
|
iotc.IOTC_Session_Close(self._sid)
|
|
256
256
|
except Exception:
|
|
257
|
-
_LOGGER.debug("
|
|
257
|
+
_LOGGER.debug("swallowed exception in %s", '_recv_loop', exc_info=True)
|
|
258
258
|
_LOGGER.debug("TUTK: recv loop exited")
|
|
259
259
|
|
|
260
260
|
async def stop(self) -> None:
|
|
@@ -106,7 +106,7 @@ class WebRTCSession:
|
|
|
106
106
|
if self._audio_sender is not None:
|
|
107
107
|
self._audio_sender.replaceTrack(None)
|
|
108
108
|
except Exception:
|
|
109
|
-
_LOGGER.debug("
|
|
109
|
+
_LOGGER.debug("swallowed exception in %s", 'async_stop_talk', exc_info=True)
|
|
110
110
|
self._talk_holder["provider"] = None
|
|
111
111
|
return True
|
|
112
112
|
|
|
@@ -185,18 +185,18 @@ class WebRTCSession:
|
|
|
185
185
|
self._talk_holder["was_active"] = False
|
|
186
186
|
await asyncio.sleep(0.4) # let the DataChannel deliver SPEAKERSTOP
|
|
187
187
|
except Exception:
|
|
188
|
-
_LOGGER.debug("
|
|
188
|
+
_LOGGER.debug("swallowed exception in %s", 'stop', exc_info=True)
|
|
189
189
|
for task in self._track_tasks:
|
|
190
190
|
task.cancel()
|
|
191
191
|
if self._recorder is not None:
|
|
192
192
|
try:
|
|
193
193
|
await self._recorder.stop()
|
|
194
194
|
except Exception:
|
|
195
|
-
_LOGGER.debug("
|
|
195
|
+
_LOGGER.debug("swallowed exception in %s", 'stop', exc_info=True)
|
|
196
196
|
# Send None sentinel to stop the MQTT session in its thread
|
|
197
197
|
self._outgoing_q.put_nowait(None)
|
|
198
198
|
await self._pc.close()
|
|
199
199
|
try:
|
|
200
200
|
await asyncio.wait_for(self._mqtt_fut, timeout=5.0)
|
|
201
201
|
except Exception:
|
|
202
|
-
_LOGGER.debug("
|
|
202
|
+
_LOGGER.debug("swallowed exception in %s", 'stop', exc_info=True)
|
|
@@ -193,7 +193,7 @@ class _WebRTCOpenMixin:
|
|
|
193
193
|
try:
|
|
194
194
|
await self.async_wake_camera()
|
|
195
195
|
except Exception:
|
|
196
|
-
_LOGGER.debug("camera %s: swallowed exception", '_async_open_webrtc_stream_impl', exc_info=True)
|
|
196
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_async_open_webrtc_stream_impl', exc_info=True)
|
|
197
197
|
|
|
198
198
|
if not use_sdes:
|
|
199
199
|
try:
|
|
@@ -1105,7 +1105,7 @@ class _WebRTCOpenMixin:
|
|
|
1105
1105
|
except RuntimeError:
|
|
1106
1106
|
raise
|
|
1107
1107
|
except Exception:
|
|
1108
|
-
_LOGGER.debug("camera %s: swallowed exception", '_http_keepalive', exc_info=True)
|
|
1108
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_http_keepalive', exc_info=True)
|
|
1109
1109
|
|
|
1110
1110
|
# ------------------------------------------------------------------ #
|
|
1111
1111
|
# Branch: SDES-SRTP cameras use ffmpeg; DTLS cameras use aiortc
|
|
@@ -1441,7 +1441,7 @@ class _WebRTCOpenMixin:
|
|
|
1441
1441
|
_hdr = struct.pack("<IIqII4x", _seq, 5156, _ts_ms, 0, 0)
|
|
1442
1442
|
_dc_ref.send(_hdr)
|
|
1443
1443
|
except Exception:
|
|
1444
|
-
_LOGGER.debug("camera %s: swallowed exception", '_send_avio_heartbeat', exc_info=True)
|
|
1444
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_send_avio_heartbeat', exc_info=True)
|
|
1445
1445
|
|
|
1446
1446
|
def _send_avio_audiostart(_dc_ref) -> None:
|
|
1447
1447
|
# IOTYPE_USER_IPCAM_AUDIOSTART = 768 (AVIOCTRLDEFs.java:154).
|
|
@@ -1460,7 +1460,7 @@ class _WebRTCOpenMixin:
|
|
|
1460
1460
|
_hdr = struct.pack("<IIqII4x", _seq, 768, _ts_ms, len(_payload), 0)
|
|
1461
1461
|
_dc_ref.send(_hdr + _payload)
|
|
1462
1462
|
except Exception:
|
|
1463
|
-
_LOGGER.debug("camera %s: swallowed exception", '_send_avio_audiostart', exc_info=True)
|
|
1463
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_send_avio_audiostart', exc_info=True)
|
|
1464
1464
|
|
|
1465
1465
|
def _send_avio_speaker(_dc_ref, start: bool) -> None:
|
|
1466
1466
|
# IOTYPE_USER_IPCAM_SPEAKERSTART = 848 / SPEAKERSTOP = 849
|
|
@@ -1507,7 +1507,7 @@ class _WebRTCOpenMixin:
|
|
|
1507
1507
|
else:
|
|
1508
1508
|
_status(f"DC[remote:{channel.label}] RX text {message!r}")
|
|
1509
1509
|
except Exception:
|
|
1510
|
-
_LOGGER.debug("camera %s: swallowed exception", '_on_remote_dc_message', exc_info=True)
|
|
1510
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_on_remote_dc_message', exc_info=True)
|
|
1511
1511
|
|
|
1512
1512
|
track_tasks: list = []
|
|
1513
1513
|
_kvs_dc = None
|
|
@@ -1617,7 +1617,7 @@ class _WebRTCOpenMixin:
|
|
|
1617
1617
|
else:
|
|
1618
1618
|
_status(f"DC[{_dc_label}] RX text {message!r}")
|
|
1619
1619
|
except Exception:
|
|
1620
|
-
_LOGGER.debug("camera %s: swallowed exception", '_on_kvs_dc_message', exc_info=True)
|
|
1620
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_on_kvs_dc_message', exc_info=True)
|
|
1621
1621
|
|
|
1622
1622
|
# Periodic readyState diagnostic - last run had no "DC OPEN"
|
|
1623
1623
|
# log line, so we want to see whether readyState ever transitions
|
|
@@ -1679,7 +1679,7 @@ class _WebRTCOpenMixin:
|
|
|
1679
1679
|
while True:
|
|
1680
1680
|
await track.recv()
|
|
1681
1681
|
except Exception:
|
|
1682
|
-
_LOGGER.debug("camera %s: swallowed exception", '_drain_audio', exc_info=True)
|
|
1682
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_drain_audio', exc_info=True)
|
|
1683
1683
|
t = asyncio.ensure_future(_drain_audio())
|
|
1684
1684
|
track_tasks.append(t)
|
|
1685
1685
|
elif track.kind == "video":
|
|
@@ -1767,7 +1767,7 @@ class _WebRTCOpenMixin:
|
|
|
1767
1767
|
_LOGGER.debug(
|
|
1768
1768
|
"highport-fix: scoped to this DTLS camera connection")
|
|
1769
1769
|
except Exception:
|
|
1770
|
-
_LOGGER.debug("camera %s: swallowed exception", '_on_track', exc_info=True)
|
|
1770
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_on_track', exc_info=True)
|
|
1771
1771
|
|
|
1772
1772
|
|
|
1773
1773
|
_sdp = pc.localDescription.sdp
|
|
@@ -2723,7 +2723,7 @@ class _WebRTCOpenMixin:
|
|
|
2723
2723
|
_NPFp(algorithm="sha-256", value=_real_fp)
|
|
2724
2724
|
]
|
|
2725
2725
|
except Exception:
|
|
2726
|
-
_LOGGER.debug("camera %s: swallowed exception", '_np_accept_cam_cert', exc_info=True)
|
|
2726
|
+
_LOGGER.debug("camera %s: swallowed exception in %s", getattr(self, "device_id", "?"), '_np_accept_cam_cert', exc_info=True)
|
|
2727
2727
|
|
|
2728
2728
|
# Diag: log PC/ICE state at patch-application time so we
|
|
2729
2729
|
# can see whether DTLS handshake has *already* started by
|
{python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1/src/python_aidot_cameras.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-aidot-cameras
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.1
|
|
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
|
|
@@ -11,11 +11,11 @@ Classifier: Operating System :: OS Independent
|
|
|
11
11
|
Requires-Python: >=3.11
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
|
-
Requires-Dist: aiohttp
|
|
14
|
+
Requires-Dist: aiohttp>=3.9
|
|
15
15
|
Requires-Dist: paho-mqtt>=2.0
|
|
16
|
-
Requires-Dist: cryptography
|
|
17
|
-
Requires-Dist: pycryptodome
|
|
18
|
-
Requires-Dist: dacite
|
|
16
|
+
Requires-Dist: cryptography>=42.0
|
|
17
|
+
Requires-Dist: pycryptodome>=3.20
|
|
18
|
+
Requires-Dist: dacite>=1.8
|
|
19
19
|
Provides-Extra: webrtc
|
|
20
20
|
Requires-Dist: aiortc>=1.9.0; extra == "webrtc"
|
|
21
21
|
Requires-Dist: aioice<0.12,>=0.9.0; extra == "webrtc"
|
|
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-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/models/device_client_model.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/src/aidot/models/discover_model.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_persistent_mqtt_robustness.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.9.0 → python_aidot_cameras-0.9.1}/tests/test_post_merge_hardening.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
|