2023-07-26 21:15:39 +00:00
|
|
|
package repositories
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
2023-08-04 09:46:27 +00:00
|
|
|
"errors"
|
2023-07-26 21:15:39 +00:00
|
|
|
"fmt"
|
2023-09-19 18:09:09 +00:00
|
|
|
"github.com/pion/interceptor"
|
2023-07-26 21:15:39 +00:00
|
|
|
"github.com/pion/rtcp"
|
|
|
|
"github.com/pion/webrtc/v3"
|
2023-09-19 18:09:09 +00:00
|
|
|
"net"
|
2023-07-26 21:15:39 +00:00
|
|
|
"net/http"
|
2023-07-31 12:27:40 +00:00
|
|
|
"sourcecode.social/greatape/goldgorilla/models"
|
|
|
|
"sourcecode.social/greatape/goldgorilla/models/dto"
|
2023-07-26 21:15:39 +00:00
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Track struct {
|
|
|
|
OwnerId uint64
|
|
|
|
TrackLocal *webrtc.TrackLocalStaticRTP
|
|
|
|
}
|
|
|
|
|
|
|
|
type Peer struct {
|
2023-09-13 10:11:30 +00:00
|
|
|
ID uint64
|
|
|
|
Conn *webrtc.PeerConnection
|
|
|
|
CanPublish bool
|
|
|
|
IsCaller bool
|
|
|
|
HandshakeLock *sync.Mutex
|
|
|
|
gotFirstVideoTrack bool
|
|
|
|
gotFirstAudioTrack bool
|
|
|
|
triggeredReconnectOnce bool
|
2023-07-26 21:15:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Room struct {
|
|
|
|
*sync.Mutex
|
|
|
|
Peers map[uint64]*Peer
|
|
|
|
trackLock *sync.Mutex
|
|
|
|
Tracks map[string]*Track
|
2023-07-31 20:10:39 +00:00
|
|
|
timer *time.Ticker
|
2023-11-02 11:42:30 +00:00
|
|
|
ggId uint64
|
2023-07-26 21:15:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type RoomRepository struct {
|
2023-09-19 18:09:09 +00:00
|
|
|
api *webrtc.API
|
2023-07-26 21:15:39 +00:00
|
|
|
Rooms map[string]*Room
|
|
|
|
conf *models.ConfigModel
|
|
|
|
*sync.Mutex
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewRoomRepository(conf *models.ConfigModel) *RoomRepository {
|
2023-09-19 18:09:09 +00:00
|
|
|
settingEngine := webrtc.SettingEngine{}
|
2023-09-21 14:37:05 +00:00
|
|
|
if len(conf.CustomICEHostCandidateIP) > 0 {
|
|
|
|
settingEngine.SetNAT1To1IPs([]string{conf.CustomICEHostCandidateIP}, webrtc.ICECandidateTypeHost)
|
|
|
|
}
|
2023-09-19 18:09:09 +00:00
|
|
|
settingEngine.SetNetworkTypes([]webrtc.NetworkType{
|
|
|
|
webrtc.NetworkTypeTCP6,
|
|
|
|
webrtc.NetworkTypeUDP6,
|
|
|
|
webrtc.NetworkTypeTCP4,
|
|
|
|
webrtc.NetworkTypeUDP4,
|
|
|
|
})
|
|
|
|
tcpListener, err := net.ListenTCP("tcp", &net.TCPAddr{
|
|
|
|
IP: net.IP{0, 0, 0, 0},
|
|
|
|
Port: int(conf.ICETCPMUXListenPort),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
fmt.Printf("Listening for ICE TCP at %s\n", tcpListener.Addr())
|
|
|
|
|
|
|
|
tcpMux := webrtc.NewICETCPMux(nil, tcpListener, 64)
|
|
|
|
settingEngine.SetICETCPMux(tcpMux)
|
|
|
|
|
|
|
|
m := &webrtc.MediaEngine{}
|
|
|
|
if err := m.RegisterDefaultCodecs(); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
i := &interceptor.Registry{}
|
|
|
|
if err := webrtc.RegisterDefaultInterceptors(m, i); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
api := webrtc.NewAPI(webrtc.WithMediaEngine(m), webrtc.WithInterceptorRegistry(i), webrtc.WithSettingEngine(settingEngine))
|
|
|
|
|
2023-07-26 21:15:39 +00:00
|
|
|
return &RoomRepository{
|
2023-09-19 18:09:09 +00:00
|
|
|
api: api,
|
2023-07-26 21:15:39 +00:00
|
|
|
Mutex: &sync.Mutex{},
|
|
|
|
Rooms: make(map[string]*Room),
|
|
|
|
conf: conf,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-31 13:19:15 +00:00
|
|
|
func (r *RoomRepository) DoesRoomExists(id string) bool {
|
|
|
|
r.Lock()
|
|
|
|
defer r.Unlock()
|
|
|
|
return r.doesRoomExists(id)
|
|
|
|
}
|
|
|
|
|
2023-07-26 21:15:39 +00:00
|
|
|
func (r *RoomRepository) doesRoomExists(id string) bool {
|
|
|
|
if _, exists := r.Rooms[id]; exists {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *RoomRepository) doesPeerExists(roomId string, id uint64) bool {
|
|
|
|
if !r.doesRoomExists(roomId) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if _, exists := r.Rooms[roomId].Peers[id]; exists {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2023-11-02 11:42:30 +00:00
|
|
|
func (r *RoomRepository) CreatePeer(roomId string, id uint64, canPublish bool, isCaller bool, ggid uint64) error {
|
2023-07-26 21:15:39 +00:00
|
|
|
r.Lock()
|
|
|
|
|
|
|
|
if !r.doesRoomExists(roomId) {
|
|
|
|
room := &Room{
|
|
|
|
Mutex: &sync.Mutex{},
|
|
|
|
Peers: make(map[uint64]*Peer),
|
|
|
|
trackLock: &sync.Mutex{},
|
|
|
|
Tracks: make(map[string]*Track),
|
2023-07-31 12:27:40 +00:00
|
|
|
timer: time.NewTicker(3 * time.Second),
|
2023-11-02 11:42:30 +00:00
|
|
|
ggId: ggid,
|
2023-07-26 21:15:39 +00:00
|
|
|
}
|
|
|
|
r.Rooms[roomId] = room
|
|
|
|
go func() {
|
2023-07-31 12:27:40 +00:00
|
|
|
for range room.timer.C {
|
2023-07-26 21:15:39 +00:00
|
|
|
room.Lock()
|
|
|
|
for _, peer := range room.Peers {
|
|
|
|
for _, receiver := range peer.Conn.GetReceivers() {
|
|
|
|
if receiver.Track() == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2023-08-04 14:43:48 +00:00
|
|
|
go func(peerConn *webrtc.PeerConnection, recv *webrtc.RTPReceiver) {
|
|
|
|
err := peerConn.WriteRTCP([]rtcp.Packet{
|
2023-08-04 09:46:27 +00:00
|
|
|
&rtcp.PictureLossIndication{
|
|
|
|
MediaSSRC: uint32(recv.Track().SSRC()),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
if err != nil {
|
2023-08-04 14:43:48 +00:00
|
|
|
println(`[E] [rtcp][PLI] `, err.Error())
|
2023-08-04 09:46:27 +00:00
|
|
|
}
|
2023-08-04 14:43:48 +00:00
|
|
|
}(peer.Conn, receiver)
|
2023-07-26 21:15:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
room.Unlock()
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
room := r.Rooms[roomId]
|
2023-08-04 09:46:27 +00:00
|
|
|
r.Unlock()
|
2023-07-26 21:15:39 +00:00
|
|
|
|
2023-09-19 18:09:09 +00:00
|
|
|
peerConn, err := r.api.NewPeerConnection(webrtc.Configuration{
|
2023-08-24 13:40:18 +00:00
|
|
|
ICEServers: r.conf.ICEServers,
|
|
|
|
})
|
2023-07-26 21:15:39 +00:00
|
|
|
if err != nil {
|
2023-07-31 12:27:40 +00:00
|
|
|
return models.NewError("can't create peer connection", 500, models.MessageResponse{Message: err.Error()})
|
2023-07-26 21:15:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
peerConn.OnICECandidate(func(ic *webrtc.ICECandidate) {
|
2023-11-02 11:42:30 +00:00
|
|
|
r.onPeerICECandidate(roomId, id, room.ggId, ic)
|
2023-07-26 21:15:39 +00:00
|
|
|
})
|
|
|
|
peerConn.OnConnectionStateChange(func(state webrtc.PeerConnectionState) {
|
2023-09-13 10:11:30 +00:00
|
|
|
r.Lock()
|
|
|
|
if !r.doesRoomExists(roomId) {
|
|
|
|
r.Unlock()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
room := r.Rooms[roomId]
|
|
|
|
r.Unlock()
|
|
|
|
room.Lock()
|
|
|
|
defer room.Unlock()
|
|
|
|
peer, stillThere := room.Peers[id]
|
|
|
|
|
|
|
|
r.onPeerConnectionStateChange(room, peer, state)
|
|
|
|
{
|
|
|
|
if state == webrtc.PeerConnectionStateClosed && isCaller {
|
|
|
|
if stillThere && peer.triggeredReconnectOnce {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
go r.onCallerDisconnected(roomId)
|
|
|
|
}
|
2023-09-01 12:47:28 +00:00
|
|
|
}
|
2023-07-26 21:15:39 +00:00
|
|
|
})
|
|
|
|
peerConn.OnTrack(func(remote *webrtc.TrackRemote, receiver *webrtc.RTPReceiver) {
|
|
|
|
r.onPeerTrack(roomId, id, remote, receiver)
|
|
|
|
})
|
2023-08-04 09:46:27 +00:00
|
|
|
/*peerConn.OnNegotiationNeeded(func() {
|
|
|
|
println("[PC] negotiating with peer", id)
|
|
|
|
r.offerPeer(peerConn,roomId,id)
|
|
|
|
})*/
|
2023-08-24 13:40:18 +00:00
|
|
|
room.Lock()
|
|
|
|
defer room.Unlock()
|
2023-07-26 21:15:39 +00:00
|
|
|
room.Peers[id] = &Peer{
|
2023-08-04 09:46:27 +00:00
|
|
|
ID: id,
|
|
|
|
Conn: peerConn,
|
|
|
|
HandshakeLock: &sync.Mutex{},
|
|
|
|
CanPublish: canPublish,
|
2023-08-04 14:43:48 +00:00
|
|
|
IsCaller: isCaller,
|
2023-07-26 21:15:39 +00:00
|
|
|
}
|
2023-07-31 12:27:40 +00:00
|
|
|
go r.updatePCTracks(roomId)
|
|
|
|
return nil
|
2023-07-26 21:15:39 +00:00
|
|
|
}
|
|
|
|
|
2023-09-01 12:47:28 +00:00
|
|
|
func (r *RoomRepository) onCallerDisconnected(roomId string) {
|
2023-11-02 11:42:30 +00:00
|
|
|
if _, err := r.ResetRoom(roomId); err != nil {
|
2023-09-01 12:47:28 +00:00
|
|
|
println(err.Error())
|
|
|
|
return
|
|
|
|
}
|
2023-11-02 11:42:30 +00:00
|
|
|
*r.conf.StartRejoinCH <- models.RejoinMode{
|
|
|
|
SimplyJoin: false,
|
|
|
|
RoomId: roomId,
|
|
|
|
}
|
2023-09-01 12:47:28 +00:00
|
|
|
}
|
|
|
|
|
2023-11-02 11:42:30 +00:00
|
|
|
func (r *RoomRepository) onPeerICECandidate(roomId string, id, ggid uint64, ic *webrtc.ICECandidate) {
|
2023-07-26 21:15:39 +00:00
|
|
|
if ic == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
reqModel := dto.AddPeerICECandidateReqModel{
|
|
|
|
PeerDTO: dto.PeerDTO{
|
|
|
|
RoomId: roomId,
|
|
|
|
ID: id,
|
|
|
|
},
|
2023-11-02 11:42:30 +00:00
|
|
|
GGID: ggid,
|
2023-07-26 21:15:39 +00:00
|
|
|
ICECandidate: ic.ToJSON(),
|
|
|
|
}
|
|
|
|
serializedReqBody, err := json.Marshal(reqModel)
|
|
|
|
if err != nil {
|
|
|
|
println(err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
resp, err := http.Post(r.conf.LogjamBaseUrl+"/ice", "application/json", bytes.NewReader(serializedReqBody))
|
|
|
|
if err != nil {
|
|
|
|
println(err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if resp.StatusCode > 204 {
|
|
|
|
println("POST /ice", resp.StatusCode)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-13 10:11:30 +00:00
|
|
|
func (r *RoomRepository) onPeerConnectionStateChange(room *Room, peer *Peer, newState webrtc.PeerConnectionState) {
|
|
|
|
if peer == nil {
|
2023-07-26 21:15:39 +00:00
|
|
|
return
|
|
|
|
}
|
2023-09-13 10:11:30 +00:00
|
|
|
println("[PC] con_stat", newState.String(), peer.ID)
|
2023-07-26 21:15:39 +00:00
|
|
|
switch newState {
|
2023-09-01 12:47:28 +00:00
|
|
|
case webrtc.PeerConnectionStateDisconnected:
|
|
|
|
fallthrough
|
2023-07-26 21:15:39 +00:00
|
|
|
case webrtc.PeerConnectionStateFailed:
|
2023-09-13 10:11:30 +00:00
|
|
|
if err := peer.Conn.Close(); err != nil {
|
2023-08-31 13:19:15 +00:00
|
|
|
println(err.Error())
|
2023-07-26 21:15:39 +00:00
|
|
|
}
|
|
|
|
case webrtc.PeerConnectionStateClosed:
|
2023-09-13 10:11:30 +00:00
|
|
|
delete(room.Peers, peer.ID)
|
2023-07-26 21:15:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *RoomRepository) onPeerTrack(roomId string, id uint64, remote *webrtc.TrackRemote, receiver *webrtc.RTPReceiver) {
|
|
|
|
fmt.Println("got a track!", remote.ID(), remote.StreamID(), remote.Kind().String())
|
|
|
|
r.Lock()
|
|
|
|
if !r.doesRoomExists(roomId) {
|
|
|
|
r.Unlock()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
room := r.Rooms[roomId]
|
|
|
|
r.Unlock()
|
|
|
|
|
|
|
|
trackLocal, err := webrtc.NewTrackLocalStaticRTP(remote.Codec().RTPCodecCapability, remote.ID(), remote.StreamID())
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
room.trackLock.Lock()
|
|
|
|
room.Tracks[remote.ID()] = &Track{
|
|
|
|
OwnerId: id,
|
|
|
|
TrackLocal: trackLocal,
|
|
|
|
}
|
|
|
|
room.trackLock.Unlock()
|
2023-09-13 10:11:30 +00:00
|
|
|
firstVideo := false
|
|
|
|
firstAudio := false
|
|
|
|
room.Lock()
|
|
|
|
peer := room.Peers[id]
|
|
|
|
room.Unlock()
|
|
|
|
if remote.Kind() == webrtc.RTPCodecTypeVideo && !peer.gotFirstVideoTrack {
|
|
|
|
peer.gotFirstVideoTrack = true
|
|
|
|
firstVideo = true
|
|
|
|
}
|
|
|
|
if remote.Kind() == webrtc.RTPCodecTypeAudio && !peer.gotFirstAudioTrack {
|
|
|
|
peer.gotFirstAudioTrack = true
|
|
|
|
firstAudio = true
|
|
|
|
}
|
2023-07-26 21:15:39 +00:00
|
|
|
|
2023-08-04 09:46:27 +00:00
|
|
|
defer func(trackId string) {
|
2023-07-26 21:15:39 +00:00
|
|
|
room.trackLock.Lock()
|
2023-08-04 09:46:27 +00:00
|
|
|
delete(room.Tracks, trackId)
|
2023-07-26 21:15:39 +00:00
|
|
|
room.trackLock.Unlock()
|
|
|
|
r.updatePCTracks(roomId)
|
2023-08-04 09:46:27 +00:00
|
|
|
}(remote.ID())
|
2023-07-26 21:15:39 +00:00
|
|
|
go r.updatePCTracks(roomId)
|
|
|
|
buffer := make([]byte, 1500)
|
|
|
|
for {
|
|
|
|
n, _, err := remote.Read(buffer)
|
|
|
|
if err != nil {
|
|
|
|
println(err.Error())
|
2023-08-31 13:19:15 +00:00
|
|
|
break
|
2023-07-26 21:15:39 +00:00
|
|
|
}
|
|
|
|
if _, err = trackLocal.Write(buffer[:n]); err != nil {
|
|
|
|
println(err.Error())
|
2023-08-31 13:19:15 +00:00
|
|
|
break
|
2023-07-26 21:15:39 +00:00
|
|
|
}
|
|
|
|
}
|
2023-09-13 10:11:30 +00:00
|
|
|
if (firstVideo || firstAudio) && peer.IsCaller && !peer.triggeredReconnectOnce {
|
|
|
|
go r.onCallerDisconnected(roomId)
|
|
|
|
peer.triggeredReconnectOnce = true
|
|
|
|
}
|
2023-07-26 21:15:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *RoomRepository) updatePCTracks(roomId string) {
|
2023-09-13 10:11:30 +00:00
|
|
|
println("[] updatePCTracks start")
|
2023-07-26 21:15:39 +00:00
|
|
|
r.Lock()
|
|
|
|
if !r.doesRoomExists(roomId) {
|
|
|
|
r.Unlock()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
room := r.Rooms[roomId]
|
2023-08-04 12:37:47 +00:00
|
|
|
r.Unlock()
|
2023-07-26 21:15:39 +00:00
|
|
|
room.Lock()
|
|
|
|
defer room.Unlock()
|
|
|
|
for _, peer := range room.Peers {
|
|
|
|
if peer.Conn == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
alreadySentTracks := map[string]*webrtc.RTPSender{}
|
|
|
|
receivingPeerTracks := map[string]*webrtc.RTPReceiver{}
|
|
|
|
for _, rtpSender := range peer.Conn.GetSenders() {
|
|
|
|
if rtpSender.Track() == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
track := rtpSender.Track()
|
|
|
|
alreadySentTracks[track.ID()] = rtpSender
|
|
|
|
}
|
|
|
|
for _, rtpReceiver := range peer.Conn.GetReceivers() {
|
|
|
|
if rtpReceiver.Track() == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
track := rtpReceiver.Track()
|
|
|
|
receivingPeerTracks[track.ID()] = rtpReceiver
|
|
|
|
}
|
|
|
|
room.trackLock.Lock()
|
2023-07-31 12:27:40 +00:00
|
|
|
renegotiate := false
|
2023-07-26 21:15:39 +00:00
|
|
|
for id, track := range room.Tracks {
|
|
|
|
_, alreadySend := alreadySentTracks[id]
|
2023-08-04 09:46:27 +00:00
|
|
|
_, alreadyReceived := receivingPeerTracks[id]
|
|
|
|
if track.OwnerId != peer.ID && (!alreadySend && !alreadyReceived) {
|
2023-07-31 12:27:40 +00:00
|
|
|
renegotiate = true
|
2023-08-31 13:19:15 +00:00
|
|
|
if peer.Conn.ConnectionState() == webrtc.PeerConnectionStateClosed {
|
|
|
|
break
|
|
|
|
}
|
2023-08-04 09:46:27 +00:00
|
|
|
println("[PC] add track", track.TrackLocal.ID(), "to", peer.ID)
|
2023-07-31 12:27:40 +00:00
|
|
|
_, err := peer.Conn.AddTrack(track.TrackLocal)
|
|
|
|
if err != nil {
|
|
|
|
println(err.Error())
|
2023-08-31 13:19:15 +00:00
|
|
|
break
|
2023-07-31 12:27:40 +00:00
|
|
|
}
|
2023-07-26 21:15:39 +00:00
|
|
|
}
|
|
|
|
}
|
2023-08-04 09:46:27 +00:00
|
|
|
for trackId, rtpSender := range alreadySentTracks {
|
|
|
|
if _, exists := room.Tracks[trackId]; !exists {
|
2023-08-04 14:43:48 +00:00
|
|
|
renegotiate = true
|
2023-08-31 13:19:15 +00:00
|
|
|
if peer.Conn.ConnectionState() == webrtc.PeerConnectionStateClosed {
|
|
|
|
break
|
|
|
|
}
|
2023-08-04 09:46:27 +00:00
|
|
|
println("[PC] remove track", trackId, "from", peer.ID)
|
2023-08-04 14:43:48 +00:00
|
|
|
err := peer.Conn.RemoveTrack(rtpSender)
|
|
|
|
if err != nil {
|
|
|
|
println(err.Error())
|
2023-08-31 13:19:15 +00:00
|
|
|
break
|
2023-08-04 14:43:48 +00:00
|
|
|
}
|
2023-08-04 09:46:27 +00:00
|
|
|
}
|
|
|
|
}
|
2023-07-26 21:15:39 +00:00
|
|
|
room.trackLock.Unlock()
|
2023-07-31 12:27:40 +00:00
|
|
|
if renegotiate {
|
2023-08-04 14:43:48 +00:00
|
|
|
go func(p *Peer, rid string) {
|
|
|
|
err := r.offerPeer(p, rid)
|
2023-08-04 12:37:47 +00:00
|
|
|
if err != nil {
|
|
|
|
println(`[E]`, err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}(peer, roomId)
|
2023-07-26 21:15:39 +00:00
|
|
|
}
|
|
|
|
}
|
2023-09-13 10:11:30 +00:00
|
|
|
println("[] updatePCTracks end")
|
2023-07-26 21:15:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *RoomRepository) AddPeerIceCandidate(roomId string, id uint64, ic webrtc.ICECandidateInit) error {
|
|
|
|
r.Lock()
|
|
|
|
if !r.doesRoomExists(roomId) {
|
|
|
|
r.Unlock()
|
|
|
|
return models.NewError("room doesn't exists", 403, map[string]any{"roomId": roomId})
|
|
|
|
}
|
|
|
|
room := r.Rooms[roomId]
|
2023-08-31 13:19:15 +00:00
|
|
|
r.Unlock()
|
2023-07-26 21:15:39 +00:00
|
|
|
room.Lock()
|
|
|
|
|
|
|
|
if !r.doesPeerExists(roomId, id) {
|
2023-08-31 13:19:15 +00:00
|
|
|
room.Unlock()
|
2023-07-26 21:15:39 +00:00
|
|
|
return models.NewError("no such a peer with this id in this room", 403, map[string]any{"roomId": roomId, "peerId": id})
|
|
|
|
}
|
2023-08-31 13:19:15 +00:00
|
|
|
peer := room.Peers[id]
|
|
|
|
room.Unlock()
|
2023-07-26 21:15:39 +00:00
|
|
|
|
2023-08-31 13:19:15 +00:00
|
|
|
err := peer.Conn.AddICECandidate(ic)
|
2023-07-26 21:15:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return models.NewError(err.Error(), 500, models.MessageResponse{Message: err.Error()})
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *RoomRepository) SetPeerAnswer(roomId string, id uint64, answer webrtc.SessionDescription) error {
|
|
|
|
r.Lock()
|
|
|
|
if !r.doesRoomExists(roomId) {
|
|
|
|
r.Unlock()
|
|
|
|
return models.NewError("room doesn't exists", 403, map[string]any{"roomId": roomId})
|
|
|
|
}
|
|
|
|
room := r.Rooms[roomId]
|
2023-08-24 13:40:18 +00:00
|
|
|
r.Unlock()
|
2023-07-26 21:15:39 +00:00
|
|
|
room.Lock()
|
|
|
|
if !r.doesPeerExists(roomId, id) {
|
2023-08-24 13:40:18 +00:00
|
|
|
room.Unlock()
|
2023-07-26 21:15:39 +00:00
|
|
|
return models.NewError("no such a peer with this id in this room", 403, map[string]any{"roomId": roomId, "peerId": id})
|
|
|
|
}
|
2023-08-24 13:40:18 +00:00
|
|
|
peer := room.Peers[id]
|
|
|
|
room.Unlock()
|
|
|
|
err := peer.Conn.SetRemoteDescription(answer)
|
2023-07-26 21:15:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return models.NewError(err.Error(), 500, models.MessageResponse{Message: err.Error()})
|
|
|
|
}
|
2023-08-24 13:40:18 +00:00
|
|
|
peer.HandshakeLock.Unlock()
|
2023-07-26 21:15:39 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
func (r *RoomRepository) SetPeerOffer(roomId string, id uint64, offer webrtc.SessionDescription) (sdpAnswer *webrtc.SessionDescription, err error) {
|
|
|
|
r.Lock()
|
|
|
|
if !r.doesRoomExists(roomId) {
|
|
|
|
r.Unlock()
|
|
|
|
return nil, models.NewError("room doesn't exists", 403, map[string]any{"roomId": roomId})
|
|
|
|
}
|
|
|
|
room := r.Rooms[roomId]
|
2023-08-04 09:46:27 +00:00
|
|
|
r.Unlock()
|
2023-07-26 21:15:39 +00:00
|
|
|
room.Lock()
|
|
|
|
|
|
|
|
if !r.doesPeerExists(roomId, id) {
|
2023-08-04 09:46:27 +00:00
|
|
|
room.Unlock()
|
2023-07-26 21:15:39 +00:00
|
|
|
return nil, models.NewError("no such a peer with this id in this room", 403, map[string]any{"roomId": roomId, "peerId": id})
|
|
|
|
}
|
2023-08-04 09:46:27 +00:00
|
|
|
peer := room.Peers[id]
|
|
|
|
room.Unlock()
|
2023-07-26 21:15:39 +00:00
|
|
|
|
2023-08-04 14:43:48 +00:00
|
|
|
if !peer.IsCaller {
|
|
|
|
return nil, models.NewError("only caller can offer", 403, nil)
|
|
|
|
}
|
2023-08-04 09:46:27 +00:00
|
|
|
peer.HandshakeLock.Lock()
|
|
|
|
defer peer.HandshakeLock.Unlock()
|
|
|
|
err = peer.Conn.SetRemoteDescription(offer)
|
2023-07-26 21:15:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, models.NewError(err.Error(), 500, models.MessageResponse{Message: err.Error()})
|
|
|
|
}
|
2023-08-04 09:46:27 +00:00
|
|
|
answer, err := peer.Conn.CreateAnswer(nil)
|
2023-07-26 21:15:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, models.NewError(err.Error(), 500, models.MessageResponse{Message: err.Error()})
|
|
|
|
}
|
2023-08-04 09:46:27 +00:00
|
|
|
err = peer.Conn.SetLocalDescription(answer)
|
2023-07-26 21:15:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, models.NewError(err.Error(), 500, models.MessageResponse{Message: err.Error()})
|
|
|
|
}
|
|
|
|
|
|
|
|
return &answer, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *RoomRepository) AllowPublish(roomId string, id uint64) error {
|
|
|
|
r.Lock()
|
|
|
|
if !r.doesRoomExists(roomId) {
|
|
|
|
r.Unlock()
|
|
|
|
return models.NewError("room doesn't exists", 403, map[string]any{"roomId": roomId})
|
|
|
|
}
|
|
|
|
r.Unlock()
|
|
|
|
room := r.Rooms[roomId]
|
|
|
|
room.Lock()
|
|
|
|
defer room.Unlock()
|
|
|
|
|
|
|
|
if !r.doesPeerExists(roomId, id) {
|
|
|
|
return models.NewError("no such a peer with this id in this room", 403, map[string]any{"roomId": roomId, "peerId": id})
|
|
|
|
}
|
|
|
|
|
|
|
|
room.Peers[id].CanPublish = true
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *RoomRepository) ClosePeer(roomId string, id uint64) error {
|
|
|
|
r.Lock()
|
|
|
|
if !r.doesRoomExists(roomId) {
|
|
|
|
r.Unlock()
|
|
|
|
return models.NewError("room doesn't exists", 403, map[string]any{"roomId": roomId})
|
|
|
|
}
|
|
|
|
room := r.Rooms[roomId]
|
2023-08-24 13:40:18 +00:00
|
|
|
r.Unlock()
|
2023-07-26 21:15:39 +00:00
|
|
|
room.Lock()
|
2023-08-24 13:40:18 +00:00
|
|
|
peer := room.Peers[id]
|
2023-07-26 21:15:39 +00:00
|
|
|
|
|
|
|
if !r.doesPeerExists(roomId, id) {
|
2023-08-24 13:40:18 +00:00
|
|
|
room.Unlock()
|
2023-07-26 21:15:39 +00:00
|
|
|
return models.NewError("no such a peer with this id in this room", 403, map[string]any{"roomId": roomId, "peerId": id})
|
|
|
|
}
|
2023-08-24 13:40:18 +00:00
|
|
|
room.Unlock()
|
|
|
|
return peer.Conn.Close()
|
2023-07-26 21:15:39 +00:00
|
|
|
}
|
2023-07-31 12:27:40 +00:00
|
|
|
|
2023-11-02 11:42:30 +00:00
|
|
|
func (r *RoomRepository) ResetRoom(roomId string) (uint64, error) {
|
2023-07-31 12:27:40 +00:00
|
|
|
r.Lock()
|
2023-08-04 09:46:27 +00:00
|
|
|
defer r.Unlock()
|
2023-07-31 12:27:40 +00:00
|
|
|
if !r.doesRoomExists(roomId) {
|
2023-11-02 11:42:30 +00:00
|
|
|
return 0, nil
|
2023-07-31 12:27:40 +00:00
|
|
|
}
|
|
|
|
room := r.Rooms[roomId]
|
|
|
|
room.Lock()
|
2023-11-02 11:42:30 +00:00
|
|
|
ggid := room.ggId
|
2023-07-31 12:27:40 +00:00
|
|
|
room.timer.Stop()
|
|
|
|
for _, peer := range room.Peers {
|
2023-08-31 13:19:15 +00:00
|
|
|
go func(conn *webrtc.PeerConnection) {
|
|
|
|
_ = conn.Close()
|
|
|
|
}(peer.Conn)
|
2023-07-31 12:27:40 +00:00
|
|
|
}
|
2023-08-31 13:19:15 +00:00
|
|
|
room.Unlock()
|
2023-07-31 12:27:40 +00:00
|
|
|
delete(r.Rooms, roomId)
|
2023-11-02 11:42:30 +00:00
|
|
|
return ggid, nil
|
2023-08-04 09:46:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *RoomRepository) offerPeer(peer *Peer, roomId string) error {
|
|
|
|
peer.HandshakeLock.Lock()
|
|
|
|
println("[PC] negotiating with peer", peer.ID)
|
|
|
|
offer, err := peer.Conn.CreateOffer(nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = peer.Conn.SetLocalDescription(offer)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-11-02 11:42:30 +00:00
|
|
|
ggid := r.GetRoomGGID(roomId)
|
2023-08-04 09:46:27 +00:00
|
|
|
reqModel := dto.SetSDPReqModel{
|
2023-11-02 11:42:30 +00:00
|
|
|
GGID: *ggid,
|
2023-08-04 09:46:27 +00:00
|
|
|
PeerDTO: dto.PeerDTO{
|
|
|
|
RoomId: roomId,
|
|
|
|
ID: peer.ID,
|
|
|
|
},
|
|
|
|
SDP: offer,
|
|
|
|
}
|
|
|
|
bodyJson, err := json.Marshal(reqModel)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
res, err := http.Post(r.conf.LogjamBaseUrl+"/offer", "application/json", bytes.NewReader(bodyJson))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if res.StatusCode > 204 {
|
|
|
|
return errors.New("POST {logjambaseurl}/offer : " + res.Status)
|
|
|
|
}
|
2023-07-31 20:10:39 +00:00
|
|
|
return nil
|
2023-07-31 12:27:40 +00:00
|
|
|
}
|
2023-11-02 11:42:30 +00:00
|
|
|
|
|
|
|
func (r *RoomRepository) GetRoomGGID(roomId string) *uint64 {
|
|
|
|
r.Lock()
|
|
|
|
defer r.Unlock()
|
|
|
|
if !r.doesRoomExists(roomId) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
gid := r.Rooms[roomId].ggId
|
|
|
|
return &gid
|
|
|
|
}
|