Skip to content

Commit

Permalink
cancellable publish
Browse files Browse the repository at this point in the history
  • Loading branch information
hiroshihorie committed Nov 14, 2023
1 parent cc6e480 commit 2d44fcd
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 99 deletions.
199 changes: 105 additions & 94 deletions Sources/LiveKit/Participant/LocalParticipant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,129 +58,140 @@ public class LocalParticipant: Participant {
throw TrackError.publish(message: "Unknown LocalTrack type")
}

// Start the track
// Try to start the Track
try await track.start()
// Starting the Track could be time consuming especially for camera etc.
// Check cancellation after track starts.
try Task.checkCancellation()

var dimensions: Dimensions? // Only for Video
do {
var dimensions: Dimensions? // Only for Video

if let track = track as? LocalVideoTrack {
// Wait for Dimensions...
log("[Publish] Waiting for dimensions to resolve...")
dimensions = try await track.capturer.dimensionsCompleter.wait()
}
if let track = track as? LocalVideoTrack {
// Wait for Dimensions...
log("[Publish] Waiting for dimensions to resolve...")
dimensions = try await track.capturer.dimensionsCompleter.wait()
}

let populatorFunc: SignalClient.AddTrackRequestPopulator<LKRTCRtpTransceiverInit> = { populator in
let populatorFunc: SignalClient.AddTrackRequestPopulator<LKRTCRtpTransceiverInit> = { populator in

let transInit = DispatchQueue.liveKitWebRTC.sync { LKRTCRtpTransceiverInit() }
transInit.direction = .sendOnly
let transInit = DispatchQueue.liveKitWebRTC.sync { LKRTCRtpTransceiverInit() }
transInit.direction = .sendOnly

if let track = track as? LocalVideoTrack {
guard let dimensions else {
throw TrackError.publish(message: "VideoCapturer dimensions are unknown")
}
if let track = track as? LocalVideoTrack {
guard let dimensions else {
throw TrackError.publish(message: "VideoCapturer dimensions are unknown")
}

self.log("[publish] computing encode settings with dimensions: \(dimensions)...")
self.log("[publish] computing encode settings with dimensions: \(dimensions)...")

let publishOptions = (publishOptions as? VideoPublishOptions) ?? self.room._state.options.defaultVideoPublishOptions
let publishOptions = (publishOptions as? VideoPublishOptions) ?? self.room._state.options.defaultVideoPublishOptions

let encodings = Utils.computeEncodings(dimensions: dimensions,
publishOptions: publishOptions,
isScreenShare: track.source == .screenShareVideo)
let encodings = Utils.computeEncodings(dimensions: dimensions,
publishOptions: publishOptions,
isScreenShare: track.source == .screenShareVideo)

self.log("[publish] using encodings: \(encodings)")
transInit.sendEncodings = encodings
self.log("[publish] using encodings: \(encodings)")
transInit.sendEncodings = encodings

let videoLayers = dimensions.videoLayers(for: encodings)
let videoLayers = dimensions.videoLayers(for: encodings)

self.log("[publish] using layers: \(videoLayers.map { String(describing: $0) }.joined(separator: ", "))")
self.log("[publish] using layers: \(videoLayers.map { String(describing: $0) }.joined(separator: ", "))")

populator.width = UInt32(dimensions.width)
populator.height = UInt32(dimensions.height)
populator.layers = videoLayers
populator.width = UInt32(dimensions.width)
populator.height = UInt32(dimensions.height)
populator.layers = videoLayers

self.log("[publish] requesting add track to server with \(populator)...")
self.log("[publish] requesting add track to server with \(populator)...")

} else if track is LocalAudioTrack {
// additional params for Audio
let publishOptions = (publishOptions as? AudioPublishOptions) ?? self.room._state.options.defaultAudioPublishOptions
} else if track is LocalAudioTrack {
// additional params for Audio
let publishOptions = (publishOptions as? AudioPublishOptions) ?? self.room._state.options.defaultAudioPublishOptions

populator.disableDtx = !publishOptions.dtx
populator.disableDtx = !publishOptions.dtx

let encoding = publishOptions.encoding ?? AudioEncoding.presetSpeech
let encoding = publishOptions.encoding ?? AudioEncoding.presetSpeech

self.log("[publish] maxBitrate: \(encoding.maxBitrate)")
self.log("[publish] maxBitrate: \(encoding.maxBitrate)")

transInit.sendEncodings = [
Engine.createRtpEncodingParameters(encoding: encoding),
]
transInit.sendEncodings = [
Engine.createRtpEncodingParameters(encoding: encoding),
]
}

return transInit
}

return transInit
}
// Request a new track to the server
let addTrackResult = try await room.engine.signalClient.sendAddTrack(cid: track.mediaTrack.trackId,
name: track.name,
type: track.kind.toPBType(),
source: track.source.toPBType(),
encryption: room.e2eeManager?.e2eeOptions.encryptionType.toPBType() ?? .none,
populatorFunc)

// Request a new track to the server
let addTrackResult = try await room.engine.signalClient.sendAddTrack(cid: track.mediaTrack.trackId,
name: track.name,
type: track.kind.toPBType(),
source: track.source.toPBType(),
encryption: room.e2eeManager?.e2eeOptions.encryptionType.toPBType() ?? .none,
populatorFunc)

log("[Publish] server responded trackInfo: \(addTrackResult.trackInfo)")

// Add transceiver to pc
let transceiver = try publisher.addTransceiver(with: track.mediaTrack, transceiverInit: addTrackResult.result)
log("[Publish] Added transceiver: \(addTrackResult.trackInfo)...")

try await track.onPublish()

// Store publishOptions used for this track...
track._publishOptions = publishOptions

// Attach sender to track...
track.set(transport: publisher, rtpSender: transceiver.sender)

if track is LocalVideoTrack {
let publishOptions = (publishOptions as? VideoPublishOptions) ?? room._state.options.defaultVideoPublishOptions
// if screen share or simulcast is enabled,
// degrade resolution by using server's layer switching logic instead of WebRTC's logic
if track.source == .screenShareVideo || publishOptions.simulcast {
log("[publish] set degradationPreference to .maintainResolution")
let params = transceiver.sender.parameters
params.degradationPreference = NSNumber(value: RTCDegradationPreference.maintainResolution.rawValue)
// changing params directly doesn't work so we need to update params
// and set it back to sender.parameters
transceiver.sender.parameters = params
}
}
log("[Publish] server responded trackInfo: \(addTrackResult.trackInfo)")

// Add transceiver to pc
let transceiver = try publisher.addTransceiver(with: track.mediaTrack, transceiverInit: addTrackResult.result)
log("[Publish] Added transceiver: \(addTrackResult.trackInfo)...")

try await room.engine.publisherShouldNegotiate()
do {
try await track.onPublish()

// Store publishOptions used for this track...
track._publishOptions = publishOptions

// Attach sender to track...
track.set(transport: publisher, rtpSender: transceiver.sender)

if track is LocalVideoTrack {
let publishOptions = (publishOptions as? VideoPublishOptions) ?? room._state.options.defaultVideoPublishOptions
// if screen share or simulcast is enabled,
// degrade resolution by using server's layer switching logic instead of WebRTC's logic
if track.source == .screenShareVideo || publishOptions.simulcast {
log("[publish] set degradationPreference to .maintainResolution")
let params = transceiver.sender.parameters
params.degradationPreference = NSNumber(value: RTCDegradationPreference.maintainResolution.rawValue)
// changing params directly doesn't work so we need to update params
// and set it back to sender.parameters
transceiver.sender.parameters = params
}
}

let publication = LocalTrackPublication(info: addTrackResult.trackInfo, track: track, participant: self)
try await room.engine.publisherShouldNegotiate()
try Task.checkCancellation()

addTrack(publication: publication)
} catch {
// Rollback
track.set(transport: nil, rtpSender: nil)
try publisher.remove(track: transceiver.sender)
// Rethrow
throw error
}

// Notify didPublish
delegates.notify(label: { "localParticipant.didPublish \(publication)" }) {
$0.localParticipant?(self, didPublish: publication)
}
room.delegates.notify(label: { "localParticipant.didPublish \(publication)" }) {
$0.room?(self.room, localParticipant: self, didPublish: publication)
}
let publication = LocalTrackPublication(info: addTrackResult.trackInfo, track: track, participant: self)

add(publication: publication)

log("[publish] success \(publication)", .info)
// Notify didPublish
delegates.notify(label: { "localParticipant.didPublish \(publication)" }) {
$0.localParticipant?(self, didPublish: publication)
}
room.delegates.notify(label: { "localParticipant.didPublish \(publication)" }) {
$0.room?(self.room, localParticipant: self, didPublish: publication)
}

return publication
log("[publish] success \(publication)", .info)

// }.catch(on: queue) { error in
//
// self.log("[publish] failed \(track), error: \(error)", .error)
//
// // stop the track
// track.stop().catch(on: self.queue) { error in
// self.log("[publish] failed to stop track, error: \(error)", .error)
// }
// }
return publication
} catch {
log("[publish] failed \(track), error: \(error)", .error)
// Stop track when publish fails
try await track.stop()
// Rethrow
throw error
}
}

/// publish a new audio track to the Room
Expand Down
2 changes: 1 addition & 1 deletion Sources/LiveKit/Participant/Participant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ public class Participant: NSObject, ObservableObject, Loggable {
fatalError("Unimplemented")
}

func addTrack(publication: TrackPublication) {
func add(publication: TrackPublication) {
_state.mutate { $0.tracks[publication.sid] = publication }
publication.track?._state.mutate { $0.sid = publication.sid }
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/LiveKit/Participant/RemoteParticipant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public class RemoteParticipant: Participant {
if publication == nil {
publication = RemoteTrackPublication(info: trackInfo, participant: self)
newTrackPublications[trackInfo.sid] = publication
addTrack(publication: publication!)
add(publication: publication!)
} else {
publication!.updateFromInfo(info: trackInfo)
}
Expand Down Expand Up @@ -117,7 +117,7 @@ public class RemoteParticipant: Participant {
track.set(transport: transport, rtpReceiver: rtpReceiver)
}

addTrack(publication: publication)
add(publication: publication)

try await track.start()

Expand Down
4 changes: 2 additions & 2 deletions Sources/LiveKit/Track/Track.swift
Original file line number Diff line number Diff line change
Expand Up @@ -182,13 +182,13 @@ public class Track: NSObject, Loggable {
log("sid: \(String(describing: sid))")
}

func set(transport: Transport, rtpSender: LKRTCRtpSender) {
func set(transport: Transport?, rtpSender: LKRTCRtpSender?) {
self.transport = transport
self.rtpSender = rtpSender
resumeOrSuspendStatisticsTimer()
}

func set(transport: Transport, rtpReceiver: LKRTCRtpReceiver) {
func set(transport: Transport?, rtpReceiver: LKRTCRtpReceiver?) {
self.transport = transport
self.rtpReceiver = rtpReceiver
resumeOrSuspendStatisticsTimer()
Expand Down

0 comments on commit 2d44fcd

Please sign in to comment.