UNPKG

rtp.js

Version:

RTP stack for Node.js and browser written in TypeScript

474 lines (473 loc) 17.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const CompoundPacket_1 = require("../../../packets/RTCP/CompoundPacket"); const RtcpPacket_1 = require("../../../packets/RTCP/RtcpPacket"); const FeedbackPacket_1 = require("../../../packets/RTCP/FeedbackPacket"); const ReceiverReportPacket_1 = require("../../../packets/RTCP/ReceiverReportPacket"); const SenderReportPacket_1 = require("../../../packets/RTCP/SenderReportPacket"); const PliPacket_1 = require("../../../packets/RTCP/PliPacket"); const GenericPacket_1 = require("../../../packets/RTCP/GenericPacket"); const helpers_1 = require("../../../utils/helpers"); describe('parse RTCP Compound packet', () => { const array = new Uint8Array([ /* (packet 1) Reception Report packet */ 0x82, 0xc9, 0x00, 0x0d, // Type: 201 (Receiver Report), Count: 2, Length: 13 0x5d, 0x93, 0x15, 0x34, // Sender SSRC: 0x5d931534 // Reception Report 0x01, 0x93, 0x2d, 0xb4, // SSRC: 0x01932db4 0x50, 0x00, 0x00, 0xd8, // Fraction lost: 80, Total lost: 216 0x00, 0x05, 0x39, 0x46, // Extended highest sequence number: 342342 0x00, 0x00, 0x00, 0x00, // Jitter: 0 0x00, 0x00, 0x20, 0x2a, // Last SR: 8234 0x00, 0x00, 0x00, 0x05, // DLSR: 5 // Reception Report 0x02, 0x93, 0x2d, 0xb4, // SSRC: 0x02932db4 0x51, 0x00, 0x00, 0xd9, // Fraction lost: 81, Total lost: 217 0x00, 0x05, 0x39, 0x47, // Extended highest sequence number: 342343 0x00, 0x00, 0x00, 0x02, // Jitter: 2 0x00, 0x00, 0x20, 0x2b, // Last SR: 8235 0x00, 0x00, 0x00, 0x06, // DLSR: 6 /* (packet 2) Sender Report packet */ 0x81, 0xc8, 0x00, 0x0c, // Type: 200 (Sender Report), Count: 1, Length: 12 0x5d, 0x93, 0x15, 0x34, // SSRC: 0x5d931534 0xdd, 0x3a, 0xc1, 0xb4, // NTP Sec: 3711615412 0x76, 0x54, 0x71, 0x71, // NTP Frac: 1985245553 0x00, 0x08, 0xcf, 0x00, // RTP timestamp: 577280 0x00, 0x00, 0x0e, 0x18, // Packet count: 3608 0x00, 0x08, 0xcf, 0x00, // Octet count: 577280 // Reception Report 0x01, 0x93, 0x2d, 0xb4, // SSRC: 0x01932db4 0x50, 0x00, 0x00, 0xd8, // Fraction lost: 0, Total lost: 1 0x00, 0x05, 0x39, 0x46, // Extended highest sequence number: 0 0x00, 0x00, 0x00, 0x00, // Jitter: 0 0x00, 0x00, 0x20, 0x2a, // Last SR: 8234 0x00, 0x00, 0x00, 0x05, // DLSR: 5 /* (packet 3) BYE packet */ 0xa2, 0xcb, 0x00, 0x07, // Padding, Type: 203 (BYE), Count: 2, Length: 7 0x62, 0x42, 0x76, 0xe0, // SSRC: 0x624276e0 0x26, 0x24, 0x67, 0x0e, // SSRC: 0x2624670e 0x0e, 0x48, 0x61, 0x73, // Length: 14, Text: "Hasta la vista" 0x74, 0x61, 0x20, 0x6c, 0x61, 0x20, 0x76, 0x69, 0x73, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00, 0x04, // Padding (4 bytes) /* (packet 4) Generic packet */ 0xa2, 0xc1, 0x00, 0x03, // Padding, Type: 193 (unknown), Count: 2, Length: 3 0x11, 0x22, 0x33, 0x44, // Body 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x00, 0x03, // Padding (3 bytes) /* (packet 5) SDES packet */ 0x81, 0xca, 0x00, 0x03, // Type: 202 (SDES), Count: 1, Length: 3 // Chunk 0x11, 0x22, 0x33, 0x44, // SSRC: 0x11223344 0x05, 0x02, 0x61, 0x62, // Item Type: 5 (XXXX), Length: 2, Text: "ab" 0x00, 0x00, 0x00, 0x00, // 4 null octets /* (packet 6) XR packet */ 0x80, 0xcf, 0x00, 0x06, // Type: 207 (XR), Length: 6 0x5d, 0x93, 0x15, 0x34, // Sender SSRC: 0x5d931534 // Extended Report LRLE 0x01, 0x09, 0x00, 0x04, // BT: 1 (LRLE), T: 9, Block Length: 4 0x03, 0x93, 0x2d, 0xb4, // SSRC of source: 0x03932db4 0x00, 0x11, 0x00, 0x22, // Begin Seq: 0x11, End Seq: 0x22 0b00101010, 0b10101010, // Run Lengh Chunk (zeros) 0b01101010, 0b10101010, // Run Lengh Chunk (ones) 0b11101010, 0b10101010, // Bit Vector Chunk 0b00000000, 0b00000000, // Terminating Null Chunk // (packet 7) NACK packet */ 0xa1, 0xcd, 0x00, 0x04, // Padding, Type: 205 (RTPFB), FMT: 1 (NACK), Length: 4 0x11, 0x22, 0x33, 0x44, // Sender SSRC: 0x11223344 0x55, 0x66, 0x77, 0x88, // Sender SSRC: 0x55667788 0x03, 0xe8, // PID: 1000 0b10101010, 0b10101010, // BLP: 0b1010101010101010 0x00, 0x00, 0x00, 0x04, // Padding (4 bytes) ]); const view = new DataView(array.buffer, array.byteOffset, array.byteLength); test('buffer view is RTCP', () => { expect((0, RtcpPacket_1.isRtcp)(view)).toBe(true); }); test('packet processing succeeds', () => { const compoundPacket = new CompoundPacket_1.CompoundPacket(view); expect(compoundPacket.needsSerialization()).toBe(false); expect(compoundPacket.getByteLength()).toBe(220); expect(compoundPacket.getPackets().length).toBe(7); expect((0, helpers_1.areDataViewsEqual)(compoundPacket.getView(), view)).toBe(true); const packet1 = compoundPacket.getPackets()[0]; expect(packet1.needsSerialization()).toBe(false); expect(packet1.getByteLength()).toBe(56); expect(packet1.getPacketType()).toBe(RtcpPacket_1.RtcpPacketType.RR); expect(packet1.getCount()).toBe(2); expect(packet1.getPadding()).toBe(0); expect(packet1.getSsrc()).toBe(0x5d931534); const packet2 = compoundPacket.getPackets()[1]; expect(packet2.needsSerialization()).toBe(false); expect(packet2.getByteLength()).toBe(52); expect(packet2.getPacketType()).toBe(RtcpPacket_1.RtcpPacketType.SR); expect(packet2.getCount()).toBe(1); expect(packet2.getPadding()).toBe(0); expect(packet2.getSsrc()).toBe(0x5d931534); expect(packet2.getNtpSeconds()).toBe(3711615412); expect(packet2.getNtpFraction()).toBe(1985245553); expect(packet2.getRtpTimestamp()).toBe(577280); expect(packet2.getPacketCount()).toBe(3608); expect(packet2.getOctetCount()).toBe(577280); const packet3 = compoundPacket.getPackets()[2]; expect(packet3.needsSerialization()).toBe(false); expect(packet3.getByteLength()).toBe(32); expect(packet3.getPacketType()).toBe(RtcpPacket_1.RtcpPacketType.BYE); expect(packet3.getCount()).toBe(2); expect(packet3.getPadding()).toBe(4); expect(packet3.getSsrcs()).toEqual([0x624276e0, 0x2624670e]); expect(packet3.getReason()).toBe('Hasta la vista'); const packet4 = compoundPacket.getPackets()[3]; expect(packet4.needsSerialization()).toBe(false); expect(packet4.getByteLength()).toBe(16); expect(packet4.getPacketType()).toBe(193); expect(packet4.getCount()).toBe(2); expect(packet4.getPadding()).toBe(3); expect(packet4.needsSerialization()).toBe(false); expect(packet4.getBody()).toEqual((0, helpers_1.numericArrayToDataView)([ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, ])); const packet5 = compoundPacket.getPackets()[4]; expect(packet5.needsSerialization()).toBe(false); expect(packet5.getByteLength()).toBe(16); expect(packet5.getPacketType()).toBe(RtcpPacket_1.RtcpPacketType.SDES); expect(packet5.getCount()).toBe(1); expect(packet5.getPadding()).toBe(0); expect(packet5.getChunks().length).toBe(1); const packet6 = compoundPacket.getPackets()[5]; expect(packet6.needsSerialization()).toBe(false); expect(packet6.getByteLength()).toBe(28); expect(packet6.getPacketType()).toBe(RtcpPacket_1.RtcpPacketType.XR); expect(packet6.getCount()).toBe(0); // No count in XR packets. expect(packet6.getPadding()).toBe(0); expect(packet6.getSsrc()).toBe(0x5d931534); expect(packet6.getReports().length).toBe(1); const packet7 = compoundPacket.getPackets()[6]; expect(packet7.needsSerialization()).toBe(false); expect(packet7.getByteLength()).toBe(20); expect(packet7.getPacketType()).toBe(RtcpPacket_1.RtcpPacketType.RTPFB); expect(packet7.getMessageType()).toBe(FeedbackPacket_1.RtpFeedbackMessageType.NACK); expect(packet7.getPadding()).toBe(4); expect(packet7.getItems()).toEqual([ { pid: 1000, bitmask: 0b1010101010101010 }, ]); expect(compoundPacket.dump()).toEqual({ padding: 0, byteLength: 220, packets: [ packet1.dump(), packet2.dump(), packet3.dump(), packet4.dump(), packet5.dump(), packet6.dump(), packet7.dump(), ], }); // Also test the same after serializing. compoundPacket.serialize(); expect(compoundPacket.needsSerialization()).toBe(false); expect(compoundPacket.getByteLength()).toBe(220); expect(compoundPacket.getPackets().length).toBe(7); expect((0, helpers_1.areDataViewsEqual)(compoundPacket.getView(), view)).toBe(true); const packet1B = compoundPacket.getPackets()[0]; expect(packet1B.needsSerialization()).toBe(false); expect(packet1B.getByteLength()).toBe(56); expect(packet1B.getPacketType()).toBe(RtcpPacket_1.RtcpPacketType.RR); expect(packet1B.getCount()).toBe(2); expect(packet1B.getPadding()).toBe(0); expect(packet1B.getSsrc()).toBe(0x5d931534); const packet2B = compoundPacket.getPackets()[1]; expect(packet2B.needsSerialization()).toBe(false); expect(packet2B.getByteLength()).toBe(52); expect(packet2B.getPacketType()).toBe(RtcpPacket_1.RtcpPacketType.SR); expect(packet2B.getCount()).toBe(1); expect(packet2B.getPadding()).toBe(0); expect(packet2B.getSsrc()).toBe(0x5d931534); expect(packet2B.getNtpSeconds()).toBe(3711615412); expect(packet2B.getNtpFraction()).toBe(1985245553); expect(packet2B.getRtpTimestamp()).toBe(577280); expect(packet2B.getPacketCount()).toBe(3608); expect(packet2B.getOctetCount()).toBe(577280); const packet3B = compoundPacket.getPackets()[2]; expect(packet3B.needsSerialization()).toBe(false); expect(packet3B.getByteLength()).toBe(32); expect(packet3B.getPacketType()).toBe(RtcpPacket_1.RtcpPacketType.BYE); expect(packet3B.getCount()).toBe(2); expect(packet3B.getPadding()).toBe(4); expect(packet3B.getSsrcs()).toEqual([0x624276e0, 0x2624670e]); expect(packet3B.getReason()).toBe('Hasta la vista'); const packet4B = compoundPacket.getPackets()[3]; expect(packet4B.needsSerialization()).toBe(false); expect(packet4B.getByteLength()).toBe(16); expect(packet4B.getPacketType()).toBe(193); expect(packet4B.getCount()).toBe(2); expect(packet4B.getPadding()).toBe(3); expect(packet4B.needsSerialization()).toBe(false); expect(packet4B.getBody()).toEqual((0, helpers_1.numericArrayToDataView)([ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, ])); const packet5B = compoundPacket.getPackets()[4]; expect(packet5B.needsSerialization()).toBe(false); expect(packet5B.getByteLength()).toBe(16); expect(packet5B.getPacketType()).toBe(RtcpPacket_1.RtcpPacketType.SDES); expect(packet5B.getCount()).toBe(1); expect(packet5B.getPadding()).toBe(0); expect(packet5B.getChunks().length).toBe(1); const packet6B = compoundPacket.getPackets()[5]; expect(packet6B.needsSerialization()).toBe(false); expect(packet6B.getByteLength()).toBe(28); expect(packet6B.getPacketType()).toBe(RtcpPacket_1.RtcpPacketType.XR); expect(packet6B.getCount()).toBe(0); // No count in XR packets. expect(packet6B.getPadding()).toBe(0); expect(packet6B.getSsrc()).toBe(0x5d931534); expect(packet6B.getReports().length).toBe(1); const packet7B = compoundPacket.getPackets()[6]; expect(packet7B.needsSerialization()).toBe(false); expect(packet7B.getByteLength()).toBe(20); expect(packet7B.getPacketType()).toBe(RtcpPacket_1.RtcpPacketType.RTPFB); expect(packet7B.getMessageType()).toBe(FeedbackPacket_1.RtpFeedbackMessageType.NACK); expect(packet7B.getPadding()).toBe(4); expect(packet7B.getItems()).toEqual([ { pid: 1000, bitmask: 0b1010101010101010 }, ]); expect(compoundPacket.dump()).toEqual({ padding: 0, byteLength: 220, packets: [ packet1B.dump(), packet2B.dump(), packet3B.dump(), packet4B.dump(), packet5B.dump(), packet6B.dump(), packet7B.dump(), ], }); // Modify BYE packet. packet3.addSsrc(666); expect(compoundPacket.needsSerialization()).toBe(true); expect(compoundPacket.getByteLength()).toBe(224); expect(compoundPacket.getPackets().length).toBe(7); expect(compoundPacket.dump()).toEqual({ padding: 0, byteLength: 224, packets: [ packet1B.dump(), packet2B.dump(), packet3B.dump(), packet4B.dump(), packet5B.dump(), packet6B.dump(), packet7B.dump(), ], }); }); test('packet.clone() succeeds', () => { const compoundPacket = new CompoundPacket_1.CompoundPacket(view); const clonedCompoundPacket = compoundPacket.clone(); expect(clonedCompoundPacket.needsSerialization()).toBe(false); expect(clonedCompoundPacket.getByteLength()).toBe(compoundPacket.getByteLength()); expect(clonedCompoundPacket.getPackets().length).toBe(compoundPacket.getPackets().length); expect(clonedCompoundPacket.dump()).toEqual(compoundPacket.dump()); expect((0, helpers_1.areDataViewsEqual)(clonedCompoundPacket.getView(), compoundPacket.getView())).toBe(true); }); test('parsing a buffer view with some incomplete packet throws', () => { // Read only 136 bytes of the buffer view. const view2 = new DataView(array.buffer, array.byteOffset, 136); expect(() => new CompoundPacket_1.CompoundPacket(view2)).toThrow(RangeError); }); }); describe('create RTCP Compound packet', () => { test('creating an Compound packet with 3 RTCP packets', () => { const compoundPacket = new CompoundPacket_1.CompoundPacket(); const packet1 = new ReceiverReportPacket_1.ReceiverReportPacket(); const packet2 = new GenericPacket_1.GenericPacket(undefined, 199); const packet3 = new SenderReportPacket_1.SenderReportPacket(); const packet4 = new PliPacket_1.PliPacket(); compoundPacket.addPacket(packet1); compoundPacket.addPacket(packet2); compoundPacket.addPacket(packet3); compoundPacket.addPacket(packet4); expect(compoundPacket.dump()).toEqual({ padding: 0, byteLength: 8 + 4 + 28 + 12, packets: [packet1.dump(), packet2.dump(), packet3.dump(), packet4.dump()], }); compoundPacket.serialize(); expect(compoundPacket.dump()).toEqual({ padding: 0, byteLength: 8 + 4 + 28 + 12, packets: [packet1.dump(), packet2.dump(), packet3.dump(), packet4.dump()], }); const clonedCompoundPacket = compoundPacket.clone(); expect(clonedCompoundPacket.dump()).toEqual({ padding: 0, byteLength: 8 + 4 + 28 + 12, packets: [packet1.dump(), packet2.dump(), packet3.dump(), packet4.dump()], }); }); });