Skip to content

Commit 1ea6c8a

Browse files
committed
feat: Update production readiness checks and enhance SCTP data channel integration tests; improve documentation and status clarity
1 parent 5a7dc4b commit 1ea6c8a

6 files changed

Lines changed: 56 additions & 59 deletions

File tree

README.md

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -259,10 +259,10 @@ association bootstrap that can exchange SCTP DATA chunks, SACK responses, and
259259
reassemble fragmented SCTP DATA messages, with duplicate DATA TSN suppression
260260
and contiguous cumulative SACK tracking. The shared media/data binder and Room
261261
live-media startup helper can select that association transport in
262-
package-internal opt-in tests, and the separately gated LiveKit integration
263-
harness now validates a two-client reliable `DataPacket` publish/receive path
264-
over that standards-shaped SCTP association transport. The public default Room
265-
path continues to use the existing packet-envelope transport until the remaining
262+
package-internal opt-in tests, and the LiveKit integration harness now validates
263+
a default-gated two-client reliable `DataPacket` publish/receive path over that
264+
standards-shaped SCTP association transport. The public default Room path
265+
continues to use the existing packet-envelope transport until the remaining
266266
standards-compliant SCTP hardening is complete.
267267
Data channel recovery now resets LiveKit channels after association restart,
268268
reopens DCEP on the next publish, and Room reconnect responses reset injected
@@ -281,9 +281,9 @@ coverage, including selected ICE pair and default media/data session assertions,
281281
into full secure RTP/RTCP send/receive validation, TURN TCP/TLS, live
282282
quality-control wiring, real-device video display hardening,
283283
default-path DTLS-SCTP association receive-pump integration, LiveKit-validated
284-
data-channel recovery, promoting the separately gated live data-packet
285-
publish/receive smoke into the default integration gate once standards SCTP is
286-
hardened, real-device audio session hardening, integration apps, and size gates.
284+
data-channel recovery, hardening the default-gated live data-packet
285+
publish/receive smoke once standards SCTP is fully complete, real-device audio
286+
session hardening, integration apps, and size gates.
287287

288288
Current builds expose `LiveKitNative.productionReadiness` and
289289
`LiveKitNative.assertProductionReady()` so applications and release automation
@@ -447,7 +447,10 @@ REQUIRE_PRODUCTION_READY=1 scripts/check_release_readiness.sh
447447
The default gate checks package shape, forbidden runtime dependencies,
448448
unit/integration opt-in tests, benchmark smoke, and the compressed release
449449
binary size proxy. The strict gate additionally requires
450-
`LiveKitNative.productionReadiness.status == .productionReady` and no blockers.
450+
`LiveKitNative.productionReadiness.status == .productionReady`, no blockers,
451+
tests, benchmarks, the size gate, Apple platform builds, and configured LiveKit
452+
integration variables so a production tag cannot pass with any release gate
453+
disabled.
451454
That strict gate intentionally fails today because LiveKit E2E secure RTP/RTCP
452455
verification, full ICE/TURN hardening, real-device video display validation,
453456
standards-compliant live SCTP, Apple-platform OpenSSL packaging validation,
@@ -475,27 +478,14 @@ LIVEKIT_NATIVE_API_SECRET=secret \
475478
swift test --filter LiveKitNativeIntegrationTests --jobs 1
476479
```
477480

478-
The separately gated data-track and DataPacket live smoke path can be included
479-
when working on the DTLS-backed SCTP blocker:
480-
481-
```sh
482-
LIVEKIT_NATIVE_RUN_INTEGRATION=1 \
483-
LIVEKIT_NATIVE_RUN_DATA_TRACK_INTEGRATION=1 \
484-
LIVEKIT_NATIVE_LIVEKIT_URL=ws://127.0.0.1:7880 \
485-
LIVEKIT_NATIVE_API_KEY=devkey \
486-
LIVEKIT_NATIVE_API_SECRET=secret \
487-
swift test --filter LiveKitNativeIntegrationTests --jobs 1
488-
```
489-
490481
The harness generates per-run room names with an `lknative-` prefix and
491482
short-lived room-scoped participant tokens. It currently covers one-client
492483
connect/disconnect, two-client participant join/leave, and live OpenSSL
493484
DTLS-SRTP publisher/subscriber media startup on the socket-backed Room media
494485
path with one publisher H.264 RTP send attempt. The live data-track
495486
subscriber-handle and standards-shaped SCTP data-packet publish/receive tests
496-
are passing but gated separately with
497-
`LIVEKIT_NATIVE_RUN_DATA_TRACK_INTEGRATION=1` until the DTLS-backed SCTP data
498-
channel transport blocker is closed. Strict production release mode now
487+
are included in the default integration gate whenever
488+
`LIVEKIT_NATIVE_RUN_INTEGRATION=1` is set. Strict production release mode now
499489
requires those integration variables so the future `productionReady` marker
500490
cannot pass while live tests are silently skipped.
501491

Sources/LiveKitNative/Core/ProductionReadiness.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public extension LiveKitNative {
3232
"Fresh join, resume reconnect, disconnect, and failed signal-loop boundaries regenerate local ICE credentials, clear stale peer negotiation state, parse TURN UDP/TCP/TLS endpoint configuration, order TURN relay fallback candidates as UDP, TCP, then TLS while identifying the currently executable UDP datagram path, select supported TURN UDP relay session configurations from parsed ICE server endpoints with credentials, exercise TURN Allocate, Refresh, CreatePermission, and ChannelBind request/authentication/response-validation primitives with one-shot stale nonce retry, cover TURN ChannelData framing, provide deterministic allocation/permission maintenance scheduling and execution, plan relayed ICE candidates from TURN bindings, compose and execute a bounded TURN relay session setup plan over abstract transports, expose a ChannelData relay transport over an abstract media datagram transport, allocate default UDP TURN relay candidates through the bound Room ICE socket, use ChannelData relay bindings for relayed ICE checks and media datagrams, provide deterministic ICE consent freshness planning plus an injected Room startup loop, run ICEAgent connectivity checks through paced scheduling with queued triggered-check priority plus role-conflict role switching and pair-priority recompute, and rebuild reconnect SyncState SDP/trickle state with fresh local ICE credentials, but TCP/TLS TURN transport execution, LiveKit TURN-only validation, and live media recovery are not complete.",
3333
"Publisher camera capture can encode H.264 through VideoToolbox with bounded frame backpressure/drop control and publisher microphone capture can encode Opus through AudioToolbox before RTP/SRTP send, while subscriber RTP can pass through jitter buffering, H.264/Opus packet assembly, NACK/PLI feedback, opt-in Opus decode-to-audio-playout scheduling, opt-in H.264 VideoToolbox decode-to-pixel-buffer scheduling, application-provided subscriber video renderer handoff, UIKit/AppKit VideoView sample-buffer rendering, and opt-in iOS voice-chat audio-session lifecycle configuration; real-device video display validation, LiveKit E2E media validation, route/interruption audio recovery, and production runtime pacing remain incomplete.",
3434
"Production H.264 now uses real VideoToolbox encode output for publish smoke coverage, opt-in VideoToolbox decode output for subscribe smoke coverage, and UIKit/AppKit VideoView rendering for decoded frames, but production readiness still requires real-device display validation, hardware acceleration verification where the OS exposes that signal, and explicit fallback behavior instead of relying on a pure Swift codec implementation.",
35-
"SCTP data channel support includes packet-level DCEP/DataPacket planning, manager-assigned stream routing, queued local publish flushing, inbound DataPacket-to-RoomEvent plumbing, publisher SDP data-channel negotiation, subscriber-side data-channel receive-loop plumbing, OpenSSL DTLS application-data transport coverage, default Room shared-media DTLS/SRTP demux binding, deterministic packet fragmentation/reassembly envelopes, fragmented-packet retransmission scheduling on the DTLS-backed packet transport, opt-in standards-shaped SCTP association bootstrap with DATA/SACK exchange, fragmented DATA reassembly, duplicate DATA TSN suppression, contiguous cumulative SACK tracking, recovery reset that reopens LiveKit data channels after association restart, and separately gated two-client LiveKit DataPacket publish/receive smoke over that standards-shaped association transport, but full standards-compliant SCTP association state, congestion control, promotion of live DataPacket coverage into the default integration gate, LiveKit-validated data-channel recovery, and E2E hardening are incomplete.",
35+
"SCTP data channel support includes packet-level DCEP/DataPacket planning, manager-assigned stream routing, queued local publish flushing, inbound DataPacket-to-RoomEvent plumbing, publisher SDP data-channel negotiation, subscriber-side data-channel receive-loop plumbing, OpenSSL DTLS application-data transport coverage, default Room shared-media DTLS/SRTP demux binding, deterministic packet fragmentation/reassembly envelopes, fragmented-packet retransmission scheduling on the DTLS-backed packet transport, opt-in standards-shaped SCTP association bootstrap with DATA/SACK exchange, fragmented DATA reassembly, duplicate DATA TSN suppression, contiguous cumulative SACK tracking, recovery reset that reopens LiveKit data channels after association restart, and default-gated two-client LiveKit DataPacket publish/receive smoke over that standards-shaped association transport, but full standards-compliant SCTP association state, congestion control, LiveKit-validated data-channel recovery, and E2E hardening are incomplete.",
3636
"Signal reconnect resets stale peer negotiation state, restarts local ICE credentials, rebuilds retained subscriber answer and publisher offer SDP with fresh ICE credentials, sends SyncState for retained subscription/local media/data publication state, re-sends local ICE trickle/final-trickle when media startup is configured, preserves publisher offer track state for later publish/unpublish re-offers, clears stale local media/data publication state for server/SFU unpublish responses, and resets injected publisher data channels for post-reconnect DCEP reopen in unit tests, but live media recovery and LiveKit integration hardening are incomplete.",
3737
"General production video meetings require the new audio-session primitives to be validated with meeting-grade capture/playout, echo cancellation, route changes, Bluetooth behavior, interruptions, background/foreground handling, and timing on real iOS devices.",
3838
"A default subscriber RTP receive pipeline now integrates jitter buffering with bounded NACK/PLI feedback, scheduled RTCP Receiver Reports with DLSR timing from observed RTP/Sender Report state, REMB bitrate-feedback packet planning/sending, deterministic RTCP receiver-report bandwidth estimation, adaptive video quality recommendations, publisher RTCP receiver-report ingestion, H.264 encoder bitrate/FPS recommendation application, manual subscriber quality preset signaling, opt-in automatic subscriber adaptive track-settings dispatch, publisher active video-layer UpdateVideoLayers signaling, single-layer H.264 AddTrack high-quality metadata, and camera publish frame backpressure primitives, but general production video meetings still require full packet-loss recovery, TWCC/full REMB interop or equivalent congestion control, default-on LiveKit-validated subscriber adaptation policy, complete encoder control policy, actual multi-encoder simulcast/SVC media production, and weak-network E2E validation.",

Tests/LiveKitNativeIntegrationTests/IntegrationOptInTests.swift

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,6 @@ final class IntegrationOptInTests: XCTestCase {
158158
}
159159

160160
func testTwoLiveKitClientsReceiveDataTrackSubscriberHandles() async throws {
161-
guard ProcessInfo.processInfo.environment["LIVEKIT_NATIVE_RUN_DATA_TRACK_INTEGRATION"] == "1" else {
162-
throw XCTSkip(
163-
"Live data-track subscriber handles require the DTLS-backed SCTP data channel transport, " +
164-
"which remains a separate production-readiness blocker."
165-
)
166-
}
167-
168161
let harness = try LiveKitIntegrationHarness.load()
169162
let roomName = harness.roomName(suffix: "data-track")
170163
let firstIdentity = "swift-native-data-sub"
@@ -201,13 +194,6 @@ final class IntegrationOptInTests: XCTestCase {
201194
}
202195

203196
func testTwoLiveKitClientsPublishAndReceiveDataPacketOverStandardsSCTP() async throws {
204-
guard ProcessInfo.processInfo.environment["LIVEKIT_NATIVE_RUN_DATA_TRACK_INTEGRATION"] == "1" else {
205-
throw XCTSkip(
206-
"Live data-packet publish/receive requires standards-shaped DTLS-backed SCTP validation, " +
207-
"which remains a separate production-readiness blocker."
208-
)
209-
}
210-
211197
let harness = try LiveKitIntegrationHarness.load()
212198
let roomName = harness.roomName(suffix: "data-packet")
213199
let subscriberIdentity = "swift-native-data-packet-sub"

Tests/LiveKitNativeTests/ProductionReadinessTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ final class ProductionReadinessTests: XCTestCase {
99
XCTAssertFalse(readiness.isProductionReady)
1010
XCTAssertFalse(readiness.blockers.isEmpty)
1111
XCTAssertTrue(readiness.blockers.contains { $0.contains("DTLS-SRTP") })
12-
XCTAssertTrue(readiness.blockers.contains { $0.contains("LiveKit DataPacket publish/receive smoke") })
12+
XCTAssertTrue(readiness.blockers.contains { $0.contains("default-gated two-client LiveKit DataPacket publish/receive smoke") })
1313
XCTAssertTrue(readiness.blockers.contains { $0.contains("full standards-compliant SCTP association state") })
14-
XCTAssertTrue(readiness.blockers.contains { $0.contains("promotion of live DataPacket coverage") })
14+
XCTAssertFalse(readiness.blockers.contains { $0.contains("promotion of live DataPacket coverage") })
1515
}
1616

1717
func testAssertProductionReadyFailsUntilBlockersAreCleared() {

docs/STATUS.md

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,11 @@ messages without replacing the default Room data-channel path yet. The
6565
association transport also suppresses duplicate DATA TSNs and tracks contiguous
6666
cumulative SACK state. The shared media/data session binder and package-internal
6767
Room live-media startup helper can now select that association transport in
68-
opt-in unit tests, and the separately gated LiveKit integration harness validates
69-
a two-client reliable `DataPacket` publish/receive path over the
70-
standards-shaped SCTP association transport. The public default Room path remains
71-
on the existing packet-envelope transport until the remaining standards-compliant
72-
SCTP hardening is complete.
68+
opt-in unit tests, and the LiveKit integration harness validates a default-gated
69+
two-client reliable `DataPacket` publish/receive path over the standards-shaped
70+
SCTP association transport. The public default Room path remains on the existing
71+
packet-envelope transport until the remaining standards-compliant SCTP hardening
72+
is complete.
7373
SCTP data-channel recovery can now reset LiveKit channels after association
7474
restart, reopen DCEP on the next publish, and Room reconnect responses reset
7575
injected publisher data channels and receive loops before post-reconnect publish.
@@ -79,8 +79,8 @@ datagram path in unit tests, and public default `Room` initialization now
7979
selects that combined startup binder for live media/data transport construction.
8080
Full standards-compliant SCTP association
8181
receive-pump integration, congestion control, LiveKit-validated data-channel
82-
recovery, promotion of the separately gated live data-packet smoke into the
83-
default integration gate, and E2E hardening remain open.
82+
recovery, hardening the default-gated live data-packet smoke once standards SCTP
83+
is fully complete, and E2E hardening remain open.
8484
Server/SFU `TrackUnpublishedResponse` cleanup for local media publications also
8585
clears local publication state and cached publisher offer reconnect state so
8686
resume reconnects and later publisher offers do not replay removed media.
@@ -267,7 +267,9 @@ The old binary WebRTC dependency path has been removed from the package model.
267267
- Release-readiness scripts:
268268
- `scripts/check_release_readiness.sh`
269269
- `scripts/check_release_size.sh`
270-
- strict production mode through `REQUIRE_PRODUCTION_READY=1`
270+
- strict production mode through `REQUIRE_PRODUCTION_READY=1`, with tests,
271+
benchmarks, the size gate, Apple platform builds, and LiveKit integration
272+
variables required
271273
- `LocalParticipant` has local video publication state for camera tracks,
272274
including idempotent `setCamera(enabled:)`, `publish(videoTrack:)`, and
273275
`unpublish(publication:)` behavior.
@@ -892,8 +894,8 @@ The following checks passed after the latest implementation pass:
892894
- 7 live tests skipped by opt-in guard without LiveKit environment variables
893895
- `LIVEKIT_NATIVE_RUN_INTEGRATION=1 swift test --filter LiveMediaStartupIntegrationTests --jobs 1`
894896
- 2 live OpenSSL DTLS-SRTP media startup tests passed against local LiveKit
895-
- `LIVEKIT_NATIVE_RUN_INTEGRATION=1 LIVEKIT_NATIVE_RUN_DATA_TRACK_INTEGRATION=1 swift test --filter IntegrationOptInTests/testTwoLiveKitClientsPublishAndReceiveDataPacketOverStandardsSCTP --jobs 1`
896-
- separately gated standards-shaped SCTP DataPacket live smoke passed against local LiveKit
897+
- `LIVEKIT_NATIVE_RUN_INTEGRATION=1 swift test --filter IntegrationOptInTests/testTwoLiveKitClientsPublishAndReceiveDataPacketOverStandardsSCTP --jobs 1`
898+
- default-gated standards-shaped SCTP DataPacket live smoke passed against local LiveKit
897899
- `LIVEKIT_NATIVE_RELEASE_RUN_TESTS=0 LIVEKIT_NATIVE_RELEASE_RUN_BENCHMARKS=0 LIVEKIT_NATIVE_RELEASE_RUN_SIZE_GATE=0 scripts/check_release_readiness.sh`
898900
- release-shape check passed with tests, benchmarks, and size gate disabled
899901
- `swift build --target LiveKitNativeWebRTC --jobs 1 --disable-index-store -debug-info-format none`
@@ -906,6 +908,8 @@ The following checks passed after the latest implementation pass:
906908
- Release gates:
907909
- `scripts/check_release_readiness.sh` validates package shape, dependency
908910
guard, tests, benchmark smoke, and size gate in non-strict mode
911+
- strict production mode also rejects disabled tests, benchmark smoke, size
912+
gate, Apple platform builds, or missing LiveKit integration variables
909913
- The release-shape check passes with tests, benchmarks, and size gate
910914
disabled through `LIVEKIT_NATIVE_RELEASE_RUN_TESTS=0`,
911915
`LIVEKIT_NATIVE_RELEASE_RUN_BENCHMARKS=0`, and
@@ -1036,13 +1040,13 @@ The following checks passed after the latest implementation pass:
10361040

10371041
- Expand the current opt-in LiveKit integration harness beyond one-client
10381042
connect/disconnect, two-client participant join/leave, generated `lknative-`
1039-
room prefixes, short-lived room-scoped tokens, the separately gated
1040-
two-client data-track subscriber-handle signaling and standards-shaped SCTP
1041-
data-packet publish/receive tests, and live OpenSSL DTLS-SRTP
1042-
publisher/subscriber media startup.
1043-
- Harden the separately gated data packet publish/receive test beyond the
1044-
current standards-shaped SCTP live smoke, then move it into the default live
1045-
integration gate once the standards-compliant SCTP blocker is closed.
1043+
room prefixes, short-lived room-scoped tokens, the two-client data-track
1044+
subscriber-handle signaling and standards-shaped SCTP data-packet
1045+
publish/receive tests, and live OpenSSL DTLS-SRTP publisher/subscriber media
1046+
startup.
1047+
- Harden the default-gated data packet publish/receive test beyond the current
1048+
standards-shaped SCTP live smoke once the standards-compliant SCTP blocker is
1049+
closed.
10461050
- Full RTP/RTCP publish/subscribe media validation beyond startup and one H.264
10471051
RTP send attempt.
10481052
- Reconnect integration test.
@@ -1123,5 +1127,7 @@ For an actual production tag gate, use:
11231127
REQUIRE_PRODUCTION_READY=1 scripts/check_release_readiness.sh
11241128
```
11251129

1126-
Strict production mode also requires the opt-in LiveKit integration variables
1127-
so a production tag cannot pass with the live server tests skipped.
1130+
Strict production mode also requires tests, benchmark smoke, the size gate,
1131+
Apple platform builds, and the opt-in LiveKit integration variables so a
1132+
production tag cannot pass with any release gate disabled or live server tests
1133+
skipped.

0 commit comments

Comments
 (0)