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.
Files changed (38) hide show
  1. matrice_streaming/__init__.py +44 -32
  2. matrice_streaming/streaming_gateway/camera_streamer/__init__.py +68 -1
  3. matrice_streaming/streaming_gateway/camera_streamer/async_camera_worker.py +1388 -0
  4. matrice_streaming/streaming_gateway/camera_streamer/async_ffmpeg_worker.py +966 -0
  5. matrice_streaming/streaming_gateway/camera_streamer/camera_streamer.py +188 -24
  6. matrice_streaming/streaming_gateway/camera_streamer/device_detection.py +507 -0
  7. matrice_streaming/streaming_gateway/camera_streamer/encoding_pool_manager.py +136 -0
  8. matrice_streaming/streaming_gateway/camera_streamer/ffmpeg_camera_streamer.py +1048 -0
  9. matrice_streaming/streaming_gateway/camera_streamer/ffmpeg_config.py +192 -0
  10. matrice_streaming/streaming_gateway/camera_streamer/ffmpeg_worker_manager.py +470 -0
  11. matrice_streaming/streaming_gateway/camera_streamer/gstreamer_camera_streamer.py +1368 -0
  12. matrice_streaming/streaming_gateway/camera_streamer/gstreamer_worker.py +1063 -0
  13. matrice_streaming/streaming_gateway/camera_streamer/gstreamer_worker_manager.py +546 -0
  14. matrice_streaming/streaming_gateway/camera_streamer/message_builder.py +60 -15
  15. matrice_streaming/streaming_gateway/camera_streamer/nvdec.py +1330 -0
  16. matrice_streaming/streaming_gateway/camera_streamer/nvdec_worker_manager.py +412 -0
  17. matrice_streaming/streaming_gateway/camera_streamer/platform_pipelines.py +680 -0
  18. matrice_streaming/streaming_gateway/camera_streamer/stream_statistics.py +111 -4
  19. matrice_streaming/streaming_gateway/camera_streamer/video_capture_manager.py +223 -27
  20. matrice_streaming/streaming_gateway/camera_streamer/worker_manager.py +694 -0
  21. matrice_streaming/streaming_gateway/debug/__init__.py +27 -2
  22. matrice_streaming/streaming_gateway/debug/benchmark.py +727 -0
  23. matrice_streaming/streaming_gateway/debug/debug_gstreamer_gateway.py +599 -0
  24. matrice_streaming/streaming_gateway/debug/debug_streaming_gateway.py +245 -95
  25. matrice_streaming/streaming_gateway/debug/debug_utils.py +29 -0
  26. matrice_streaming/streaming_gateway/debug/test_videoplayback.py +318 -0
  27. matrice_streaming/streaming_gateway/dynamic_camera_manager.py +656 -39
  28. matrice_streaming/streaming_gateway/metrics_reporter.py +676 -139
  29. matrice_streaming/streaming_gateway/streaming_action.py +71 -20
  30. matrice_streaming/streaming_gateway/streaming_gateway.py +1026 -78
  31. matrice_streaming/streaming_gateway/streaming_gateway_utils.py +175 -20
  32. matrice_streaming/streaming_gateway/streaming_status_listener.py +89 -0
  33. {matrice_streaming-0.1.14.dist-info → matrice_streaming-0.1.65.dist-info}/METADATA +1 -1
  34. matrice_streaming-0.1.65.dist-info/RECORD +56 -0
  35. matrice_streaming-0.1.14.dist-info/RECORD +0 -38
  36. {matrice_streaming-0.1.14.dist-info → matrice_streaming-0.1.65.dist-info}/WHEEL +0 -0
  37. {matrice_streaming-0.1.14.dist-info → matrice_streaming-0.1.65.dist-info}/licenses/LICENSE.txt +0 -0
  38. {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 = 60.0,
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
- raise RuntimeError(
246
- "No input streams configured for this streaming gateway"
247
- )
248
-
249
- logging.info("Found %d input streams configured", len(input_streams))
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=60.0, # Report every 60 seconds
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
- # Update status to running
300
- # self.update_status("STG_RUNNING", "SUCCESS", "Streaming gateway started successfully")
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 otherwise
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
- if not gateway_details:
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 streaming gateway details for action ID check"
529
+ "Action ID check: Failed to fetch gateway details (API returned None), skipping check"
482
530
  )
483
- self.stats["action_id_check_failures"] += 1
484
- return False
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
- self.stats["action_id_check_failures"] += 1
506
- logging.error("Error checking action ID match: %s", str(exc), exc_info=True)
507
- return False
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."""