mirror of
https://gitlab.com/comunic/ComunicRTCProxy
synced 2024-11-17 02:51:12 +00:00
137 lines
2.9 KiB
Go
137 lines
2.9 KiB
Go
/// RTC Relay
|
|
///
|
|
/// @author Pierre Hubert
|
|
|
|
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"log"
|
|
"time"
|
|
|
|
"github.com/pion/webrtc/v2"
|
|
)
|
|
|
|
const (
|
|
// SDP This is a SDP signal
|
|
SDP = iota
|
|
|
|
// CANDIDATE This is a candidate
|
|
CANDIDATE = iota
|
|
)
|
|
|
|
type receivedSignal struct {
|
|
peerID string
|
|
callHash string
|
|
sigType uint
|
|
offer webrtc.SessionDescription
|
|
candidate webrtc.ICECandidateInit
|
|
}
|
|
|
|
/// We keep for each connection its channel
|
|
var closeChan = make(chan string)
|
|
var connections = make(map[string]chan receivedSignal)
|
|
|
|
/// Process incoming messages
|
|
func onSignal(callHash, peerID string, data map[string]interface{}) {
|
|
|
|
// Close all the channels that requested so
|
|
processCloseRequests()
|
|
|
|
// Decode received signal
|
|
newSignal := receivedSignal{
|
|
peerID: peerID,
|
|
callHash: callHash,
|
|
}
|
|
|
|
if data["type"] == "SDP" {
|
|
newSignal.sigType = SDP
|
|
newSignal.offer.Type = webrtc.SDPTypeOffer
|
|
newSignal.offer.SDP = data["data"].(map[string]interface{})["sdp"].(string)
|
|
|
|
} else if data["type"] == "CANDIDATE" {
|
|
newSignal.sigType = CANDIDATE
|
|
|
|
// I have to re-encode data to initialize ICECandidate
|
|
var enc []byte
|
|
enc, err := json.Marshal(data["data"])
|
|
if err != nil {
|
|
log.Printf("Could not re-encode candidate ! %s", err)
|
|
return
|
|
}
|
|
|
|
err = json.Unmarshal(enc, &newSignal.candidate)
|
|
if err != nil {
|
|
log.Printf("Discarding invalid candidate: %s", err)
|
|
return
|
|
}
|
|
|
|
} else {
|
|
log.Fatalf("Invalid signal type: %s !", data["type"])
|
|
}
|
|
|
|
// Check if we are attempting to connect as viewer to a non existing channel
|
|
if _, ok := connections[callHash]; !ok {
|
|
if peerID != "0" || newSignal.sigType != SDP {
|
|
println("Attempting to connect as viewer | send candidate to a non-ready broadcast!")
|
|
return
|
|
}
|
|
}
|
|
|
|
// Handle new offers
|
|
if newSignal.sigType == SDP && peerID == "0" {
|
|
|
|
// Check if we are overwriting another connection
|
|
if _, ok := connections[callHash]; ok {
|
|
closeConnection(callHash)
|
|
}
|
|
|
|
connections[callHash] = make(chan receivedSignal, 10)
|
|
go newCall(newSignal, connections[callHash])
|
|
|
|
} else {
|
|
// Forward the message to the channel
|
|
connections[callHash] <- newSignal
|
|
}
|
|
}
|
|
|
|
/// Close a connection
|
|
func closeConnection(callHash string) {
|
|
log.Printf("Closing call %s", callHash)
|
|
if val, ok := connections[callHash]; ok {
|
|
close(val)
|
|
delete(connections, callHash)
|
|
}
|
|
}
|
|
|
|
// Ask for a channel to be closed
|
|
func askForClose(callHash string) {
|
|
closeChan <- callHash
|
|
}
|
|
|
|
// Process channel close requests (in thread safe way)
|
|
func processCloseRequests() {
|
|
for {
|
|
select {
|
|
case id := <-closeChan:
|
|
closeConnection(id)
|
|
case <-time.After(time.Millisecond * 10):
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Start new call
|
|
func newCall(mainOffer receivedSignal, ch chan receivedSignal) {
|
|
|
|
// Since we are answering use PayloadTypes declared by offerer
|
|
mediaEngine := webrtc.MediaEngine{}
|
|
err := mediaEngine.PopulateFromSDP(mainOffer.offer)
|
|
if err != nil {
|
|
log.Println("Error: invalid data in offer!", err)
|
|
askForClose(mainOffer.callHash)
|
|
return
|
|
}
|
|
|
|
}
|