[PR #229] [CLOSED] Minimal WebRTC sender client with WHIP, DTLS via NWConnection, and SRTP #234

Closed
opened 2026-03-02 04:00:51 +03:00 by kerem · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/eerimoq/moblin/pull/229
Author: @Copilot
Created: 2/9/2026
Status: Closed

Base: mainHead: copilot/implement-webrtc-client-sender


📝 Commits (6)

  • 163db0d Initial plan
  • 092ab41 Add minimal WebRTC sender client with WHIP protocol support
  • f3f7c29 Fix code review: use marker param in RtpHeader, safe unwrap in SDP parser
  • 32c97aa Fix missing fingerprint in SDP offer
  • 8ce18f8 Add DTLS session and SRTP encryption for WebRTC
  • e7c5d98 Refactor DTLS to use NWConnection instead of custom protocol

📊 Changes

14 files changed (+1952 additions, -0 deletions)

View changed files

📝 Common/Various/Validate.swift (+2 -0)
Moblin/Media/HaishinKit/WebRtc/DtlsSession.swift (+334 -0)
Moblin/Media/HaishinKit/WebRtc/IceAgent.swift (+119 -0)
Moblin/Media/HaishinKit/WebRtc/RtpPacket.swift (+98 -0)
Moblin/Media/HaishinKit/WebRtc/SdpMessage.swift (+306 -0)
Moblin/Media/HaishinKit/WebRtc/SrtpSession.swift (+221 -0)
Moblin/Media/HaishinKit/WebRtc/StunMessage.swift (+146 -0)
Moblin/Media/HaishinKit/WebRtc/WebRtcStream.swift (+194 -0)
Moblin/Media/HaishinKit/WebRtc/WhipSession.swift (+136 -0)
📝 Moblin/Various/Media.swift (+37 -0)
📝 Moblin/Various/Model/ModelStream.swift (+27 -0)
📝 Moblin/Various/Settings/SettingsStream.swift (+6 -0)
📝 Moblin/View/Settings/Streams/Stream/StreamSettingsView.swift (+2 -0)
MoblinTests/WebRtcSuite.swift (+324 -0)

📄 Description

From-scratch WebRTC send-only client: single outgoing stream (H.264 video + Opus audio), WHIP signaling, local ICE candidates only. No incoming streams, no data channels, no WHEP, no STUN/TURN.

DTLS uses NWConnection with NWParameters(dtls:udp:) rather than a custom protocol implementation — Apple handles the handshake natively.

New files (Moblin/Media/HaishinKit/WebRtc/)

  • RtpPacket.swift — RTP header encode/decode, sequencer with SSRC/timestamp management
  • StunMessage.swift — STUN binding request/response (RFC 5389) for ICE connectivity checks
  • SdpMessage.swift — SDP offer/answer generation and parsing; sendonly, BUNDLE, rtcp-mux
  • IceAgent.swift — Host candidate gathering via getifaddrs() (IPv4 only)
  • WhipSession.swift — WHIP client: POST offer → parse answer → DELETE teardown; whip://https://
  • DtlsSession.swiftNWConnection-based DTLS 1.2 session with self-signed EC P-256 certificate, SHA-256 fingerprint for SDP, SRTP keying material export via SSLExportKeyingMaterial
  • SrtpSession.swift — SRTP key derivation (RFC 3711), AES-128-CTR payload encryption, HMAC-SHA1 auth tags
  • WebRtcStream.swift — Top-level stream wiring WHIP → ICE → DTLS → SRTP → encoder pipeline

DTLS approach

let params = NWParameters(dtls: tlsOptions, udp: .init())
connection = NWConnection(host: nwHost, port: nwPort, using: params)
// NWConnection.State.ready = DTLS handshake complete
// SRTP keys extracted via sec_protocol_metadata_access_handle

Self-signed cert created via keychain (SecIdentity), fingerprint derived from DER data, keychain entries cleaned up immediately after identity creation.

Integration

  • SettingsStreamProtocol — added .webRtc
  • SettingsStream.getProtocol() — maps whip:// scheme → .webRtc
  • Media.swiftwebRtcStream lifecycle, WebRtcStreamDelegate conformance
  • ModelStream.swift.webRtc case in start/stop stream
  • Validate.swiftwhip recognized as valid URL scheme

Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/eerimoq/moblin/pull/229 **Author:** [@Copilot](https://github.com/apps/copilot-swe-agent) **Created:** 2/9/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `copilot/implement-webrtc-client-sender` --- ### 📝 Commits (6) - [`163db0d`](https://github.com/eerimoq/moblin/commit/163db0d2269dc3053b1dfa289e287533789643f2) Initial plan - [`092ab41`](https://github.com/eerimoq/moblin/commit/092ab41f0ac131a0f2493424415c1f3ef07b0bfa) Add minimal WebRTC sender client with WHIP protocol support - [`f3f7c29`](https://github.com/eerimoq/moblin/commit/f3f7c295b7ef0d698aa1df76ece7ae33f4dde0fa) Fix code review: use marker param in RtpHeader, safe unwrap in SDP parser - [`32c97aa`](https://github.com/eerimoq/moblin/commit/32c97aafd52b2d078a87794df95bec952568f04d) Fix missing fingerprint in SDP offer - [`8ce18f8`](https://github.com/eerimoq/moblin/commit/8ce18f82075b81cf0ea8add4d8166123894385e7) Add DTLS session and SRTP encryption for WebRTC - [`e7c5d98`](https://github.com/eerimoq/moblin/commit/e7c5d98e323c70631ac93e68557713330fd86a3a) Refactor DTLS to use NWConnection instead of custom protocol ### 📊 Changes **14 files changed** (+1952 additions, -0 deletions) <details> <summary>View changed files</summary> 📝 `Common/Various/Validate.swift` (+2 -0) ➕ `Moblin/Media/HaishinKit/WebRtc/DtlsSession.swift` (+334 -0) ➕ `Moblin/Media/HaishinKit/WebRtc/IceAgent.swift` (+119 -0) ➕ `Moblin/Media/HaishinKit/WebRtc/RtpPacket.swift` (+98 -0) ➕ `Moblin/Media/HaishinKit/WebRtc/SdpMessage.swift` (+306 -0) ➕ `Moblin/Media/HaishinKit/WebRtc/SrtpSession.swift` (+221 -0) ➕ `Moblin/Media/HaishinKit/WebRtc/StunMessage.swift` (+146 -0) ➕ `Moblin/Media/HaishinKit/WebRtc/WebRtcStream.swift` (+194 -0) ➕ `Moblin/Media/HaishinKit/WebRtc/WhipSession.swift` (+136 -0) 📝 `Moblin/Various/Media.swift` (+37 -0) 📝 `Moblin/Various/Model/ModelStream.swift` (+27 -0) 📝 `Moblin/Various/Settings/SettingsStream.swift` (+6 -0) 📝 `Moblin/View/Settings/Streams/Stream/StreamSettingsView.swift` (+2 -0) ➕ `MoblinTests/WebRtcSuite.swift` (+324 -0) </details> ### 📄 Description From-scratch WebRTC send-only client: single outgoing stream (H.264 video + Opus audio), WHIP signaling, local ICE candidates only. No incoming streams, no data channels, no WHEP, no STUN/TURN. DTLS uses `NWConnection` with `NWParameters(dtls:udp:)` rather than a custom protocol implementation — Apple handles the handshake natively. ### New files (`Moblin/Media/HaishinKit/WebRtc/`) - **`RtpPacket.swift`** — RTP header encode/decode, sequencer with SSRC/timestamp management - **`StunMessage.swift`** — STUN binding request/response (RFC 5389) for ICE connectivity checks - **`SdpMessage.swift`** — SDP offer/answer generation and parsing; sendonly, BUNDLE, rtcp-mux - **`IceAgent.swift`** — Host candidate gathering via `getifaddrs()` (IPv4 only) - **`WhipSession.swift`** — WHIP client: POST offer → parse answer → DELETE teardown; `whip://` → `https://` - **`DtlsSession.swift`** — `NWConnection`-based DTLS 1.2 session with self-signed EC P-256 certificate, SHA-256 fingerprint for SDP, SRTP keying material export via `SSLExportKeyingMaterial` - **`SrtpSession.swift`** — SRTP key derivation (RFC 3711), AES-128-CTR payload encryption, HMAC-SHA1 auth tags - **`WebRtcStream.swift`** — Top-level stream wiring WHIP → ICE → DTLS → SRTP → encoder pipeline ### DTLS approach ```swift let params = NWParameters(dtls: tlsOptions, udp: .init()) connection = NWConnection(host: nwHost, port: nwPort, using: params) // NWConnection.State.ready = DTLS handshake complete // SRTP keys extracted via sec_protocol_metadata_access_handle ``` Self-signed cert created via keychain (`SecIdentity`), fingerprint derived from DER data, keychain entries cleaned up immediately after identity creation. ### Integration - `SettingsStreamProtocol` — added `.webRtc` - `SettingsStream.getProtocol()` — maps `whip://` scheme → `.webRtc` - `Media.swift` — `webRtcStream` lifecycle, `WebRtcStreamDelegate` conformance - `ModelStream.swift` — `.webRtc` case in start/stop stream - `Validate.swift` — `whip` recognized as valid URL scheme <!-- START COPILOT CODING AGENT TIPS --> --- ✨ Let Copilot coding agent [set things up for you](https://github.com/eerimoq/moblin/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot) — coding agent works faster and does higher quality work when set up for your repo. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
kerem 2026-03-02 04:00:51 +03:00
Sign in to join this conversation.
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/moblin#234
No description provided.