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.
88 lines
3.4 KiB
Swift
88 lines
3.4 KiB
Swift
import XCTest
|
|
@testable import Receiver
|
|
|
|
final class RtpHeaderTests: XCTestCase {
|
|
func testRoundtrip() {
|
|
let header = RtpHeader(version: 2, padding: false, extensionHeader: false, csrcCount: 0,
|
|
marker: true, payloadType: 96, sequenceNumber: 0xABCD,
|
|
timestamp: 0xDEADBEEF, ssrc: 0x12345678)
|
|
let wire = header.serialize()
|
|
XCTAssertEqual(wire.count, 12)
|
|
XCTAssertEqual(RtpHeader.parse(wire), header)
|
|
}
|
|
|
|
func testRejectsBadVersion() {
|
|
var wire = RtpHeader().serialize()
|
|
wire[0] = (wire[0] & 0x3F) | (1 << 6)
|
|
XCTAssertNil(RtpHeader.parse(wire))
|
|
}
|
|
|
|
func testRejectsShortInput() {
|
|
let header = RtpHeader()
|
|
XCTAssertNil(RtpHeader.parse(Array(header.serialize().prefix(11))))
|
|
XCTAssertNil(RtpHeader.parse([]))
|
|
}
|
|
|
|
func testPreservesFlags() {
|
|
let header = RtpHeader(padding: true, csrcCount: 2, marker: true, payloadType: 63)
|
|
let parsed = RtpHeader.parse(header.serialize())
|
|
XCTAssertEqual(parsed?.padding, true)
|
|
XCTAssertEqual(parsed?.csrcCount, 2)
|
|
XCTAssertEqual(parsed?.marker, true)
|
|
XCTAssertEqual(parsed?.payloadType, 63)
|
|
}
|
|
}
|
|
|
|
final class RtpPacketTests: XCTestCase {
|
|
private func header(seq: Int, marker: Bool = false) -> RtpHeader {
|
|
RtpHeader(sequenceNumber: seq, payloadType: 96, marker: marker)
|
|
}
|
|
|
|
func testRoundtripWithPayload() {
|
|
let packet = RtpPacket(header: header(seq: 7), payload: [0x11, 0x22, 0x33])
|
|
let wire = packet.header.serialize() + packet.payload
|
|
let parsed = RtpPacket.parse(wire)
|
|
XCTAssertEqual(parsed?.header, header(seq: 7))
|
|
XCTAssertEqual(parsed?.payload, [0x11, 0x22, 0x33])
|
|
}
|
|
|
|
func testSkipsCsrcList() {
|
|
let header = RtpHeader(csrcCount: 1, sequenceNumber: 3)
|
|
let wire = header.serialize() + [0x0A, 0x00, 0x00, 0x01] + [0x99]
|
|
let parsed = RtpPacket.parse(wire)
|
|
XCTAssertEqual(parsed?.header.csrcCount, 1)
|
|
XCTAssertEqual(parsed?.payload, [0x99])
|
|
}
|
|
|
|
func testSkipsExtensionHeader() {
|
|
let header = RtpHeader(extensionHeader: true, sequenceNumber: 4)
|
|
// profile=0x0001, length=1 word, one word of data.
|
|
let wire = header.serialize() + [0x00, 0x01, 0x00, 0x01, 0xDE, 0xAD, 0xBE, 0xEF] + [0x77]
|
|
let parsed = RtpPacket.parse(wire)
|
|
XCTAssertEqual(parsed?.payload, [0x77])
|
|
}
|
|
|
|
func testStripsPadding() {
|
|
let header = RtpHeader(padding: true, sequenceNumber: 5)
|
|
// Payload byte, one padding zero, size byte (2 = padding incl. itself).
|
|
let wire = header.serialize() + [0x55, 0x00, 0x02]
|
|
let parsed = RtpPacket.parse(wire)
|
|
XCTAssertEqual(parsed?.payload, [0x55])
|
|
}
|
|
|
|
func testRejectsTruncatedCsrcAndExtension() {
|
|
let csrc = RtpHeader(csrcCount: 1).serialize()
|
|
XCTAssertNil(RtpPacket.parse(csrc)) // 12 bytes, needs 16
|
|
let ext = RtpHeader(extensionHeader: true).serialize() + [0x00, 0x01]
|
|
XCTAssertNil(RtpPacket.parse(ext)) // extension length field cut off
|
|
}
|
|
|
|
func testRejectsBadPadding() {
|
|
let zeroPad = RtpHeader(padding: true).serialize() + [0x00]
|
|
XCTAssertNil(RtpPacket.parse(zeroPad))
|
|
let oversized = RtpHeader(padding: true).serialize() + [0x00, 0x00, 0x05]
|
|
XCTAssertNil(RtpPacket.parse(oversized))
|
|
XCTAssertNil(RtpPacket.parse([UInt8](repeating: 0, count: 11)))
|
|
}
|
|
}
|