rtp.js
Version:
RTP stack for Node.js and browser written in TypeScript
211 lines (210 loc) • 7.07 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PrtExtendedReport = void 0;
const ExtendedReport_1 = require("./ExtendedReport");
const bitOps_1 = require("../../../utils/bitOps");
// Common header + SSRC of source + begin seq + end seq.
const PRT_EXTENDED_REPORT_MIN_LENGTH = ExtendedReport_1.COMMON_HEADER_LENGTH + 8;
/**
* Packet Receipt Times Extended Report.
*
* ```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=3 | rsvd. | T | block length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | SSRC of source |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | begin_seq | end_seq |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Receipt time of packet begin_seq |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Receipt time of packet (begin_seq + 1) mod 65536 |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* : ... :
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Receipt time of packet (end_seq - 1) mod 65536 |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* ```
*
* @category RTCP Extended Reports
*
* @see
* - [RFC 3611 section 4.3](https://datatracker.ietf.org/doc/html/rfc3611#section-4.3)
*/
class PrtExtendedReport extends ExtendedReport_1.ExtendedReport {
// Receipt times (4 bytes numbers, unparsed).
#receiptTimes = [];
/**
* @param view - If given it will be parsed. Otherwise an empty Packet Receipt
* Times Extended Report will be created.
*/
constructor(view) {
super(ExtendedReport_1.ExtendedReportType.PRT, view);
if (!this.view) {
this.view = new DataView(new ArrayBuffer(PRT_EXTENDED_REPORT_MIN_LENGTH));
// Write report type.
this.writeCommonHeader();
return;
}
if (this.view.byteLength < PRT_EXTENDED_REPORT_MIN_LENGTH) {
throw new TypeError('wrong byte length for a Packet Receipt Times Extended Report');
}
// Position relative to the DataView byte offset.
let pos = 0;
// Move to receipt times.
pos += PRT_EXTENDED_REPORT_MIN_LENGTH;
while (pos < this.view.byteLength) {
const receiptTime = this.view.getUint32(pos);
this.#receiptTimes.push(receiptTime);
pos += 4;
}
}
/**
* Dump Packet Receipt Times Extended Report info.
*/
dump() {
return {
...super.dump(),
thinning: this.getThinning(),
ssrc: this.getSsrc(),
beginSeq: this.getBeginSeq(),
endSeq: this.getEndSeq(),
receiptTimes: this.getReceiptTimes(),
};
}
/**
* @inheritDoc
*/
getByteLength() {
if (!this.needsSerialization()) {
return this.view.byteLength;
}
// Common header + SSRC + begin seq + end seq.
let reportLength = PRT_EXTENDED_REPORT_MIN_LENGTH;
// Add receipt times.
reportLength += this.#receiptTimes.length * 4;
return reportLength;
}
/**
* @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 the fixed header fields after the common header.
pos += ExtendedReport_1.COMMON_HEADER_LENGTH;
// Copy the rest of the fixed fields into the new buffer.
uint8Array.set(new Uint8Array(this.view.buffer, this.view.byteOffset + pos, PRT_EXTENDED_REPORT_MIN_LENGTH - ExtendedReport_1.COMMON_HEADER_LENGTH), pos);
// Move to receipt times.
pos += PRT_EXTENDED_REPORT_MIN_LENGTH - ExtendedReport_1.COMMON_HEADER_LENGTH;
// Copy receipt times.
for (const receiptTime of this.#receiptTimes) {
view.setUint32(pos, receiptTime);
pos += 4;
}
if (pos !== view.byteLength) {
throw new RangeError(`filled length (${pos} bytes) does not match 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 PrtExtendedReport(view);
}
/**
* Get thinning.
*/
getThinning() {
return (0, bitOps_1.readBitsInDataView)({ view: this.view, pos: 1, mask: 0x0f });
}
/**
* Set thinning.
*/
setThinning(thinning) {
(0, bitOps_1.writeBitsInDataView)({
view: this.view,
pos: 1,
mask: 0x0f,
value: thinning,
});
this.setSerializationNeeded(true);
}
/**
* Get SSRC of source.
*/
getSsrc() {
return this.view.getUint32(4);
}
/**
* Set SSRC of source.
*/
setSsrc(ssrc) {
this.view.setUint32(4, ssrc);
this.setSerializationNeeded(true);
}
/**
* Get begin sequence number.
*/
getBeginSeq() {
return this.view.getUint16(8);
}
/**
* Set begin sequence number.
*/
setBeginSeq(seq) {
this.view.setUint16(8, seq);
this.setSerializationNeeded(true);
}
/**
* Get end sequence number.
*/
getEndSeq() {
return this.view.getUint16(10);
}
/**
* Set end sequence number.
*/
setEndSeq(seq) {
this.view.setUint16(10, seq);
this.setSerializationNeeded(true);
}
/**
* Get receipt times.
*
* @remarks
* - Receipt times are given as a list of 4 byte integers.
*/
getReceiptTimes() {
return Array.from(this.#receiptTimes);
}
/**
* Set receipt times.
*
* @remarks
* - Receipt times must be given as a list of 4 byte integers.
*/
setReceiptTimes(receiptTimes) {
this.#receiptTimes = Array.from(receiptTimes);
this.setSerializationNeeded(true);
}
/**
* Add receipt time.
*
* @remarks
* - Receipt time must be given as 4 byte integer.
*/
addReceiptTime(receiptTime) {
this.#receiptTimes.push(receiptTime);
this.setSerializationNeeded(true);
}
}
exports.PrtExtendedReport = PrtExtendedReport;