rtp.js
Version:
RTP stack for Node.js and browser written in TypeScript
204 lines (203 loc) • 6.82 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExtendedReport = exports.ExtendedReportType = exports.COMMON_HEADER_LENGTH = void 0;
exports.getExtendedReportType = getExtendedReportType;
exports.getExtendedReportLength = getExtendedReportLength;
exports.setExtendedReportLength = setExtendedReportLength;
const Serializable_1 = require("../../Serializable");
const helpers_1 = require("../../../utils/helpers");
exports.COMMON_HEADER_LENGTH = 4;
/**
* Extended Report types.
*
* @category RTCP Extended Reports
*/
var ExtendedReportType;
(function (ExtendedReportType) {
/**
* Loss RLE Report.
*/
ExtendedReportType[ExtendedReportType["LRLE"] = 1] = "LRLE";
/**
* Duplicate RLE Report.
*/
ExtendedReportType[ExtendedReportType["DRLE"] = 2] = "DRLE";
/**
* Packet Receipt Times Report.
*/
ExtendedReportType[ExtendedReportType["PRT"] = 3] = "PRT";
/**
* Receiver Reference Time Report.
*/
ExtendedReportType[ExtendedReportType["RRT"] = 4] = "RRT";
/**
* DLRR Report.
*/
ExtendedReportType[ExtendedReportType["DLRR"] = 5] = "DLRR";
/**
* Statistics Summary Report.
*/
ExtendedReportType[ExtendedReportType["SS"] = 6] = "SS";
/**
* VoIP Metrics Report.
*/
ExtendedReportType[ExtendedReportType["VM"] = 7] = "VM";
/**
* ECN Summary Report.
*/
ExtendedReportType[ExtendedReportType["ECN"] = 13] = "ECN";
})(ExtendedReportType || (exports.ExtendedReportType = ExtendedReportType = {}));
/**
* Get the RTCP packet type.
*
* @hidden
*/
function getExtendedReportType(view) {
return view.getUint8(0);
}
/**
* Read the report length value of an Extended Report and compute its size in
* bytes (including first octet).
*
* @hidden
*/
function getExtendedReportLength(view) {
// As per RFC 3611, this is the length of this Extended Report in 32-bit words
// minus one, including the header and any padding.
const length = view.getUint16(2);
const byteLength = (length + 1) * 4;
return byteLength;
}
/**
* Writes given length (in bytes) in the report length field of an Extended
* Report.
*
* @hidden
*/
function setExtendedReportLength(view, byteLength) {
// Report byte length must be multiple of 4.
if (byteLength % 4 !== 0) {
throw new RangeError(`Extended Report byte length must be multiple of 4 but given byte length is ${byteLength} bytes`);
}
const length = byteLength / 4 - 1;
view.setUint16(2, length);
}
/**
* Parent class of all {@link XrPacket} Extended Reports.
*
* ```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
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | BT | type-specific | block length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* : type-specific block contents :
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* ```
*
* @category RTCP Extended Reports
*
* @see
* - [RFC 3611 section 3](https://datatracker.ietf.org/doc/html/rfc3611#section-3)
*/
class ExtendedReport extends Serializable_1.Serializable {
#reportType;
constructor(reportType, view) {
super(view);
this.#reportType = reportType;
if (this.view) {
if (this.view.byteLength < exports.COMMON_HEADER_LENGTH) {
throw new TypeError('too small buffer');
}
// Extended Report byte length must be multiple of 4.
else if (this.view.byteLength % 4 !== 0) {
throw new RangeError(`Extended Report byte length must be multiple of 4 but given buffer view is ${this.view.byteLength} bytes`);
}
else if (getExtendedReportType(this.view) !== reportType) {
throw new TypeError(`not a ${reportTypeToString(reportType)} Extended Report`);
}
else if (getExtendedReportLength(this.view) !== this.view.byteLength) {
throw new RangeError(`length in the RTCP header (${getExtendedReportLength(this.view)} bytes) does not match view length (${this.view.byteLength} bytes)`);
}
}
}
/**
* Base Extended Report dump.
*
* @remarks
* - Read the info dump type of each Extended Report instead.
*/
dump() {
return {
...super.dump(),
reportType: this.getReportType(),
};
}
/**
* Get the Extended Report type.
*/
getReportType() {
return this.view.getUint8(0);
}
writeCommonHeader() {
this.setReportType(this.#reportType);
// Update the report length field in the report header.
setExtendedReportLength(this.view, this.view.byteLength);
}
/**
* Serialize base RTCP packet into a new buffer.
*/
serializeBase(buffer, byteOffset) {
const bufferData = this.getSerializationBuffer(buffer, byteOffset);
// Create new DataView with new buffer.
const view = new DataView(bufferData.buffer, bufferData.byteOffset, bufferData.byteLength);
const uint8Array = new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
// Copy the common header into the new buffer.
uint8Array.set(new Uint8Array(this.view.buffer, this.view.byteOffset, exports.COMMON_HEADER_LENGTH), 0);
// Update the report length field in the report header.
setExtendedReportLength(view, view.byteLength);
return view;
}
/**
* Set the Extended Report type.
*
* @privateRemarks
* - This method is not public since users should not manipulate this field
* directly.
*/
setReportType(reportType) {
this.view.setUint8(0, reportType);
}
}
exports.ExtendedReport = ExtendedReport;
function reportTypeToString(reportType) {
switch (reportType) {
case ExtendedReportType.LRLE: {
return 'Loss RLE';
}
case ExtendedReportType.DRLE: {
return 'Duplicate RLE';
}
case ExtendedReportType.PRT: {
return 'Packet Receipt Times';
}
case ExtendedReportType.RRT: {
return 'Receiver Reference Time';
}
case ExtendedReportType.DLRR: {
return 'DLRR';
}
case ExtendedReportType.SS: {
return 'Statistics Summary';
}
case ExtendedReportType.VM: {
return 'VoIP Metrics';
}
case ExtendedReportType.ECN: {
return 'ECN Summary';
}
default: {
(0, helpers_1.assertUnreachable)(reportType);
}
}
}