Исправлена гонка записи в сокет
This commit is contained in:
@@ -3,10 +3,31 @@ package sfu
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/pion/webrtc/v4"
|
||||
)
|
||||
|
||||
var (
|
||||
pendingMu sync.Mutex
|
||||
pendingCandidates = map[string][]webrtc.ICECandidateInit{} // key: roomID|peerID
|
||||
)
|
||||
|
||||
func peerKey(roomID, peerID string) string {
|
||||
return roomID + "|" + peerID
|
||||
}
|
||||
|
||||
func extractICEUfrag(sdp string) string {
|
||||
for _, line := range strings.Split(sdp, "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
if strings.HasPrefix(line, "a=ice-ufrag:") {
|
||||
return strings.TrimPrefix(line, "a=ice-ufrag:")
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Вызывается при JoinWithOffer для ретрансляции RTP пакетов от издателя к другим участникам комнаты
|
||||
func SetupForwardingForPeer(roomID string, publisherPeerID string, publisherPC *webrtc.PeerConnection) {
|
||||
publisherPC.OnTrack(func(remote *webrtc.TrackRemote, _ *webrtc.RTPReceiver) {
|
||||
@@ -95,21 +116,47 @@ func AddICECandidate(roomID string, peerID string, candidate webrtc.ICECandidate
|
||||
return ErrRoomNotFound
|
||||
}
|
||||
|
||||
for _, peer := range room.Peers {
|
||||
if peer.PeerID == peerID {
|
||||
return peer.PeerConnection.AddICECandidate(candidate)
|
||||
var pc *webrtc.PeerConnection
|
||||
for _, p := range room.Peers {
|
||||
if p.PeerID == peerID {
|
||||
pc = p.PeerConnection
|
||||
break
|
||||
}
|
||||
}
|
||||
if pc == nil {
|
||||
return ErrPeerNotFound
|
||||
}
|
||||
|
||||
rd := pc.RemoteDescription()
|
||||
if rd == nil {
|
||||
// answer/offer еще не применен — буферизуем
|
||||
pendingMu.Lock()
|
||||
k := peerKey(roomID, peerID)
|
||||
pendingCandidates[k] = append(pendingCandidates[k], candidate)
|
||||
pendingMu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// отбрасываем stale candidate по ufrag
|
||||
if candidate.UsernameFragment != nil {
|
||||
current := extractICEUfrag(rd.SDP)
|
||||
if current != "" && *candidate.UsernameFragment != current {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return ErrPeerNotFound
|
||||
err := pc.AddICECandidate(candidate)
|
||||
if err != nil && strings.Contains(err.Error(), "doesn't match the current ufrags") {
|
||||
// поздний старый кандидат — игнорируем
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Обрабатывает SDP ответ от клиента при renegotiation
|
||||
func HandleClientAnswer(roomID string, peerID string, answer webrtc.SessionDescription) error {
|
||||
roomsMu.RLock()
|
||||
room, ok := rooms[roomID]
|
||||
if !ok {
|
||||
roomsMu.RUnlock()
|
||||
room, exists := GetRoom(roomID)
|
||||
if !exists {
|
||||
return ErrRoomNotFound
|
||||
}
|
||||
|
||||
@@ -120,10 +167,24 @@ func HandleClientAnswer(roomID string, peerID string, answer webrtc.SessionDescr
|
||||
break
|
||||
}
|
||||
}
|
||||
roomsMu.RUnlock()
|
||||
|
||||
if pc == nil {
|
||||
return ErrPeerNotFound
|
||||
}
|
||||
return pc.SetRemoteDescription(answer)
|
||||
|
||||
if err := pc.SetRemoteDescription(answer); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// после применения answer — применяем отложенные кандидаты
|
||||
k := peerKey(roomID, peerID)
|
||||
pendingMu.Lock()
|
||||
queue := pendingCandidates[k]
|
||||
delete(pendingCandidates, k)
|
||||
pendingMu.Unlock()
|
||||
|
||||
for _, c := range queue {
|
||||
_ = AddICECandidate(roomID, peerID, c)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user