Skip to content
Open
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
17 changes: 13 additions & 4 deletions localparticipant.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,14 +164,16 @@ func (p *LocalParticipant) prepareTrackPublication(track webrtc.TrackLocal, opts
if primaryCodec.MimeType != "" && (kind == TrackKindVideo || withBackupCodec) {
req.SimulcastCodecs = []*livekit.SimulcastCodec{
{
Codec: primaryCodec.MimeType,
Cid: track.ID(),
Codec: primaryCodec.MimeType,
Cid: track.ID(),
VideoLayerMode: sampleTrackLayerMode(kind, track),
},
}
if withBackupCodec {
req.SimulcastCodecs = append(req.SimulcastCodecs, &livekit.SimulcastCodec{
Codec: pubOptions.backupCodecTrack.Codec().MimeType,
Cid: pubOptions.backupCodecTrack.ID(),
Codec: pubOptions.backupCodecTrack.Codec().MimeType,
Cid: pubOptions.backupCodecTrack.ID(),
VideoLayerMode: sampleTrackLayerMode(kind, pubOptions.backupCodecTrack),
})
pub.setBackupCodecTrack(pubOptions.backupCodecTrack)
}
Expand All @@ -181,6 +183,13 @@ func (p *LocalParticipant) prepareTrackPublication(track webrtc.TrackLocal, opts
return pub, req, nil
}

func sampleTrackLayerMode(kind TrackKind, track webrtc.TrackLocal) livekit.VideoLayer_Mode {
if _, ok := track.(*LocalTrack); ok && kind == TrackKindVideo {
return livekit.VideoLayer_ONE_SPATIAL_LAYER_PER_STREAM
}
return livekit.VideoLayer_MODE_UNUSED
Comment on lines +187 to +190

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Single-layer external tracks declared as SVC

For a single-layer VP9 or AV1 TrackLocalStaticSample, sampleTrackLayerMode returns MODE_UNUSED because it is not *LocalTrack. The server infers multiple spatial layers, mislabeling the primary or backup video stream as SVC.

Learn more

PublishTrack accepts any webrtc.TrackLocal, and prepareTrackPublication declares the codec for external tracks implementing TrackLocalWithCodec. The server infers multiple spatial layers for VP9 and AV1 when VideoLayerMode is unset. The concrete type test only recognizes SDK LocalTrack, so a single-layer Pion sample track gets an unset mode even though its samples contain only one spatial layer. The backup codec entry uses the same helper.

Example: Publish a VP9 webrtc.TrackLocalStaticSample with ordinary single-layer samples. Its codec is declared, but its video layer mode is unset; the server reports MULTIPLE_SPATIAL_LAYERS_PER_STREAM rather than ONE_SPATIAL_LAYER_PER_STREAM.

Recommended fix: Set ONE_SPATIAL_LAYER_PER_STREAM for known single-layer sample tracks beyond *LocalTrack, including Pion's static sample tracks. Preserve an explicit route for external tracks that genuinely carry SVC if that behavior is required.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

}

func (p *LocalParticipant) notifyTrackPublished(pub *LocalTrackPublication) {
p.Callback.OnLocalTrackPublished(pub, p)
p.roomCallback.OnLocalTrackPublished(pub, p)
Expand Down
Loading