ionorg / ion-sfu

Pure Go WebRTC SFU

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Simulcast issue

Rollooo opened this issue · comments

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)
}