Исправление Race при renegotiation

This commit is contained in:
set
2026-03-17 19:17:02 +02:00
parent 96df1e52f9
commit 6dadec6b64
6 changed files with 109 additions and 78 deletions

View File

@@ -90,6 +90,7 @@ func BindPeerLifecycle(roomID, peerID string, pc *webrtc.PeerConnection) {
mu sync.Mutex
disconnecting bool
timer *time.Timer
leaveOnce sync.Once
)
room, exists := GetRoom(roomID)
@@ -99,6 +100,26 @@ func BindPeerLifecycle(roomID, peerID string, pc *webrtc.PeerConnection) {
}
server := room.Server
cancelTimer := func() {
mu.Lock()
defer mu.Unlock()
if timer != nil {
timer.Stop()
timer = nil
}
disconnecting = false
}
leaveAndNotify := func(reason DisconnectReason) {
leaveOnce.Do(func() {
cancelTimer()
err := LeaveRoom(roomID, peerID)
if OnPeerDisconnected != nil && err == nil {
OnPeerDisconnected(roomID, peerID, server, reason)
}
})
}
startTimer := func() {
mu.Lock()
defer mu.Unlock()
@@ -114,35 +135,20 @@ func BindPeerLifecycle(roomID, peerID string, pc *webrtc.PeerConnection) {
mu.Unlock()
return
}
_ = LeaveRoom(roomID, peerID)
if OnPeerDisconnected != nil {
OnPeerDisconnected(roomID, peerID, server)
}
leaveAndNotify(DisconnectReasonFailed)
})
}
cancelTimer := func() {
mu.Lock()
defer mu.Unlock()
if timer != nil {
timer.Stop()
timer = nil
}
disconnecting = false
}
pc.OnICEConnectionStateChange(func(state webrtc.ICEConnectionState) {
switch state {
case webrtc.ICEConnectionStateConnected, webrtc.ICEConnectionStateCompleted:
cancelTimer()
case webrtc.ICEConnectionStateDisconnected:
startTimer()
case webrtc.ICEConnectionStateFailed, webrtc.ICEConnectionStateClosed:
cancelTimer()
_ = LeaveRoom(roomID, peerID)
if OnPeerDisconnected != nil {
OnPeerDisconnected(roomID, peerID, server)
}
case webrtc.ICEConnectionStateClosed:
leaveAndNotify(DisconnectReasonClosed)
case webrtc.ICEConnectionStateFailed:
leaveAndNotify(DisconnectReasonFailed)
}
})
@@ -152,16 +158,15 @@ func BindPeerLifecycle(roomID, peerID string, pc *webrtc.PeerConnection) {
cancelTimer()
case webrtc.PeerConnectionStateDisconnected:
startTimer()
case webrtc.PeerConnectionStateFailed, webrtc.PeerConnectionStateClosed:
cancelTimer()
_ = LeaveRoom(roomID, peerID)
if OnPeerDisconnected != nil {
OnPeerDisconnected(roomID, peerID, server)
}
case webrtc.PeerConnectionStateClosed:
leaveAndNotify(DisconnectReasonClosed)
case webrtc.PeerConnectionStateFailed:
leaveAndNotify(DisconnectReasonFailed)
}
})
}
// Вызывается при JoinWithOffer для ретрансляции RTP пакетов от издателя к другим участникам комнаты
// Вызывается при JoinWithOffer для ретрансляции RTP пакетов от издателя к другим участникам комнаты
func SetupForwardingForPeer(roomID string, publisherPeerID string, publisherPC *webrtc.PeerConnection) {
publisherPC.OnTrack(func(remote *webrtc.TrackRemote, _ *webrtc.RTPReceiver) {
@@ -178,7 +183,7 @@ func SetupForwardingForPeer(roomID string, publisherPeerID string, publisherPC *
remote.StreamID(),
)
if err != nil {
logger.LogErrorMessage("SetupForwardingForPeer: NewTrackLocalStaticRTP error")
logger.LogErrorMessage("SetupForwardingForPeer: NewTrackLocalStaticRTP error: " + err.Error())
return
}
defer removeRoomTrack(roomID, localTrack.ID())
@@ -203,32 +208,35 @@ func SetupForwardingForPeer(roomID string, publisherPeerID string, publisherPC *
continue
}
// Не трогаем закрытые/failed соединения
if !isPeerConnectionAlive(sub.PeerConnection) {
fmt.Println("SetupForwardingForPeer: skipping dead peer:", sub.PeerID,
sub.PeerConnection.ConnectionState().String())
continue
}
sender, err := sub.PeerConnection.AddTrack(localTrack)
if err != nil {
fmt.Println("SetupForwardingForPeer: AddTrack error:", roomID, sub.PeerID, err)
logger.LogWarnMessage("SetupForwardingForPeer: AddTrack error: " + sub.PeerID + " " + err.Error())
continue
}
// RTCP drain
senderCopy := sender
go func() {
buf := make([]byte, 1500)
for {
if _, _, e := sender.Read(buf); e != nil {
if _, _, e := senderCopy.Read(buf); e != nil {
return
}
}
}()
if err = renegotiatePeer(roomID, sub.PeerID, sub.PeerConnection); err != nil {
fmt.Println("SetupForwardingForPeer: renegotiatePeer error:", roomID, sub.PeerID, err)
}
subID := sub.PeerID
subPC := sub.PeerConnection
go func() {
logger.LogInfoMessage("SetupForwardingForPeer: starting renegotiation for peer=" + subID)
if err := renegotiatePeer(roomID, subID, subPC); err != nil {
logger.LogWarnMessage("SetupForwardingForPeer: renegotiatePeer error: " + subID + " " + err.Error())
}
}()
}
// Для video просим keyframe
@@ -245,11 +253,11 @@ func SetupForwardingForPeer(roomID string, publisherPeerID string, publisherPC *
if err == io.EOF {
return
}
fmt.Println("SetupForwardingForPeer: ReadRTP error:", err)
logger.LogWarnMessage("SetupForwardingForPeer: ReadRTP error: " + err.Error())
return
}
if err = localTrack.WriteRTP(pkt); err != nil {
fmt.Println("SetupForwardingForPeer: WriteRTP error:", err)
logger.LogWarnMessage("SetupForwardingForPeer: WriteRTP error: " + err.Error())
return
}
}