Skip to content

Expose complete reconnect mode cycle #694

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions Sources/LiveKit/Core/Room+Engine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ extension Room {
log("\(_state.connectStopwatch)")
}

func startReconnect(reason: StartReconnectReason, nextReconnectMode: ReconnectMode? = nil) async throws {
func startReconnect(reason: StartReconnectReason, nextReconnectMode: ReconnectMode = .none) async throws {
log("[Connect] Starting, reason: \(reason)")

guard case .connected = _state.connectionState else {
Expand All @@ -286,7 +286,7 @@ extension Room {
throw LiveKitError(.invalidState)
}

guard _state.isReconnectingWithMode == nil else {
guard _state.isReconnectingWithMode == .none else {
log("[Connect] Reconnect already in progress...", .warning)
throw LiveKitError(.invalidState)
}
Expand Down Expand Up @@ -368,7 +368,8 @@ extension Room {
return delay
}) { currentAttempt, totalAttempts in
// Not reconnecting state anymore
guard let currentMode = self._state.isReconnectingWithMode else {
let currentMode = self._state.isReconnectingWithMode
guard currentMode != .none else {
self.log("[Connect] Not in reconnect state anymore, exiting retry cycle.")
return
}
Expand All @@ -379,14 +380,14 @@ extension Room {
self.log("[Connect] Starting retry attempt \(currentAttempt)/\(totalAttempts) with mode: \(currentMode)")

// Try full reconnect for the final attempt
if totalAttempts == currentAttempt, self._state.nextReconnectMode == nil {
if totalAttempts == currentAttempt, self._state.nextReconnectMode == .none {
self._state.mutate { $0.nextReconnectMode = .full }
}

let mode: ReconnectMode = self._state.mutate {
let mode: ReconnectMode = ($0.nextReconnectMode == .full || $0.isReconnectingWithMode == .full) ? .full : .quick
$0.isReconnectingWithMode = mode
$0.nextReconnectMode = nil
$0.nextReconnectMode = .none
return mode
}

Expand All @@ -409,8 +410,8 @@ extension Room {
log("[Connect] Sequence completed")
_state.mutate {
$0.connectionState = .connected
$0.isReconnectingWithMode = nil
$0.nextReconnectMode = nil
$0.isReconnectingWithMode = .none
$0.nextReconnectMode = .none
}
} catch {
log("[Connect] Sequence failed with error: \(error)")
Expand Down
6 changes: 2 additions & 4 deletions Sources/LiveKit/Core/Room+EngineDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,9 @@ extension Room {
}

// Notify when reconnection mode changes
if state.isReconnectingWithMode != oldState.isReconnectingWithMode,
let mode = state.isReconnectingWithMode
{
if state.isReconnectingWithMode != oldState.isReconnectingWithMode {
delegates.notify(label: { "room.didUpdate reconnectionMode: \(String(describing: state.isReconnectingWithMode)) oldValue: \(String(describing: oldState.isReconnectingWithMode))" }) {
$0.room?(self, didUpdateReconnectMode: mode)
$0.room?(self, didUpdateReconnectMode: state.isReconnectingWithMode)
}
}

Expand Down
6 changes: 3 additions & 3 deletions Sources/LiveKit/Core/Room.swift
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,8 @@ public class Room: NSObject, @unchecked Sendable, ObservableObject, Loggable {
var url: URL?
var token: String?
// preferred reconnect mode which will be used only for next attempt
var nextReconnectMode: ReconnectMode?
var isReconnectingWithMode: ReconnectMode?
var nextReconnectMode: ReconnectMode = .none
var isReconnectingWithMode: ReconnectMode = .none
var connectionState: ConnectionState = .disconnected
var disconnectError: LiveKitError?
var connectStopwatch = Stopwatch(label: "connect")
Expand Down Expand Up @@ -269,7 +269,7 @@ public class Room: NSObject, @unchecked Sendable, ObservableObject, Loggable {
}
}

if newState.connectionState == .reconnecting, newState.isReconnectingWithMode == nil {
if newState.connectionState == .reconnecting, newState.isReconnectingWithMode == .none {
self.log("reconnectMode should not be .none", .error)
}

Expand Down
10 changes: 5 additions & 5 deletions Sources/LiveKit/Core/SignalClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,13 @@
func connect(_ url: URL,
_ token: String,
connectOptions: ConnectOptions? = nil,
reconnectMode: ReconnectMode? = nil,
reconnectMode: ReconnectMode = .none,
participantSid: Participant.Sid? = nil,
adaptiveStream: Bool) async throws -> ConnectResponse
{
await cleanUp()

if let reconnectMode {
if reconnectMode != .none {
log("[Connect] mode: \(String(describing: reconnectMode))")
}

Expand All @@ -135,13 +135,13 @@
participantSid: participantSid,
adaptiveStream: adaptiveStream)

if reconnectMode != nil {
if reconnectMode != .none {
log("[Connect] with url: \(url)")
} else {
log("Connecting with url: \(url)")
}

_state.mutate { $0.connectionState = (reconnectMode != nil ? .reconnecting : .connecting) }
_state.mutate { $0.connectionState = (reconnectMode != .none ? .reconnecting : .connecting) }

do {
let socket = try await WebSocket(url: url, connectOptions: connectOptions)
Expand Down Expand Up @@ -177,7 +177,7 @@
}

// Skip validation if reconnect mode
if reconnectMode != nil {
if reconnectMode != .none {
await cleanUp(withError: error)
throw error
}
Expand Down Expand Up @@ -244,7 +244,7 @@
func _onWebSocketMessage(message: URLSessionWebSocketTask.Message) async {
let response: Livekit_SignalResponse? = {
switch message {
case let .data(data): return try? Livekit_SignalResponse(serializedData: data)

Check warning on line 247 in Sources/LiveKit/Core/SignalClient.swift

View workflow job for this annotation

GitHub Actions / Build & Test (macos-14, 15.4, macOS)

'init(serializedData:extensions:partial:options:)' is deprecated: replaced by 'init(serializedBytes:extensions:partial:options:)'

Check warning on line 247 in Sources/LiveKit/Core/SignalClient.swift

View workflow job for this annotation

GitHub Actions / Build & Test (macos-14, 15.4, iOS Simulator,OS=17.5,name=iPhone 15 Pro)

'init(serializedData:extensions:partial:options:)' is deprecated: replaced by 'init(serializedBytes:extensions:partial:options:)'

Check warning on line 247 in Sources/LiveKit/Core/SignalClient.swift

View workflow job for this annotation

GitHub Actions / Build & Test (macos-14, 15.4, macOS,variant=Mac Catalyst)

'init(serializedData:extensions:partial:options:)' is deprecated: replaced by 'init(serializedBytes:extensions:partial:options:)'

Check warning on line 247 in Sources/LiveKit/Core/SignalClient.swift

View workflow job for this annotation

GitHub Actions / Build & Test (macos-14, 15.4, tvOS Simulator,name=Apple TV)

'init(serializedData:extensions:partial:options:)' is deprecated: replaced by 'init(serializedBytes:extensions:partial:options:)'

Check warning on line 247 in Sources/LiveKit/Core/SignalClient.swift

View workflow job for this annotation

GitHub Actions / Build & Test (macos-15, 16.2, macOS, true)

'init(serializedData:extensions:partial:options:)' is deprecated: replaced by 'init(serializedBytes:extensions:partial:options:)'

Check warning on line 247 in Sources/LiveKit/Core/SignalClient.swift

View workflow job for this annotation

GitHub Actions / Build & Test (macos-15, 16.2, iOS Simulator,OS=18.1,name=iPhone 16 Pro, true)

'init(serializedData:extensions:partial:options:)' is deprecated: replaced by 'init(serializedBytes:extensions:partial:options:)'

Check warning on line 247 in Sources/LiveKit/Core/SignalClient.swift

View workflow job for this annotation

GitHub Actions / Build & Test (macos-14, 15.4, visionOS Simulator,name=Apple Vision Pro)

'init(serializedData:extensions:partial:options:)' is deprecated: replaced by 'init(serializedBytes:extensions:partial:options:)'
case let .string(string): return try? Livekit_SignalResponse(jsonString: string)
default: return nil
}
Expand Down
1 change: 1 addition & 0 deletions Sources/LiveKit/Extensions/CustomStringConvertible.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ extension ConnectionState: CustomStringConvertible {
extension ReconnectMode: CustomStringConvertible {
public var description: String {
switch self {
case .none: return ".none"
case .quick: return ".quick"
case .full: return ".full"
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/LiveKit/Support/Utils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ class Utils {
_ url: URL,
_ token: String,
connectOptions: ConnectOptions? = nil,
reconnectMode: ReconnectMode? = nil,
reconnectMode: ReconnectMode = .none,
participantSid: Participant.Sid? = nil,
adaptiveStream: Bool,
validate: Bool = false,
Expand Down
3 changes: 3 additions & 0 deletions Sources/LiveKit/Types/ConnectionState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import Foundation

@objc
public enum ReconnectMode: Int, Sendable {
/// Not trying to reconnect
case none

/// Quick reconnection mode attempts to maintain the same session, reusing existing
/// transport connections and published tracks. This is faster but may not succeed
/// in all network conditions.
Expand Down
Loading