getstream 3.0.2__tar.gz → 3.0.4__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 (118) hide show
  1. {getstream-3.0.2 → getstream-3.0.4}/PKG-INFO +1 -1
  2. {getstream-3.0.2 → getstream-3.0.4}/getstream/stream.py +15 -0
  3. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/connection_manager.py +4 -1
  4. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/pc.py +19 -2
  5. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/peer_connection.py +3 -1
  6. {getstream-3.0.2 → getstream-3.0.4}/.cursor/worktrees.json +0 -0
  7. {getstream-3.0.2 → getstream-3.0.4}/.env.example +0 -0
  8. {getstream-3.0.2 → getstream-3.0.4}/.github/actions/python-uv-setup/action.yml +0 -0
  9. {getstream-3.0.2 → getstream-3.0.4}/.github/workflows/ci.yml +0 -0
  10. {getstream-3.0.2 → getstream-3.0.4}/.github/workflows/release.yml +0 -0
  11. {getstream-3.0.2 → getstream-3.0.4}/.github/workflows/run_tests.yml +0 -0
  12. {getstream-3.0.2 → getstream-3.0.4}/.github/workflows/stream-py.code-workspace +0 -0
  13. {getstream-3.0.2 → getstream-3.0.4}/.gitignore +0 -0
  14. {getstream-3.0.2 → getstream-3.0.4}/.gitmodules +0 -0
  15. {getstream-3.0.2 → getstream-3.0.4}/.pre-commit-config.yaml +0 -0
  16. {getstream-3.0.2 → getstream-3.0.4}/AGENTS.md +0 -0
  17. {getstream-3.0.2 → getstream-3.0.4}/CHANGELOG.md +0 -0
  18. {getstream-3.0.2 → getstream-3.0.4}/DEVELOPMENT.md +0 -0
  19. {getstream-3.0.2 → getstream-3.0.4}/LICENSE.md +0 -0
  20. {getstream-3.0.2 → getstream-3.0.4}/MIGRATION_v2_to_v3.md +0 -0
  21. {getstream-3.0.2 → getstream-3.0.4}/Makefile +0 -0
  22. {getstream-3.0.2 → getstream-3.0.4}/README.md +0 -0
  23. {getstream-3.0.2 → getstream-3.0.4}/dev.py +0 -0
  24. {getstream-3.0.2 → getstream-3.0.4}/docs/migration-from-stream-chat-python/01-setup-and-auth.md +0 -0
  25. {getstream-3.0.2 → getstream-3.0.4}/docs/migration-from-stream-chat-python/02-users.md +0 -0
  26. {getstream-3.0.2 → getstream-3.0.4}/docs/migration-from-stream-chat-python/03-channels.md +0 -0
  27. {getstream-3.0.2 → getstream-3.0.4}/docs/migration-from-stream-chat-python/04-messages-and-reactions.md +0 -0
  28. {getstream-3.0.2 → getstream-3.0.4}/docs/migration-from-stream-chat-python/05-moderation.md +0 -0
  29. {getstream-3.0.2 → getstream-3.0.4}/docs/migration-from-stream-chat-python/06-devices.md +0 -0
  30. {getstream-3.0.2 → getstream-3.0.4}/docs/migration-from-stream-chat-python/README.md +0 -0
  31. {getstream-3.0.2 → getstream-3.0.4}/generate.sh +0 -0
  32. {getstream-3.0.2 → getstream-3.0.4}/generate_webrtc.sh +0 -0
  33. {getstream-3.0.2 → getstream-3.0.4}/getstream/__init__.py +0 -0
  34. {getstream-3.0.2 → getstream-3.0.4}/getstream/base.py +0 -0
  35. {getstream-3.0.2 → getstream-3.0.4}/getstream/chat/__init__.py +0 -0
  36. {getstream-3.0.2 → getstream-3.0.4}/getstream/chat/async_channel.py +0 -0
  37. {getstream-3.0.2 → getstream-3.0.4}/getstream/chat/async_client.py +0 -0
  38. {getstream-3.0.2 → getstream-3.0.4}/getstream/chat/async_rest_client.py +0 -0
  39. {getstream-3.0.2 → getstream-3.0.4}/getstream/chat/channel.py +0 -0
  40. {getstream-3.0.2 → getstream-3.0.4}/getstream/chat/client.py +0 -0
  41. {getstream-3.0.2 → getstream-3.0.4}/getstream/chat/rest_client.py +0 -0
  42. {getstream-3.0.2 → getstream-3.0.4}/getstream/common/__init__.py +0 -0
  43. {getstream-3.0.2 → getstream-3.0.4}/getstream/common/async_client.py +0 -0
  44. {getstream-3.0.2 → getstream-3.0.4}/getstream/common/async_rest_client.py +0 -0
  45. {getstream-3.0.2 → getstream-3.0.4}/getstream/common/client.py +0 -0
  46. {getstream-3.0.2 → getstream-3.0.4}/getstream/common/rest_client.py +0 -0
  47. {getstream-3.0.2 → getstream-3.0.4}/getstream/common/telemetry.py +0 -0
  48. {getstream-3.0.2 → getstream-3.0.4}/getstream/config.py +0 -0
  49. {getstream-3.0.2 → getstream-3.0.4}/getstream/feeds/__init__.py +0 -0
  50. {getstream-3.0.2 → getstream-3.0.4}/getstream/feeds/client.py +0 -0
  51. {getstream-3.0.2 → getstream-3.0.4}/getstream/feeds/feeds.py +0 -0
  52. {getstream-3.0.2 → getstream-3.0.4}/getstream/feeds/rest_client.py +0 -0
  53. {getstream-3.0.2 → getstream-3.0.4}/getstream/generic.py +0 -0
  54. {getstream-3.0.2 → getstream-3.0.4}/getstream/meta.py +0 -0
  55. {getstream-3.0.2 → getstream-3.0.4}/getstream/models/__init__.py +0 -0
  56. {getstream-3.0.2 → getstream-3.0.4}/getstream/moderation/__init__.py +0 -0
  57. {getstream-3.0.2 → getstream-3.0.4}/getstream/moderation/async_client.py +0 -0
  58. {getstream-3.0.2 → getstream-3.0.4}/getstream/moderation/async_rest_client.py +0 -0
  59. {getstream-3.0.2 → getstream-3.0.4}/getstream/moderation/client.py +0 -0
  60. {getstream-3.0.2 → getstream-3.0.4}/getstream/moderation/rest_client.py +0 -0
  61. {getstream-3.0.2 → getstream-3.0.4}/getstream/rate_limit.py +0 -0
  62. {getstream-3.0.2 → getstream-3.0.4}/getstream/stream_response.py +0 -0
  63. {getstream-3.0.2 → getstream-3.0.4}/getstream/tests/test_webhook.py +0 -0
  64. {getstream-3.0.2 → getstream-3.0.4}/getstream/utils/__init__.py +0 -0
  65. {getstream-3.0.2 → getstream-3.0.4}/getstream/utils/event_emitter.py +0 -0
  66. {getstream-3.0.2 → getstream-3.0.4}/getstream/utils/retry.py +0 -0
  67. {getstream-3.0.2 → getstream-3.0.4}/getstream/version.py +0 -0
  68. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/__init__.py +0 -0
  69. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/async_call.py +0 -0
  70. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/async_client.py +0 -0
  71. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/async_rest_client.py +0 -0
  72. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/call.py +0 -0
  73. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/client.py +0 -0
  74. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/openai.py +0 -0
  75. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rest_client.py +0 -0
  76. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/README.md +0 -0
  77. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/__init__.py +0 -0
  78. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/audio_track.py +0 -0
  79. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/connection_utils.py +0 -0
  80. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/coordinator/__init__.py +0 -0
  81. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/coordinator/backoff.py +0 -0
  82. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/coordinator/errors.py +0 -0
  83. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/coordinator/ws.py +0 -0
  84. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/coordinator_api.py +0 -0
  85. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/encoders_patches.py +0 -0
  86. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/g711.py +0 -0
  87. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/location_discovery.py +0 -0
  88. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/models.py +0 -0
  89. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/network_monitor.py +0 -0
  90. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/participants.py +0 -0
  91. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/pb/__init__.py +0 -0
  92. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/pb/stream/__init__.py +0 -0
  93. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/pb/stream/video/__init__.py +0 -0
  94. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/pb/stream/video/sfu/__init__.py +0 -0
  95. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/pb/stream/video/sfu/event/__init__.py +0 -0
  96. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/pb/stream/video/sfu/event/events_pb2.py +0 -0
  97. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/pb/stream/video/sfu/event/events_pb2.pyi +0 -0
  98. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/pb/stream/video/sfu/models/__init__.py +0 -0
  99. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/pb/stream/video/sfu/models/models_pb2.py +0 -0
  100. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/pb/stream/video/sfu/models/models_pb2.pyi +0 -0
  101. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/pb/stream/video/sfu/signal_rpc/__init__.py +0 -0
  102. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/pb/stream/video/sfu/signal_rpc/signal_pb2.py +0 -0
  103. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/pb/stream/video/sfu/signal_rpc/signal_pb2.pyi +0 -0
  104. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/pb/stream/video/sfu/signal_rpc/signal_twirp.py +0 -0
  105. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/reconnection.py +0 -0
  106. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/recording.py +0 -0
  107. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/signaling.py +0 -0
  108. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/stats_reporter.py +0 -0
  109. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/stats_tracer.py +0 -0
  110. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/tracer.py +0 -0
  111. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/track_util.py +0 -0
  112. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/tracks.py +0 -0
  113. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/twirp_client_wrapper.py +0 -0
  114. {getstream-3.0.2 → getstream-3.0.4}/getstream/video/rtc/utils.py +0 -0
  115. {getstream-3.0.2 → getstream-3.0.4}/getstream/webhook.py +0 -0
  116. {getstream-3.0.2 → getstream-3.0.4}/pyproject.toml +0 -0
  117. {getstream-3.0.2 → getstream-3.0.4}/pytest.ini +0 -0
  118. {getstream-3.0.2 → getstream-3.0.4}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: getstream
3
- Version: 3.0.2
3
+ Version: 3.0.4
4
4
  Summary: GetStream Python SDK - Build scalable activity feeds, chat, and video calling applications
5
5
  Author-email: sachaarbonel <sacha.arbonel@hotmail.fr>, tbarbugli <tbarbugli@gmail.com>
6
6
  License-File: LICENSE.md
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from contextlib import AsyncExitStack
3
4
  from functools import cached_property
4
5
  import time
5
6
  from typing import List, Optional
@@ -207,6 +208,20 @@ class AsyncStream(BaseStream, AsyncCommonClient):
207
208
  user_agent=self.user_agent,
208
209
  )
209
210
 
211
+ async def aclose(self):
212
+ """Close all child clients and the main HTTPX client."""
213
+ # AsyncExitStack ensures all clients are closed even if one fails.
214
+ # video/chat/moderation are @cached_property - only close if accessed.
215
+ async with AsyncExitStack() as stack:
216
+ cached = self.__dict__
217
+ if "video" in cached:
218
+ stack.push_async_callback(self.video.aclose)
219
+ if "chat" in cached:
220
+ stack.push_async_callback(self.chat.aclose)
221
+ if "moderation" in cached:
222
+ stack.push_async_callback(self.moderation.aclose)
223
+ stack.push_async_callback(super().aclose)
224
+
210
225
  @cached_property
211
226
  def feeds(self):
212
227
  raise NotImplementedError("Feeds not supported for async client")
@@ -58,6 +58,7 @@ class ConnectionManager(StreamAsyncIOEventEmitter):
58
58
  create: bool = True,
59
59
  subscription_config: Optional[SubscriptionConfig] = None,
60
60
  max_join_retries: int = 3,
61
+ drain_video_frames: bool = False,
61
62
  **kwargs: Any,
62
63
  ):
63
64
  super().__init__()
@@ -90,7 +91,9 @@ class ConnectionManager(StreamAsyncIOEventEmitter):
90
91
  self._subscription_manager: SubscriptionManager = SubscriptionManager(
91
92
  self, subscription_config
92
93
  )
93
- self._peer_manager: PeerConnectionManager = PeerConnectionManager(self)
94
+ self._peer_manager: PeerConnectionManager = PeerConnectionManager(
95
+ self, drain_video_frames=drain_video_frames
96
+ )
94
97
 
95
98
  self.recording_manager = self._recording_manager
96
99
  self.participants_state = self._participants_state
@@ -3,7 +3,7 @@ import logging
3
3
  from typing import Any, Optional
4
4
 
5
5
  import aiortc
6
- from aiortc.contrib.media import MediaRelay
6
+ from aiortc.contrib.media import MediaBlackhole, MediaRelay
7
7
  from aiortc.mediastreams import MediaStreamTrack
8
8
  from aiortc.rtcrtpparameters import RTCRtpCodecCapability
9
9
  from aiortc.rtcrtpsender import RTCRtpSender
@@ -131,15 +131,19 @@ class SubscriberPeerConnection(aiortc.RTCPeerConnection, AsyncIOEventEmitter):
131
131
  self,
132
132
  connection,
133
133
  configuration: aiortc.RTCConfiguration,
134
+ drain_video_frames: bool = False,
134
135
  ) -> None:
135
136
  logger.info(
136
137
  f"creating subscriber peer connection with configuration: {configuration}"
137
138
  )
138
139
  super().__init__(configuration)
139
140
  self.connection = connection
141
+ self._drain_video_frames = drain_video_frames
140
142
 
141
143
  self.track_map = {} # track_id -> (MediaRelay, original_track)
142
144
  self.video_frame_trackers = {} # track_id -> VideoFrameTracker
145
+ self._video_blackholes: dict[str, MediaBlackhole] = {}
146
+ self._video_drain_tasks: dict[str, asyncio.Task] = {}
143
147
 
144
148
  @self.on("track")
145
149
  async def on_track(track: aiortc.mediastreams.MediaStreamTrack):
@@ -177,7 +181,20 @@ class SubscriberPeerConnection(aiortc.RTCPeerConnection, AsyncIOEventEmitter):
177
181
  handler = AudioTrackHandler(relay.subscribe(tracked_track), _emit_pcm)
178
182
  asyncio.create_task(handler.start())
179
183
 
180
- self.emit("track_added", relay.subscribe(tracked_track), user)
184
+ proxy = relay.subscribe(tracked_track)
185
+
186
+ # Drain unconsumed video frames to prevent unbounded queue growth
187
+ # in RTCRtpReceiver (aiortc issue #554)
188
+ if track.kind == "video" and self._drain_video_frames:
189
+ drain_proxy = relay.subscribe(tracked_track)
190
+ blackhole = MediaBlackhole()
191
+ blackhole.addTrack(drain_proxy)
192
+ self._video_blackholes[track.id] = blackhole
193
+ self._video_drain_tasks[track.id] = asyncio.create_task(
194
+ blackhole.start()
195
+ )
196
+
197
+ self.emit("track_added", proxy, user)
181
198
 
182
199
  @self.on("icegatheringstatechange")
183
200
  def on_icegatheringstatechange():
@@ -28,8 +28,9 @@ logger = logging.getLogger(__name__)
28
28
  class PeerConnectionManager:
29
29
  """Manages WebRTC peer connections for publishing and subscribing."""
30
30
 
31
- def __init__(self, connection_manager):
31
+ def __init__(self, connection_manager, drain_video_frames: bool = False):
32
32
  self.connection_manager = connection_manager
33
+ self._drain_video_frames = drain_video_frames
33
34
  self.publisher_pc: Optional[PublisherPeerConnection] = None
34
35
  self.subscriber_pc: Optional[SubscriberPeerConnection] = None
35
36
  self.publisher_negotiation_lock = asyncio.Lock()
@@ -47,6 +48,7 @@ class PeerConnectionManager:
47
48
  self.subscriber_pc = SubscriberPeerConnection(
48
49
  connection=self.connection_manager,
49
50
  configuration=self._build_rtc_configuration(),
51
+ drain_video_frames=self._drain_video_frames,
50
52
  )
51
53
 
52
54
  # Trace create event
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