parser_rtp.js (5016B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 /** 8 * Parses an RTP packet 9 * 10 * @param buffer an ArrayBuffer that contains the packet 11 * @return { type: "rtp", header: {...}, payload: a DataView } 12 */ 13 var ParseRtpPacket = buffer => { 14 // DataView.getFooInt returns big endian numbers by default 15 let view = new DataView(buffer); 16 17 // Standard Header Fields 18 // https://tools.ietf.org/html/rfc3550#section-5.1 19 // 0 1 2 3 20 // 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 21 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 22 // |V=2|P|X| CC |M| PT | sequence number | 23 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 24 // | timestamp | 25 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 26 // | synchronization source (SSRC) identifier | 27 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 28 // | contributing source (CSRC) identifiers | 29 // | .... | 30 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 31 32 let header = {}; 33 let offset = 0; 34 // Note that incrementing the offset happens as close to reading the data as 35 // possible. This simplifies ensuring that the number of read bytes and the 36 // offset increment match. Data may be manipulated between when the offset is 37 // incremented and before the next read. 38 let byte = view.getUint8(offset); 39 offset++; 40 // Version 2 Bit 41 header.version = (0xc0 & byte) >> 6; 42 // Padding 1 Bit 43 header.padding = (0x30 & byte) >> 5; 44 // Extension 1 Bit 45 header.extensionsPresent = (0x10 & byte) >> 4 == 1; 46 // CSRC count 4 Bit 47 header.csrcCount = 0xf & byte; 48 49 byte = view.getUint8(offset); 50 offset++; 51 // Marker 1 Bit 52 header.marker = (0x80 & byte) >> 7; 53 // Payload Type 7 Bit 54 header.payloadType = 0x7f & byte; 55 // Sequence Number 16 Bit 56 header.sequenceNumber = view.getUint16(offset); 57 offset += 2; 58 // Timestamp 32 Bit 59 header.timestamp = view.getUint32(offset); 60 offset += 4; 61 // SSRC 32 Bit 62 header.ssrc = view.getUint32(offset); 63 offset += 4; 64 65 // CSRC 32 Bit 66 header.csrcs = []; 67 for (let c = 0; c < header.csrcCount; c++) { 68 header.csrcs.push(view.getUint32(offset)); 69 offset += 4; 70 } 71 72 // Extensions 73 header.extensions = []; 74 header.extensionPaddingBytes = 0; 75 header.extensionsTotalLength = 0; 76 if (header.extensionsPresent) { 77 // https://tools.ietf.org/html/rfc3550#section-5.3.1 78 // 0 1 2 3 79 // 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 80 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 81 // | defined by profile | length | 82 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 83 // | header extension | 84 // | .... | 85 let addExtension = (id, len) => 86 header.extensions.push({ 87 id, 88 data: new DataView(buffer, offset, len), 89 }); 90 let extensionId = view.getUint16(offset); 91 offset += 2; 92 // len is in 32 bit units, not bytes 93 header.extensionsTotalLength = view.getUint16(offset) * 4; 94 offset += 2; 95 // Check for https://tools.ietf.org/html/rfc5285 96 if (extensionId != 0xbede) { 97 // No rfc5285 98 addExtension(extensionId, header.extensionsTotalLength); 99 offset += header.extensionsTotalLength; 100 } else { 101 let expectedEnd = offset + header.extensionsTotalLength; 102 while (offset < expectedEnd) { 103 // We only support "one-byte" extension headers ATM 104 // https://tools.ietf.org/html/rfc5285#section-4.2 105 // 0 106 // 0 1 2 3 4 5 6 7 107 // +-+-+-+-+-+-+-+-+ 108 // | ID | len | 109 // +-+-+-+-+-+-+-+-+ 110 byte = view.getUint8(offset); 111 offset++; 112 // Check for padding which can occur between extensions or at the end 113 if (byte == 0) { 114 header.extensionPaddingBytes++; 115 continue; 116 } 117 let id = (byte & 0xf0) >> 4; 118 // Check for the FORBIDDEN id (15), dun dun dun 119 if (id == 15) { 120 // Ignore bytes until until the end of extensions 121 offset = expectedEnd; 122 break; 123 } 124 // the length of the extention is len + 1 125 let len = (byte & 0x0f) + 1; 126 addExtension(id, len); 127 offset += len; 128 } 129 } 130 } 131 return { type: "rtp", header, payload: new DataView(buffer, offset) }; 132 };