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.
screencast iOS receiver
A native iOS receiver app (Swift) so an iPhone can act as a second receiver. It speaks the existing signaling + RTP protocol unchanged — no C++ changes — mirroring the Android receiver (Phase 8) source-to-source.
- Min iOS: 17 (validated on iPhone 16 / iOS 26.6.1)
- No third-party dependencies — only Apple system frameworks (SwiftUI, AVFoundation, VideoToolbox, CoreMedia, BSD sockets).
Pipeline
Bonjour advertise (_screencast._tcp) + TCP signaling server (offer → answer)
UDP RTP → jitter buffer (16 pkt / 60 ms) → depacketize (single-NAL + FU-A)
→ VideoToolbox H.264 (in-band SPS/PPS) → AVSampleBufferDisplayLayer (letterbox)
Recovery matches the C++ receiver: a damaged frame is dropped and a PLI (rate-limited to one per 500 ms) asks the sender for a keyframe.
Layout
Receiver/
App/ SwiftUI app, video surface (AVSampleBufferDisplayLayer), controller
Rtp/ RtpHeader, RtpPacket, JitterBuffer, H264Depacketizer, Avcc, NAL extraction
Signaling/ SignalingMessage (JSON), LineAssembler, SignalingServer (BSD sockets)
Decode/ RenderSink, H.264 format description, VideoToolbox decoder
Support/ UdpTransport (poll-based), LocalAddress
Pipeline/ ReceiverPipeline (coordinates everything)
ReceiverTests/
XCTest port of the Android JVM tests + added coverage (signaling, line
framing, AVCC, NAL extraction)
Build and test (on a Mac with Xcode 26)
./bootstrap.sh # installs XcodeGen, generates the project, builds for device
./bootstrap.sh test # runs the unit tests on the simulator
bootstrap.sh downloads XcodeGen from the GitHub release into tools/ (no
Homebrew). Override the simulator with IOS_DEST="platform=iOS Simulator,name=…".
Install on a device
Free provisioning (or your team) is set in Xcode — this can't be scripted:
- Open
Receiver.xcodeproj. - Select the Receiver target → Signing & Capabilities → set your Apple ID (a 7-day development certificate is fine for sideloading).
- Run to the iPhone (USB, trust the computer).
The first run prompts for Local Network access — allow it, or the sender
will never discover the phone (silent failure, like the Android
PROTOCOL_DNS_SD bug).
Stream to the phone
On the sender (Linux desktop):
screencast --send --peer <phone-ip>:5005 # target the phone directly
screencast --discover # or list receivers; the phone shows up
Expected: the phone shows the captured desktop, letterboxed to its screen, with PLI recovery on Wi-Fi loss.
Testing notes
The pure protocol core (RTP, jitter, depacketizer, signaling JSON, line framing, AVCC, NAL extraction) is unit-tested in the simulator. The VideoToolbox decode path and the local-network/Bonjour flow are on-device validation items — the highest-risk parts to verify on the borrowed Mac + iPhone.