matrice-streaming 0.1.14__py3-none-any.whl → 0.1.65__py3-none-any.whl
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.
- matrice_streaming/__init__.py +44 -32
- matrice_streaming/streaming_gateway/camera_streamer/__init__.py +68 -1
- matrice_streaming/streaming_gateway/camera_streamer/async_camera_worker.py +1388 -0
- matrice_streaming/streaming_gateway/camera_streamer/async_ffmpeg_worker.py +966 -0
- matrice_streaming/streaming_gateway/camera_streamer/camera_streamer.py +188 -24
- matrice_streaming/streaming_gateway/camera_streamer/device_detection.py +507 -0
- matrice_streaming/streaming_gateway/camera_streamer/encoding_pool_manager.py +136 -0
- matrice_streaming/streaming_gateway/camera_streamer/ffmpeg_camera_streamer.py +1048 -0
- matrice_streaming/streaming_gateway/camera_streamer/ffmpeg_config.py +192 -0
- matrice_streaming/streaming_gateway/camera_streamer/ffmpeg_worker_manager.py +470 -0
- matrice_streaming/streaming_gateway/camera_streamer/gstreamer_camera_streamer.py +1368 -0
- matrice_streaming/streaming_gateway/camera_streamer/gstreamer_worker.py +1063 -0
- matrice_streaming/streaming_gateway/camera_streamer/gstreamer_worker_manager.py +546 -0
- matrice_streaming/streaming_gateway/camera_streamer/message_builder.py +60 -15
- matrice_streaming/streaming_gateway/camera_streamer/nvdec.py +1330 -0
- matrice_streaming/streaming_gateway/camera_streamer/nvdec_worker_manager.py +412 -0
- matrice_streaming/streaming_gateway/camera_streamer/platform_pipelines.py +680 -0
- matrice_streaming/streaming_gateway/camera_streamer/stream_statistics.py +111 -4
- matrice_streaming/streaming_gateway/camera_streamer/video_capture_manager.py +223 -27
- matrice_streaming/streaming_gateway/camera_streamer/worker_manager.py +694 -0
- matrice_streaming/streaming_gateway/debug/__init__.py +27 -2
- matrice_streaming/streaming_gateway/debug/benchmark.py +727 -0
- matrice_streaming/streaming_gateway/debug/debug_gstreamer_gateway.py +599 -0
- matrice_streaming/streaming_gateway/debug/debug_streaming_gateway.py +245 -95
- matrice_streaming/streaming_gateway/debug/debug_utils.py +29 -0
- matrice_streaming/streaming_gateway/debug/test_videoplayback.py +318 -0
- matrice_streaming/streaming_gateway/dynamic_camera_manager.py +656 -39
- matrice_streaming/streaming_gateway/metrics_reporter.py +676 -139
- matrice_streaming/streaming_gateway/streaming_action.py +71 -20
- matrice_streaming/streaming_gateway/streaming_gateway.py +1026 -78
- matrice_streaming/streaming_gateway/streaming_gateway_utils.py +175 -20
- matrice_streaming/streaming_gateway/streaming_status_listener.py +89 -0
- {matrice_streaming-0.1.14.dist-info → matrice_streaming-0.1.65.dist-info}/METADATA +1 -1
- matrice_streaming-0.1.65.dist-info/RECORD +56 -0
- matrice_streaming-0.1.14.dist-info/RECORD +0 -38
- {matrice_streaming-0.1.14.dist-info → matrice_streaming-0.1.65.dist-info}/WHEEL +0 -0
- {matrice_streaming-0.1.14.dist-info → matrice_streaming-0.1.65.dist-info}/licenses/LICENSE.txt +0 -0
- {matrice_streaming-0.1.14.dist-info → matrice_streaming-0.1.65.dist-info}/top_level.txt +0 -0
|
@@ -15,6 +15,7 @@ from matrice_common.rpc import RPC
|
|
|
15
15
|
from .streaming_gateway import StreamingGateway
|
|
16
16
|
from .streaming_gateway_utils import StreamingGatewayUtil
|
|
17
17
|
from .metrics_reporter import MetricsManager, MetricsConfig
|
|
18
|
+
from .streaming_status_listener import StreamingStatusListener
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
class StreamingAction:
|
|
@@ -56,11 +57,12 @@ class StreamingAction:
|
|
|
56
57
|
session: Session,
|
|
57
58
|
action_id: str,
|
|
58
59
|
enable_intelligent_transmission: bool = True,
|
|
59
|
-
monitoring_interval: float = 30.0,
|
|
60
|
+
monitoring_interval: float = 30.0, # Heartbeat sent every monitoring_interval seconds
|
|
60
61
|
auto_restart: bool = True,
|
|
61
62
|
max_restart_attempts: int = 3,
|
|
62
|
-
action_id_check_interval: float =
|
|
63
|
+
action_id_check_interval: float = 600.0, # 10 minutes (was 60 seconds)
|
|
63
64
|
enable_event_listening: bool = True,
|
|
65
|
+
allow_empty_start: bool = True, # Allow starting with zero cameras
|
|
64
66
|
):
|
|
65
67
|
"""Initialize StreamingAction.
|
|
66
68
|
|
|
@@ -68,11 +70,12 @@ class StreamingAction:
|
|
|
68
70
|
session: Session object for authentication
|
|
69
71
|
action_id: ID of the action to manage
|
|
70
72
|
enable_intelligent_transmission: Whether to enable intelligent frame transmission
|
|
71
|
-
monitoring_interval: Interval in seconds between health checks
|
|
73
|
+
monitoring_interval: Interval in seconds between health checks and heartbeats (default: 30 seconds)
|
|
72
74
|
auto_restart: Whether to automatically restart on failures
|
|
73
75
|
max_restart_attempts: Maximum number of restart attempts before giving up
|
|
74
76
|
action_id_check_interval: Interval in seconds between checks to verify action ID matches streaming gateway
|
|
75
77
|
enable_event_listening: Enable dynamic event listening for configuration updates
|
|
78
|
+
allow_empty_start: Allow starting with zero cameras (default True). Cameras can be added dynamically.
|
|
76
79
|
"""
|
|
77
80
|
if not session:
|
|
78
81
|
raise ValueError("Session is required")
|
|
@@ -141,10 +144,11 @@ class StreamingAction:
|
|
|
141
144
|
self.max_restart_attempts = max_restart_attempts
|
|
142
145
|
self.action_id_check_interval = action_id_check_interval
|
|
143
146
|
self.enable_event_listening = enable_event_listening
|
|
147
|
+
self.allow_empty_start = allow_empty_start
|
|
144
148
|
|
|
145
149
|
# Initialize utility and gateway objects
|
|
146
150
|
self.gateway_util = StreamingGatewayUtil(
|
|
147
|
-
session, self.streaming_gateway_id, self.server_id
|
|
151
|
+
session, self.streaming_gateway_id, self.server_id, action_id=self.action_id
|
|
148
152
|
)
|
|
149
153
|
self.streaming_gateway: Optional[StreamingGateway] = None
|
|
150
154
|
|
|
@@ -174,6 +178,9 @@ class StreamingAction:
|
|
|
174
178
|
# Initialize metrics manager
|
|
175
179
|
self.metrics_manager: Optional[MetricsManager] = None
|
|
176
180
|
|
|
181
|
+
# Initialize status listener for stop commands
|
|
182
|
+
self.status_listener: Optional[StreamingStatusListener] = None
|
|
183
|
+
|
|
177
184
|
logging.info(
|
|
178
185
|
"StreamingAction initialized successfully for gateway: %s",
|
|
179
186
|
self.streaming_gateway_id,
|
|
@@ -242,11 +249,18 @@ class StreamingAction:
|
|
|
242
249
|
input_streams = self.gateway_util.get_input_streams()
|
|
243
250
|
|
|
244
251
|
if not input_streams:
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
252
|
+
if self.allow_empty_start:
|
|
253
|
+
logging.warning(
|
|
254
|
+
"No input streams configured - starting with zero cameras. "
|
|
255
|
+
"Cameras can be added dynamically via event listener."
|
|
256
|
+
)
|
|
257
|
+
input_streams = []
|
|
258
|
+
else:
|
|
259
|
+
raise RuntimeError(
|
|
260
|
+
"No input streams configured for this streaming gateway"
|
|
261
|
+
)
|
|
262
|
+
else:
|
|
263
|
+
logging.info("Found %d input streams configured", len(input_streams))
|
|
250
264
|
|
|
251
265
|
# Create StreamingGateway with fetched configuration
|
|
252
266
|
logging.info("Creating StreamingGateway instance...")
|
|
@@ -259,6 +273,8 @@ class StreamingAction:
|
|
|
259
273
|
video_codec=self.video_codec, # Pass video codec setting
|
|
260
274
|
force_restart=True, # Always force restart for orchestrator
|
|
261
275
|
enable_event_listening=self.enable_event_listening, # Enable dynamic event updates
|
|
276
|
+
action_id=self.action_id, # Pass action_id for API requests
|
|
277
|
+
allow_empty_start=self.allow_empty_start, # Allow starting with zero cameras
|
|
262
278
|
)
|
|
263
279
|
|
|
264
280
|
# Start streaming
|
|
@@ -271,7 +287,7 @@ class StreamingAction:
|
|
|
271
287
|
logging.info("Initializing metrics manager...")
|
|
272
288
|
metrics_config = MetricsConfig(
|
|
273
289
|
collection_interval=1.0, # Collect every second
|
|
274
|
-
reporting_interval=
|
|
290
|
+
reporting_interval=30.0, # Report every 30 seconds
|
|
275
291
|
)
|
|
276
292
|
self.metrics_manager = MetricsManager(
|
|
277
293
|
streaming_gateway=self.streaming_gateway,
|
|
@@ -296,8 +312,26 @@ class StreamingAction:
|
|
|
296
312
|
# Start health monitoring thread
|
|
297
313
|
self._start_monitoring()
|
|
298
314
|
|
|
299
|
-
#
|
|
300
|
-
|
|
315
|
+
# Initialize and start status listener for stop commands
|
|
316
|
+
try:
|
|
317
|
+
self.status_listener = StreamingStatusListener(
|
|
318
|
+
session=self.session,
|
|
319
|
+
streaming_gateway_id=self.streaming_gateway_id,
|
|
320
|
+
action_id=self.action_id,
|
|
321
|
+
on_stop_callback=self.stop
|
|
322
|
+
)
|
|
323
|
+
self.status_listener.start()
|
|
324
|
+
logging.info("Status listener started for stop commands")
|
|
325
|
+
except Exception as exc:
|
|
326
|
+
logging.warning(f"Failed to initialize status listener: {exc}", exc_info=True)
|
|
327
|
+
self.status_listener = None
|
|
328
|
+
|
|
329
|
+
# Update gateway status to running
|
|
330
|
+
try:
|
|
331
|
+
self.gateway_util.update_status("running")
|
|
332
|
+
logging.info("Gateway status updated to 'running'")
|
|
333
|
+
except Exception as exc:
|
|
334
|
+
logging.warning(f"Failed to update gateway status to running: {exc}")
|
|
301
335
|
|
|
302
336
|
logging.info("StreamingAction started successfully")
|
|
303
337
|
|
|
@@ -350,6 +384,14 @@ class StreamingAction:
|
|
|
350
384
|
if self._monitor_thread.is_alive():
|
|
351
385
|
logging.warning("Monitor thread did not stop gracefully")
|
|
352
386
|
|
|
387
|
+
# Stop status listener
|
|
388
|
+
if self.status_listener:
|
|
389
|
+
try:
|
|
390
|
+
logging.info("Stopping status listener...")
|
|
391
|
+
self.status_listener.stop()
|
|
392
|
+
except Exception as exc:
|
|
393
|
+
logging.warning(f"Error stopping status listener: {exc}")
|
|
394
|
+
|
|
353
395
|
# Stop metrics manager
|
|
354
396
|
if self.metrics_manager:
|
|
355
397
|
try:
|
|
@@ -467,8 +509,13 @@ class StreamingAction:
|
|
|
467
509
|
"""
|
|
468
510
|
Check if the current action ID matches the streaming gateway's actionRecordID.
|
|
469
511
|
|
|
512
|
+
Handles transient errors gracefully:
|
|
513
|
+
- 502 Bad Gateway: Skip check, continue streaming (server temporarily unavailable)
|
|
514
|
+
- 404 Not Found: Stop streaming (gateway may be deleted)
|
|
515
|
+
- Other API errors: Skip check, continue streaming (don't stop on transient issues)
|
|
516
|
+
|
|
470
517
|
Returns:
|
|
471
|
-
bool: True if action ID matches, False
|
|
518
|
+
bool: True if action ID matches or check should be skipped, False if mismatch or gateway deleted
|
|
472
519
|
"""
|
|
473
520
|
try:
|
|
474
521
|
self.stats["action_id_checks"] += 1
|
|
@@ -476,12 +523,13 @@ class StreamingAction:
|
|
|
476
523
|
# Fetch current streaming gateway details
|
|
477
524
|
gateway_details = self.gateway_util.get_streaming_gateway_by_id()
|
|
478
525
|
|
|
479
|
-
|
|
526
|
+
# Handle API failures gracefully - don't stop streaming on transient errors
|
|
527
|
+
if gateway_details is None:
|
|
480
528
|
logging.warning(
|
|
481
|
-
"Failed to fetch
|
|
529
|
+
"Action ID check: Failed to fetch gateway details (API returned None), skipping check"
|
|
482
530
|
)
|
|
483
|
-
|
|
484
|
-
return
|
|
531
|
+
# Don't increment failure counter - this is expected during transient issues
|
|
532
|
+
return True # Continue streaming, don't stop on API errors
|
|
485
533
|
|
|
486
534
|
gateway_action_id = gateway_details.get("actionRecordID", "")
|
|
487
535
|
|
|
@@ -502,9 +550,12 @@ class StreamingAction:
|
|
|
502
550
|
return True
|
|
503
551
|
|
|
504
552
|
except Exception as exc:
|
|
505
|
-
|
|
506
|
-
logging.
|
|
507
|
-
|
|
553
|
+
# Unknown error - don't stop streaming on unexpected issues
|
|
554
|
+
logging.warning(
|
|
555
|
+
"Action ID check: Unexpected error '%s', skipping check to avoid false shutdown",
|
|
556
|
+
str(exc)
|
|
557
|
+
)
|
|
558
|
+
return True # Continue streaming, be conservative
|
|
508
559
|
|
|
509
560
|
def _start_monitoring(self):
|
|
510
561
|
"""Start the health monitoring thread."""
|