Simulcast issue
Rollooo opened this issue · comments
Seungho Jung commented
Your environment.
- Version: Latest
- Client: echotest
- Environement: OSX
- Are you using a TURN server? No
- Other Information - stacktraces, webrtc dumps, related issues, suggestions how to fix, links for us to have context
What did you do?
Change spatial layer using SubscriberAPI
What did you expect?
Change resolution and framerate of video that I want to change.(only one video)
What happened?
Multiple down tracks those have same track id were removed in receiver.
And then stopped other participant's remote video.
Reason
It try to delete downtrack by id. So it can remove multiple tracks in receiver.
func (w *WebRTCReceiver) writeRTP(layer int) {
// ...
if w.isSimulcast {
if w.pending[layer].get() {
if pkt.KeyFrame {
w.Lock()
for idx, dt := range w.pendingTracks[layer] {
w.deleteDownTrack(dt.CurrentSpatialLayer(), dt.id)
w.storeDownTrack(layer, dt)
dt.SwitchSpatialLayerDone(int32(layer))
w.pendingTracks[layer][idx] = nil
}
w.pendingTracks[layer] = w.pendingTracks[layer][:0]
w.pending[layer].set(false)
w.Unlock()
} else {
w.SendRTCP(pli)
}
}
}
// ...
}
// ...
func (w *WebRTCReceiver) deleteDownTrack(layer int, id string) {
dts := w.downTracks[layer].Load().([]*DownTrack)
ndts := make([]*DownTrack, 0, len(dts))
for _, dt := range dts {
if dt.id != id {
ndts = append(ndts, dt)
}
}
w.downTracks[layer].Store(ndts)
}
(https://github.com/pion/ion-sfu/blob/802a11b66a21e7e8dd369f25c4c4a8b24b38253d/pkg/sfu/receiver.go#L333)
(https://github.com/pion/ion-sfu/blob/802a11b66a21e7e8dd369f25c4c4a8b24b38253d/pkg/sfu/receiver.go#L252)
So I think when client try to change layer of specific down track, it should delete down track by track like as below
func (w *WebRTCReceiver) writeRTP(layer int) {
// ...
if w.isSimulcast {
if w.pending[layer].get() {
if pkt.KeyFrame {
w.Lock()
for idx, dt := range w.pendingTracks[layer] {
w.deleteDownTrack(dt.CurrentSpatialLayer(), track) // <-- Change this
w.storeDownTrack(layer, dt)
dt.SwitchSpatialLayerDone(int32(layer))
w.pendingTracks[layer][idx] = nil
}
w.pendingTracks[layer] = w.pendingTracks[layer][:0]
w.pending[layer].set(false)
w.Unlock()
} else {
w.SendRTCP(pli)
}
}
}
for _, dt := range w.downTracks[layer].Load().([]*DownTrack) {
if err = dt.WriteRTP(pkt, layer); err != nil {
if err == io.EOF && err == io.ErrClosedPipe {
w.Lock()
w.deleteDownTrack(layer, dt) // <-- Change this
w.Unlock()
}
log.Error().Err(err).Str("id", dt.id).Msg("Error writing to down track")
}
}
// ...
}
// ...
func (w *WebRTCReceiver) deleteDownTrack(layer int, track *DownTrack) {
dts := w.downTracks[layer].Load().([]*DownTrack)
ndts := make([]*DownTrack, 0, len(dts))
for _, dt := range dts {
if dt != track {
ndts = append(ndts, dt)
}
}
w.downTracks[layer].Store(ndts)
}