c43dd3ca4a
A native iOS receiver so an iPhone can act as the second receiver, speaking the existing signaling + RTP protocol (no C++ changes) and mirroring the Android receiver (Phase 8) source-to-source. - RTP core (header/packet, jitter buffer, H.264 depacketizer) ported from the Android receiver - BSD-socket signaling server (dual-stack, most-recent-peer, never-throwing sends) + NSBonjourServices - VideoToolbox H.264 decode (in-band SPS/PPS, real-time, rebuilds on size change) -> AVSampleBufferDisplayLayer - PLI keyframe recovery (500 ms) + pendingOffer for late surface attach - XcodeGen project + bootstrap.sh; XCTest port of the Android suite + new coverage - .gitignore for generated artifacts; CHANGELOG; PHASES + MEMORY updated Status: authored; on-device validation pending a Mac + Xcode 26 + iPhone 16.
39 lines
1.5 KiB
Swift
39 lines
1.5 KiB
Swift
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)]))
|
|
}
|
|
}
|