fix(srt): prevent OOM from unbounded SrtSender queue under network backpressure#2073
Closed
pird32 wants to merge 2 commits intopedroSG94:masterfrom
Closed
fix(srt): prevent OOM from unbounded SrtSender queue under network backpressure#2073pird32 wants to merge 2 commits intopedroSG94:masterfrom
pird32 wants to merge 2 commits intopedroSG94:masterfrom
Conversation
- BaseSender: fix getCacheSize() to track actual capacity after resizeCache() (was always returning initial 400 even after resizeCache(128)) - BaseSender: add getQueueSnapshot() returning QueueSnapshot(capacity, items) - BaseSender: add frameLifecycleListener for pooled-copy buffer recycling - BaseSender: emit rate-limited ConnectChecker.onTransportEvent(QueueOverflow) when sendMediaFrame() drops a frame (cooldown: 1500 ms, no flooding) - New: QueueSnapshot data class with usageRatio and summary() - New: TransportEvent sealed class (QueueOverflow, NetworkSendError) - New: FrameLifecycleListener fun interface for buffer pool integration - ConnectChecker: add onTransportEvent(TransportEvent) default no-op method Upstream-friendliness: onTransportEvent is a default method; existing ConnectChecker implementors are not required to override it. Made-with: Cursor
…all senders All four protocol senders (RtmpSender, SrtSender, RtspSender, UdpSender) now: - Call notifyFrameConsumed(mediaFrame) after the dispatch loop finishes processing each frame (after network write). Wired to frameLifecycleListener so buffer pools can release slots at the correct point in the lifecycle. - Emit ConnectChecker.onTransportEvent(NetworkSendError) on send errors in addition to the existing onConnectionFailed(String) call (backward compatible). Made-with: Cursor
Author
|
Closing this PR to keep only one consolidated PR for easier review/testing, as requested. All changes are included in #2072. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Under low-bandwidth network conditions,
SrtSenderenqueues frames faster than it can transmit them. The internalStreamBlockingQueuehas no hard-reject enforcement in itstrySend()path — frames silently accumulate until the Android process runs out of heap memory (OutOfMemoryError).Reproduced: SRT stream to a throttled endpoint (500 kbps), ~30 minutes. Heap grew from 80 MB to >400 MB before the process was killed by the OOM reaper.
Solution
This PR builds on the transport contract from the companion PR (see
fork/rootencoder-transport-contract).BaseSender.sendMediaFrame()now:queue.trySend(mediaFrame). On rejection (queue full), increments drop counter.ConnectChecker.onTransportEvent(QueueOverflow(...))so callers can react to queue pressure as a typed event without being flooded.This is equivalent to the existing
onConnectionFailed(String)signal semantics, but with structured data (frame type, drop total, queue depth) and without the 1:1 rate of dropped frames.What this is NOT
This PR does not change the default queue capacity (still 400). Callers that want a tighter budget can call
resizeCache(128)as before. A follow-up PR may reduce the default.Metrics
Backward compatibility
sendMediaFrame()behavior is unchanged for callers that do not implementonTransportEvent.onTransportEventdefault is no-op, so existingConnectCheckerimplementors are unaffected.