From e616c584b6e80877f2bf1249d0ec45fac02c8325 Mon Sep 17 00:00:00 2001 From: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com> Date: Sat, 17 Jan 2026 04:11:15 +0900 Subject: [PATCH 1/9] impl 1 --- Sources/LiveKit/Core/RTC.swift | 12 ++- .../Extensions/CustomStringConvertible.swift | 10 ++- Sources/LiveKit/Types/Priority.swift | 78 +++++++++++++++++++ 3 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 Sources/LiveKit/Types/Priority.swift diff --git a/Sources/LiveKit/Core/RTC.swift b/Sources/LiveKit/Core/RTC.swift index 8efc78f40..0b09a5a4f 100644 --- a/Sources/LiveKit/Core/RTC.swift +++ b/Sources/LiveKit/Core/RTC.swift @@ -165,7 +165,9 @@ actor RTC { encoding: MediaEncoding? = nil, scaleDownBy: Double? = nil, active: Bool = true, - scalabilityMode: ScalabilityMode? = nil) -> LKRTCRtpEncodingParameters + scalabilityMode: ScalabilityMode? = nil, + priority: Priority? = nil, + networkPriority: Priority? = nil) -> LKRTCRtpEncodingParameters { let result = DispatchQueue.liveKitWebRTC.sync { LKRTCRtpEncodingParameters() } @@ -189,6 +191,14 @@ actor RTC { result.scalabilityMode = scalabilityMode.rawStringValue } + if let priority { + result.bitratePriority = priority.toBitratePriority() + } + + if let networkPriority { + result.networkPriority = networkPriority.toRTCPriority() + } + return result } } diff --git a/Sources/LiveKit/Extensions/CustomStringConvertible.swift b/Sources/LiveKit/Extensions/CustomStringConvertible.swift index 271619b2a..6798b4d16 100644 --- a/Sources/LiveKit/Extensions/CustomStringConvertible.swift +++ b/Sources/LiveKit/Extensions/CustomStringConvertible.swift @@ -191,10 +191,12 @@ extension LKRTCRtpEncodingParameters { "RTCRtpEncodingParameters(" + "rid: \(String(describing: rid)), " + "isActive: \(String(describing: isActive)), " + - "minBitrateBps: \(String(describing: minBitrateBps))" + - "maxBitrateBps: \(String(describing: maxBitrateBps))" + - "maxFramerate: \(String(describing: maxFramerate))" + - "scaleResolutionDownBy: \(String(describing: scaleResolutionDownBy))" + + "minBitrateBps: \(String(describing: minBitrateBps)), " + + "maxBitrateBps: \(String(describing: maxBitrateBps)), " + + "maxFramerate: \(String(describing: maxFramerate)), " + + "scaleResolutionDownBy: \(String(describing: scaleResolutionDownBy)), " + + "bitratePriority: \(bitratePriority), " + + "networkPriority: \(networkPriority)" + ")" } } diff --git a/Sources/LiveKit/Types/Priority.swift b/Sources/LiveKit/Types/Priority.swift new file mode 100644 index 000000000..4a7c89e15 --- /dev/null +++ b/Sources/LiveKit/Types/Priority.swift @@ -0,0 +1,78 @@ +/* + * Copyright 2026 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. + */ + +internal import LiveKitWebRTC + +/// Priority levels for RTP encoding parameters. +/// +/// `priority` controls WebRTC internal bandwidth allocation between streams. +/// `networkPriority` controls DSCP marking for network-level QoS. +@objc +public enum Priority: Int, Sendable { + case veryLow + case low + case medium + case high +} + +extension Priority { + /// Converts to the native RTCPriority enum used for networkPriority. + func toRTCPriority() -> LKRTCPriority { + switch self { + case .veryLow: .veryLow + case .low: .low + case .medium: .medium + case .high: .high + } + } + + /// Converts to bitratePriority double value. + /// - veryLow: 0.5x + /// - low: 1.0x (default) + /// - medium: 2.0x + /// - high: 4.0x + func toBitratePriority() -> Double { + switch self { + case .veryLow: 0.5 + case .low: 1.0 + case .medium: 2.0 + case .high: 4.0 + } + } + + /// Creates a Priority from a bitratePriority double value. + static func from(bitratePriority: Double) -> Priority { + if bitratePriority <= 0.5 { + return .veryLow + } else if bitratePriority <= 1.0 { + return .low + } else if bitratePriority <= 2.0 { + return .medium + } + return .high + } + + /// Creates a Priority from native RTCPriority. + static func from(rtcPriority: LKRTCPriority) -> Priority { + switch rtcPriority { + case .veryLow: .veryLow + case .low: .low + case .medium: .medium + case .high: .high + @unknown default: .low + } + } +} From 6c87025ea269133277c17839c113191cb67e5a09 Mon Sep 17 00:00:00 2001 From: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com> Date: Tue, 20 Jan 2026 16:19:03 +0800 Subject: [PATCH 2/9] expose options --- Sources/LiveKit/Core/RTC.swift | 11 +++-- Sources/LiveKit/Protocols/MediaEncoding.swift | 9 ++++ Sources/LiveKit/Types/AudioEncoding.swift | 40 +++++++++++++++++- Sources/LiveKit/Types/Dimensions.swift | 4 +- Sources/LiveKit/Types/Priority.swift | 2 +- Sources/LiveKit/Types/VideoEncoding.swift | 42 ++++++++++++++++++- Sources/LiveKit/Types/VideoParameters.swift | 11 +++-- 7 files changed, 108 insertions(+), 11 deletions(-) diff --git a/Sources/LiveKit/Core/RTC.swift b/Sources/LiveKit/Core/RTC.swift index 0b09a5a4f..a5c02caa7 100644 --- a/Sources/LiveKit/Core/RTC.swift +++ b/Sources/LiveKit/Core/RTC.swift @@ -191,12 +191,15 @@ actor RTC { result.scalabilityMode = scalabilityMode.rawStringValue } - if let priority { - result.bitratePriority = priority.toBitratePriority() + let resolvedBitratePriority = priority ?? encoding?.bitratePriority ?? encoding?.priority + let resolvedNetworkPriority = networkPriority ?? encoding?.networkPriority ?? encoding?.priority + + if let resolvedBitratePriority { + result.bitratePriority = resolvedBitratePriority.toBitratePriority() } - if let networkPriority { - result.networkPriority = networkPriority.toRTCPriority() + if let resolvedNetworkPriority { + result.networkPriority = resolvedNetworkPriority.toRTCPriority() } return result diff --git a/Sources/LiveKit/Protocols/MediaEncoding.swift b/Sources/LiveKit/Protocols/MediaEncoding.swift index 88e24d340..d2e1db202 100644 --- a/Sources/LiveKit/Protocols/MediaEncoding.swift +++ b/Sources/LiveKit/Protocols/MediaEncoding.swift @@ -20,4 +20,13 @@ import Foundation public protocol MediaEncoding { // var maxBitrate: Int { get } + + /// Priority for bandwidth allocation. + var bitratePriority: Priority? { get } + + /// Priority for DSCP marking. + var networkPriority: Priority? { get } + + /// Convenience priority applied to both bitrate and network priority. + var priority: Priority? { get } } diff --git a/Sources/LiveKit/Types/AudioEncoding.swift b/Sources/LiveKit/Types/AudioEncoding.swift index 06fdc54b7..baacf615d 100644 --- a/Sources/LiveKit/Types/AudioEncoding.swift +++ b/Sources/LiveKit/Types/AudioEncoding.swift @@ -23,23 +23,61 @@ public final class AudioEncoding: NSObject, MediaEncoding, Sendable { @objc public let maxBitrate: Int + /// Priority for bandwidth allocation. + public let bitratePriority: Priority? + + /// Priority for DSCP marking. + public let networkPriority: Priority? + + /// Convenience priority applied to both bitrate and network priority. + public let priority: Priority? + @objc public init(maxBitrate: Int) { self.maxBitrate = maxBitrate + bitratePriority = nil + networkPriority = nil + priority = nil + } + + public init(maxBitrate: Int, priority: Priority?) { + self.maxBitrate = maxBitrate + self.priority = priority + bitratePriority = priority + networkPriority = priority + } + + public init(maxBitrate: Int, bitratePriority: Priority?, networkPriority: Priority?) { + self.maxBitrate = maxBitrate + self.bitratePriority = bitratePriority + self.networkPriority = networkPriority + priority = nil } // MARK: - Equal override public func isEqual(_ object: Any?) -> Bool { guard let other = object as? Self else { return false } - return maxBitrate == other.maxBitrate + return maxBitrate == other.maxBitrate && + resolvedBitratePriority == other.resolvedBitratePriority && + resolvedNetworkPriority == other.resolvedNetworkPriority } override public var hash: Int { var hasher = Hasher() hasher.combine(maxBitrate) + hasher.combine(resolvedBitratePriority) + hasher.combine(resolvedNetworkPriority) return hasher.finalize() } + + private var resolvedBitratePriority: Priority? { + bitratePriority ?? priority + } + + private var resolvedNetworkPriority: Priority? { + networkPriority ?? priority + } } // MARK: - Presets diff --git a/Sources/LiveKit/Types/Dimensions.swift b/Sources/LiveKit/Types/Dimensions.swift index 7fc3c7cac..cc7403e3e 100644 --- a/Sources/LiveKit/Types/Dimensions.swift +++ b/Sources/LiveKit/Types/Dimensions.swift @@ -144,7 +144,9 @@ extension Dimensions { let parameters = RTC.createRtpEncodingParameters( rid: rid, encoding: preset.encoding, - scaleDownBy: Double(max) / Double(preset.dimensions.max) + scaleDownBy: Double(max) / Double(preset.dimensions.max), + priority: preset.encoding.bitratePriority ?? preset.encoding.priority, + networkPriority: preset.encoding.networkPriority ?? preset.encoding.priority ) result.append(parameters) diff --git a/Sources/LiveKit/Types/Priority.swift b/Sources/LiveKit/Types/Priority.swift index 4a7c89e15..668a439ac 100644 --- a/Sources/LiveKit/Types/Priority.swift +++ b/Sources/LiveKit/Types/Priority.swift @@ -18,7 +18,7 @@ internal import LiveKitWebRTC /// Priority levels for RTP encoding parameters. /// -/// `priority` controls WebRTC internal bandwidth allocation between streams. +/// `bitratePriority` controls WebRTC internal bandwidth allocation between streams. /// `networkPriority` controls DSCP marking for network-level QoS. @objc public enum Priority: Int, Sendable { diff --git a/Sources/LiveKit/Types/VideoEncoding.swift b/Sources/LiveKit/Types/VideoEncoding.swift index b6aa56151..574043581 100644 --- a/Sources/LiveKit/Types/VideoEncoding.swift +++ b/Sources/LiveKit/Types/VideoEncoding.swift @@ -24,10 +24,38 @@ public final class VideoEncoding: NSObject, MediaEncoding, Sendable { @objc public let maxFps: Int + /// Priority for bandwidth allocation. + public let bitratePriority: Priority? + + /// Priority for DSCP marking. + public let networkPriority: Priority? + + /// Convenience priority applied to both bitrate and network priority. + public let priority: Priority? + @objc public init(maxBitrate: Int, maxFps: Int) { self.maxBitrate = maxBitrate self.maxFps = maxFps + bitratePriority = nil + networkPriority = nil + priority = nil + } + + public init(maxBitrate: Int, maxFps: Int, priority: Priority?) { + self.maxBitrate = maxBitrate + self.maxFps = maxFps + self.priority = priority + bitratePriority = priority + networkPriority = priority + } + + public init(maxBitrate: Int, maxFps: Int, bitratePriority: Priority?, networkPriority: Priority?) { + self.maxBitrate = maxBitrate + self.maxFps = maxFps + self.bitratePriority = bitratePriority + self.networkPriority = networkPriority + priority = nil } // MARK: - Equal @@ -35,13 +63,25 @@ public final class VideoEncoding: NSObject, MediaEncoding, Sendable { override public func isEqual(_ object: Any?) -> Bool { guard let other = object as? Self else { return false } return maxBitrate == other.maxBitrate && - maxFps == other.maxFps + maxFps == other.maxFps && + resolvedBitratePriority == other.resolvedBitratePriority && + resolvedNetworkPriority == other.resolvedNetworkPriority } override public var hash: Int { var hasher = Hasher() hasher.combine(maxBitrate) hasher.combine(maxFps) + hasher.combine(resolvedBitratePriority) + hasher.combine(resolvedNetworkPriority) return hasher.finalize() } + + private var resolvedBitratePriority: Priority? { + bitratePriority ?? priority + } + + private var resolvedNetworkPriority: Priority? { + networkPriority ?? priority + } } diff --git a/Sources/LiveKit/Types/VideoParameters.swift b/Sources/LiveKit/Types/VideoParameters.swift index 02995a7fd..9ccec2c68 100644 --- a/Sources/LiveKit/Types/VideoParameters.swift +++ b/Sources/LiveKit/Types/VideoParameters.swift @@ -91,9 +91,14 @@ extension VideoParameters { let dimensions = Dimensions(width: Int32((Double(dimensions.width) / $0.scaleDownBy).rounded(.down)), height: Int32((Double(dimensions.height) / $0.scaleDownBy).rounded(.down))) let bitrate2 = Int((Double(encoding.maxBitrate) / (pow(Double($0.scaleDownBy), 2) * (Double(encoding.maxFps) / Double($0.fps)))).rounded(.down)) - let encoding = VideoEncoding(maxBitrate: Swift.max(150_000, bitrate2), maxFps: $0.fps) - - return VideoParameters(dimensions: dimensions, encoding: encoding) + let layerEncoding = VideoEncoding( + maxBitrate: Swift.max(150_000, bitrate2), + maxFps: $0.fps, + bitratePriority: encoding.bitratePriority ?? encoding.priority, + networkPriority: encoding.networkPriority ?? encoding.priority + ) + + return VideoParameters(dimensions: dimensions, encoding: layerEncoding) } } From 394586e5a84b50f5da2f5b844ff373993238d132 Mon Sep 17 00:00:00 2001 From: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com> Date: Tue, 20 Jan 2026 21:04:12 +0800 Subject: [PATCH 3/9] fix compile --- Sources/LiveKit/Protocols/MediaEncoding.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/LiveKit/Protocols/MediaEncoding.swift b/Sources/LiveKit/Protocols/MediaEncoding.swift index d2e1db202..0206153f4 100644 --- a/Sources/LiveKit/Protocols/MediaEncoding.swift +++ b/Sources/LiveKit/Protocols/MediaEncoding.swift @@ -16,7 +16,6 @@ import Foundation -@objc public protocol MediaEncoding { // var maxBitrate: Int { get } From a92df4025f18fd4cd7e48ba5934ba2e3796c6773 Mon Sep 17 00:00:00 2001 From: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com> Date: Tue, 20 Jan 2026 21:19:55 +0800 Subject: [PATCH 4/9] option --- Sources/LiveKit/Core/Room+Engine.swift | 2 ++ Sources/LiveKit/Protocols/MediaEncoding.swift | 1 + Sources/LiveKit/Types/AudioEncoding.swift | 1 + Sources/LiveKit/Types/Options/ConnectOptions.swift | 10 ++++++++++ Sources/LiveKit/Types/Priority.swift | 2 +- Sources/LiveKit/Types/VideoEncoding.swift | 1 + 6 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Sources/LiveKit/Core/Room+Engine.swift b/Sources/LiveKit/Core/Room+Engine.swift index 11162bcdb..be3a294e9 100644 --- a/Sources/LiveKit/Core/Room+Engine.swift +++ b/Sources/LiveKit/Core/Room+Engine.swift @@ -137,6 +137,8 @@ extension Room { rtcConfiguration.iceTransportPolicy = connectOptions.iceTransportPolicy.toRTCType() } + rtcConfiguration.enableDscp = connectOptions.enableDscp + return rtcConfiguration } diff --git a/Sources/LiveKit/Protocols/MediaEncoding.swift b/Sources/LiveKit/Protocols/MediaEncoding.swift index 0206153f4..f59c1c469 100644 --- a/Sources/LiveKit/Protocols/MediaEncoding.swift +++ b/Sources/LiveKit/Protocols/MediaEncoding.swift @@ -24,6 +24,7 @@ public protocol MediaEncoding { var bitratePriority: Priority? { get } /// Priority for DSCP marking. + /// Requires `ConnectOptions.enableDscp` to be true. var networkPriority: Priority? { get } /// Convenience priority applied to both bitrate and network priority. diff --git a/Sources/LiveKit/Types/AudioEncoding.swift b/Sources/LiveKit/Types/AudioEncoding.swift index baacf615d..932c11a17 100644 --- a/Sources/LiveKit/Types/AudioEncoding.swift +++ b/Sources/LiveKit/Types/AudioEncoding.swift @@ -27,6 +27,7 @@ public final class AudioEncoding: NSObject, MediaEncoding, Sendable { public let bitratePriority: Priority? /// Priority for DSCP marking. + /// Requires `ConnectOptions.enableDscp` to be true. public let networkPriority: Priority? /// Convenience priority applied to both bitrate and network priority. diff --git a/Sources/LiveKit/Types/Options/ConnectOptions.swift b/Sources/LiveKit/Types/Options/ConnectOptions.swift index e5269eb0e..9c5bbd4d4 100644 --- a/Sources/LiveKit/Types/Options/ConnectOptions.swift +++ b/Sources/LiveKit/Types/Options/ConnectOptions.swift @@ -73,6 +73,11 @@ public final class ConnectOptions: NSObject, Sendable { @objc public let iceTransportPolicy: IceTransportPolicy + /// Allows DSCP codes to be set on outgoing packets when network priority is used. + /// Defaults to false. + @objc + public let enableDscp: Bool + /// Enable microphone concurrently while connecting. @objc public let enableMicrophone: Bool @@ -92,6 +97,7 @@ public final class ConnectOptions: NSObject, Sendable { publisherTransportConnectTimeout = .defaultTransportState iceServers = [] iceTransportPolicy = .all + enableDscp = false enableMicrophone = false protocolVersion = .v16 } @@ -106,6 +112,7 @@ public final class ConnectOptions: NSObject, Sendable { publisherTransportConnectTimeout: TimeInterval = .defaultTransportState, iceServers: [IceServer] = [], iceTransportPolicy: IceTransportPolicy = .all, + enableDscp: Bool = false, enableMicrophone: Bool = false, protocolVersion: ProtocolVersion = .v16) { @@ -118,6 +125,7 @@ public final class ConnectOptions: NSObject, Sendable { self.publisherTransportConnectTimeout = publisherTransportConnectTimeout self.iceServers = iceServers self.iceTransportPolicy = iceTransportPolicy + self.enableDscp = enableDscp self.enableMicrophone = enableMicrophone self.protocolVersion = protocolVersion } @@ -135,6 +143,7 @@ public final class ConnectOptions: NSObject, Sendable { publisherTransportConnectTimeout == other.publisherTransportConnectTimeout && iceServers == other.iceServers && iceTransportPolicy == other.iceTransportPolicy && + enableDscp == other.enableDscp && enableMicrophone == other.enableMicrophone && protocolVersion == other.protocolVersion } @@ -150,6 +159,7 @@ public final class ConnectOptions: NSObject, Sendable { hasher.combine(publisherTransportConnectTimeout) hasher.combine(iceServers) hasher.combine(iceTransportPolicy) + hasher.combine(enableDscp) hasher.combine(enableMicrophone) hasher.combine(protocolVersion) return hasher.finalize() diff --git a/Sources/LiveKit/Types/Priority.swift b/Sources/LiveKit/Types/Priority.swift index 668a439ac..27053a352 100644 --- a/Sources/LiveKit/Types/Priority.swift +++ b/Sources/LiveKit/Types/Priority.swift @@ -19,7 +19,7 @@ internal import LiveKitWebRTC /// Priority levels for RTP encoding parameters. /// /// `bitratePriority` controls WebRTC internal bandwidth allocation between streams. -/// `networkPriority` controls DSCP marking for network-level QoS. +/// `networkPriority` controls DSCP marking for network-level QoS. Requires `ConnectOptions.enableDscp` to be true. @objc public enum Priority: Int, Sendable { case veryLow diff --git a/Sources/LiveKit/Types/VideoEncoding.swift b/Sources/LiveKit/Types/VideoEncoding.swift index 574043581..e432b2788 100644 --- a/Sources/LiveKit/Types/VideoEncoding.swift +++ b/Sources/LiveKit/Types/VideoEncoding.swift @@ -28,6 +28,7 @@ public final class VideoEncoding: NSObject, MediaEncoding, Sendable { public let bitratePriority: Priority? /// Priority for DSCP marking. + /// Requires `ConnectOptions.enableDscp` to be true. public let networkPriority: Priority? /// Convenience priority applied to both bitrate and network priority. From adf8236fea1595df476c16533e03d75bda1d9b4a Mon Sep 17 00:00:00 2001 From: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com> Date: Tue, 20 Jan 2026 22:06:16 +0800 Subject: [PATCH 5/9] simplify --- Sources/LiveKit/Core/RTC.swift | 15 ++++------ Sources/LiveKit/Protocols/MediaEncoding.swift | 3 -- Sources/LiveKit/Types/AudioEncoding.swift | 28 +++--------------- Sources/LiveKit/Types/Dimensions.swift | 4 +-- Sources/LiveKit/Types/VideoEncoding.swift | 29 +++---------------- Sources/LiveKit/Types/VideoParameters.swift | 4 +-- 6 files changed, 16 insertions(+), 67 deletions(-) diff --git a/Sources/LiveKit/Core/RTC.swift b/Sources/LiveKit/Core/RTC.swift index a5c02caa7..6c1de4cbe 100644 --- a/Sources/LiveKit/Core/RTC.swift +++ b/Sources/LiveKit/Core/RTC.swift @@ -165,9 +165,7 @@ actor RTC { encoding: MediaEncoding? = nil, scaleDownBy: Double? = nil, active: Bool = true, - scalabilityMode: ScalabilityMode? = nil, - priority: Priority? = nil, - networkPriority: Priority? = nil) -> LKRTCRtpEncodingParameters + scalabilityMode: ScalabilityMode? = nil) -> LKRTCRtpEncodingParameters { let result = DispatchQueue.liveKitWebRTC.sync { LKRTCRtpEncodingParameters() } @@ -191,15 +189,12 @@ actor RTC { result.scalabilityMode = scalabilityMode.rawStringValue } - let resolvedBitratePriority = priority ?? encoding?.bitratePriority ?? encoding?.priority - let resolvedNetworkPriority = networkPriority ?? encoding?.networkPriority ?? encoding?.priority - - if let resolvedBitratePriority { - result.bitratePriority = resolvedBitratePriority.toBitratePriority() + if let bitratePriority = encoding?.bitratePriority { + result.bitratePriority = bitratePriority.toBitratePriority() } - if let resolvedNetworkPriority { - result.networkPriority = resolvedNetworkPriority.toRTCPriority() + if let networkPriority = encoding?.networkPriority { + result.networkPriority = networkPriority.toRTCPriority() } return result diff --git a/Sources/LiveKit/Protocols/MediaEncoding.swift b/Sources/LiveKit/Protocols/MediaEncoding.swift index f59c1c469..ffc411a23 100644 --- a/Sources/LiveKit/Protocols/MediaEncoding.swift +++ b/Sources/LiveKit/Protocols/MediaEncoding.swift @@ -26,7 +26,4 @@ public protocol MediaEncoding { /// Priority for DSCP marking. /// Requires `ConnectOptions.enableDscp` to be true. var networkPriority: Priority? { get } - - /// Convenience priority applied to both bitrate and network priority. - var priority: Priority? { get } } diff --git a/Sources/LiveKit/Types/AudioEncoding.swift b/Sources/LiveKit/Types/AudioEncoding.swift index 932c11a17..d32f501b0 100644 --- a/Sources/LiveKit/Types/AudioEncoding.swift +++ b/Sources/LiveKit/Types/AudioEncoding.swift @@ -30,29 +30,17 @@ public final class AudioEncoding: NSObject, MediaEncoding, Sendable { /// Requires `ConnectOptions.enableDscp` to be true. public let networkPriority: Priority? - /// Convenience priority applied to both bitrate and network priority. - public let priority: Priority? - @objc public init(maxBitrate: Int) { self.maxBitrate = maxBitrate bitratePriority = nil networkPriority = nil - priority = nil - } - - public init(maxBitrate: Int, priority: Priority?) { - self.maxBitrate = maxBitrate - self.priority = priority - bitratePriority = priority - networkPriority = priority } public init(maxBitrate: Int, bitratePriority: Priority?, networkPriority: Priority?) { self.maxBitrate = maxBitrate self.bitratePriority = bitratePriority self.networkPriority = networkPriority - priority = nil } // MARK: - Equal @@ -60,25 +48,17 @@ public final class AudioEncoding: NSObject, MediaEncoding, Sendable { override public func isEqual(_ object: Any?) -> Bool { guard let other = object as? Self else { return false } return maxBitrate == other.maxBitrate && - resolvedBitratePriority == other.resolvedBitratePriority && - resolvedNetworkPriority == other.resolvedNetworkPriority + bitratePriority == other.bitratePriority && + networkPriority == other.networkPriority } override public var hash: Int { var hasher = Hasher() hasher.combine(maxBitrate) - hasher.combine(resolvedBitratePriority) - hasher.combine(resolvedNetworkPriority) + hasher.combine(bitratePriority) + hasher.combine(networkPriority) return hasher.finalize() } - - private var resolvedBitratePriority: Priority? { - bitratePriority ?? priority - } - - private var resolvedNetworkPriority: Priority? { - networkPriority ?? priority - } } // MARK: - Presets diff --git a/Sources/LiveKit/Types/Dimensions.swift b/Sources/LiveKit/Types/Dimensions.swift index cc7403e3e..7fc3c7cac 100644 --- a/Sources/LiveKit/Types/Dimensions.swift +++ b/Sources/LiveKit/Types/Dimensions.swift @@ -144,9 +144,7 @@ extension Dimensions { let parameters = RTC.createRtpEncodingParameters( rid: rid, encoding: preset.encoding, - scaleDownBy: Double(max) / Double(preset.dimensions.max), - priority: preset.encoding.bitratePriority ?? preset.encoding.priority, - networkPriority: preset.encoding.networkPriority ?? preset.encoding.priority + scaleDownBy: Double(max) / Double(preset.dimensions.max) ) result.append(parameters) diff --git a/Sources/LiveKit/Types/VideoEncoding.swift b/Sources/LiveKit/Types/VideoEncoding.swift index e432b2788..adeacfcfc 100644 --- a/Sources/LiveKit/Types/VideoEncoding.swift +++ b/Sources/LiveKit/Types/VideoEncoding.swift @@ -31,24 +31,12 @@ public final class VideoEncoding: NSObject, MediaEncoding, Sendable { /// Requires `ConnectOptions.enableDscp` to be true. public let networkPriority: Priority? - /// Convenience priority applied to both bitrate and network priority. - public let priority: Priority? - @objc public init(maxBitrate: Int, maxFps: Int) { self.maxBitrate = maxBitrate self.maxFps = maxFps bitratePriority = nil networkPriority = nil - priority = nil - } - - public init(maxBitrate: Int, maxFps: Int, priority: Priority?) { - self.maxBitrate = maxBitrate - self.maxFps = maxFps - self.priority = priority - bitratePriority = priority - networkPriority = priority } public init(maxBitrate: Int, maxFps: Int, bitratePriority: Priority?, networkPriority: Priority?) { @@ -56,7 +44,6 @@ public final class VideoEncoding: NSObject, MediaEncoding, Sendable { self.maxFps = maxFps self.bitratePriority = bitratePriority self.networkPriority = networkPriority - priority = nil } // MARK: - Equal @@ -65,24 +52,16 @@ public final class VideoEncoding: NSObject, MediaEncoding, Sendable { guard let other = object as? Self else { return false } return maxBitrate == other.maxBitrate && maxFps == other.maxFps && - resolvedBitratePriority == other.resolvedBitratePriority && - resolvedNetworkPriority == other.resolvedNetworkPriority + bitratePriority == other.bitratePriority && + networkPriority == other.networkPriority } override public var hash: Int { var hasher = Hasher() hasher.combine(maxBitrate) hasher.combine(maxFps) - hasher.combine(resolvedBitratePriority) - hasher.combine(resolvedNetworkPriority) + hasher.combine(bitratePriority) + hasher.combine(networkPriority) return hasher.finalize() } - - private var resolvedBitratePriority: Priority? { - bitratePriority ?? priority - } - - private var resolvedNetworkPriority: Priority? { - networkPriority ?? priority - } } diff --git a/Sources/LiveKit/Types/VideoParameters.swift b/Sources/LiveKit/Types/VideoParameters.swift index 9ccec2c68..71e20a980 100644 --- a/Sources/LiveKit/Types/VideoParameters.swift +++ b/Sources/LiveKit/Types/VideoParameters.swift @@ -94,8 +94,8 @@ extension VideoParameters { let layerEncoding = VideoEncoding( maxBitrate: Swift.max(150_000, bitrate2), maxFps: $0.fps, - bitratePriority: encoding.bitratePriority ?? encoding.priority, - networkPriority: encoding.networkPriority ?? encoding.priority + bitratePriority: encoding.bitratePriority, + networkPriority: encoding.networkPriority ) return VideoParameters(dimensions: dimensions, encoding: layerEncoding) From 06caae3172b37d3c94bc3c1dabffe439d80f3411 Mon Sep 17 00:00:00 2001 From: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com> Date: Tue, 20 Jan 2026 22:25:27 +0800 Subject: [PATCH 6/9] changes --- .changes/priority-control | 1 + 1 file changed, 1 insertion(+) create mode 100644 .changes/priority-control diff --git a/.changes/priority-control b/.changes/priority-control new file mode 100644 index 000000000..fb17dcef0 --- /dev/null +++ b/.changes/priority-control @@ -0,0 +1 @@ +minor type="added" "Expose separate bitrate/network priorities for media tracks" From 557320c6c7d305eb65964c0f1147d3c948c85c99 Mon Sep 17 00:00:00 2001 From: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com> Date: Sat, 24 Jan 2026 02:42:20 +0800 Subject: [PATCH 7/9] clean unused code --- Sources/LiveKit/Types/Priority.swift | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/Sources/LiveKit/Types/Priority.swift b/Sources/LiveKit/Types/Priority.swift index 27053a352..3cf683cb8 100644 --- a/Sources/LiveKit/Types/Priority.swift +++ b/Sources/LiveKit/Types/Priority.swift @@ -52,27 +52,4 @@ extension Priority { case .high: 4.0 } } - - /// Creates a Priority from a bitratePriority double value. - static func from(bitratePriority: Double) -> Priority { - if bitratePriority <= 0.5 { - return .veryLow - } else if bitratePriority <= 1.0 { - return .low - } else if bitratePriority <= 2.0 { - return .medium - } - return .high - } - - /// Creates a Priority from native RTCPriority. - static func from(rtcPriority: LKRTCPriority) -> Priority { - switch rtcPriority { - case .veryLow: .veryLow - case .low: .low - case .medium: .medium - case .high: .high - @unknown default: .low - } - } } From 9417f20489959a72df7ec2c6325092e6b554226f Mon Sep 17 00:00:00 2001 From: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com> Date: Tue, 27 Jan 2026 18:36:36 +0800 Subject: [PATCH 8/9] docs --- Sources/LiveKit/Protocols/MediaEncoding.swift | 2 +- Sources/LiveKit/Types/Priority.swift | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Sources/LiveKit/Protocols/MediaEncoding.swift b/Sources/LiveKit/Protocols/MediaEncoding.swift index ffc411a23..415fb1e9c 100644 --- a/Sources/LiveKit/Protocols/MediaEncoding.swift +++ b/Sources/LiveKit/Protocols/MediaEncoding.swift @@ -17,7 +17,7 @@ import Foundation public protocol MediaEncoding { - // + /// Maximum bitrate in bits per second. var maxBitrate: Int { get } /// Priority for bandwidth allocation. diff --git a/Sources/LiveKit/Types/Priority.swift b/Sources/LiveKit/Types/Priority.swift index 3cf683cb8..45c03890c 100644 --- a/Sources/LiveKit/Types/Priority.swift +++ b/Sources/LiveKit/Types/Priority.swift @@ -19,7 +19,10 @@ internal import LiveKitWebRTC /// Priority levels for RTP encoding parameters. /// /// `bitratePriority` controls WebRTC internal bandwidth allocation between streams. -/// `networkPriority` controls DSCP marking for network-level QoS. Requires `ConnectOptions.enableDscp` to be true. +/// When not set, WebRTC uses its default value equivalent to `.low` (1.0x). +/// +/// `networkPriority` controls DSCP marking for network-level QoS. +/// Requires `ConnectOptions.enableDscp` to be true. @objc public enum Priority: Int, Sendable { case veryLow From 422f9b97216c2b7ca959fa94de6bbc208fcda5d3 Mon Sep 17 00:00:00 2001 From: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com> Date: Tue, 27 Jan 2026 18:41:40 +0800 Subject: [PATCH 9/9] rename to isDscpEnabled to align with SDK --- Sources/LiveKit/Core/Room+Engine.swift | 2 +- Sources/LiveKit/Protocols/MediaEncoding.swift | 2 +- Sources/LiveKit/Types/AudioEncoding.swift | 2 +- Sources/LiveKit/Types/Options/ConnectOptions.swift | 12 ++++++------ Sources/LiveKit/Types/Priority.swift | 2 +- Sources/LiveKit/Types/VideoEncoding.swift | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Sources/LiveKit/Core/Room+Engine.swift b/Sources/LiveKit/Core/Room+Engine.swift index be3a294e9..e128a3be2 100644 --- a/Sources/LiveKit/Core/Room+Engine.swift +++ b/Sources/LiveKit/Core/Room+Engine.swift @@ -137,7 +137,7 @@ extension Room { rtcConfiguration.iceTransportPolicy = connectOptions.iceTransportPolicy.toRTCType() } - rtcConfiguration.enableDscp = connectOptions.enableDscp + rtcConfiguration.enableDscp = connectOptions.isDscpEnabled return rtcConfiguration } diff --git a/Sources/LiveKit/Protocols/MediaEncoding.swift b/Sources/LiveKit/Protocols/MediaEncoding.swift index 415fb1e9c..cc8cda2c7 100644 --- a/Sources/LiveKit/Protocols/MediaEncoding.swift +++ b/Sources/LiveKit/Protocols/MediaEncoding.swift @@ -24,6 +24,6 @@ public protocol MediaEncoding { var bitratePriority: Priority? { get } /// Priority for DSCP marking. - /// Requires `ConnectOptions.enableDscp` to be true. + /// Requires `ConnectOptions.isDscpEnabled` to be true. var networkPriority: Priority? { get } } diff --git a/Sources/LiveKit/Types/AudioEncoding.swift b/Sources/LiveKit/Types/AudioEncoding.swift index d32f501b0..f57981557 100644 --- a/Sources/LiveKit/Types/AudioEncoding.swift +++ b/Sources/LiveKit/Types/AudioEncoding.swift @@ -27,7 +27,7 @@ public final class AudioEncoding: NSObject, MediaEncoding, Sendable { public let bitratePriority: Priority? /// Priority for DSCP marking. - /// Requires `ConnectOptions.enableDscp` to be true. + /// Requires `ConnectOptions.isDscpEnabled` to be true. public let networkPriority: Priority? @objc diff --git a/Sources/LiveKit/Types/Options/ConnectOptions.swift b/Sources/LiveKit/Types/Options/ConnectOptions.swift index 9c5bbd4d4..a72bad1cf 100644 --- a/Sources/LiveKit/Types/Options/ConnectOptions.swift +++ b/Sources/LiveKit/Types/Options/ConnectOptions.swift @@ -76,7 +76,7 @@ public final class ConnectOptions: NSObject, Sendable { /// Allows DSCP codes to be set on outgoing packets when network priority is used. /// Defaults to false. @objc - public let enableDscp: Bool + public let isDscpEnabled: Bool /// Enable microphone concurrently while connecting. @objc @@ -97,7 +97,7 @@ public final class ConnectOptions: NSObject, Sendable { publisherTransportConnectTimeout = .defaultTransportState iceServers = [] iceTransportPolicy = .all - enableDscp = false + isDscpEnabled = false enableMicrophone = false protocolVersion = .v16 } @@ -112,7 +112,7 @@ public final class ConnectOptions: NSObject, Sendable { publisherTransportConnectTimeout: TimeInterval = .defaultTransportState, iceServers: [IceServer] = [], iceTransportPolicy: IceTransportPolicy = .all, - enableDscp: Bool = false, + isDscpEnabled: Bool = false, enableMicrophone: Bool = false, protocolVersion: ProtocolVersion = .v16) { @@ -125,7 +125,7 @@ public final class ConnectOptions: NSObject, Sendable { self.publisherTransportConnectTimeout = publisherTransportConnectTimeout self.iceServers = iceServers self.iceTransportPolicy = iceTransportPolicy - self.enableDscp = enableDscp + self.isDscpEnabled = isDscpEnabled self.enableMicrophone = enableMicrophone self.protocolVersion = protocolVersion } @@ -143,7 +143,7 @@ public final class ConnectOptions: NSObject, Sendable { publisherTransportConnectTimeout == other.publisherTransportConnectTimeout && iceServers == other.iceServers && iceTransportPolicy == other.iceTransportPolicy && - enableDscp == other.enableDscp && + isDscpEnabled == other.isDscpEnabled && enableMicrophone == other.enableMicrophone && protocolVersion == other.protocolVersion } @@ -159,7 +159,7 @@ public final class ConnectOptions: NSObject, Sendable { hasher.combine(publisherTransportConnectTimeout) hasher.combine(iceServers) hasher.combine(iceTransportPolicy) - hasher.combine(enableDscp) + hasher.combine(isDscpEnabled) hasher.combine(enableMicrophone) hasher.combine(protocolVersion) return hasher.finalize() diff --git a/Sources/LiveKit/Types/Priority.swift b/Sources/LiveKit/Types/Priority.swift index 45c03890c..eeca7558b 100644 --- a/Sources/LiveKit/Types/Priority.swift +++ b/Sources/LiveKit/Types/Priority.swift @@ -22,7 +22,7 @@ internal import LiveKitWebRTC /// When not set, WebRTC uses its default value equivalent to `.low` (1.0x). /// /// `networkPriority` controls DSCP marking for network-level QoS. -/// Requires `ConnectOptions.enableDscp` to be true. +/// Requires `ConnectOptions.isDscpEnabled` to be true. @objc public enum Priority: Int, Sendable { case veryLow diff --git a/Sources/LiveKit/Types/VideoEncoding.swift b/Sources/LiveKit/Types/VideoEncoding.swift index adeacfcfc..ead9153b9 100644 --- a/Sources/LiveKit/Types/VideoEncoding.swift +++ b/Sources/LiveKit/Types/VideoEncoding.swift @@ -28,7 +28,7 @@ public final class VideoEncoding: NSObject, MediaEncoding, Sendable { public let bitratePriority: Priority? /// Priority for DSCP marking. - /// Requires `ConnectOptions.enableDscp` to be true. + /// Requires `ConnectOptions.isDscpEnabled` to be true. public let networkPriority: Priority? @objc