import Foundation /// An RTP packet: 12-byte base header (plus optional CSRC/extension) and payload. struct RtpPacket { let header: RtpHeader let payload: [UInt8] init(header: RtpHeader, payload: [UInt8]) { self.header = header self.payload = payload } /// Parses a full RTP datagram. Honors CSRC lists, one-level extension /// headers, and RFC 3550 padding, mirroring the C++ receiver. static func parse(_ input: [UInt8]) -> RtpPacket? { guard input.count >= 12, let header = RtpHeader.parse(input) else { return nil } var offset = 12 + header.csrcCount * 4 guard input.count >= offset else { return nil } if header.extensionHeader { guard input.count >= offset + 4 else { return nil } let extensionWords = (Int(input[offset + 2]) << 8) | Int(input[offset + 3]) offset += 4 + extensionWords * 4 guard input.count >= offset else { return nil } } var payloadSize = input.count - offset if header.padding { // RFC 3550: the last byte holds the padding size, including itself. guard payloadSize > 0 else { return nil } let paddingSize = Int(input[input.count - 1]) guard paddingSize != 0, paddingSize <= payloadSize else { return nil } payloadSize -= paddingSize } return RtpPacket(header: header, payload: Array(input[offset..<(offset + payloadSize)])) } }