mirror of
https://github.com/koush/scrypted.git
synced 2026-03-01 08:42:57 +00:00
rebroadcast: fix RTMP acknowledgement uint32 overflow (#1980)
The RTMP client's totalBytesReceived counter grows unbounded as a JavaScript number. When it exceeds 2^31 (~2.15 GB received), the writeUInt32BE call in sendAcknowledgementIfNeeded throws a RangeError because JavaScript bitwise operations produce signed 32-bit integers. This crashes the RTMP session and drops the video stream. For a high-bitrate camera like the Reolink D340P (~4 Mbps main stream), this overflow occurs after approximately 90 minutes of continuous streaming, causing periodic stream drops at a consistent interval. Fix by using the unsigned right shift operator (>>> 0) to keep totalBytesReceived and bytesToAck in the unsigned uint32 range [0, 4294967295], matching the RTMP spec's sequence number wrapping behavior. Co-authored-by: Josh Casada <joshcasada@Joshs-Mac-mini.ts.net lan> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -398,7 +398,7 @@ export class RtmpClient {
|
||||
// Count: basic header (1 byte) + message header (0-11 bytes) + extended timestamp (0-4 bytes) + payload
|
||||
const extTimestampSize = (hasExtendedTimestamp || chunkStream.hasExtendedTimestamp) ? 4 : 0;
|
||||
const bytesInChunk = 1 + headerSize + extTimestampSize + chunkDataSize;
|
||||
this.totalBytesReceived += bytesInChunk;
|
||||
this.totalBytesReceived = (this.totalBytesReceived + bytesInChunk) >>> 0;
|
||||
|
||||
// Send window acknowledgement if threshold exceeded
|
||||
this.sendAcknowledgementIfNeeded();
|
||||
@@ -421,12 +421,14 @@ export class RtmpClient {
|
||||
* Send acknowledgement if window threshold exceeded
|
||||
*/
|
||||
private sendAcknowledgementIfNeeded(): void {
|
||||
const bytesToAck = this.totalBytesReceived - this.lastAcknowledgementBytes;
|
||||
// Handle uint32 wrap-around: if totalBytesReceived wrapped past 0,
|
||||
// bytesToAck will be a large positive number, which is correct.
|
||||
const bytesToAck = (this.totalBytesReceived - this.lastAcknowledgementBytes) >>> 0;
|
||||
if (bytesToAck >= this.windowAckSize) {
|
||||
this.lastAcknowledgementBytes = this.totalBytesReceived;
|
||||
console.log(`Sending acknowledgement: ${this.lastAcknowledgementBytes} bytes received (${bytesToAck} since last ACK)`);
|
||||
const data = Buffer.alloc(4);
|
||||
data.writeUInt32BE(this.lastAcknowledgementBytes & 0xFFFFFFFF, 0);
|
||||
data.writeUInt32BE(this.lastAcknowledgementBytes, 0);
|
||||
this.sendMessage(2, 0, RtmpMessageType.ACKNOWLEDGEMENT, 0, data);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user