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 // } // } // } // }