Skip to content
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
1 change: 1 addition & 0 deletions .changes/uniffi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
minor type="added" "Experimental support and bindings for shared Rust crates using UniFFI"
9 changes: 5 additions & 4 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,13 @@ jobs:
platform: "tvOS Simulator,name=Apple TV,OS=18.5"

# https://github.com/actions/runner-images/blob/main/images/macos/macos-26-arm64-Readme.md
# Use latest-stable temporarily to avoid missing sims
- os: macos-26
xcode: latest
xcode: latest-stable
platform: "iOS Simulator,name=iPhone 17 Pro,OS=26.1"
symbol-graph: true
- os: macos-26
xcode: latest
xcode: latest-stable
platform: "iOS Simulator,name=iPhone 17 Pro,OS=26.1"
extension-api-only: true
- os: macos-26
Expand All @@ -83,10 +84,10 @@ jobs:
xcode: latest
platform: "macOS,variant=Mac Catalyst"
- os: macos-26
xcode: latest
xcode: latest-stable
platform: "visionOS Simulator,name=Apple Vision Pro,OS=26.1"
- os: macos-26
xcode: latest
xcode: latest-stable
platform: "tvOS Simulator,name=Apple TV,OS=26.1"

runs-on: ${{ matrix.os }}
Expand Down
1 change: 0 additions & 1 deletion LiveKitClient.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ Pod::Spec.new do |spec|
spec.dependency("SwiftProtobuf")
spec.dependency("DequeModule", "= 1.1.4")
spec.dependency("OrderedCollections", " = 1.1.4")
spec.dependency("JWTKit", "= 4.13.5")

spec.resource_bundles = {"Privacy" => ["Sources/LiveKit/PrivacyInfo.xcprivacy"]}

Expand Down
4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ let package = Package(
dependencies: [
// LK-Prefixed Dynamic WebRTC XCFramework
.package(url: "https://github.com/livekit/webrtc-xcframework.git", exact: "137.7151.10"),
.package(url: "https://github.com/livekit/livekit-uniffi-xcframework.git", exact: "0.0.2"),
.package(url: "https://github.com/apple/swift-protobuf.git", from: "1.31.0"),
.package(url: "https://github.com/apple/swift-collections.git", "1.1.0" ..< "1.3.0"),
.package(url: "https://github.com/vapor/jwt-kit.git", from: "4.13.5"),
// Only used for DocC generation
.package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.3.0"),
],
Expand All @@ -35,10 +35,10 @@ let package = Package(
name: "LiveKit",
dependencies: [
.product(name: "LiveKitWebRTC", package: "webrtc-xcframework"),
.product(name: "LiveKitUniFFI", package: "livekit-uniffi-xcframework"),
.product(name: "SwiftProtobuf", package: "swift-protobuf"),
.product(name: "DequeModule", package: "swift-collections"),
.product(name: "OrderedCollections", package: "swift-collections"),
.product(name: "JWTKit", package: "jwt-kit"),
"LKObjCHelpers",
],
exclude: [
Expand Down
4 changes: 2 additions & 2 deletions [email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ let package = Package(
dependencies: [
// LK-Prefixed Dynamic WebRTC XCFramework
.package(url: "https://github.com/livekit/webrtc-xcframework.git", exact: "137.7151.10"),
.package(url: "https://github.com/livekit/livekit-uniffi-xcframework.git", exact: "0.0.2"),
.package(url: "https://github.com/apple/swift-protobuf.git", from: "1.31.0"),
.package(url: "https://github.com/apple/swift-collections.git", "1.1.0" ..< "1.3.0"),
.package(url: "https://github.com/vapor/jwt-kit.git", from: "4.13.5"),
// Only used for DocC generation
.package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.3.0"),
],
Expand All @@ -36,10 +36,10 @@ let package = Package(
name: "LiveKit",
dependencies: [
.product(name: "LiveKitWebRTC", package: "webrtc-xcframework"),
.product(name: "LiveKitUniFFI", package: "livekit-uniffi-xcframework"),
.product(name: "SwiftProtobuf", package: "swift-protobuf"),
.product(name: "DequeModule", package: "swift-collections"),
.product(name: "OrderedCollections", package: "swift-collections"),
.product(name: "JWTKit", package: "jwt-kit"),
"LKObjCHelpers",
],
exclude: [
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 @@ -226,7 +226,7 @@ public class Room: NSObject, @unchecked Sendable, ObservableObject, Loggable {

super.init()
// log sdk & os versions
log("sdk: \(LiveKitSDK.version), os: \(String(describing: Utils.os()))(\(Utils.osVersionString())), modelId: \(String(describing: Utils.modelIdentifier() ?? "unknown"))")
log("sdk: \(LiveKitSDK.version), ffi: \(LiveKitSDK.ffiVersion), os: \(String(describing: Utils.os()))(\(Utils.osVersionString())), modelId: \(String(describing: Utils.modelIdentifier() ?? "unknown"))")

signalClient._delegate.set(delegate: self)

Expand Down
2 changes: 2 additions & 0 deletions Sources/LiveKit/LiveKit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import Foundation
internal import LiveKitWebRTC
internal import LiveKitUniFFI

/// The open source platform for real-time communication.
///
Expand All @@ -33,6 +34,7 @@ public class LiveKitSDK: NSObject, Loggable {

@objc(sdkVersion)
public static let version = "2.10.1"
public static let ffiVersion = buildVersion()

fileprivate struct State {
var logger: Logger = OSLogger()
Expand Down
62 changes: 56 additions & 6 deletions Sources/LiveKit/Support/Logger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import OSLog
internal import LiveKitWebRTC
internal import LiveKitUniFFI

// MARK: - Logger

Expand Down Expand Up @@ -108,6 +109,7 @@
/// A logger that logs to OSLog
/// - Parameter minLevel: The minimum level to log
/// - Parameter rtc: Whether to log WebRTC output
/// - Parameter ffi: Whether to log Rust FFI output
open class OSLogger: Logger, @unchecked Sendable {
private static let subsystem = "io.livekit.sdk"

Expand All @@ -118,15 +120,15 @@

private let minLevel: LogLevel

public init(minLevel: LogLevel = .info, rtc: Bool = false) {
public init(minLevel: LogLevel = .info, rtc: Bool = false, ffi: Bool = true) {
self.minLevel = minLevel

guard rtc else { return }
if rtc {
startRTCLogForwarding(minLevel: minLevel)
}

let rtcLog = OSLog(subsystem: Self.subsystem, category: "WebRTC")
rtcLogger.severity = minLevel.rtcSeverity
rtcLogger.start { message, severity in
os_log("%{public}@", log: rtcLog, type: severity.osLogType, message)
if ffi {
startFFILogForwarding(minLevel: minLevel)
}
}

Expand Down Expand Up @@ -171,6 +173,33 @@
os_log("%{public}@", log: getOSLog(for: type), type: level.osLogType, "\(type).\(function) \(message)\(metadata)")
}
}

private func startRTCLogForwarding(minLevel: LogLevel) {
let rtcLog = OSLog(subsystem: Self.subsystem, category: "WebRTC")

rtcLogger.severity = minLevel.rtcSeverity
rtcLogger.start { message, severity in
os_log("%{public}@", log: rtcLog, type: severity.osLogType, message)
}
}

private func startFFILogForwarding(minLevel: LogLevel) {
Task(priority: .utility) { [weak self] in
guard self != nil else { return } // don't initialize global level when releasing
logForwardBootstrap(level: minLevel.logForwardFilter)

let ffiLog = OSLog(subsystem: Self.subsystem, category: "FFI")
let ffiStream = AsyncStream(unfolding: logForwardReceive)

for await entry in ffiStream {
guard self != nil else { return }

let message = "\(entry.target) \(entry.message)"

os_log("%{public}@", log: ffiLog, type: entry.level.osLogType, message)
}
}
}
}

// MARK: - Loggable
Expand Down Expand Up @@ -236,6 +265,15 @@
}
}

var logForwardFilter: LogForwardFilter {
switch self {
case .debug: .debug
case .info: .info
case .warning: .warn
case .error: .error
}
}

@inlinable
public static func < (lhs: LogLevel, rhs: LogLevel) -> Bool {
lhs.rawValue < rhs.rawValue
Expand Down Expand Up @@ -263,3 +301,15 @@
}
}
}

extension LogForwardLevel {
var osLogType: OSLogType {
switch self {
case .error: .error
case .warn: .default
case .info: .info
case .debug, .trace: .debug
@unknown default: .debug

Check warning on line 312 in Sources/LiveKit/Support/Logger.swift

View workflow job for this annotation

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

default will never be executed

Check warning on line 312 in Sources/LiveKit/Support/Logger.swift

View workflow job for this annotation

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

default will never be executed
}
}
}
21 changes: 14 additions & 7 deletions Sources/LiveKit/Token/CachingTokenSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,20 @@ public extension TokenSourceResponse {
return false
}

do {
try jwt.nbf.verifyNotBefore()
try jwt.exp.verifyNotExpired(currentDate: Date().addingTimeInterval(tolerance))
} catch {
return false
}
return jwt.nbf.verifyNotBefore() && jwt.exp.verifyNotExpired(currentDate: Date().addingTimeInterval(tolerance))
}
}

private extension UInt64 {
var asDate: Date {
Date(timeIntervalSince1970: TimeInterval(self))
}

func verifyNotBefore(currentDate: Date = Date()) -> Bool {
currentDate >= asDate
}

return true
func verifyNotExpired(currentDate: Date = Date()) -> Bool {
currentDate < asDate
}
}
126 changes: 0 additions & 126 deletions Sources/LiveKit/Token/JWT.swift

This file was deleted.

5 changes: 3 additions & 2 deletions Sources/LiveKit/Token/TokenSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import Foundation
internal import LiveKitUniFFI

// MARK: - Source

Expand Down Expand Up @@ -144,8 +145,8 @@ public extension TokenSourceResponse {
/// Extracts the JWT payload from the participant token.
///
/// - Returns: The JWT payload if successfully parsed, nil otherwise
internal func jwt() -> LiveKitJWTPayload? {
LiveKitJWTPayload.fromUnverified(token: participantToken)
internal func jwt() -> Claims? {
try? tokenClaimsFromUnverified(token: participantToken)
}

/// Checks if the JWT token contains agent dispatch configuration.
Expand Down
Loading
Loading