Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Incremental migration to strict concurrency checking #1 #481

Merged
merged 13 commits into from
Sep 28, 2024
1 change: 1 addition & 0 deletions [email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ let package = Package(
],
swiftSettings: [
.enableExperimentalFeature("AccessLevelOnImport"),
.enableExperimentalFeature("StrictConcurrency"),
]
),
.testTarget(
Expand Down
18 changes: 7 additions & 11 deletions Sources/LiveKit/Broadcast/Uploader/DarwinNotificationCenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,16 @@ enum DarwinNotification: String {
case broadcastStopped = "iOS_BroadcastStopped"
}

class DarwinNotificationCenter {
#if compiler(>=6.0)
public nonisolated(unsafe) static let shared = DarwinNotificationCenter()
#else
final class DarwinNotificationCenter: @unchecked Sendable {
public static let shared = DarwinNotificationCenter()
#endif

private let notificationCenter: CFNotificationCenter

init() {
notificationCenter = CFNotificationCenterGetDarwinNotifyCenter()
}
private let notificationCenter = CFNotificationCenterGetDarwinNotifyCenter()

func postNotification(_ name: DarwinNotification) {
CFNotificationCenterPostNotification(notificationCenter, CFNotificationName(rawValue: name.rawValue as CFString), nil, nil, true)
CFNotificationCenterPostNotification(notificationCenter,
CFNotificationName(rawValue: name.rawValue as CFString),
nil,
nil,
true)
}
}
2 changes: 1 addition & 1 deletion Sources/LiveKit/Core/Room+Debug.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import Foundation

public enum SimulateScenario {
public enum SimulateScenario: Sendable {
// Client
case quickReconnect
case fullReconnect
Expand Down
2 changes: 1 addition & 1 deletion Sources/LiveKit/Core/Room+Engine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ extension Room {

// MARK: - Connection / Reconnection logic

public enum StartReconnectReason {
public enum StartReconnectReason: Sendable {
case websocket
case transport
case networkSwitch
Expand Down
2 changes: 1 addition & 1 deletion Sources/LiveKit/Core/Room+SignalClientDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ extension Room: SignalClientDelegate {
}
}

func signalClient(_: SignalClient, didReceiveIceCandidate iceCandidate: LKRTCIceCandidate, target: Livekit_SignalTarget) async {
func signalClient(_: SignalClient, didReceiveIceCandidate iceCandidate: IceCandidate, target: Livekit_SignalTarget) async {
guard let transport = target == .subscriber ? _state.subscriber : _state.publisher else {
log("Failed to add ice candidate, transport is nil for target: \(target)", .error)
return
Expand Down
2 changes: 1 addition & 1 deletion Sources/LiveKit/Core/Room+TransportDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ extension Room: TransportDelegate {
}
}

func transport(_ transport: Transport, didGenerateIceCandidate iceCandidate: LKRTCIceCandidate) {
func transport(_ transport: Transport, didGenerateIceCandidate iceCandidate: IceCandidate) {
Task {
do {
log("sending iceCandidate")
Expand Down
2 changes: 1 addition & 1 deletion Sources/LiveKit/Core/Room.swift
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ public class Room: NSObject, ObservableObject, Loggable {
}

// listen to app states
AppStateListener.shared.add(delegate: self)
AppStateListener.shared.delegates.add(delegate: self)

// trigger events when state mutates
_state.onDidMutate = { [weak self] newState, oldState in
Expand Down
8 changes: 4 additions & 4 deletions Sources/LiveKit/Core/SignalClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ actor SignalClient: Loggable {
typealias AddTrackRequestPopulator<R> = (inout Livekit_AddTrackRequest) throws -> R
typealias AddTrackResult<R> = (result: R, trackInfo: Livekit_TrackInfo)

public enum ConnectResponse {
public enum ConnectResponse: Sendable {
case join(Livekit_JoinResponse)
case reconnect(Livekit_ReconnectResponse)

Expand Down Expand Up @@ -289,7 +289,7 @@ private extension SignalClient {
return
}

_delegate.notifyDetached { await $0.signalClient(self, didReceiveIceCandidate: rtcCandidate, target: trickle.target) }
_delegate.notifyDetached { await $0.signalClient(self, didReceiveIceCandidate: rtcCandidate.toLKType(), target: trickle.target) }

case let .update(update):
_delegate.notifyDetached { await $0.signalClient(self, didUpdateParticipants: update.participants) }
Expand Down Expand Up @@ -377,11 +377,11 @@ extension SignalClient {
try await _sendRequest(r)
}

func sendCandidate(candidate: LKRTCIceCandidate, target: Livekit_SignalTarget) async throws {
func sendCandidate(candidate: IceCandidate, target: Livekit_SignalTarget) async throws {
let r = try Livekit_SignalRequest.with {
$0.trickle = try Livekit_TrickleRequest.with {
$0.target = target
$0.candidateInit = try candidate.toLKType().toJsonString()
$0.candidateInit = try candidate.toJsonString()
}
}

Expand Down
8 changes: 4 additions & 4 deletions Sources/LiveKit/Core/Transport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ actor Transport: NSObject, Loggable {
// forbid direct access to PeerConnection
private let _pc: LKRTCPeerConnection

private lazy var _iceCandidatesQueue = QueueActor<LKRTCIceCandidate>(onProcess: { [weak self] iceCandidate in
private lazy var _iceCandidatesQueue = QueueActor<IceCandidate>(onProcess: { [weak self] iceCandidate in
guard let self else { return }

do {
try await self._pc.add(iceCandidate)
try await self._pc.add(iceCandidate.toRTCType())
} catch {
self.log("Failed to add(iceCandidate:) with error: \(error)", .error)
}
Expand Down Expand Up @@ -114,7 +114,7 @@ actor Transport: NSObject, Loggable {
_isRestartingIce = true
}

func add(iceCandidate candidate: LKRTCIceCandidate) async throws {
func add(iceCandidate candidate: IceCandidate) async throws {
await _iceCandidatesQueue.process(candidate, if: remoteDescription != nil && !_isRestartingIce)
}

Expand Down Expand Up @@ -222,7 +222,7 @@ extension Transport: LKRTCPeerConnectionDelegate {
}

nonisolated func peerConnection(_: LKRTCPeerConnection, didGenerate candidate: LKRTCIceCandidate) {
_delegate.notify { $0.transport(self, didGenerateIceCandidate: candidate) }
_delegate.notify { $0.transport(self, didGenerateIceCandidate: candidate.toLKType()) }
}

nonisolated func peerConnectionShouldNegotiate(_: LKRTCPeerConnection) {
Expand Down
4 changes: 2 additions & 2 deletions Sources/LiveKit/E2EE/KeyProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public let defaultRatchetWindowSize: Int32 = 0
public let defaultFailureTolerance: Int32 = -1

@objc
public class KeyProviderOptions: NSObject {
public final class KeyProviderOptions: NSObject, Sendable {
@objc
public let sharedKey: Bool

Expand Down Expand Up @@ -80,7 +80,7 @@ public class KeyProviderOptions: NSObject {
}

@objc
public class BaseKeyProvider: NSObject, Loggable {
public final class BaseKeyProvider: NSObject, Loggable, Sendable {
@objc
public let options: KeyProviderOptions

Expand Down
4 changes: 2 additions & 2 deletions Sources/LiveKit/E2EE/Options.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import Foundation

@objc
public enum EncryptionType: Int {
public enum EncryptionType: Int, Sendable {
case none
case gcm
case custom
Expand Down Expand Up @@ -46,7 +46,7 @@ extension Livekit_Encryption.TypeEnum {
}

@objc
public class E2EEOptions: NSObject {
public final class E2EEOptions: NSObject, Sendable {
@objc
public let keyProvider: BaseKeyProvider

Expand Down
2 changes: 1 addition & 1 deletion Sources/LiveKit/E2EE/State.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ internal import LiveKitWebRTC
#endif

@objc
public enum E2EEState: Int {
public enum E2EEState: Int, Sendable {
case new
case ok
case key_ratcheted
Expand Down
4 changes: 2 additions & 2 deletions Sources/LiveKit/Errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ internal import LiveKitWebRTC
@_implementationOnly import LiveKitWebRTC
#endif

public enum LiveKitErrorType: Int {
public enum LiveKitErrorType: Int, Sendable {
case unknown = 0
case cancelled = 100
case timedOut = 101
Expand Down Expand Up @@ -98,7 +98,7 @@ extension LiveKitErrorType: CustomStringConvertible {
}

@objc
public class LiveKitError: NSError {
public class LiveKitError: NSError, @unchecked Sendable {
public let type: LiveKitErrorType
public let message: String?
public let underlyingError: Error?
Expand Down
12 changes: 2 additions & 10 deletions Sources/LiveKit/Extensions/RTCMediaConstraints.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,8 @@ internal import LiveKitWebRTC
#endif

extension LKRTCMediaConstraints {
// static let defaultOfferConstraints = RTCMediaConstraints(
// mandatoryConstraints: [
// kRTCMediaConstraintsOfferToReceiveAudio: kRTCMediaConstraintsValueFalse,
// kRTCMediaConstraintsOfferToReceiveVideo: kRTCMediaConstraintsValueFalse,
// ],
// optionalConstraints: nil
// )

static let defaultPCConstraints = DispatchQueue.liveKitWebRTC.sync { LKRTCMediaConstraints(
static let defaultPCConstraints = LKRTCMediaConstraints(
mandatoryConstraints: nil,
optionalConstraints: ["DtlsSrtpKeyAgreement": kRTCMediaConstraintsValueTrue]
) }
)
}
27 changes: 27 additions & 0 deletions Sources/LiveKit/Extensions/Sendable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2024 LiveKit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import Foundation

#if swift(>=5.9)
internal import LiveKitWebRTC
#else
@_implementationOnly import LiveKitWebRTC
#endif

// Immutable classes.
extension LKRTCMediaConstraints: @unchecked Sendable {}
extension LKRTCSessionDescription: @unchecked Sendable {}
2 changes: 1 addition & 1 deletion Sources/LiveKit/Protocols/SignalClientDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ protocol SignalClientDelegate: AnyObject {
func signalClient(_ signalClient: SignalClient, didReceiveConnectResponse connectResponse: SignalClient.ConnectResponse) async
func signalClient(_ signalClient: SignalClient, didReceiveAnswer answer: LKRTCSessionDescription) async
func signalClient(_ signalClient: SignalClient, didReceiveOffer offer: LKRTCSessionDescription) async
func signalClient(_ signalClient: SignalClient, didReceiveIceCandidate iceCandidate: LKRTCIceCandidate, target: Livekit_SignalTarget) async
func signalClient(_ signalClient: SignalClient, didReceiveIceCandidate iceCandidate: IceCandidate, target: Livekit_SignalTarget) async
func signalClient(_ signalClient: SignalClient, didUnpublishLocalTrack localTrack: Livekit_TrackUnpublishedResponse) async
func signalClient(_ signalClient: SignalClient, didUpdateParticipants participants: [Livekit_ParticipantInfo]) async
func signalClient(_ signalClient: SignalClient, didUpdateRoom room: Livekit_Room) async
Expand Down
2 changes: 1 addition & 1 deletion Sources/LiveKit/Protocols/TransportDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ internal import LiveKitWebRTC

protocol TransportDelegate: AnyObject {
func transport(_ transport: Transport, didUpdateState state: RTCPeerConnectionState)
func transport(_ transport: Transport, didGenerateIceCandidate iceCandidate: LKRTCIceCandidate)
func transport(_ transport: Transport, didGenerateIceCandidate iceCandidate: IceCandidate)
func transport(_ transport: Transport, didOpenDataChannel dataChannel: LKRTCDataChannel)
func transport(_ transport: Transport, didAddTrack track: LKRTCMediaStreamTrack, rtpReceiver: LKRTCRtpReceiver, streams: [LKRTCMediaStream])
func transport(_ transport: Transport, didRemoveTrack track: LKRTCMediaStreamTrack)
Expand Down
27 changes: 13 additions & 14 deletions Sources/LiveKit/Support/AppStateListener.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,57 +35,56 @@ protocol AppStateDelegate: AnyObject {
func appDidWake()
}

class AppStateListener: MulticastDelegate<AppStateDelegate> {
class AppStateListener: Loggable {
static let shared = AppStateListener()

private let queue = OperationQueue()
private let _queue = OperationQueue()
let delegates = MulticastDelegate<AppStateDelegate>(label: "AppStateDelegate")

private init() {
super.init(label: "AppStateDelegate")

let defaultCenter = NotificationCenter.default

#if os(iOS) || os(visionOS) || os(tvOS)
defaultCenter.addObserver(forName: UIApplication.didEnterBackgroundNotification,
object: nil,
queue: queue)
queue: _queue)
{ _ in
self.log("UIApplication.didEnterBackground")
self.notify { $0.appDidEnterBackground() }
self.delegates.notify { $0.appDidEnterBackground() }
}

defaultCenter.addObserver(forName: UIApplication.willEnterForegroundNotification,
object: nil,
queue: queue)
queue: _queue)
{ _ in
self.log("UIApplication.willEnterForeground")
self.notify { $0.appWillEnterForeground() }
self.delegates.notify { $0.appWillEnterForeground() }
}

defaultCenter.addObserver(forName: UIApplication.willTerminateNotification,
object: nil,
queue: queue)
queue: _queue)
{ _ in
self.log("UIApplication.willTerminate")
self.notify { $0.appWillTerminate() }
self.delegates.notify { $0.appWillTerminate() }
}
#elseif os(macOS)
let workspaceCenter = NSWorkspace.shared.notificationCenter

workspaceCenter.addObserver(forName: NSWorkspace.willSleepNotification,
object: nil,
queue: queue)
_queue: _queue)
{ _ in
self.log("NSWorkspace.willSleepNotification")
self.notify { $0.appWillSleep() }
self.delegates.notify { $0.appWillSleep() }
}

workspaceCenter.addObserver(forName: NSWorkspace.didWakeNotification,
object: nil,
queue: queue)
_queue: _queue)
{ _ in
self.log("NSWorkspace.didWakeNotification")
self.notify { $0.appDidWake() }
self.delegates.notify { $0.appDidWake() }
}
#endif
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/LiveKit/Support/QueueActor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ actor QueueActor<T>: Loggable {

// MARK: - Public

public enum State {
public enum State: Sendable {
case resumed
case suspended
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/LiveKit/Support/ValueOrAbsent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

/// Allows distinguishing between setting nil and no-op in copyWith operations.
public enum ValueOrAbsent<T> {
public enum ValueOrAbsent<T: Sendable>: Sendable {
case value(T)
case absent

Expand Down
2 changes: 1 addition & 1 deletion Sources/LiveKit/Track/Capturers/MacOSScreenCapturer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ public extension LocalVideoTrack {
}

@objc
public enum MacOSScreenShareSourceType: Int {
public enum MacOSScreenShareSourceType: Int, Sendable {
case any
case display
case window
Expand Down
2 changes: 1 addition & 1 deletion Sources/LiveKit/Track/Capturers/VideoCapturer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public class VideoCapturer: NSObject, Loggable, VideoCapturerProtocol {
}

@objc
public enum CapturerState: Int {
public enum CapturerState: Int, Sendable {
case stopped
case started
}
Expand Down
Loading
Loading