Zippytal-Node/webrtcCallManager.go

839 lines
28 KiB
Go

package localserver
// import (
// "bytes"
// "context"
// "encoding/json"
// "errors"
// "fmt"
// "io"
// "strconv"
// sync "sync"
// "sync/atomic"
// "time"
// "github.com/google/uuid"
// "github.com/pion/rtcp"
// "github.com/pion/webrtc/v3"
// )
// const (
// NAME = "name"
// ID = "ID"
// SDP = "sdp"
// CANDIDATE = "webrtc_candidate"
// SQUAD_ID = "squadId"
// FROM = "from"
// TO = "to"
// STOP_CALL = "stop_call"
// LIST_HOSTED_SQUADS_BY_HOST = "list_hosted_squads_by_host"
// )
// type Squad struct {
// ID string
// Members []string
// }
// type WebRTCCallManager struct {
// stream SignalingService_LinkClient
// middlewares []WebrtcCallEventManager
// ID string
// LocalSD map[string]*webrtc.SessionDescription
// RTCPeerConnections map[string]*RTCPeerConnection
// AudioTransceiver map[string][]*PeerSender
// VideoTransceiver map[string][]*PeerSender
// DataChannels map[string]*DataChannel
// PendingCandidates map[string][]*webrtc.ICECandidate
// RemoteTracks map[string][]*RemoteTrack
// Squads map[string]*Squad
// SquadMapMux *sync.RWMutex
// CandidateChannel chan *IncomingCandidate
// CandidateMux *sync.RWMutex
// RemoteTracksMux *sync.RWMutex
// RTCPeerConnectionMapMux *sync.RWMutex
// DataChannelMapMux *sync.RWMutex
// LocalSDMapMux *sync.RWMutex
// AudioSenderMux *sync.RWMutex
// VideoSenderMux *sync.RWMutex
// }
// type IncomingCandidate struct {
// For string
// Candidate *webrtc.ICECandidateInit
// }
// type RTCPeerConnection struct {
// *webrtc.PeerConnection
// id string
// makingOffer bool
// negotiate func(string, string)
// makingOfferLock *sync.Mutex
// }
// type DataChannel struct {
// DataChannel *webrtc.DataChannel
// bufferedAmountLowThresholdReached <-chan struct{}
// l *uint32
// }
// type PeerSender struct {
// ID string
// Transceiver *webrtc.RTPTransceiver
// Sender *webrtc.RTPSender
// }
// type CallEvent struct {
// EventId string `json:"eventId"`
// From string `json:"from"`
// Data []byte `json:"data"`
// Payload map[string]interface{} `json:"payload"`
// }
// type RemoteTrack struct {
// ID string
// Track *webrtc.TrackLocalStaticRTP
// rdv *int32
// }
// type OnICECandidateFunc func(string, *webrtc.ICECandidate) error
// func NewWebRTCCallManager(id string, token string, eventHandlers ...WebrtcCallEventManager) (webRTCCallManager *WebRTCCallManager, err error) {
// squadList, err := loadHostedSquads(token, id)
// if err != nil {
// return
// }
// squads := make(map[string]*Squad)
// for _, squad := range squadList {
// squads[squad.ID] = squad
// }
// logger.Println(squads)
// webRTCCallManager = &WebRTCCallManager{
// middlewares: eventHandlers,
// ID: id,
// AudioTransceiver: make(map[string][]*PeerSender),
// VideoTransceiver: make(map[string][]*PeerSender),
// DataChannels: make(map[string]*DataChannel),
// PendingCandidates: make(map[string][]*webrtc.ICECandidate),
// LocalSD: make(map[string]*webrtc.SessionDescription),
// RTCPeerConnections: make(map[string]*RTCPeerConnection),
// RemoteTracks: make(map[string][]*RemoteTrack),
// Squads: squads,
// SquadMapMux: &sync.RWMutex{},
// RTCPeerConnectionMapMux: &sync.RWMutex{},
// LocalSDMapMux: &sync.RWMutex{},
// CandidateMux: &sync.RWMutex{},
// DataChannelMapMux: &sync.RWMutex{},
// AudioSenderMux: &sync.RWMutex{},
// VideoSenderMux: &sync.RWMutex{},
// RemoteTracksMux: &sync.RWMutex{},
// }
// return
// }
// func loadHostedSquads(token string, hostId string) (squads []*Squad, err error) {
// em := NewEncryptionManager()
// sig := em.SignRequestHMAC(hostId)
// body, err := json.Marshal(map[string]interface{}{
// "type": LIST_HOSTED_SQUADS_BY_HOST,
// "mac": sig,
// "from": hostId,
// "peerType": "node",
// "payload": map[string]string{
// "host": hostId,
// "lastIndex": "0",
// },
// })
// if err != nil {
// return
// }
// res, err := HTTPClient.Post("https://dev.zippytal.com/req", "application/json", bytes.NewBuffer(body))
// if err != nil {
// logger.Println("error come from there in webrtc call manager")
// return
// }
// bs, err := io.ReadAll(res.Body)
// if err != nil {
// return
// }
// var payload map[string]any
// if err = json.Unmarshal(bs, &payload); err != nil {
// return
// }
// b, err := json.Marshal(payload["squads"])
// if err != nil {
// return
// }
// err = json.Unmarshal(b, &squads)
// return
// }
// func (wm *WebRTCCallManager) sendSignalingMessage(messageType, from, to string, payload map[string]interface{}) (err error) {
// bs, err := json.Marshal(payload)
// if err != nil {
// return
// }
// err = wm.stream.Send(&SignalingMessage{
// Type: messageType,
// From: from,
// To: to,
// Payload: bs,
// })
// return
// }
// func (wm *WebRTCCallManager) CreateOffer(ctx context.Context, target string, from string, cb OnICECandidateFunc) (err error) {
// peerConnection, err := wm.createPeerConnection(target, from, "aa5da62f-2800-4dd5-bf86-423cda048120", webrtc.SDPTypeOffer, cb)
// if err != nil {
// return
// }
// logger.Println("connection created")
// rawOffer, err := peerConnection.CreateOffer(nil)
// if err != nil {
// return
// }
// if err = peerConnection.SetLocalDescription(rawOffer); err != nil {
// return
// }
// wm.RTCPeerConnectionMapMux.Lock()
// logger.Println("adding for target", target)
// wm.RTCPeerConnections[target] = &RTCPeerConnection{
// PeerConnection: peerConnection,
// makingOffer: true,
// makingOfferLock: &sync.Mutex{},
// negotiate: wm.negotiate,
// }
// wm.RTCPeerConnectionMapMux.Unlock()
// err = wm.sendSignalingMessage(string(HOSTED_SQUAD_WEBRTC_OFFER), wm.ID, target, map[string]interface{}{
// "to": target,
// "from": wm.ID,
// "sdp": rawOffer.SDP,
// })
// return
// }
// func (wm *WebRTCCallManager) HandleOffer(ctx context.Context, from, to string, req map[string]string, cb OnICECandidateFunc) (err error) {
// done, errCh := make(chan struct{}), make(chan error)
// go func() {
// if _, ok := wm.Squads[req[SQUAD_ID]]; !ok {
// err = fmt.Errorf("no corresponding squad")
// errCh <- err
// return
// }
// peerConnection, err := wm.createPeerConnection(from, to, req[SQUAD_ID], webrtc.SDPTypeAnswer, cb)
// if err != nil {
// errCh <- err
// return
// }
// wm.RTCPeerConnectionMapMux.Lock()
// wm.RTCPeerConnections[from] = &RTCPeerConnection{
// PeerConnection: peerConnection,
// makingOffer: false,
// makingOfferLock: &sync.Mutex{},
// negotiate: wm.negotiate,
// }
// wm.RTCPeerConnectionMapMux.Unlock()
// offer := webrtc.SessionDescription{
// Type: webrtc.SDPTypeOffer,
// SDP: req[SDP],
// }
// if err = peerConnection.SetRemoteDescription(offer); err != nil {
// errCh <- err
// return
// }
// rawAnswer, err := peerConnection.CreateAnswer(nil)
// if err != nil {
// errCh <- err
// return
// }
// wm.LocalSDMapMux.Lock()
// wm.LocalSD[from] = &rawAnswer
// wm.LocalSDMapMux.Unlock()
// if err = peerConnection.SetLocalDescription(rawAnswer); err != nil {
// errCh <- err
// return
// }
// wm.SquadMapMux.Lock()
// wm.Squads[req[SQUAD_ID]].Members = append(wm.Squads[req[SQUAD_ID]].Members, from)
// wm.SquadMapMux.Unlock()
// if err = wm.sendSignalingMessage(string(HOSTED_SQUAD_WEBRTC_ANSWER), wm.ID, from, map[string]interface{}{
// "to": from,
// "from": wm.ID,
// "sdp": rawAnswer.SDP,
// }); err != nil {
// errCh <- err
// return
// }
// done <- struct{}{}
// }()
// select {
// case <-done:
// return
// case err = <-errCh:
// return
// case <-ctx.Done():
// err = ctx.Err()
// return
// }
// }
// func (wm *WebRTCCallManager) HandleAnswer(ctx context.Context, from, to string, req map[string]string) (err error) {
// wm.RTCPeerConnectionMapMux.Lock()
// defer wm.RTCPeerConnectionMapMux.Unlock()
// defer func() {
// if r := recover(); err != nil {
// logger.Printf("recover from panic in handle answer : %v\n", r)
// }
// }()
// if _, ok := wm.RTCPeerConnections[from]; !ok {
// err = fmt.Errorf("no corresponding peer connection for id : %s", from)
// return
// }
// peerConnnection := wm.RTCPeerConnections[from]
// logger.Println("---------------------")
// logger.Println(req[SDP])
// logger.Println("---------------------")
// if err = peerConnnection.SetRemoteDescription(webrtc.SessionDescription{
// Type: webrtc.SDPTypeAnswer,
// SDP: req[SDP],
// }); err != nil {
// logger.Println("error occured while setting remote description in handle answer")
// return
// }
// if err = wm.sendSignalingMessage(string(HOSTED_SQUAD_WEBRTC_COUNTER_OFFER), wm.ID, from, map[string]interface{}{
// "from": wm.ID,
// "to": from,
// }); err != nil {
// return
// }
// wm.CandidateMux.Lock()
// for _, candidate := range wm.PendingCandidates[from] {
// logger.Println("sending candidate from answer to", from)
// if err = wm.sendSignalingMessage(string(HOSTED_SQUAD_WEBRTC_CANDIDATE), wm.ID, from, map[string]interface{}{
// "from": wm.ID,
// "to": from,
// "candidate": candidate.ToJSON().Candidate,
// "sdpMid": *candidate.ToJSON().SDPMid,
// "sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
// }); err != nil {
// wm.CandidateMux.Unlock()
// return
// }
// }
// wm.CandidateMux.Unlock()
// wm.CandidateMux.Lock()
// delete(wm.PendingCandidates, from)
// wm.CandidateMux.Unlock()
// wm.LocalSDMapMux.Lock()
// delete(wm.LocalSD, from)
// wm.LocalSDMapMux.Unlock()
// return
// }
// func (wm *WebRTCCallManager) HandleCounterOffer(ctx context.Context, from, to string, req map[string]string) (err error) {
// wm.RTCPeerConnectionMapMux.Lock()
// if _, ok := wm.RTCPeerConnections[from]; !ok {
// err = fmt.Errorf("no field corresponding peer connection for id %s", from)
// wm.RTCPeerConnectionMapMux.Unlock()
// return
// }
// logger.Println("handling counter offer")
// //connection := wm.RTCPeerConnections[from]
// wm.RTCPeerConnectionMapMux.Unlock()
// // wm.LocalSDMapMux.Lock()
// // if err = connection.SetLocalDescription(*wm.LocalSD[from]); err != nil {
// // wm.LocalSDMapMux.Unlock()
// // return
// // }
// // wm.LocalSDMapMux.Unlock()
// wm.CandidateMux.Lock()
// for _, candidate := range wm.PendingCandidates[from] {
// logger.Println("sending candidate to", from)
// if err = wm.sendSignalingMessage(string(HOSTED_SQUAD_WEBRTC_CANDIDATE), wm.ID, from, map[string]interface{}{
// "from": wm.ID,
// "to": from,
// "candidate": candidate.ToJSON().Candidate,
// "sdpMid": *candidate.ToJSON().SDPMid,
// "sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
// }); err != nil {
// wm.CandidateMux.Unlock()
// return
// }
// }
// delete(wm.PendingCandidates, from)
// wm.CandidateMux.Unlock()
// wm.LocalSDMapMux.Lock()
// delete(wm.LocalSD, from)
// wm.LocalSDMapMux.Unlock()
// return
// }
// func (wm *WebRTCCallManager) createPeerConnection(target string, from string, squadId string, peerType webrtc.SDPType, cb OnICECandidateFunc) (peerConnection *webrtc.PeerConnection, err error) {
// defer func() {
// if r := recover(); err != nil {
// logger.Printf("recover from panic : %v\n", r)
// }
// }()
// config := webrtc.Configuration{
// ICEServers: []webrtc.ICEServer{
// {
// URLs: []string{"stun:stun.l.google.com:19302", "stun:stun.l.google.com:19302"},
// },
// },
// SDPSemantics: webrtc.SDPSemanticsUnifiedPlanWithFallback,
// }
// peerConnection, err = webrtc.NewPeerConnection(config)
// if err != nil {
// return
// }
// logger.Println("---------------------------------------------------")
// if peerType == webrtc.SDPTypeAnswer {
// maxRetransmits := uint16(100)
// channel, err := peerConnection.CreateDataChannel("data", &webrtc.DataChannelInit{
// MaxRetransmits: &maxRetransmits,
// })
// if err != nil {
// return nil, err
// }
// channel.OnOpen(func() {
// logger.Println("channel opened")
// if chanErr := channel.SendText("yooo man this is open"); chanErr != nil {
// logger.Println(chanErr)
// }
// })
// channel.OnMessage(func(msg webrtc.DataChannelMessage) {
// var event CallEvent
// if err := json.Unmarshal(msg.Data, &event); err != nil {
// logger.Println(err)
// return
// }
// for _, handler := range wm.middlewares {
// if err := handler.HandleCallEvent(event.From, squadId, event.EventId, event.Payload, event.Data, wm); err != nil {
// logger.Println(err)
// continue
// }
// }
// })
// logger.Println("new channel for target : ", target)
// channel.SetBufferedAmountLowThreshold(bufferedAmountLowThreshold)
// channel.OnBufferedAmountLow(func() {
// })
// wm.DataChannelMapMux.Lock()
// logger.Println(target)
// l := uint32(0)
// wm.DataChannels[target] = &DataChannel{
// DataChannel: channel,
// l: &l,
// }
// wm.DataChannelMapMux.Unlock()
// } else {
// peerConnection.OnDataChannel(func(dc *webrtc.DataChannel) {
// wm.DataChannelMapMux.Lock()
// l := uint32(0)
// wm.DataChannels[target] = &DataChannel{
// DataChannel: dc,
// l: &l,
// }
// wm.DataChannelMapMux.Unlock()
// dc.OnOpen(func() {
// logger.Printf("got a new open datachannel %s\n", dc.Label())
// })
// dc.OnMessage(func(msg webrtc.DataChannelMessage) {
// var event CallEvent
// if err := json.Unmarshal(msg.Data, &event); err != nil {
// logger.Println(err)
// return
// }
// for _, handler := range wm.middlewares {
// if err := handler.HandleCallEvent(event.From, squadId, event.EventId, event.Payload, event.Data, wm); err != nil {
// logger.Println(err)
// continue
// }
// }
// })
// })
// }
// wm.RemoteTracksMux.RLock()
// for _, id := range wm.Squads[squadId].Members {
// if id != target {
// <-time.NewTimer(time.Millisecond * 50).C
// if _, ok := wm.RemoteTracks[id]; !ok {
// continue
// }
// for _, track := range wm.RemoteTracks[id] {
// transceiver, err := peerConnection.AddTransceiverFromKind(track.Track.Kind(), webrtc.RTPTransceiverInit{Direction: webrtc.RTPTransceiverDirectionSendonly})
// if err != nil {
// logger.Println("add track error")
// continue
// }
// if err := transceiver.Sender().ReplaceTrack(track.Track); err != nil {
// logger.Println("add track error")
// continue
// }
// if track.Track.Kind() == webrtc.RTPCodecTypeVideo {
// wm.VideoSenderMux.Lock()
// if len(wm.VideoTransceiver) == 0 {
// wm.VideoTransceiver[id] = []*PeerSender{{ID: target, Transceiver: transceiver}}
// } else {
// wm.VideoTransceiver[id] = append(wm.VideoTransceiver[id], &PeerSender{ID: target, Transceiver: transceiver})
// }
// wm.VideoSenderMux.Unlock()
// } else if track.Track.Kind() == webrtc.RTPCodecTypeAudio {
// wm.AudioSenderMux.Lock()
// if len(wm.AudioTransceiver) == 0 {
// wm.AudioTransceiver[id] = []*PeerSender{{ID: target, Transceiver: transceiver}}
// } else {
// wm.AudioTransceiver[id] = append(wm.AudioTransceiver[id], &PeerSender{ID: target, Transceiver: transceiver})
// }
// wm.AudioSenderMux.Unlock()
// }
// logger.Println("track added", track)
// }
// }
// }
// wm.RemoteTracksMux.RUnlock()
// peerConnection.OnConnectionStateChange(func(pcs webrtc.PeerConnectionState) {
// if pcs == webrtc.PeerConnectionStateClosed || pcs == webrtc.PeerConnectionStateDisconnected || pcs == webrtc.PeerConnectionStateFailed {
// logger.Println(pcs)
// wm.HandleLeavingMember(target, squadId)
// }
// })
// peerConnection.OnICEConnectionStateChange(func(is webrtc.ICEConnectionState) {
// logger.Printf("ICE connection state has changed %s\n", is.String())
// if is == webrtc.ICEConnectionStateDisconnected || is == webrtc.ICEConnectionStateFailed {
// logger.Println(is)
// }
// })
// peerConnection.OnTrack(func(tr *webrtc.TrackRemote, r *webrtc.RTPReceiver) {
// logger.Println("got new track")
// defer func() {
// if stopErr := r.Stop(); stopErr != nil {
// logger.Println(stopErr)
// }
// }()
// go func() {
// ticker := time.NewTicker(1500 * time.Millisecond)
// for range ticker.C {
// if rtcpSendErr := peerConnection.WriteRTCP([]rtcp.Packet{&rtcp.PictureLossIndication{MediaSSRC: uint32(tr.SSRC())}}); rtcpSendErr != nil {
// logger.Println(rtcpSendErr)
// break
// }
// }
// }()
// uniqId := uuid.New()
// i := fmt.Sprintf("%s/%s", target, uniqId.String())
// localTrack, newTrackErr := webrtc.NewTrackLocalStaticRTP(tr.Codec().RTPCodecCapability, i, i)
// if newTrackErr != nil {
// return
// }
// logger.Println(localTrack)
// rtpbuf := make([]byte, 1400)
// flag := int32(0)
// remote := &RemoteTrack{ID: target, Track: localTrack, rdv: &flag}
// wm.RemoteTracksMux.Lock()
// if len(wm.RemoteTracks[target]) == 0 {
// wm.RemoteTracks[target] = []*RemoteTrack{remote}
// } else {
// wm.RemoteTracks[target] = append(wm.RemoteTracks[target], remote)
// }
// index := len(wm.RemoteTracks[target])
// logger.Println(index, wm.RemoteTracks)
// wm.RemoteTracksMux.Unlock()
// wm.SquadMapMux.RLock()
// for _, id := range wm.Squads[squadId].Members {
// if id != target {
// if _, ok := wm.RTCPeerConnections[id]; !ok {
// continue
// }
// connection := wm.RTCPeerConnections[id]
// transceiver, tranceiverErr := connection.AddTransceiverFromKind(localTrack.Kind(), webrtc.RTPTransceiverInit{Direction: webrtc.RTPTransceiverDirectionSendonly})
// if tranceiverErr != nil {
// logger.Println(tranceiverErr)
// continue
// }
// if replaceTrackErr := transceiver.Sender().ReplaceTrack(localTrack); replaceTrackErr != nil {
// logger.Println(replaceTrackErr)
// continue
// }
// go func() {
// rtcpBuf := make([]byte, 1500)
// for {
// if _, _, rtcpErr := transceiver.Sender().Read(rtcpBuf); rtcpErr != nil {
// return
// }
// }
// }()
// if localTrack.Kind() == webrtc.RTPCodecTypeAudio {
// wm.AudioSenderMux.Lock()
// if len(wm.AudioTransceiver) == 0 {
// wm.AudioTransceiver[target] = []*PeerSender{{ID: id, Transceiver: transceiver}}
// } else {
// wm.AudioTransceiver[target] = append(wm.AudioTransceiver[target], &PeerSender{ID: id, Transceiver: transceiver})
// }
// wm.AudioSenderMux.Unlock()
// } else if localTrack.Kind() == webrtc.RTPCodecTypeVideo {
// wm.VideoSenderMux.Lock()
// if len(wm.VideoTransceiver) == 0 {
// wm.VideoTransceiver[target] = []*PeerSender{{ID: id, Transceiver: transceiver}}
// } else {
// wm.VideoTransceiver[target] = append(wm.VideoTransceiver[target], &PeerSender{ID: id, Transceiver: transceiver})
// }
// wm.VideoSenderMux.Unlock()
// }
// go func() {
// <-time.NewTimer(time.Second).C
// connection.negotiate(id, squadId)
// }()
// }
// }
// wm.SquadMapMux.RUnlock()
// for {
// i, _, readErr := tr.Read(rtpbuf)
// if readErr != nil {
// logger.Println(readErr)
// break
// }
// f := atomic.LoadInt32(remote.rdv)
// if f == 0 {
// if _, writeErr := localTrack.Write(rtpbuf[:i]); writeErr != nil && !errors.Is(writeErr, io.ErrClosedPipe) {
// logger.Println(writeErr)
// break
// } else {
// _ = rtpbuf[:i]
// }
// }
// }
// })
// peerConnection.OnICECandidate(func(i *webrtc.ICECandidate) {
// if i == nil {
// return
// }
// wm.CandidateMux.Lock()
// defer wm.CandidateMux.Unlock()
// desc := peerConnection.RemoteDescription()
// if desc == nil {
// logger.Println("generated candidate appended to list : ", i)
// wm.PendingCandidates[target] = append(wm.PendingCandidates[target], i)
// } else {
// logger.Println("generated candidate : ", i)
// if iceCandidateErr := cb(target, i); iceCandidateErr != nil {
// logger.Println(iceCandidateErr)
// }
// }
// })
// return
// }
// func (wm *WebRTCCallManager) HandleRennegotiationOffer(from string, sdp string) (err error) {
// wm.RTCPeerConnectionMapMux.Lock()
// defer wm.RTCPeerConnectionMapMux.Unlock()
// if _, ok := wm.RTCPeerConnections[from]; !ok {
// err = fmt.Errorf("no corresponding peer connection for id %s", from)
// return
// }
// wm.RTCPeerConnections[from].makingOfferLock.Lock()
// if wm.RTCPeerConnections[from].makingOffer {
// wm.RTCPeerConnections[from].makingOfferLock.Unlock()
// return fmt.Errorf("already making an offer or state is stable")
// }
// wm.RTCPeerConnections[from].makingOfferLock.Unlock()
// if err = wm.RTCPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeOffer}); err != nil {
// return
// }
// localSd, err := wm.RTCPeerConnections[from].CreateAnswer(nil)
// if err != nil {
// return
// }
// if err = wm.RTCPeerConnections[from].SetLocalDescription(localSd); err != nil {
// return
// }
// if err = wm.sendSignalingMessage(string(HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_ANSWER), wm.ID, from, map[string]interface{}{
// "to": from,
// "sdp": localSd.SDP,
// }); err != nil {
// logger.Println(err)
// return
// }
// return
// }
// func (wm *WebRTCCallManager) HandleRennegotiationAnswer(from string, sdp string) (err error) {
// wm.RTCPeerConnectionMapMux.Lock()
// defer wm.RTCPeerConnectionMapMux.Unlock()
// wm.RTCPeerConnections[from].makingOfferLock.Lock()
// if wm.RTCPeerConnections[from].makingOffer {
// wm.RTCPeerConnections[from].makingOfferLock.Unlock()
// return fmt.Errorf("already making an offer or state is stable")
// }
// wm.RTCPeerConnections[from].makingOfferLock.Unlock()
// if _, ok := wm.RTCPeerConnections[from]; !ok {
// err = fmt.Errorf("no corresponding peer connection for id %s", from)
// return
// }
// err = wm.RTCPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeAnswer})
// return
// }
// func (wm *WebRTCCallManager) AddCandidate(candidate *webrtc.ICECandidateInit, from string) (err error) {
// wm.RTCPeerConnectionMapMux.Lock()
// defer wm.RTCPeerConnectionMapMux.Unlock()
// if candidate != nil {
// err = wm.RTCPeerConnections[from].AddICECandidate(*candidate)
// }
// return
// }
// func (wm *WebRTCCallManager) HandleLeavingMember(id string, squadId string) {
// wm.RTCPeerConnectionMapMux.Lock()
// if _, ok := wm.RTCPeerConnections[id]; !ok {
// wm.RTCPeerConnectionMapMux.Unlock()
// return
// }
// wm.RTCPeerConnectionMapMux.Unlock()
// defer func() {
// wm.RTCPeerConnectionMapMux.Lock()
// if _, ok := wm.RTCPeerConnections[id]; ok {
// if closeErr := wm.RTCPeerConnections[id].Close(); closeErr != nil {
// logger.Println("peer connection close error", closeErr)
// }
// }
// delete(wm.RTCPeerConnections, id)
// wm.RTCPeerConnectionMapMux.Unlock()
// }()
// logger.Printf("peer %s is leaving the squad\n", id)
// wm.DataChannelMapMux.Lock()
// if _, ok := wm.DataChannels[id]; ok {
// wm.DataChannels[id].DataChannel.Close()
// }
// delete(wm.DataChannels, id)
// wm.DataChannelMapMux.Unlock()
// wm.LocalSDMapMux.Lock()
// delete(wm.LocalSD, id)
// wm.LocalSDMapMux.Unlock()
// delete(wm.PendingCandidates, id)
// wm.RemoteTracksMux.Lock()
// delete(wm.RemoteTracks, id)
// wm.RemoteTracksMux.Unlock()
// wm.AudioSenderMux.Lock()
// for peerId, peerSender := range wm.AudioTransceiver {
// if peerId != id {
// logger.Println("senders", peerSender)
// c := 0
// for i, sender := range peerSender {
// if sender.ID == id {
// if senderErr := sender.Transceiver.Sender().Stop(); senderErr != nil {
// logger.Println(senderErr)
// }
// if transceiverErr := sender.Transceiver.Stop(); transceiverErr != nil {
// logger.Println("transceiverErr occured with video", transceiverErr)
// }
// peerSender[len(peerSender)-i-1], peerSender[i] = peerSender[i], peerSender[len(peerSender)-i-1]
// c++
// }
// }
// wm.AudioTransceiver[peerId] = wm.AudioTransceiver[peerId][:len(peerSender)-(c)]
// logger.Println(wm.AudioTransceiver[peerId])
// }
// }
// for _, transceiver := range wm.AudioTransceiver[id] {
// if senderErr := transceiver.Transceiver.Sender().Stop(); senderErr != nil {
// logger.Println(senderErr)
// }
// if stopErr := transceiver.Transceiver.Stop(); stopErr != nil {
// logger.Println("transceiver audio stop error", stopErr)
// }
// }
// delete(wm.AudioTransceiver, id)
// wm.AudioSenderMux.Unlock()
// wm.VideoSenderMux.Lock()
// for peerId, peerSender := range wm.VideoTransceiver {
// if peerId != id {
// c := 0
// logger.Println("senders", peerSender)
// for i, sender := range peerSender {
// if sender.ID == id {
// if senderErr := sender.Transceiver.Sender().Stop(); senderErr != nil {
// logger.Println(senderErr)
// }
// if transceiverErr := sender.Transceiver.Stop(); transceiverErr != nil {
// logger.Println("transceiverErr occured with video", transceiverErr)
// }
// peerSender[len(peerSender)-i-1], peerSender[i] = peerSender[i], peerSender[len(peerSender)-i-1]
// c++
// }
// }
// wm.VideoTransceiver[peerId] = wm.VideoTransceiver[peerId][:len(peerSender)-(c)]
// logger.Println(wm.VideoTransceiver[peerId])
// }
// }
// for _, transceiver := range wm.VideoTransceiver[id] {
// if senderErr := transceiver.Transceiver.Sender().Stop(); senderErr != nil {
// logger.Println(senderErr)
// }
// if stopErr := transceiver.Transceiver.Stop(); stopErr != nil {
// logger.Println("transceiver video stop error", stopErr)
// }
// }
// delete(wm.VideoTransceiver, id)
// wm.VideoSenderMux.Unlock()
// if _, ok := wm.Squads[squadId]; ok {
// wm.SquadMapMux.Lock()
// var index int
// for i, v := range wm.Squads[squadId].Members {
// if v == id {
// index = i
// break
// }
// }
// if len(wm.Squads[squadId].Members) < 2 {
// wm.Squads[squadId].Members = []string{}
// } else {
// wm.Squads[squadId].Members = append(wm.Squads[squadId].Members[:index], wm.Squads[squadId].Members[index+1:]...)
// }
// wm.SquadMapMux.Unlock()
// }
// }
// func (wm *WebRTCCallManager) negotiate(target string, squadId string) {
// wm.RTCPeerConnectionMapMux.Lock()
// defer wm.RTCPeerConnectionMapMux.Unlock()
// if _, ok := wm.RTCPeerConnections[target]; !ok {
// return
// }
// wm.RTCPeerConnections[target].makingOfferLock.Lock()
// wm.RTCPeerConnections[target].makingOffer = true
// wm.RTCPeerConnections[target].makingOfferLock.Unlock()
// defer func() {
// wm.RTCPeerConnections[target].makingOfferLock.Lock()
// wm.RTCPeerConnections[target].makingOffer = false
// wm.RTCPeerConnections[target].makingOfferLock.Unlock()
// }()
// wm.SquadMapMux.RLock()
// defer wm.SquadMapMux.RUnlock()
// for _, id := range wm.Squads[squadId].Members {
// if _, ok := wm.RTCPeerConnections[id]; !ok {
// continue
// }
// connection := wm.RTCPeerConnections[id]
// if connection.SignalingState() == webrtc.SignalingStateStable {
// localSd, err := connection.CreateOffer(nil)
// if err != nil {
// logger.Println(err)
// return
// }
// if err = connection.SetLocalDescription(localSd); err != nil {
// logger.Println(err)
// return
// }
// if err = wm.sendSignalingMessage(string(HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_OFFER), wm.ID, id, map[string]interface{}{
// "to": id,
// "sdp": localSd.SDP,
// }); err != nil {
// logger.Println(err)
// return
// }
// }
// }
// }