Новые события с пирами и комнатами, базовый форвардинг

This commit is contained in:
set
2026-03-16 17:08:56 +02:00
parent a9a1dc5895
commit e67bd3d824
5 changed files with 370 additions and 48 deletions

View File

@@ -16,6 +16,12 @@ type Peer struct {
PeerConnection *webrtc.PeerConnection
}
type RoomTrack struct {
TrackID string
OwnerPeer string
Local *webrtc.TrackLocalStaticRTP
}
type Room struct {
//Уникальный идентификатор комнаты
RoomID string
@@ -23,6 +29,10 @@ type Room struct {
Server *connection.Connection
//Пиры которые подключились к комнате
Peers []Peer
Tracks []RoomTrack
mu sync.RWMutex
}
// Общие переменные
@@ -54,13 +64,6 @@ func GetRoom(roomID string) (*Room, bool) {
return room, exists
}
// DeleteRoom удаляет комнату по идентификатору
func DeleteRoom(roomID string) {
roomsMu.Lock()
defer roomsMu.Unlock()
delete(rooms, roomID)
}
// JoinWithOffer позволяет пиру присоединиться к комнате с помощью SDP оффера
func JoinWithOffer(roomID string, peerID string, offer webrtc.SessionDescription) (*webrtc.SessionDescription, error) {
room, exists := GetRoom(roomID)
@@ -73,43 +76,96 @@ func JoinWithOffer(roomID string, peerID string, offer webrtc.SessionDescription
return nil, err
}
// SFU локальные ICE-кандидаты отправляем сначала бекенду затем тот их
// пересылает клиенту для установления соединения
peerConnection.OnICECandidate(func(c *webrtc.ICECandidate) {
if c == nil {
return // gathering finished
return
}
if OnLocalICECandidate != nil {
OnLocalICECandidate(roomID, peerID, c.ToJSON())
}
})
err = peerConnection.SetRemoteDescription(offer)
if err != nil {
BindPeerLifecycle(roomID, peerID, peerConnection)
SetupForwardingForPeer(roomID, peerID, peerConnection)
room.mu.RLock()
existingTracks := make([]RoomTrack, len(room.Tracks))
copy(existingTracks, room.Tracks)
room.mu.RUnlock()
for _, t := range existingTracks {
if t.OwnerPeer == peerID {
continue
}
sender, err := peerConnection.AddTrack(t.Local)
if err != nil {
continue
}
go func() {
buf := make([]byte, 1500)
for {
if _, _, e := sender.Read(buf); e != nil {
return
}
}
}()
}
if err = peerConnection.SetRemoteDescription(offer); err != nil {
_ = peerConnection.Close()
return nil, err
}
answer, err := peerConnection.CreateAnswer(nil)
if err != nil {
_ = peerConnection.Close()
return nil, err
}
err = peerConnection.SetLocalDescription(answer)
if err != nil {
gatherDone := webrtc.GatheringCompletePromise(peerConnection)
if err = peerConnection.SetLocalDescription(answer); err != nil {
_ = peerConnection.Close()
return nil, err
}
<-gatherDone
// Настраиваем пересылку RTP пакетов от издателя к другим участникам комнаты
SetupForwardingForPeer(roomID, peerID, peerConnection)
room.mu.Lock()
room.Peers = append(room.Peers, Peer{
PeerID: peerID,
PeerConnection: peerConnection,
})
room.mu.Unlock()
return peerConnection.LocalDescription(), nil
}
func DeleteRoom(roomID string) error {
roomsMu.Lock()
room, exists := rooms[roomID]
if !exists {
roomsMu.Unlock()
return ErrRoomNotFound
}
delete(rooms, roomID)
roomsMu.Unlock()
room.mu.Lock()
peers := make([]Peer, len(room.Peers))
copy(peers, room.Peers)
room.Peers = nil
room.Tracks = nil
room.mu.Unlock()
for _, p := range peers {
_ = p.PeerConnection.Close()
cleanupForwardingState(roomID, p.PeerID)
}
return nil
}
// LeaveRoom позволяет пиру покинуть комнату
func LeaveRoom(roomID string, peerID string) error {
room, exists := GetRoom(roomID)
@@ -117,12 +173,59 @@ func LeaveRoom(roomID string, peerID string) error {
return ErrRoomNotFound
}
for i, peer := range room.Peers {
if peer.PeerID == peerID {
peer.PeerConnection.Close()
room.Peers = append(room.Peers[:i], room.Peers[i+1:]...)
break
var (
removedPC *webrtc.PeerConnection
removed bool
shouldDrop bool
)
room.mu.Lock()
// удаляем peer
nextPeers := make([]Peer, 0, len(room.Peers))
for _, p := range room.Peers {
if p.PeerID == peerID {
removedPC = p.PeerConnection
removed = true
continue
}
nextPeers = append(nextPeers, p)
}
room.Peers = nextPeers
// удаляем треки этого publisher
nextTracks := room.Tracks[:0]
for _, t := range room.Tracks {
if t.OwnerPeer != peerID {
nextTracks = append(nextTracks, t)
}
}
room.Tracks = nextTracks
shouldDrop = len(room.Peers) == 0
room.mu.Unlock()
if !removed {
return ErrPeerNotFound
}
if removedPC != nil {
_ = removedPC.Close()
}
cleanupForwardingState(roomID, peerID)
// Комната пустая -> удаляем
if shouldDrop {
return DeleteRoom(roomID)
}
// Опционально: renegotiation оставшимся peer после удаления треков/peer
room.mu.RLock()
rest := make([]Peer, len(room.Peers))
copy(rest, room.Peers)
room.mu.RUnlock()
for _, p := range rest {
_ = renegotiatePeer(roomID, p.PeerID, p.PeerConnection)
}
return nil