UNPKG

rtp.js

Version:

RTP stack for Node.js and browser written in TypeScript

189 lines (188 loc) 6.44 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ByePacket = void 0; const RtcpPacket_1 = require("./RtcpPacket"); const helpers_1 = require("../../utils/helpers"); /** * RTCP BYE 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * header |V=2|P| SC | PT=BYE=203 | length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | SSRC/CSRC | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * : ... : * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * (opt) | length | reason for leaving ... * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * ``` * * @category RTCP * * @see * - [RFC 3550 section 6.6](https://datatracker.ietf.org/doc/html/rfc3550#section-6.6) */ class ByePacket extends RtcpPacket_1.RtcpPacket { // SSRC/CSRC array. #ssrcs = []; // Termination season. #reason; /** * @param view - If given it will be parsed. Otherwise an empty RTCP BYE * packet will be created. * * @throws * - If given `view` does not contain a valid RTCP BYE packet. */ constructor(view) { super(RtcpPacket_1.RtcpPacketType.BYE, view); if (!this.view) { this.view = new DataView(new ArrayBuffer(RtcpPacket_1.COMMON_HEADER_LENGTH)); // Write version and packet type. this.writeCommonHeader(); return; } // Position relative to the DataView byte offset. let pos = 0; // Move to SSRC/CSRC field(s). pos += RtcpPacket_1.COMMON_HEADER_LENGTH; let count = this.getCount(); while (count-- > 0) { const ssrc = this.view.getUint32(pos); this.#ssrcs.push(ssrc); pos += 4; } // Check if there is reason. if (pos + this.padding < this.view.byteLength) { const reasonLength = this.view.getUint8(pos); const reasonPadding = -(reasonLength + 1) & 3; // Move to the reason field. pos += 1; const reasonView = new DataView(this.view.buffer, this.view.byteOffset + pos, reasonLength); this.#reason = (0, helpers_1.dataViewToString)(reasonView); pos += reasonLength + reasonPadding; } pos += this.padding; // Ensure that view length and parsed length match. if (pos !== this.view.byteLength) { throw new RangeError(`parsed length (${pos} bytes) does not match view length (${this.view.byteLength} bytes)`); } } /** * Dump RTCP BYE packet info. */ dump() { return { ...super.dump(), ssrcs: this.getSsrcs(), reason: this.getReason(), }; } /** * @inheritDoc */ getByteLength() { if (!this.needsSerialization()) { return this.view.byteLength; } let packetLength = RtcpPacket_1.COMMON_HEADER_LENGTH + this.#ssrcs.length * 4; if (this.#reason) { const reasonLength = (0, helpers_1.getStringByteLength)(this.#reason); const reasonPadding = -(reasonLength + 1) & 3; packetLength += 1 + reasonLength + reasonPadding; } packetLength += this.padding; return packetLength; } /** * @inheritDoc */ serialize(buffer, byteOffset) { const view = this.serializeBase(buffer, byteOffset); // Position relative to the DataView byte offset. let pos = 0; // Move to SSRCs/CSRCs. pos += RtcpPacket_1.COMMON_HEADER_LENGTH; // Write SSRCs/CSRCs. for (const ssrc of this.#ssrcs) { view.setUint32(pos, ssrc); pos += 4; } if (this.#reason) { const reasonUint8Array = (0, helpers_1.stringToUint8Array)(this.#reason); const reasonLength = reasonUint8Array.byteLength; const reasonPadding = -(reasonLength + 1) & 3; const uint8Array = new Uint8Array(view.buffer, view.byteOffset, view.byteLength); // Write reason length. view.setUint8(pos, reasonLength); // Move to reason field. pos += 1; // Copy reason. uint8Array.set(reasonUint8Array, pos); // Move to padding. pos += reasonLength + reasonPadding; } pos += this.padding; // Assert that current position is equal than new buffer length. if (pos !== view.byteLength) { throw new RangeError(`filled length (${pos} bytes) is different than 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 ByePacket(view); } /** * Get SSRC values. */ getSsrcs() { return Array.from(this.#ssrcs); } /** * Set SSRC values. * * @remarks * - Serialization is needed after calling this method. */ setSsrcs(ssrcs) { this.#ssrcs = Array.from(ssrcs); // Update RTCP count. this.setCount(this.#ssrcs.length); this.setSerializationNeeded(true); } /** * Add SSRC value. * * @remarks * - Serialization is needed after calling this method. */ addSsrc(ssrc) { this.#ssrcs.push(ssrc); // Update RTCP count. this.setCount(this.#ssrcs.length); this.setSerializationNeeded(true); } /** * Get reason. */ getReason() { return this.#reason; } /** * Set reason. */ setReason(reason) { this.#reason = reason; this.setSerializationNeeded(true); } } exports.ByePacket = ByePacket;