Новые события с пирами и комнатами, базовый форвардинг
This commit is contained in:
147
sfu/rooms.go
147
sfu/rooms.go
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user