diff --git a/pkg/media/webrtc_playback2.go b/pkg/media/webrtc_playback2.go index 1bbc1b71..b17a217e 100644 --- a/pkg/media/webrtc_playback2.go +++ b/pkg/media/webrtc_playback2.go @@ -3,6 +3,7 @@ package media import ( "context" "fmt" + "sync" "time" "github.com/google/uuid" @@ -83,9 +84,37 @@ func (mm *MediaManager) WebRTCPlayback2(ctx context.Context, user string, rendit // Setup complete! Now we boot up streaming in the background while returning the SDP offer to the user. + // The session only counts as a viewer once the peer connection actually + // establishes — counting at SDP-answer time inflated the count with + // handshakes that never connected (each lingering until ICE failure + // detection). The mutex pairs the increment with exactly one decrement + // even if a connect races session teardown. + var viewerMu sync.Mutex + viewerCounted := false + viewerDone := false + markConnected := func() { + viewerMu.Lock() + defer viewerMu.Unlock() + if viewerDone || viewerCounted { + return + } + viewerCounted = true + mm.IncrementViewerCount(user, "webrtc") + } + markDone := func() { + viewerMu.Lock() + defer viewerMu.Unlock() + viewerDone = true + if viewerCounted { + viewerCounted = false + mm.DecrementViewerCount(user, "webrtc") + } + } + go func() { ctx, cancel := context.WithCancel(ctx) defer cancel() + defer markDone() latency := time.Duration(0) @@ -194,9 +223,6 @@ func (mm *MediaManager) WebRTCPlayback2(ctx context.Context, user string, rendit } }() - mm.IncrementViewerCount(user, "webrtc") - defer mm.DecrementViewerCount(user, "webrtc") - if !audioOnly { go func() { rtcpBuf := make([]byte, 1500) @@ -228,6 +254,10 @@ func (mm *MediaManager) WebRTCPlayback2(ctx context.Context, user string, rendit peerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { log.Log(ctx, "Peer Connection State has changed", "state", s.String()) + if s == webrtc.PeerConnectionStateConnected { + markConnected() + } + if s == webrtc.PeerConnectionStateFailed || s == webrtc.PeerConnectionStateClosed || s == webrtc.PeerConnectionStateDisconnected { // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. diff --git a/pkg/spmetrics/spmetrics.go b/pkg/spmetrics/spmetrics.go index 9c25f351..b62673ba 100644 --- a/pkg/spmetrics/spmetrics.go +++ b/pkg/spmetrics/spmetrics.go @@ -237,9 +237,9 @@ func ViewerDec(user string, protocol string) { } viewersByProtocol[protocol]-- if viewersByProtocol[protocol] == 0 { - Viewers.DeleteLabelValues(protocol) + ViewersTotal.DeleteLabelValues(protocol) } else { - Viewers.WithLabelValues(protocol).Set(float64(viewersByProtocol[protocol])) + ViewersTotal.WithLabelValues(protocol).Set(float64(viewersByProtocol[protocol])) } }() }