Skip to content

Commit d85f1f9

Browse files
committed
feat: add video_buffered option to control video frame buffering
Pass video_buffered=False through ConnectionManager → PeerConnectionManager → SubscriberPeerConnection to relay.subscribe(buffered=False) for video tracks. Default True preserves current behavior. Without buffering, only the latest video frame is kept in memory instead of an unbounded queue. This prevents OOM on voice-only agents that subscribe to video but never consume frames (~400 MiB/10sec leak).
1 parent 4e3c87d commit d85f1f9

File tree

3 files changed

+11
-3
lines changed

3 files changed

+11
-3
lines changed

getstream/video/rtc/connection_manager.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ def __init__(
5858
create: bool = True,
5959
subscription_config: Optional[SubscriptionConfig] = None,
6060
max_join_retries: int = 3,
61+
video_buffered: bool = True,
6162
**kwargs: Any,
6263
):
6364
super().__init__()
@@ -90,7 +91,9 @@ def __init__(
9091
self._subscription_manager: SubscriptionManager = SubscriptionManager(
9192
self, subscription_config
9293
)
93-
self._peer_manager: PeerConnectionManager = PeerConnectionManager(self)
94+
self._peer_manager: PeerConnectionManager = PeerConnectionManager(
95+
self, video_buffered=video_buffered
96+
)
9497

9598
self.recording_manager = self._recording_manager
9699
self.participants_state = self._participants_state

getstream/video/rtc/pc.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,14 @@ def __init__(
131131
self,
132132
connection,
133133
configuration: aiortc.RTCConfiguration,
134+
video_buffered: bool = True,
134135
) -> None:
135136
logger.info(
136137
f"creating subscriber peer connection with configuration: {configuration}"
137138
)
138139
super().__init__(configuration)
139140
self.connection = connection
141+
self._video_buffered = video_buffered
140142

141143
self.track_map = {} # track_id -> (MediaRelay, original_track)
142144
self.video_frame_trackers = {} # track_id -> VideoFrameTracker
@@ -177,7 +179,8 @@ def _emit_pcm(pcm: PcmData):
177179
handler = AudioTrackHandler(relay.subscribe(tracked_track), _emit_pcm)
178180
asyncio.create_task(handler.start())
179181

180-
self.emit("track_added", relay.subscribe(tracked_track), user)
182+
buffered = self._video_buffered if track.kind == "video" else True
183+
self.emit("track_added", relay.subscribe(tracked_track, buffered=buffered), user)
181184

182185
@self.on("icegatheringstatechange")
183186
def on_icegatheringstatechange():

getstream/video/rtc/peer_connection.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@
2828
class PeerConnectionManager:
2929
"""Manages WebRTC peer connections for publishing and subscribing."""
3030

31-
def __init__(self, connection_manager):
31+
def __init__(self, connection_manager, video_buffered: bool = True):
3232
self.connection_manager = connection_manager
33+
self._video_buffered = video_buffered
3334
self.publisher_pc: Optional[PublisherPeerConnection] = None
3435
self.subscriber_pc: Optional[SubscriberPeerConnection] = None
3536
self.publisher_negotiation_lock = asyncio.Lock()
@@ -47,6 +48,7 @@ async def setup_subscriber(self):
4748
self.subscriber_pc = SubscriberPeerConnection(
4849
connection=self.connection_manager,
4950
configuration=self._build_rtc_configuration(),
51+
video_buffered=self._video_buffered,
5052
)
5153

5254
# Trace create event

0 commit comments

Comments
 (0)