rtp.js
Version:
RTP stack for Node.js and browser written in TypeScript
226 lines (225 loc) • 7.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.FeedbackPacket = exports.PsFeedbackMessageType = exports.RtpFeedbackMessageType = exports.FIXED_HEADER_LENGTH = void 0;
exports.getRtcpFeedbackMessageType = getRtcpFeedbackMessageType;
const RtcpPacket_1 = require("./RtcpPacket");
const helpers_1 = require("../../utils/helpers");
const bitOps_1 = require("../../utils/bitOps");
// Common RTCP header length + 4 (SSRC of packet sender) + 4 (SSRC of media
// source).
exports.FIXED_HEADER_LENGTH = RtcpPacket_1.COMMON_HEADER_LENGTH + 8;
/**
* RTCP Feedback transport layer message types.
*
* @category RTCP
*/
var RtpFeedbackMessageType;
(function (RtpFeedbackMessageType) {
/**
* Generic NACK.
*/
RtpFeedbackMessageType[RtpFeedbackMessageType["NACK"] = 1] = "NACK";
/**
* Rapid Resynchronisation Request.
*/
RtpFeedbackMessageType[RtpFeedbackMessageType["SR_REQ"] = 5] = "SR_REQ";
/**
* Explicit Congestion Notification (ECN).
*/
RtpFeedbackMessageType[RtpFeedbackMessageType["ECN"] = 8] = "ECN";
})(RtpFeedbackMessageType || (exports.RtpFeedbackMessageType = RtpFeedbackMessageType = {}));
/**
* RTCP Feedback payload specific message types.
*
* @category RTCP
*/
var PsFeedbackMessageType;
(function (PsFeedbackMessageType) {
/**
* Picture Loss Indication.
*/
PsFeedbackMessageType[PsFeedbackMessageType["PLI"] = 1] = "PLI";
/**
* Slice Loss Indication.
*/
PsFeedbackMessageType[PsFeedbackMessageType["SLI"] = 2] = "SLI";
/**
* Reference Picture Selection Indication.
*/
PsFeedbackMessageType[PsFeedbackMessageType["RPSI"] = 3] = "RPSI";
/**
* Application layer FB message.
*/
PsFeedbackMessageType[PsFeedbackMessageType["AFB"] = 15] = "AFB";
})(PsFeedbackMessageType || (exports.PsFeedbackMessageType = PsFeedbackMessageType = {}));
/**
* Get the RTCP Feedback message type.
*
* @hidden
*/
function getRtcpFeedbackMessageType(view) {
return (0, bitOps_1.readBitsInDataView)({ view, pos: 0, mask: 0b00011111 });
}
function messageTypeToString(packetType, messageType) {
switch (packetType) {
case RtcpPacket_1.RtcpPacketType.RTPFB: {
messageType = messageType;
switch (messageType) {
case RtpFeedbackMessageType.NACK: {
return 'Generic NACK';
}
case RtpFeedbackMessageType.SR_REQ: {
return 'Rapid Resynchronisation Request';
}
case RtpFeedbackMessageType.ECN: {
return 'Explicit Congestion Notification (ECN)';
}
default: {
(0, helpers_1.assertUnreachable)(messageType);
}
}
// @ts-expect-error --- Ignore "error TS7027: Unreachable code detected"
// to not conflict with ESLint rules.
break;
}
case RtcpPacket_1.RtcpPacketType.PSFB: {
messageType = messageType;
switch (messageType) {
case PsFeedbackMessageType.PLI: {
return 'Picture Loss Indication';
}
case PsFeedbackMessageType.SLI: {
return 'Slice Loss Indication';
}
case PsFeedbackMessageType.RPSI: {
return 'Reference Picture Selection Indication';
}
case PsFeedbackMessageType.AFB: {
return 'Application layer FB message';
}
default: {
(0, helpers_1.assertUnreachable)(messageType);
}
}
// @ts-expect-error --- Ignore "error TS7027: Unreachable code detected"
// to not conflict with ESLint rules.
break;
}
default: {
(0, helpers_1.assertUnreachable)(packetType);
}
}
}
/**
* RTCP Feedback packet.
*
* ```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 | PT | length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | SSRC of packet sender |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | SSRC of media source |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* : Feedback Control Information (FCI) :
* : :
* ```
*
* @category RTCP
*
* @see
* - [RFC 4585 section 6.1](https://datatracker.ietf.org/doc/html/rfc4585#section-6.1)
*/
class FeedbackPacket extends RtcpPacket_1.RtcpPacket {
// RTCP Feedback message type.
#messageType;
constructor(packetType, messageType, view) {
super(packetType, view);
this.#messageType = messageType;
if (this.view) {
if (this.getMessageType() !== this.#messageType) {
throw new TypeError(`given buffer view is not a RTCP ${(0, RtcpPacket_1.packetTypeToString)(this.getPacketType())} packet with ${messageTypeToString(packetType, this.#messageType)} message type`);
}
}
}
/**
* Base RTCP Feedback packet dump.
*
* @remarks
* - Read the info dump type of each RTCP Feedback packet instead.
*/
dump() {
return {
...super.dump(),
messageType: this.getMessageType(),
senderSsrc: this.getSenderSsrc(),
mediaSsrc: this.getMediaSsrc(),
};
}
/**
* Get the RTCP Feedback message type.
*/
getMessageType() {
return (0, bitOps_1.readBitsInDataView)({ view: this.view, pos: 0, mask: 0b00011111 });
}
/**
* Get sender SSRC.
*/
getSenderSsrc() {
return this.view.getUint32(4);
}
/**
* Set sender SSRC.
*/
setSenderSsrc(ssrc) {
this.view.setUint32(4, ssrc);
}
/**
* Get media SSRC.
*/
getMediaSsrc() {
return this.view.getUint32(8);
}
/**
* Set media SSRC.
*/
setMediaSsrc(ssrc) {
this.view.setUint32(8, ssrc);
}
writeFixedHeader() {
super.writeCommonHeader();
this.setMessageType();
}
/**
* Serialize base RTCP Feedback packet into a new buffer.
*/
serializeBase(buffer, byteOffset) {
const view = super.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 += RtcpPacket_1.COMMON_HEADER_LENGTH;
// Copy the rest of the fixed header into the new buffer.
uint8Array.set(new Uint8Array(this.view.buffer, this.view.byteOffset + pos, exports.FIXED_HEADER_LENGTH - RtcpPacket_1.COMMON_HEADER_LENGTH), pos);
return view;
}
/**
* Set the RTCP Feedback message type.
*
* @privateRemarks
* - This method is not public since users should not manipulate this field
* directly.
*/
setMessageType() {
(0, bitOps_1.writeBitsInDataView)({
view: this.view,
pos: 0,
mask: 0b00011111,
value: this.#messageType,
});
}
}
exports.FeedbackPacket = FeedbackPacket;