rtp.js
Version:
RTP stack for Node.js and browser written in TypeScript
490 lines (489 loc) • 14.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SsExtendedReport = void 0;
const ExtendedReport_1 = require("./ExtendedReport");
const bitOps_1 = require("../../../utils/bitOps");
const SS_EXTENDED_REPORT_LENGTH = ExtendedReport_1.COMMON_HEADER_LENGTH + 36;
/**
* Statistics Summary 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=6 |L|D|J|ToH|rsvd.| block length = 9 |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | SSRC of source |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | begin_seq | end_seq |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | lost_packets |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | dup_packets |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | min_jitter |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | max_jitter |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | mean_jitter |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | dev_jitter |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | min_ttl_or_hl | max_ttl_or_hl |mean_ttl_or_hl | dev_ttl_or_hl |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* ```
*
* @category RTCP Extended Reports
*
* @see
* - [RFC 3611 section 4.6](https://datatracker.ietf.org/doc/html/rfc3611#section-4.6)
*/
class SsExtendedReport extends ExtendedReport_1.ExtendedReport {
/**
* @param view - If given it will be parsed. Otherwise an empty Statistics
* Summary Extended Report will be created.
*/
constructor(view) {
super(ExtendedReport_1.ExtendedReportType.SS, view);
if (!this.view) {
this.view = new DataView(new ArrayBuffer(SS_EXTENDED_REPORT_LENGTH));
// Write report type.
this.writeCommonHeader();
return;
}
if (this.view.byteLength !== SS_EXTENDED_REPORT_LENGTH) {
throw new TypeError('wrong byte length for a Statistics Summary Extended Report');
}
}
/**
* Dump Statistics Summary Extended Report info.
*/
dump() {
return {
...super.dump(),
ssrc: this.getSsrc(),
beginSeq: this.getBeginSeq(),
endSeq: this.getEndSeq(),
lostPackets: this.getLostPackets(),
duplicatePackets: this.getDuplicatePackets(),
minJitter: this.getMinJitter(),
maxJitter: this.getMaxJitter(),
meanJitter: this.getMeanJitter(),
devJitter: this.getDevJitter(),
minTtlOrHl: this.getMinTtlOrHopLimit(),
maxTtlOrHl: this.getMaxTtlOrHopLimit(),
meanTtlOrHl: this.getMeanTtlOrHopLimit(),
devTtlOrHl: this.getDevTtlOrHopLimit(),
ttlOrHlMode: this.getTtlOrHopLimitMode(),
};
}
/**
* @inheritDoc
*/
getByteLength() {
return SS_EXTENDED_REPORT_LENGTH;
}
/**
* @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 Extended Report into the new buffer.
uint8Array.set(new Uint8Array(this.view.buffer, this.view.byteOffset + pos, SS_EXTENDED_REPORT_LENGTH - ExtendedReport_1.COMMON_HEADER_LENGTH), pos);
// Move to the end.
pos += SS_EXTENDED_REPORT_LENGTH - ExtendedReport_1.COMMON_HEADER_LENGTH;
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 SsExtendedReport(view);
}
/**
* 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 number of lost packets.
*
* @remarks
* - It could be `undefined` if the field is unset in the report.
*/
getLostPackets() {
if (!this.hasLostPacketsBit()) {
return undefined;
}
return this.view.getUint32(12);
}
/**
* Set number of lost packets.
*/
setLostPackets(lostPackets) {
if (lostPackets !== undefined) {
this.setLostPacketsBit(true);
this.view.setUint32(12, lostPackets);
}
else {
this.setLostPacketsBit(false);
}
this.setSerializationNeeded(true);
}
/**
* Get number of duplicate packets.
*
* @remarks
* - It could be `undefined` if the field is unset in the report.
*/
getDuplicatePackets() {
if (!this.hasDuplicatePacketsBit()) {
return undefined;
}
return this.view.getUint32(16);
}
/**
* Set number of duplicate packets.
*/
setDuplicatePackets(duplicatePackets) {
if (duplicatePackets !== undefined) {
this.setDuplicatePacketsBit(true);
this.view.setUint32(16, duplicatePackets);
}
else {
this.setDuplicatePacketsBit(false);
}
this.setSerializationNeeded(true);
}
/**
* Get minimum jitter.
*
* @remarks
* - It could be `undefined` if the field is unset in the report.
*/
getMinJitter() {
if (!this.hasJitterBit()) {
return undefined;
}
return this.view.getUint32(20);
}
/**
* Set minimum jitter.
*/
setMinJitter(minJitter) {
if (minJitter !== undefined) {
this.setJitterBit(true);
this.view.setUint32(20, minJitter);
}
else {
this.setJitterBit(false);
}
this.setSerializationNeeded(true);
}
/**
* Get maximum jitter.
*
* @remarks
* - It could be `undefined` if the field is unset in the report.
*/
getMaxJitter() {
if (!this.hasJitterBit()) {
return undefined;
}
return this.view.getUint32(24);
}
/**
* Set maximum jitter.
*/
setMaxJitter(maxJitter) {
if (maxJitter !== undefined) {
this.setJitterBit(true);
this.view.setUint32(24, maxJitter);
}
else {
this.setJitterBit(false);
}
this.setSerializationNeeded(true);
}
/**
* Get mean jitter.
*
* @remarks
* - It could be `undefined` if the field is unset in the report.
*/
getMeanJitter() {
if (!this.hasJitterBit()) {
return undefined;
}
return this.view.getUint32(28);
}
/**
* Set mean jitter.
*/
setMeanJitter(meanJitter) {
if (meanJitter !== undefined) {
this.setJitterBit(true);
this.view.setUint32(28, meanJitter);
}
else {
this.setJitterBit(false);
}
this.setSerializationNeeded(true);
}
/**
* Get dev jitter.
*
* @remarks
* - It could be `undefined` if the field is unset in the report.
*/
getDevJitter() {
if (!this.hasJitterBit()) {
return undefined;
}
return this.view.getUint32(32);
}
/**
* Set dev jitter.
*/
setDevJitter(devJitter) {
if (devJitter !== undefined) {
this.setJitterBit(true);
this.view.setUint32(32, devJitter);
}
else {
this.setJitterBit(false);
}
this.setSerializationNeeded(true);
}
/**
* Get minimum TTL or Hop Limit value.
*
* @remarks
* - It could be `undefined` if the field is unset in the report.
*/
getMinTtlOrHopLimit() {
if (!this.getTtlOrHopLimitMode()) {
return undefined;
}
return this.view.getUint8(36);
}
/**
* Set minimum TTL or Hop Limit value.
*/
setMinTtlOrHl(minTtlOrHl) {
if (minTtlOrHl !== undefined) {
if (!this.getTtlOrHopLimitMode()) {
this.setTtlOrHlMode('ipv4-ttl');
}
this.view.setUint8(36, minTtlOrHl);
}
else {
this.setTtlOrHlMode(undefined);
}
this.setSerializationNeeded(true);
}
/**
* Get maximum TTL or Hop Limit value.
*
* @remarks
* - It could be `undefined` if the field is unset in the report.
*/
getMaxTtlOrHopLimit() {
if (!this.getTtlOrHopLimitMode()) {
return undefined;
}
return this.view.getUint8(37);
}
/**
* Set maximum TTL or Hop Limit value.
*/
setMaxTtlOrHl(maxTtlOrHl) {
if (maxTtlOrHl !== undefined) {
if (!this.getTtlOrHopLimitMode()) {
this.setTtlOrHlMode('ipv4-ttl');
}
this.view.setUint8(37, maxTtlOrHl);
}
else {
this.setTtlOrHlMode(undefined);
}
this.setSerializationNeeded(true);
}
/**
* Get mean TTL or Hop Limit value.
*
* @remarks
* - It could be `undefined` if the field is unset in the report.
*/
getMeanTtlOrHopLimit() {
if (!this.getTtlOrHopLimitMode()) {
return undefined;
}
return this.view.getUint8(38);
}
/**
* Set mean TTL or Hop Limit value.
*/
setMeanTtlOrHl(meanTtlOrHl) {
if (meanTtlOrHl !== undefined) {
if (!this.getTtlOrHopLimitMode()) {
this.setTtlOrHlMode('ipv4-ttl');
}
this.view.setUint8(38, meanTtlOrHl);
}
else {
this.setTtlOrHlMode(undefined);
}
this.setSerializationNeeded(true);
}
/**
* Get dev TTL or Hop Limit value.
*
* @remarks
* - It could be `undefined` if the field is unset in the report.
*/
getDevTtlOrHopLimit() {
if (!this.getTtlOrHopLimitMode()) {
return undefined;
}
return this.view.getUint8(39);
}
/**
* Set dev TTL or Hop Limit value.
*/
setDevTtlOrHl(devTtlOrHl) {
if (devTtlOrHl !== undefined) {
if (!this.getTtlOrHopLimitMode()) {
this.setTtlOrHlMode('ipv4-ttl');
}
this.view.setUint8(39, devTtlOrHl);
}
else {
this.setTtlOrHlMode(undefined);
}
this.setSerializationNeeded(true);
}
getTtlOrHopLimitMode() {
const value = (0, bitOps_1.readBitsInDataView)({
view: this.view,
pos: 1,
mask: 0b00011000,
});
if (value === 1) {
return 'ipv4-ttl';
}
else if (value === 2) {
return 'ipv6-hop-limit';
}
else {
return undefined;
}
}
setTtlOrHlMode(mode) {
if (mode === 'ipv4-ttl') {
(0, bitOps_1.writeBitsInDataView)({
view: this.view,
pos: 1,
mask: 0b00011000,
value: 1,
});
}
else if (mode === 'ipv6-hop-limit') {
(0, bitOps_1.writeBitsInDataView)({
view: this.view,
pos: 1,
mask: 0b00011000,
value: 2,
});
}
else {
(0, bitOps_1.writeBitsInDataView)({
view: this.view,
pos: 1,
mask: 0b00011000,
value: 0,
});
this.view.setUint8(36, 0);
this.view.setUint8(37, 0);
this.view.setUint8(38, 0);
this.view.setUint8(39, 0);
}
this.setSerializationNeeded(true);
}
hasLostPacketsBit() {
return (0, bitOps_1.readBitInDataView)({ view: this.view, pos: 1, bit: 7 });
}
setLostPacketsBit(flag) {
(0, bitOps_1.writeBitInDataView)({ view: this.view, pos: 1, bit: 1, flag });
if (!flag) {
this.view.setUint32(12, 0);
}
}
hasDuplicatePacketsBit() {
return (0, bitOps_1.readBitInDataView)({ view: this.view, pos: 1, bit: 6 });
}
setDuplicatePacketsBit(flag) {
(0, bitOps_1.writeBitInDataView)({ view: this.view, pos: 1, bit: 6, flag });
if (!flag) {
this.view.setUint32(16, 0);
}
}
hasJitterBit() {
return (0, bitOps_1.readBitInDataView)({ view: this.view, pos: 1, bit: 5 });
}
setJitterBit(flag) {
(0, bitOps_1.writeBitInDataView)({ view: this.view, pos: 1, bit: 5, flag });
if (!flag) {
this.view.setUint32(20, 0);
this.view.setUint32(24, 0);
this.view.setUint32(28, 0);
this.view.setUint32(32, 0);
}
}
}
exports.SsExtendedReport = SsExtendedReport;