Conversation
|
|
refactor: introduce TransportMode enum to consolidate transport state
|
can you port these single / dual PC rust tests over to swift ? They should be able to catch most of the issues I ran into when working on the single peer connection issues on Rust |
Port V0 (dual PC) and V1 (single PC) signaling integration tests from rust-sdks peer_connection_signaling_test.rs. Adds 17 tests covering connect, two-participant discovery, audio track pub/sub, reconnect, data channels, node failure recovery, many-tracks publish, and double reconnect for both signaling modes. - Add PeerConnectionSignalingTests with SignalingMode enum and ReconnectWatcher helper - Parameterize singlePeerConnection in RoomTestingOptions - Extract shared TestAudioTrack to LiveKitTestSupport/Tracks.swift - Consolidate duplicate TestTrack from TrackTests.swift Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Verify 50 audio frames received (not just first frame) in audio track tests, matching Rust's NativeAudioStream frame count validation - Add subscriber-side track verification after reconnect, confirming remote participant still sees publisher's tracks post-reconnect - Add frame counting and expect(minimumFrames:) to AudioTrackWatcher Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Done, there's some duplication with existing tests, plus I left The reason I did not add them is most of these scenarios are covered somewhere e.g. in data channel tests (reconnect, etc.). |
|
Getting some timeouts in tests, looks like general problem with the runner. |
|
Curiously, do you need the same DSP munging in Swift SDK like in Rust SDK ? |
Yes, seems like it's necessary for the same reasons ⬇️ |
WebRTC's sdp_offer_answer.cc can generate a=inactive instead of a=recvonly for recvOnly transceivers during renegotiation in single peer connection mode, breaking video track subscription. This matches the fix applied in the Rust SDK (commit 2827707f). - Add singlePCMode flag to Transport - Add mungeInactiveToRecvOnlyForMedia() to rewrite a=inactive in RTP m-sections while preserving data channel sections - Apply munging in _negotiateSequence() before setLocalDescription - Add 3 unit tests for SDP munging Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
There's some flakiness in these stress tests - not sure if caused by invalid server state or something on the client yet. |
39340bc to
f608281
Compare
- Retry room connect (3 attempts, 2s delay) to handle transient POSIX 57 - Graceful track cleanup: unpublishAll + disconnect in withRooms teardown - Reduce post-disconnect sleep from 5s to 1s - Set server departure_timeout to 1s for faster room cleanup - Use didPublishTrack delegate to fix fullReconnect race condition - Replace nodeFailure with fullReconnect in signaling tests - Update macos-26 to Xcode 26.3 and 26.2 simulators Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
I made some global changes here to reduce test flakiness, key findings:
publishManyTrackscan poison other tests as the server is unable to listen for socket connections- it does not look like a bug in the server code (listener is a separate goroutine), but rather a restricted VM environment (3 cores here)
- it works reasonably well for fewer tracks
- we can consider moving to
-xlargerunners for other "stress" tests, however it's paid
|
@lukasIO @xianshijing-lk do you see any gaps in the logic? You've got the full context. @hiroshihorie is the swift side acceptable? |
| delegate: self) | ||
| let isSinglePC = singlePeerConnection | ||
| let isSubscriberPrimary = isSinglePC ? false : joinResponse.subscriberPrimary | ||
| log("subscriberPrimary: \(isSubscriberPrimary), singlePeerConnection: \(isSinglePC)") |
There was a problem hiding this comment.
is the log intentional ?
There was a problem hiding this comment.
it's .debug and it existed before: log("subscriberPrimary: \(joinResponse.subscriberPrimary)")
| let publisher = try Transport(config: rtcConfiguration, | ||
| target: .publisher, | ||
| primary: !isSubscriberPrimary, | ||
| primary: isSinglePC || !isSubscriberPrimary, |
There was a problem hiding this comment.
curiously, what does primary mean here ? why primary is true when isSinglePC is true ?
There was a problem hiding this comment.
it maps the inverse relationship between the TransportMode and Transport, mostly in Room+TransportDelegate (transport wouldn't know if it's "the only one" in single PC mode):
func transport(_ transport: Transport, didUpdateState pcState: LKRTCPeerConnectionState) {
log("target: \(transport.target), connectionState: \(pcState.description)")
// primary connected
if transport.isPrimary {
if pcState.isConnected {
primaryTransportConnectedCompleter.resume(returning: ())
@pblazej , can you check if things are working with auto_subscribe is set to false ? |
# Conflicts: # Sources/LiveKit/Protos/livekit_metrics.pb.swift
@xianshijing-lk I think there's some regression here vs main: after unsubscribing a video track I'm left with 8x8 "empty" video - is it confirmed to be on the SFU side? |
In single PC mode the receive transceiver is reused (direction changes) rather than removed, so peerConnection(didRemove:) never fires and the VideoView is left with a stale track producing 8x8 empty frames. Clear the track immediately like the Rust SDK does. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
The above issue with (un)subscribe seems to be tangentially related to transceiver management again, as we were listening to a wrong signal: b64d296 Now it mimics Rust (see cc @xianshijing-lk anything else reproducible in Rust? |
TransportMode(mirrors JS naming) 🎉