rtp.js
Version:
RTP stack for Node.js and browser written in TypeScript
199 lines (198 loc) • 6.59 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EcnPacket = void 0;
const RtcpPacket_1 = require("./RtcpPacket");
const FeedbackPacket_1 = require("./FeedbackPacket");
const ECN_PACKET_LENGTH = FeedbackPacket_1.FIXED_HEADER_LENGTH + 20;
/**
* RTCP ECN packet (RTCP Transport Layer Feedback).
*
* ```text
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |V=2|P| FMT=8 | PT=RTPFB=205 | length=7 |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | SSRC of packet sender |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | SSRC of media source |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Extended Highest Sequence Number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | ECT (0) Counter |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | ECT (1) Counter |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | ECN-CE Counter | not-ECT Counter |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Lost Packets Counter | Duplication Counter |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* ```
*
* @category RTCP
*
* @see
* - [RFC 6679 section 5.1](https://datatracker.ietf.org/doc/html/rfc6679#section-5.1)
*/
class EcnPacket extends FeedbackPacket_1.FeedbackPacket {
/**
* @param view - If given it will be parsed. Otherwise an empty RTCP ECN
* packet will be created.
*
* @throws
* - If given `view` does not contain a valid RTCP ECN packet.
*/
constructor(view) {
super(RtcpPacket_1.RtcpPacketType.RTPFB, FeedbackPacket_1.RtpFeedbackMessageType.ECN, view);
if (!this.view) {
this.view = new DataView(new ArrayBuffer(ECN_PACKET_LENGTH));
// Write version, packet type and feedback message type.
this.writeFixedHeader();
return;
}
// Position relative to the DataView byte offset.
let pos = 0;
// Move to the end.
pos += ECN_PACKET_LENGTH;
pos += this.padding;
// Ensure that view length and parsed length match.
if (pos !== this.view.byteLength) {
throw new RangeError(`parsed length (${pos} bytes) does not match view length (${this.view.byteLength} bytes)`);
}
}
/**
* Dump RTCP ECN packet info.
*/
dump() {
return {
...super.dump(),
extendedHighestSequenceNumber: this.getExtendedHighestSequenceNumber(),
ect0Counter: this.getEct0Counter(),
ect1Counter: this.getEct1Counter(),
ecnCeCounter: this.getEcnCeCounter(),
nonEctCounter: this.getNonEctCounter(),
lostPacketsCounter: this.getLostPacketsCounter(),
duplicationCounter: this.getDuplicationCounter(),
};
}
/**
* @inheritDoc
*/
getByteLength() {
return ECN_PACKET_LENGTH + this.padding;
}
/**
* @inheritDoc
*/
serialize(buffer, byteOffset) {
const view = this.serializeBase(buffer, byteOffset);
const uint8Array = new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
// Position relative to the DataView byte offset.
let pos = 0;
// Move to FCI.
pos += FeedbackPacket_1.FIXED_HEADER_LENGTH;
// Copy the entire FCI into the new buffer.
uint8Array.set(new Uint8Array(this.view.buffer, this.view.byteOffset + pos, ECN_PACKET_LENGTH - FeedbackPacket_1.FIXED_HEADER_LENGTH), pos);
pos += ECN_PACKET_LENGTH - FeedbackPacket_1.FIXED_HEADER_LENGTH;
pos += this.padding;
// Assert that current position is equal than new buffer length.
if (pos !== view.byteLength) {
throw new RangeError(`filled length (${pos} bytes) is different than the available buffer size (${view.byteLength} bytes)`);
}
// Update DataView.
this.view = view;
this.setSerializationNeeded(false);
}
/**
* @inheritDoc
*/
clone(buffer, byteOffset, serializationBuffer, serializationByteOffset) {
const view = this.cloneInternal(buffer, byteOffset, serializationBuffer, serializationByteOffset);
return new EcnPacket(view);
}
/**
* Get Extended Highest Sequence Number.
*/
getExtendedHighestSequenceNumber() {
return this.view.getUint32(12);
}
/**
* Set Extended Highest Sequence Number.
*/
setExtendedHighestSequenceNumber(sequenceNumber) {
this.view.setUint32(12, sequenceNumber);
}
/**
* Get ECT (0) Counter.
*/
getEct0Counter() {
return this.view.getUint32(16);
}
/**
* Set ECT (0) Counter.
*/
setEct0Counter(counter) {
this.view.setUint32(16, counter);
}
/**
* Get ECT (1) Counter.
*/
getEct1Counter() {
return this.view.getUint32(20);
}
/**
* Set ECT (1) Counter.
*/
setEct1Counter(counter) {
this.view.setUint32(20, counter);
}
/**
* Get ECN-CE Counter.
*/
getEcnCeCounter() {
return this.view.getUint16(24);
}
/**
* Set ECN-CE Counter.
*/
setEcnCeCounter(counter) {
this.view.setUint16(24, counter);
}
/**
* Get not-ECT Counter.
*/
getNonEctCounter() {
return this.view.getUint16(26);
}
/**
* Set not-ECT Counter.
*/
setNonEctCounter(counter) {
this.view.setUint16(26, counter);
}
/**
* Get Lost Packets Counter.
*/
getLostPacketsCounter() {
return this.view.getUint16(28);
}
/**
* Set Lost Packets Counter.
*/
setLostPacketsCounter(counter) {
this.view.setUint16(28, counter);
}
/**
* Get Duplication Counter.
*/
getDuplicationCounter() {
return this.view.getUint16(30);
}
/**
* Set Duplication Counter.
*/
setDuplicationCounter(counter) {
this.view.setUint16(30, counter);
}
}
exports.EcnPacket = EcnPacket;