package localserver // import ( // "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" // ) // type VideoChannel struct { // ID string `json:"id"` // Owner string `json:"owner"` // ChannelType string `json:"channelType"` // Members []string `json:"members"` // CurrentMembersId []string `json:"currentMembersId"` // CurrentMembers map[string]*VideoChannelMember `json:"currentMembers"` // localSD map[string]*webrtc.SessionDescription `json:"-"` // rtcPeerConnections map[string]*ZoneRTCPeerConnection `json:"-"` // audioTransceiver map[string][]*PeerSender `json:"-"` // videoTransceiver map[string][]*PeerSender `json:"-"` // videoChannelDataChannels map[string]*DataChannel `json:"-"` // pendingCandidates map[string][]*webrtc.ICECandidate `json:"-"` // remoteTracks map[string][]*RemoteTrack `json:"-"` // middlewares []interface{} `json:"-"` // candidateFlag *uint32 `json:"-"` // remoteTracksFlag *uint32 `json:"-"` // rtcPeerConnectionMapFlag *uint32 `json:"-"` // dataChannelMapFlag *uint32 `json:"-"` // localSDMapFlag *uint32 `json:"-"` // audioSenderFlag *uint32 `json:"-"` // videoSenderFlag *uint32 `json:"-"` // } // type VideoChannelOnICECandidateFunc = func(string, string, *webrtc.ICECandidate) error // func NewVideoChannel(id string, owner string, channelType string, members []string, currentMembersId []string, currentMembers map[string]*VideoChannelMember) (audioChannel *VideoChannel) { // candidateFlag := uint32(0) // remoteTracksFlag := uint32(0) // rtcPeerConnectionMapFlag := uint32(0) // dataChannelMapFlag := uint32(0) // localSDMapFlag := uint32(0) // audioSenderFlag := uint32(0) // videoSenderFlag := uint32(0) // audioChannel = &VideoChannel{ // ID: id, // Owner: owner, // ChannelType: channelType, // Members: members, // CurrentMembersId: currentMembersId, // CurrentMembers: currentMembers, // localSD: make(map[string]*webrtc.SessionDescription), // videoTransceiver: make(map[string][]*PeerSender), // rtcPeerConnections: make(map[string]*ZoneRTCPeerConnection), // audioTransceiver: make(map[string][]*PeerSender), // videoChannelDataChannels: make(map[string]*DataChannel), // pendingCandidates: make(map[string][]*webrtc.ICECandidate), // remoteTracks: make(map[string][]*RemoteTrack), // middlewares: make([]interface{}, 0), // candidateFlag: &candidateFlag, // remoteTracksFlag: &remoteTracksFlag, // rtcPeerConnectionMapFlag: &rtcPeerConnectionMapFlag, // dataChannelMapFlag: &dataChannelMapFlag, // localSDMapFlag: &localSDMapFlag, // audioSenderFlag: &audioSenderFlag, // videoSenderFlag: &videoSenderFlag, // } // return // } // func (vc *VideoChannel) HandleOffer(ctx context.Context, channelId string, userId string, sdp string, hostId string, sendDCMessage SendDCMessageFunc, cb VideoChannelOnICECandidateFunc) (done chan struct{}, errCh chan error) { // done, errCh = make(chan struct{}), make(chan error) // go func() { // peerConnection, err := vc.createPeerConnection(userId, vc.ID, webrtc.SDPTypeAnswer, cb, sendDCMessage) // if err != nil { // errCh <- err // return // } // _ = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) { // vc.rtcPeerConnections[userId] = &ZoneRTCPeerConnection{ // PeerConnection: peerConnection, // makingOffer: false, // makingOfferLock: &sync.Mutex{}, // negotiate: vc.negotiate, // } // return // }) // offer := webrtc.SessionDescription{ // Type: webrtc.SDPTypeOffer, // SDP: sdp, // } // if err = peerConnection.SetRemoteDescription(offer); err != nil { // errCh <- err // return // } // rawAnswer, err := peerConnection.CreateAnswer(nil) // if err != nil { // errCh <- err // return // } // if err = peerConnection.SetLocalDescription(rawAnswer); err != nil { // errCh <- err // return // } // _, _ = sendDCMessage(string(VIDEO_CHANNEL_WEBRTC_ANSWER), hostId, userId, map[string]interface{}{ // "to": userId, // "from": vc.ID, // "channelId": channelId, // "sdp": rawAnswer.SDP, // }) // done <- struct{}{} // // logger.Println("handle offer done") // }() // return // } // func (vc *VideoChannel) HandleCounterOffer(ctx context.Context, userId string, sendDCMessage SendDCMessageFunc) (err error) { // // if err = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) { // // if _, ok := vc.rtcPeerConnections[userId]; !ok { // // err = fmt.Errorf("no field corresponding peer connection for id %s", userId) // // return // // } // // // logger.Println("handling counter offer") // // connection := vc.rtcPeerConnections[userId] // // err = atomicallyExecute(vc.localSDMapFlag, func() (err error) { // // err = connection.SetLocalDescription(*vc.localSD[userId]) // // return // // }) // // return // // }); err != nil { // // return // // } // // _ = atomicallyExecute(vc.localSDMapFlag, func() (err error) { // // delete(vc.localSD, userId) // // return // // }) // if err = atomicallyExecute(vc.candidateFlag, func() (err error) { // for _, candidate := range vc.pendingCandidates[userId] { // // logger.Println("sending candidate to", userId, candidate) // d, e := sendDCMessage(string(VIDEO_CHANNEL_WEBRTC_CANDIDATE), "", userId, map[string]interface{}{ // "from": vc.ID, // "to": userId, // "candidate": candidate.ToJSON().Candidate, // "sdpMid": *candidate.ToJSON().SDPMid, // "sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)), // }) // select { // case <-d: // case err = <-e: // return // } // } // delete(vc.pendingCandidates, userId) // return // }); err != nil { // return // } // return // } // func (vc *VideoChannel) HandleRennegotiationOffer(from string, sdp string, sendDCMessage SendDCMessageFunc) (err error) { // err = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) { // if _, ok := vc.rtcPeerConnections[from]; !ok { // err = fmt.Errorf("no corresponding peer connection for id %s", from) // return // } // // vc.rtcPeerConnections[from].makingOfferLock.Lock() // // if vc.rtcPeerConnections[from].makingOffer { // // vc.rtcPeerConnections[from].makingOfferLock.Unlock() // // return fmt.Errorf("already making an offer or state is stable") // // } // // vc.rtcPeerConnections[from].makingOfferLock.Unlock() // if err = vc.rtcPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeOffer}); err != nil { // return // } // localSd, err := vc.rtcPeerConnections[from].CreateAnswer(nil) // if err != nil { // return // } // if err = vc.rtcPeerConnections[from].SetLocalDescription(localSd); err != nil { // return // } // d, e := sendDCMessage(string(VIDEO_CHANNEL_WEBRTC_RENNEGOTIATION_ANSWER), vc.ID, from, map[string]interface{}{ // "from": vc.ID, // "to": from, // "sdp": localSd.SDP, // }) // select { // case <-d: // case err = <-e: // } // return // }) // return // } // func (vc *VideoChannel) HandleRennegotiationAnswer(from string, sdp string) (err error) { // // logger.Println("---------------------handling rennego answer") // err = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) { // // vc.rtcPeerConnections[from].makingOfferLock.Lock() // // if vc.rtcPeerConnections[from].makingOffer { // // vc.rtcPeerConnections[from].makingOfferLock.Unlock() // // return fmt.Errorf("already making an offer or state is stable") // // } // // vc.rtcPeerConnections[from].makingOfferLock.Unlock() // // if _, ok := vc.rtcPeerConnections[from]; !ok { // // err = fmt.Errorf("no corresponding peer connection for id %s", from) // // return // // } // err = vc.rtcPeerConnections[from].SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeAnswer}) // return // }) // return // } // func (vc *VideoChannel) AddCandidate(candidate *webrtc.ICECandidateInit, from string) (err error) { // // logger.Println("adding ice candidate", candidate) // err = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) { // if _, ok := vc.rtcPeerConnections[from]; ok && candidate != nil { // err = vc.rtcPeerConnections[from].AddICECandidate(*candidate) // } // return // }) // return // } // func (vc *VideoChannel) createPeerConnection(target string, from string, peerType webrtc.SDPType, cb VideoChannelOnICECandidateFunc, sendDCMessage SendDCMessageFunc) (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("video-channel", &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 // } // if e := vc.HandleDataChannelEvents(event.From, event.EventId, event.Payload); e != nil { // // logger.Println("*-------------- datachannel error: ", e) // } // }) // // logger.Println("new channel for target : ", target) // _ = atomicallyExecute(vc.dataChannelMapFlag, func() (err error) { // // logger.Println(target) // l := uint32(0) // vc.videoChannelDataChannels[target] = &DataChannel{ // DataChannel: channel, // l: &l, // } // return // }) // } else { // peerConnection.OnDataChannel(func(dc *webrtc.DataChannel) { // _ = atomicallyExecute(vc.dataChannelMapFlag, func() (err error) { // l := uint32(0) // vc.videoChannelDataChannels[target] = &DataChannel{ // DataChannel: dc, // l: &l, // } // return // }) // 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 // } // if e := vc.HandleDataChannelEvents(event.From, event.EventId, event.Payload); e != nil { // // logger.Println("*-------------- datachannel error: ", e) // } // }) // }) // } // err = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) { // err = atomicallyExecute(vc.remoteTracksFlag, func() (err error) { // // logger.Println("------------------", vc.CurrentMembersId) // for _, id := range vc.CurrentMembersId { // // logger.Println(id) // if id != target { // if _, ok := vc.remoteTracks[id]; !ok { // continue // } // for _, track := range vc.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 { // _ = atomicallyExecute(vc.videoSenderFlag, func() (err error) { // if len(vc.videoTransceiver) == 0 { // vc.videoTransceiver[id] = []*PeerSender{{ID: target, Transceiver: transceiver}} // } else { // vc.videoTransceiver[id] = append(vc.videoTransceiver[id], &PeerSender{ID: target, Transceiver: transceiver}) // } // return // }) // } else if track.Track.Kind() == webrtc.RTPCodecTypeAudio { // _ = atomicallyExecute(vc.audioSenderFlag, func() (err error) { // if len(vc.audioTransceiver) == 0 { // vc.audioTransceiver[id] = []*PeerSender{{ID: target, Transceiver: transceiver}} // } else { // vc.audioTransceiver[id] = append(vc.audioTransceiver[id], &PeerSender{ID: target, Transceiver: transceiver}) // } // return // }) // } // // logger.Println("track added", track) // } // } // } // return // }) // return // }) // peerConnection.OnConnectionStateChange(func(pcs webrtc.PeerConnectionState) { // if pcs == webrtc.PeerConnectionStateClosed || pcs == webrtc.PeerConnectionStateDisconnected || pcs == webrtc.PeerConnectionStateFailed { // // logger.Println(pcs) // //vc.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()) // // logger.Println("*************************----------------", i, "-----------------------***************") // 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} // _ = atomicallyExecute(vc.remoteTracksFlag, func() (err error) { // if len(vc.remoteTracks[target]) == 0 { // vc.remoteTracks[target] = []*RemoteTrack{remote} // } else { // vc.remoteTracks[target] = append(vc.remoteTracks[target], remote) // } // index := len(vc.remoteTracks[target]) // // logger.Println(index, vc.remoteTracks) // return // }) // _ = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) { // for _, id := range vc.CurrentMembersId { // if id != target { // if _, ok := vc.rtcPeerConnections[id]; !ok { // continue // } // connection := vc.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 { // _ = atomicallyExecute(vc.audioSenderFlag, func() (err error) { // if len(vc.audioTransceiver) == 0 { // vc.audioTransceiver[target] = []*PeerSender{{ID: id, Transceiver: transceiver}} // } else { // vc.audioTransceiver[target] = append(vc.audioTransceiver[target], &PeerSender{ID: id, Transceiver: transceiver}) // } // return // }) // } else if localTrack.Kind() == webrtc.RTPCodecTypeVideo { // _ = atomicallyExecute(vc.videoSenderFlag, func() (err error) { // if len(vc.videoTransceiver) == 0 { // vc.videoTransceiver[target] = []*PeerSender{{ID: id, Transceiver: transceiver}} // } else { // vc.videoTransceiver[target] = append(vc.videoTransceiver[target], &PeerSender{ID: id, Transceiver: transceiver}) // } // return // }) // } // go func() { // <-time.After(time.Second * 1) // connection.negotiate(id, sendDCMessage) // }() // } // } // return // }) // d := make(chan struct{}) // go func() { // 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] // } // } // } // d <- struct{}{} // }() // <-d // }) // peerConnection.OnICECandidate(func(i *webrtc.ICECandidate) { // if i == nil { // return // } // _ = atomicallyExecute(vc.candidateFlag, func() (err error) { // desc := peerConnection.RemoteDescription() // if desc == nil { // // logger.Println("generated candidate appended to list : ", i) // vc.pendingCandidates[target] = append(vc.pendingCandidates[target], i) // } else { // // logger.Println("generated candidate : ", i) // if iceCandidateErr := cb(from, target, i); iceCandidateErr != nil { // // logger.Println(iceCandidateErr) // } // } // return // }) // }) // // peerConnection.OnNegotiationNeeded(func() { // // // logger.Println("---------------- rennego is needed -----------") // // // _ = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) { // // // for _, id := range vc.CurrentMembersId { // // // // logger.Println("----------------- sending renego to peer with id", id) // // // if _, ok := vc.rtcPeerConnections[id]; !ok { // // // continue // // // } // // // if peerConnection.SignalingState() == webrtc.SignalingStateStable { // // // localSd, localSdErr := peerConnection.CreateOffer(nil) // // // if localSdErr != nil { // // // // logger.Println(localSdErr) // // // return localSdErr // // // } // // // if err = peerConnection.SetLocalDescription(localSd); err != nil { // // // // logger.Println(err) // // // return // // // } // // // d, e := sendDCMessage(string(VIDEO_CHANNEL_WEBRTC_RENNEGOTIATION_OFFER), vc.ID, id, map[string]interface{}{ // // // "from": vc.ID, // // // "to": id, // // // "sdp": localSd.SDP, // // // }) // // // select { // // // case <-d: // // // case err = <-e: // // // // logger.Println(err) // // // } // // // } // // // } // // // return // // // }) // // }) // return // } // func (vc *VideoChannel) HandleLeavingMember(id string) { // if err := atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) { // if _, ok := vc.rtcPeerConnections[id]; !ok { // err = fmt.Errorf("no corresponding peerconnection for audio channel leaving member") // } // return // }); err != nil { // // logger.Println(err) // } else { // defer func() { // _ = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) { // if _, ok := vc.rtcPeerConnections[id]; ok { // if closeErr := vc.rtcPeerConnections[id].Close(); closeErr != nil { // err = closeErr // // logger.Println("peer connection close error", closeErr) // } // } // delete(vc.rtcPeerConnections, id) // return // }) // }() // } // // logger.Printf("peer %s is leaving the squad\n", id) // _ = atomicallyExecute(vc.dataChannelMapFlag, func() (err error) { // if _, ok := vc.videoChannelDataChannels[id]; ok { // vc.videoChannelDataChannels[id].DataChannel.Close() // } // delete(vc.videoChannelDataChannels, id) // return // }) // _ = atomicallyExecute(vc.localSDMapFlag, func() (err error) { // delete(vc.localSD, id) // return // }) // _ = atomicallyExecute(vc.candidateFlag, func() (err error) { // delete(vc.pendingCandidates, id) // return // }) // _ = atomicallyExecute(vc.audioSenderFlag, func() (err error) { // for peerId, peerSender := range vc.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++ // } // } // vc.audioTransceiver[peerId] = vc.audioTransceiver[peerId][:len(peerSender)-(c)] // // logger.Println(vc.audioTransceiver[peerId]) // } // } // for _, transceiver := range vc.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(vc.audioTransceiver, id) // return // }) // _ = atomicallyExecute(vc.videoSenderFlag, func() (err error) { // for peerId, peerSender := range vc.videoTransceiver { // 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++ // } // } // vc.videoTransceiver[peerId] = vc.videoTransceiver[peerId][:len(peerSender)-(c)] // // logger.Println(vc.videoTransceiver[peerId]) // } // } // for _, transceiver := range vc.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(vc.videoTransceiver, id) // return // }) // _ = atomicallyExecute(vc.remoteTracksFlag, func() (err error) { // delete(vc.remoteTracks, id) // return // }) // } // func (vc *VideoChannel) negotiate(target string, sendDCMessage SendDCMessageFunc) { // // logger.Println("------------------negotiate is called") // _ = atomicallyExecute(vc.rtcPeerConnectionMapFlag, func() (err error) { // if _, ok := vc.rtcPeerConnections[target]; !ok { // return // } // // vc.rtcPeerConnections[target].makingOfferLock.Lock() // // vc.rtcPeerConnections[target].makingOffer = true // // vc.rtcPeerConnections[target].makingOfferLock.Unlock() // defer func() { // // vc.rtcPeerConnections[target].makingOfferLock.Lock() // // vc.rtcPeerConnections[target].makingOffer = false // // vc.rtcPeerConnections[target].makingOfferLock.Unlock() // }() // for _, id := range vc.CurrentMembersId { // // logger.Println("----------------- sending renego to peer with id", id) // if _, ok := vc.rtcPeerConnections[id]; !ok { // continue // } // connection := vc.rtcPeerConnections[id] // if connection.SignalingState() == webrtc.SignalingStateStable { // localSd, err := connection.CreateOffer(nil) // if err != nil { // // logger.Println(err) // return err // } // if err = connection.SetLocalDescription(localSd); err != nil { // // logger.Println(err) // return err // } // d, e := sendDCMessage(string(VIDEO_CHANNEL_WEBRTC_RENNEGOTIATION_OFFER), vc.ID, id, map[string]interface{}{ // "from": vc.ID, // "to": id, // "sdp": localSd.SDP, // }) // select { // case <-d: // case err = <-e: // // logger.Println(err) // } // } // } // return // }) // } // func (vc *VideoChannel) broadcastDatachannelMessage(from string, eventId string, payload map[string]interface{}) (done chan struct{}, errCh chan error) { // done, errCh = make(chan struct{}), make(chan error) // go func() { // bs, jsonErr := json.Marshal(&ZoneResponse{ // Type: eventId, // From: vc.ID, // Payload: payload, // }) // if jsonErr != nil { // errCh <- jsonErr // return // } // if err := atomicallyExecute(vc.dataChannelMapFlag, func() (err error) { // for id, dc := range vc.videoChannelDataChannels { // if from != id { // if err = dc.DataChannel.SendText(string(bs)); err != nil { // return // } // } // } // return // }); err != nil { // errCh <- err // } // done <- struct{}{} // }() // return // } // func (vc *VideoChannel) HandleDataChannelEvents(from string, eventId string, payload map[string]interface{}) (err error) { // switch eventId { // case VIDEO_CHANNEL_USER_VIDEO_STOP: // if err = atomicallyExecute(vc.remoteTracksFlag, func() (err error) { // if _, ok := vc.remoteTracks[from]; !ok { // err = fmt.Errorf("no corresponding remote tracks entry for id %s", from) // return // } // for _, track := range vc.remoteTracks[from] { // if track.Track.Kind() == webrtc.RTPCodecTypeVideo { // atomic.SwapInt32(track.rdv, 1) // } // } // return // }); err != nil { // return // } // done, errCh := vc.broadcastDatachannelMessage(from, VIDEO_CHANNEL_USER_VIDEO_STOP, map[string]interface{}{ // "userId": from, // }) // select { // case <-done: // case err = <-errCh: // } // case VIDEO_CHANNEL_USER_VIDEO_RESUME: // if err = atomicallyExecute(vc.remoteTracksFlag, func() (err error) { // if _, ok := vc.remoteTracks[from]; !ok { // err = fmt.Errorf("no corresponding remote tracks entry for id %s", from) // return // } // for _, track := range vc.remoteTracks[from] { // if track.Track.Kind() == webrtc.RTPCodecTypeVideo { // atomic.SwapInt32(track.rdv, 0) // } // } // return // }); err != nil { // return // } // done, errCh := vc.broadcastDatachannelMessage(from, VIDEO_CHANNEL_USER_VIDEO_RESUME, map[string]interface{}{ // "userId": from, // }) // select { // case <-done: // case err = <-errCh: // } // case VIDEO_CHANNEL_USER_MUTE: // if err = atomicallyExecute(vc.remoteTracksFlag, func() (err error) { // if _, ok := vc.remoteTracks[from]; !ok { // err = fmt.Errorf("no corresponding remote tracks entry for id %s", from) // return // } // for _, track := range vc.remoteTracks[from] { // if track.Track.Kind() == webrtc.RTPCodecTypeAudio { // atomic.SwapInt32(track.rdv, 1) // } // } // return // }); err != nil { // return // } // done, errCh := vc.broadcastDatachannelMessage(from, VIDEO_CHANNEL_USER_MUTE, map[string]interface{}{ // "userId": from, // }) // select { // case <-done: // case err = <-errCh: // } // case VIDEO_CHANNEL_USER_UNMUTE: // if err = atomicallyExecute(vc.remoteTracksFlag, func() (err error) { // if _, ok := vc.remoteTracks[from]; !ok { // err = fmt.Errorf("no corresponding remote tracks entry for id %s", from) // return // } // for _, track := range vc.remoteTracks[from] { // if track.Track.Kind() == webrtc.RTPCodecTypeAudio { // atomic.SwapInt32(track.rdv, 0) // } // } // return // }); err != nil { // return // } // done, errCh := vc.broadcastDatachannelMessage(from, VIDEO_CHANNEL_USER_UNMUTE, map[string]interface{}{ // "userId": from, // }) // select { // case <-done: // case err = <-errCh: // } // case VIDEO_CHANNEL_USER_SPEAKING: // done, errCh := vc.broadcastDatachannelMessage(from, VIDEO_CHANNEL_USER_SPEAKING, map[string]interface{}{ // "userId": from, // }) // select { // case <-done: // case err = <-errCh: // } // case VIDEO_CHANNEL_USER_STOPPED_SPEAKING: // done, errCh := vc.broadcastDatachannelMessage(from, VIDEO_CHANNEL_USER_STOPPED_SPEAKING, map[string]interface{}{ // "userId": from, // }) // select { // case <-done: // case err = <-errCh: // } // } // return // }