Skip to content

Commit 1461398

Browse files
authored
Sync streams (Protocol 10) (#291)
Reference: livekit/client-sdk-js#881 Protocol is already set to v10.
1 parent 67401d6 commit 1461398

File tree

9 files changed

+51
-28
lines changed

9 files changed

+51
-28
lines changed

Sources/LiveKit/Core/Engine+TransportDelegate.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,19 @@ extension Engine: TransportDelegate {
5454
}
5555

5656
func transport(_ transport: Transport, didAddTrack track: LKRTCMediaStreamTrack, rtpReceiver: LKRTCRtpReceiver, streams: [LKRTCMediaStream]) {
57-
log("did add track")
57+
guard !streams.isEmpty else {
58+
log("Received onTrack with no streams!", .warning)
59+
return
60+
}
61+
5862
if transport.target == .subscriber {
5963
// execute block when connected
6064
execute(when: { state, _ in state.connectionState == .connected },
6165
// always remove this block when disconnected
6266
removeWhen: { state, _ in state.connectionState == .disconnected })
6367
{ [weak self] in
6468
guard let self else { return }
65-
self.notify { $0.engine(self, didAddTrack: track, rtpReceiver: rtpReceiver, streams: streams) }
69+
self.notify { $0.engine(self, didAddTrack: track, rtpReceiver: rtpReceiver, stream: streams.first!) }
6670
}
6771
}
6872
}

Sources/LiveKit/Core/Room+EngineDelegate.swift

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -129,31 +129,21 @@ extension Room: EngineDelegate {
129129
}
130130
}
131131

132-
func engine(_: Engine, didAddTrack track: LKRTCMediaStreamTrack, rtpReceiver: LKRTCRtpReceiver, streams: [LKRTCMediaStream]) {
133-
guard !streams.isEmpty else {
134-
log("Received onTrack with no streams!", .warning)
135-
return
136-
}
137-
138-
let unpacked = streams[0].streamId.unpack()
139-
let participantSid = unpacked.sid
140-
var trackSid = unpacked.trackId
141-
if trackSid == "" {
142-
trackSid = track.trackId
143-
}
132+
func engine(_: Engine, didAddTrack track: LKRTCMediaStreamTrack, rtpReceiver: LKRTCRtpReceiver, stream: LKRTCMediaStream) {
133+
let parts = stream.streamId.unpack()
144134

145135
let participant = _state.read {
146-
$0.remoteParticipants.values.first { $0.sid == participantSid }
136+
$0.remoteParticipants.values.first { $0.sid == parts.participantSid }
147137
}
148138

149139
guard let participant else {
150-
log("RemoteParticipant not found for sid: \(participantSid), remoteParticipants: \(remoteParticipants)", .warning)
140+
log("RemoteParticipant not found for sid: \(parts.participantSid), remoteParticipants: \(remoteParticipants)", .warning)
151141
return
152142
}
153143

154144
let task = Task.retrying(retryDelay: 0.2) { _, _ in
155145
// TODO: Only retry for TrackError.state = error
156-
try await participant.addSubscribedMediaTrack(rtcTrack: track, rtpReceiver: rtpReceiver, sid: trackSid)
146+
try await participant.addSubscribedMediaTrack(rtcTrack: track, rtpReceiver: rtpReceiver, sid: track.trackId)
157147
}
158148

159149
Task {

Sources/LiveKit/Core/Transport.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,15 +218,15 @@ extension Transport: LKRTCPeerConnectionDelegate {
218218

219219
func peerConnection(_: LKRTCPeerConnection,
220220
didAdd rtpReceiver: LKRTCRtpReceiver,
221-
streams mediaStreams: [LKRTCMediaStream])
221+
streams: [LKRTCMediaStream])
222222
{
223223
guard let track = rtpReceiver.track else {
224224
log("Track is empty for \(target)", .warning)
225225
return
226226
}
227227

228-
log("didAddTrack type: \(type(of: track)), id: \(track.trackId)")
229-
notify { $0.transport(self, didAddTrack: track, rtpReceiver: rtpReceiver, streams: mediaStreams) }
228+
log("type: \(type(of: track)), track.id: \(track.trackId), streams: \(streams.map { "Stream(hash: \($0.hash), id: \($0.streamId), videoTracks: \($0.videoTracks.count), audioTracks: \($0.audioTracks.count))" })")
229+
notify { $0.transport(self, didAddTrack: track, rtpReceiver: rtpReceiver, streams: streams) }
230230
}
231231

232232
func peerConnection(_: LKRTCPeerConnection,

Sources/LiveKit/Extensions/Primitives.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import Foundation
1818

1919
extension String {
20-
func unpack() -> (sid: Sid, trackId: String) {
20+
func unpack() -> (participantSid: Sid, trackId: String) {
2121
let parts = split(separator: "|")
2222
if parts.count == 2 {
2323
return (String(parts[0]), String(parts[1]))

Sources/LiveKit/Participant/LocalParticipant.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,13 @@ public class LocalParticipant: Participant {
139139
]
140140
}
141141

142+
if let mediaPublishOptions = publishOptions as? MediaPublishOptions,
143+
let streamName = mediaPublishOptions.streamName
144+
{
145+
// Set stream name if specified in options
146+
populator.stream = streamName
147+
}
148+
142149
return transInit
143150
}
144151

Sources/LiveKit/Protocols/EngineDelegate.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import Foundation
2121
protocol EngineDelegate: AnyObject {
2222
func engine(_ engine: Engine, didMutateState state: Engine.State, oldState: Engine.State)
2323
func engine(_ engine: Engine, didUpdateSpeakers speakers: [Livekit_SpeakerInfo])
24-
func engine(_ engine: Engine, didAddTrack track: LKRTCMediaStreamTrack, rtpReceiver: LKRTCRtpReceiver, streams: [LKRTCMediaStream])
24+
func engine(_ engine: Engine, didAddTrack track: LKRTCMediaStreamTrack, rtpReceiver: LKRTCRtpReceiver, stream: LKRTCMediaStream)
2525
func engine(_ engine: Engine, didRemoveTrack track: LKRTCMediaStreamTrack)
2626
func engine(_ engine: Engine, didReceiveUserPacket packet: Livekit_UserPacket)
2727
}

Sources/LiveKit/Types/Options/AudioPublishOptions.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import Foundation
1818

1919
@objc
20-
public class AudioPublishOptions: NSObject, PublishOptions {
20+
public class AudioPublishOptions: NSObject, MediaPublishOptions {
2121
@objc
2222
public let name: String?
2323

@@ -28,13 +28,18 @@ public class AudioPublishOptions: NSObject, PublishOptions {
2828
@objc
2929
public let dtx: Bool
3030

31+
@objc
32+
public let streamName: String?
33+
3134
public init(name: String? = nil,
3235
encoding: AudioEncoding? = nil,
33-
dtx: Bool = true)
36+
dtx: Bool = true,
37+
streamName: String? = nil)
3438
{
3539
self.name = name
3640
self.encoding = encoding
3741
self.dtx = dtx
42+
self.streamName = streamName
3843
}
3944

4045
// MARK: - Equal
@@ -43,14 +48,16 @@ public class AudioPublishOptions: NSObject, PublishOptions {
4348
guard let other = object as? Self else { return false }
4449
return name == other.name &&
4550
encoding == other.encoding &&
46-
dtx == other.dtx
51+
dtx == other.dtx &&
52+
streamName == other.streamName
4753
}
4854

4955
override public var hash: Int {
5056
var hasher = Hasher()
5157
hasher.combine(name)
5258
hasher.combine(encoding)
5359
hasher.combine(dtx)
60+
hasher.combine(streamName)
5461
return hasher.finalize()
5562
}
5663
}

Sources/LiveKit/Types/Options/PublishOptions.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,11 @@ import Foundation
2020
public protocol PublishOptions {
2121
var name: String? { get }
2222
}
23+
24+
@objc
25+
public protocol MediaPublishOptions: PublishOptions {
26+
/// Set stream name for the track. Audio and video tracks with the same stream name
27+
/// will be placed in the same `MediaStream` and offer better synchronization.
28+
/// By default, camera and microphone will be placed in a stream; as would screen_share and screen_share_audio
29+
var streamName: String? { get }
30+
}

Sources/LiveKit/Types/Options/VideoPublishOptions.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import Foundation
1818

1919
@objc
20-
public class VideoPublishOptions: NSObject, PublishOptions {
20+
public class VideoPublishOptions: NSObject, MediaPublishOptions {
2121
@objc
2222
public let name: String?
2323

@@ -45,14 +45,18 @@ public class VideoPublishOptions: NSObject, PublishOptions {
4545
@objc
4646
public let preferredBackupCodec: VideoCodec?
4747

48+
@objc
49+
public let streamName: String?
50+
4851
public init(name: String? = nil,
4952
encoding: VideoEncoding? = nil,
5053
screenShareEncoding: VideoEncoding? = nil,
5154
simulcast: Bool = true,
5255
simulcastLayers: [VideoParameters] = [],
5356
screenShareSimulcastLayers: [VideoParameters] = [],
5457
preferredCodec: VideoCodec? = nil,
55-
preferredBackupCodec: VideoCodec? = nil)
58+
preferredBackupCodec: VideoCodec? = nil,
59+
streamName: String? = nil)
5660
{
5761
self.name = name
5862
self.encoding = encoding
@@ -62,6 +66,7 @@ public class VideoPublishOptions: NSObject, PublishOptions {
6266
self.screenShareSimulcastLayers = screenShareSimulcastLayers
6367
self.preferredCodec = preferredCodec
6468
self.preferredBackupCodec = preferredBackupCodec
69+
self.streamName = streamName
6570
}
6671

6772
// MARK: - Equal
@@ -75,7 +80,8 @@ public class VideoPublishOptions: NSObject, PublishOptions {
7580
simulcastLayers == other.simulcastLayers &&
7681
screenShareSimulcastLayers == other.screenShareSimulcastLayers &&
7782
preferredCodec == other.preferredCodec &&
78-
preferredBackupCodec == other.preferredBackupCodec
83+
preferredBackupCodec == other.preferredBackupCodec &&
84+
streamName == other.streamName
7985
}
8086

8187
override public var hash: Int {
@@ -88,6 +94,7 @@ public class VideoPublishOptions: NSObject, PublishOptions {
8894
hasher.combine(screenShareSimulcastLayers)
8995
hasher.combine(preferredCodec)
9096
hasher.combine(preferredBackupCodec)
97+
hasher.combine(streamName)
9198
return hasher.finalize()
9299
}
93100
}

0 commit comments

Comments
 (0)