UNPKG

rtp.js

Version:

RTP stack for Node.js and browser written in TypeScript

281 lines (280 loc) 9.12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RtcpPacket = exports.RtcpPacketType = exports.COMMON_HEADER_LENGTH = void 0; exports.isRtcp = isRtcp; exports.getRtcpPacketType = getRtcpPacketType; exports.getRtcpLength = getRtcpLength; exports.packetTypeToString = packetTypeToString; const Packet_1 = require("../Packet"); const helpers_1 = require("../../utils/helpers"); const bitOps_1 = require("../../utils/bitOps"); /** * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * header |V=2|P| SC | PT | length | * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ */ exports.COMMON_HEADER_LENGTH = 4; /** * RTCP packet types. * * @category RTCP */ var RtcpPacketType; (function (RtcpPacketType) { /** * Extended Jitter Reports packet. */ RtcpPacketType[RtcpPacketType["IJ"] = 195] = "IJ"; /** * RTCP Sender Report packet. */ RtcpPacketType[RtcpPacketType["SR"] = 200] = "SR"; /** * RTCP Receiver Report packet. */ RtcpPacketType[RtcpPacketType["RR"] = 201] = "RR"; /** * RTCP Sender Report packet. */ RtcpPacketType[RtcpPacketType["SDES"] = 202] = "SDES"; /** * RTCP BYE packet. */ RtcpPacketType[RtcpPacketType["BYE"] = 203] = "BYE"; /** * RTCP APP packet. */ RtcpPacketType[RtcpPacketType["APP"] = 204] = "APP"; /** * RTCP Transport Layer Feedback packet. */ RtcpPacketType[RtcpPacketType["RTPFB"] = 205] = "RTPFB"; /** * RTCP Payload Specific Feedback packet. */ RtcpPacketType[RtcpPacketType["PSFB"] = 206] = "PSFB"; /** * RTCP Extended Report packet. */ RtcpPacketType[RtcpPacketType["XR"] = 207] = "XR"; })(RtcpPacketType || (exports.RtcpPacketType = RtcpPacketType = {})); /** * Whether the given buffer view could be a valid RTCP packet or not. * * @category RTCP */ function isRtcp(view) { const firstByte = view.getUint8(0); const secondByte = view.getUint8(1); return (view.byteLength >= exports.COMMON_HEADER_LENGTH && // DOC: https://tools.ietf.org/html/draft-ietf-avtcore-rfc5764-mux-fixes firstByte > 127 && firstByte < 192 && // RTCP Version must be 2. firstByte >> 6 === Packet_1.RTP_VERSION && // RTCP packet types defined by IANA: // http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-4 // RFC 5761 (RTCP-mux) states this range for secure RTCP/RTP detection. secondByte >= 192 && secondByte <= 223); } /** * Get the RTCP packet type. * * @hidden */ function getRtcpPacketType(view) { return view.getUint8(1); } /** * Read the RTCP header length value and compute its size in bytes (including * first octet). * * @hidden */ function getRtcpLength(view) { // As per RFC 3550, this is the length of this RTCP packet 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 RTCP header length field. * * @hidden */ function setRtcpLength(view, byteLength) { // RTCP packet byte length must be multiple of 4. if (byteLength % 4 !== 0) { throw new RangeError(`RTCP packet byte length must be multiple of 4 but given byte length is ${byteLength} bytes`); } const length = byteLength / 4 - 1; view.setUint16(2, length); } /** * @hidden */ function packetTypeToString(packetType) { switch (packetType) { case RtcpPacketType.SR: { return 'Sender Report'; } case RtcpPacketType.RR: { return 'Receiver Report'; } case RtcpPacketType.SDES: { return 'SDES'; } case RtcpPacketType.BYE: { return 'BYE'; } case RtcpPacketType.APP: { return 'APP'; } case RtcpPacketType.RTPFB: { return 'RTP Feedback'; } case RtcpPacketType.PSFB: { return 'PS Feedback'; } case RtcpPacketType.XR: { return 'Extended Report'; } case RtcpPacketType.IJ: { return 'Extended Jitter Reports'; } default: { (0, helpers_1.assertUnreachable)(packetType); } } } /** * RTCP packet. Parent class of all RTCP packets. * * ```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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * header |V=2|P| SC | PT | length | * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * ``` * * @category RTCP * * @see * - [RFC 3550 section 6.1](https://datatracker.ietf.org/doc/html/rfc3550#section-6.1) */ class RtcpPacket extends Packet_1.Packet { // RTCP packet type. #packetType; constructor(packetType, view) { super(view); this.#packetType = packetType; if (this.view) { if (!isRtcp(this.view)) { throw new TypeError('not a RTCP packet'); } else if (this.getPacketType() !== this.#packetType) { throw new TypeError(`given buffer view is not a RTCP ${packetTypeToString(this.#packetType)} packet`); } // RTCP packet byte length must be multiple of 4. else if (this.view.byteLength % 4 !== 0) { throw new RangeError(`RTCP packet byte length must be multiple of 4 but given buffer view is ${this.view.byteLength} bytes`); } else if (getRtcpLength(this.view) !== this.view.byteLength) { throw new RangeError(`length in the RTCP header (${getRtcpLength(this.view)} bytes) does not match buffer view length (${this.view.byteLength} bytes)`); } // Get padding. if (this.hasPaddingBit()) { this.padding = this.view.getUint8(this.view.byteLength - 1); } } } /** * Base RTCP packet dump. * * @remarks * - Read the info dump type of each RTCP packet instead. */ dump() { return { ...super.dump(), packetType: this.getPacketType(), count: this.getCount(), }; } /** * Get the RTCP packet type. */ getPacketType() { return this.view.getUint8(1); } /** * Get the RTCP header count value. * * @remarks * - Some RTCP packets do not use this byte (the second one in the common * RTCP header) for counting chunks or items. */ getCount() { return (0, bitOps_1.readBitsInDataView)({ view: this.view, pos: 0, mask: 0b00011111 }); } writeCommonHeader() { this.setVersion(); this.setPacketType(); // Update the length field in the RTCP header. setRtcpLength(this.view, this.view.byteLength); } /** * Set the RTCP header count value. * * @privateRemarks * - This method is not public since users should not manipulate this field * directly. * - Also, there is no `count` field in all RTCP packets. For instance, XR * and APP packets do not have it. */ setCount(count) { (0, bitOps_1.writeBitsInDataView)({ view: this.view, pos: 0, mask: 0b00011111, value: count, }); } /** * 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 length field in the RTCP header. setRtcpLength(view, view.byteLength); // Write padding. if (this.padding > 0) { if (this.padding > 255) { throw new TypeError(`padding (${this.padding} bytes) cannot be higher than 255`); } view.setUint8(view.byteLength - 1, this.padding); } return view; } /** * Set the RTCP packet type. * * @privateRemarks * - This method is not public since users should not manipulate this field * directly. */ setPacketType() { this.view.setUint8(1, this.#packetType); } } exports.RtcpPacket = RtcpPacket;