TrackPublication represents a track that has been published to a room. It contains metadata about the track and provides access to the underlying media track.
Overview
There are two types of track publications:
LocalTrackPublication - for tracks published by the local participant
RemoteTrackPublication - for tracks published by remote participants
Both extend the base TrackPublication class and are accessed through participant objects.
Properties
Server-assigned unique identifier for the track
Type of track (.audio or .video)
Source of the track (.camera, .microphone, .screenShareVideo, .screenShareAudio, .unknown)
The underlying media track (available when subscribed)
Whether the track is currently muted
Current streaming state (.active, .paused, .unknown)
Video dimensions (width and height) for video tracks
Whether the track uses simulcast (multiple quality layers)
MIME type of the track (e.g., “audio/opus”, “video/vp8”)
Whether the track is currently subscribed (always true for local tracks)
Type of encryption applied to the track (.none, .gcm, .custom)
LocalTrackPublication
LocalTrackPublication represents tracks published by the local participant.
Properties
Always returns .active for local tracks
Methods
mute()
Mutes the local track.
Throws: Error if muting fails
if let publication = room.localParticipant.getTrackPublication(source: .camera) as? LocalTrackPublication {
try await publication.mute()
}
unmute()
Unmutes the local track.
Throws: Error if unmuting fails
if let publication = room.localParticipant.getTrackPublication(source: .microphone) as? LocalTrackPublication {
try await publication.unmute()
}
Usage Example
// Publish a camera track
let videoTrack = LocalVideoTrack.createCameraTrack()
let publication = try await room.localParticipant.publish(videoTrack: videoTrack)
print("Published track: \(publication.name)")
print("Track SID: \(publication.sid)")
print("Is muted: \(publication.isMuted)")
// Mute the track later
try await publication.mute()
RemoteTrackPublication
RemoteTrackPublication represents tracks published by remote participants.
Properties
Whether subscription to this track is permitted by the publisher
Whether the track is enabled on the server (affects bandwidth)
Current subscription state (.subscribed, .unsubscribed, .notAllowed)
Methods
set(subscribed:)
Subscribe or unsubscribe from a remote track.
true to subscribe, false to unsubscribe
Throws: Error if subscription change fails
if let publication = participant.getTrackPublication(source: .camera) as? RemoteTrackPublication {
try await publication.set(subscribed: true)
}
set(enabled:)
Enable or disable the track on the server to save bandwidth.
true to enable, false to disable
Throws: Error if operation fails
Useful when a participant is off-screen and you want to reduce bandwidth usage.
// Disable video when participant is off-screen
if let videoPublication = participant.getTrackPublication(source: .camera) as? RemoteTrackPublication {
try await videoPublication.set(enabled: false)
}
set(preferredFPS:)
Set the preferred frame rate for a video track.
Desired frames per second
Throws: Error if operation fails
if let videoPublication = participant.getTrackPublication(source: .camera) as? RemoteTrackPublication {
try await videoPublication.set(preferredFPS: 15)
}
set(preferredDimensions:)
Set the preferred video dimensions.
Throws: Error if operation fails
The server will select the appropriate simulcast layer based on this value.
if let videoPublication = participant.getTrackPublication(source: .camera) as? RemoteTrackPublication {
let dimensions = Dimensions(width: 640, height: 480)
try await videoPublication.set(preferredDimensions: dimensions)
}
set(videoQuality:)
Set the maximum video quality for simulcast tracks.
Desired quality (.low, .medium, .high)
Throws: Error if operation fails
if let videoPublication = participant.getTrackPublication(source: .camera) as? RemoteTrackPublication {
try await videoPublication.set(videoQuality: .high)
}
Usage Example
func room(_ room: Room, participant: RemoteParticipant, didPublishTrack publication: RemoteTrackPublication) {
print("Track published: \(publication.name)")
print("Kind: \(publication.kind)")
print("Source: \(publication.source)")
print("Dimensions: \(publication.dimensions?.description ?? "none")")
// Subscribe to video tracks
if publication.kind == .video {
Task {
try await publication.set(subscribed: true)
}
}
}
func room(_ room: Room, participant: RemoteParticipant, didSubscribeTrack publication: RemoteTrackPublication) {
if let videoTrack = publication.track as? VideoTrack {
DispatchQueue.main.async {
self.videoView.track = videoTrack
}
}
}
Adaptive Stream
The SDK supports adaptive streaming, which automatically adjusts video quality based on the view size:
// Enable adaptive streaming in RoomOptions
let roomOptions = RoomOptions(
adaptiveStream: true
)
let room = Room(roomOptions: roomOptions)
When adaptive streaming is enabled:
- Video tracks are automatically enabled/disabled based on whether they’re visible
- Video quality is adjusted based on the view size
- Bandwidth is optimized automatically
Delegate Events
Track publication events are delivered through RoomDelegate and ParticipantDelegate:
extension MyClass: RoomDelegate {
func room(_ room: Room, participant: Participant, trackPublication: TrackPublication, didUpdateIsMuted isMuted: Bool) {
print("Track \(trackPublication.name) muted: \(isMuted)")
}
func room(_ room: Room, participant: RemoteParticipant, trackPublication: RemoteTrackPublication, didUpdateStreamState streamState: StreamState) {
print("Stream state: \(streamState)")
}
func room(_ room: Room, participant: RemoteParticipant, trackPublication: RemoteTrackPublication, didUpdateIsSubscriptionAllowed isAllowed: Bool) {
print("Subscription allowed: \(isAllowed)")
}
}
Common Patterns
Finding Specific Tracks
// Find camera track
if let cameraPublication = participant.getTrackPublication(source: .camera) {
print("Camera track found: \(cameraPublication.name)")
}
// Find all video tracks
for publication in participant.videoTracks {
print("Video track: \(publication.name), source: \(publication.source)")
}
// Find by track SID
if let publication = participant.trackPublications[trackSid] {
print("Found publication: \(publication.name)")
}
Managing Bandwidth
// Disable tracks for off-screen participants
func participantWentOffScreen(_ participant: RemoteParticipant) {
for publication in participant.videoTracks {
if let remotePublication = publication as? RemoteTrackPublication {
Task {
try await remotePublication.set(enabled: false)
}
}
}
}
// Re-enable when participant comes back on screen
func participantCameOnScreen(_ participant: RemoteParticipant) {
for publication in participant.videoTracks {
if let remotePublication = publication as? RemoteTrackPublication {
Task {
try await remotePublication.set(enabled: true)
}
}
}
}
See Also