198 lines
6.0 KiB
Go
198 lines
6.0 KiB
Go
package localserver
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strconv"
|
|
|
|
"github.com/pion/webrtc/v3"
|
|
)
|
|
|
|
type GrpcRequestType string
|
|
|
|
const (
|
|
PEER_CONNECTION_REQUEST GrpcRequestType = "peer_connection_request"
|
|
)
|
|
|
|
const (
|
|
OFFER ReqType = "offer"
|
|
ANSWER ReqType = "answer"
|
|
COUNTER_OFFER ReqType = "webrtc_counter_offer"
|
|
JOIN_HOSTED_SQUAD ReqType = "join_hosted_squad"
|
|
HOSTED_SQUAD_ACCESS_DENIED ReqType = "hosted_squad_access_denied"
|
|
HOSTED_SQUAD_STOP_CALL ReqType = "hosted_squad_stop_call"
|
|
HOSTED_SQUAD_ACCESS_GRANTED ReqType = "hosted_squad_access_granted"
|
|
LEAVE_HOSTED_SQUAD ReqType = "leave_hosted_squad"
|
|
INCOMING_MEMBER_HOSTED ReqType = "incoming_member_hosted"
|
|
LEAVING_MEMBER_HOSTED ReqType = "leaving_member_hosted"
|
|
HOSTED_SQUAD_WEBRTC_OFFER ReqType = "hosted_squad_offer"
|
|
HOSTED_SQUAD_WEBRTC_ANSWER ReqType = "hosted_squad_answer"
|
|
HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_OFFER ReqType = "hosted_squad_rennegotiation_offer"
|
|
HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_ANSWER ReqType = "hosted_squad_rennegotiation_answer"
|
|
HOSTED_SQUAD_WEBRTC_COUNTER_OFFER ReqType = "hosted_squad_webrtc_counter_offer"
|
|
HOSTED_SQUAD_WEBRTC_CANDIDATE ReqType = "hosted_squad_webrtc_candidate"
|
|
HOSTED_SQUAD_REMOVE_VIDEO ReqType = "hosted_squad_remove_video"
|
|
GET_HOSTED_SQUAD_TRACKS ReqType = "hosted_squad_get_tracks"
|
|
NEW_HOSTED_SQUAD = "new_hosted_squad"
|
|
)
|
|
|
|
type WebRTCGrpcMiddleware struct {
|
|
Manager *WebRTCCallManager
|
|
stream SignalingService_LinkClient
|
|
}
|
|
|
|
func NewWebRTCGrpcMiddleware(manager *WebRTCCallManager) (webrtcGrpcMiddleware *WebRTCGrpcMiddleware) {
|
|
webrtcGrpcMiddleware = &WebRTCGrpcMiddleware{
|
|
Manager: manager,
|
|
}
|
|
return
|
|
}
|
|
|
|
func validateRequest(req map[string]string, entries ...string) (err error) {
|
|
for _, entry := range entries {
|
|
if _, ok := req[entry]; !ok {
|
|
err = fmt.Errorf("no field %s in req payload", entry)
|
|
return
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (wgm *WebRTCGrpcMiddleware) signalCandidate(to string, candidate *webrtc.ICECandidate) (err error) {
|
|
bs, err := json.Marshal(map[string]string{
|
|
"from": wgm.Manager.ID,
|
|
"to": to,
|
|
"candidate": candidate.ToJSON().Candidate,
|
|
"sdpMid": *candidate.ToJSON().SDPMid,
|
|
"sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
|
|
})
|
|
if err != nil {
|
|
return
|
|
}
|
|
err = wgm.stream.Send(&SignalingMessage{
|
|
Type: string(HOSTED_SQUAD_WEBRTC_CANDIDATE),
|
|
From: wgm.Manager.ID,
|
|
To: to,
|
|
Payload: bs,
|
|
})
|
|
return
|
|
}
|
|
|
|
func (wgm *WebRTCGrpcMiddleware) Process(ctx context.Context, req *SignalingMessage, stream SignalingService_LinkClient) (err error) {
|
|
done, errCh := make(chan struct{}), make(chan error)
|
|
go func() {
|
|
defer func() {
|
|
done <- struct{}{}
|
|
}()
|
|
var payload map[string]string
|
|
if e := json.Unmarshal(req.Payload, &payload); err != nil {
|
|
errCh <- e
|
|
return
|
|
}
|
|
switch req.Type {
|
|
case NEW_HOSTED_SQUAD:
|
|
if err := validateRequest(payload, "ID"); err != nil {
|
|
errCh <- err
|
|
return
|
|
}
|
|
logger.Println("new squad incoming")
|
|
wgm.Manager.SquadMapMux.Lock()
|
|
wgm.Manager.Squads[payload["ID"]] = &Squad{
|
|
ID: payload["ID"],
|
|
Members: []string{},
|
|
}
|
|
wgm.Manager.SquadMapMux.Unlock()
|
|
case string(HOSTED_SQUAD_STOP_CALL):
|
|
logger.Println("quit squad called")
|
|
if err := validateRequest(payload, "squadId"); err != nil {
|
|
errCh <- err
|
|
return
|
|
}
|
|
wgm.Manager.HandleLeavingMember(req.GetFrom(), payload["squadId"])
|
|
done <- struct{}{}
|
|
case string(PEER_CONNECTION_REQUEST):
|
|
logger.Println("creating offer for peer")
|
|
if err := wgm.Manager.CreateOffer(ctx, req.GetFrom(), req.GetTo(), wgm.signalCandidate); err != nil {
|
|
errCh <- err
|
|
return
|
|
}
|
|
case string(HOSTED_SQUAD_WEBRTC_OFFER):
|
|
if err := validateRequest(payload, SDP, SQUAD_ID); err != nil {
|
|
errCh <- err
|
|
return
|
|
}
|
|
if err := wgm.Manager.HandleOffer(ctx, req.GetFrom(), req.GetTo(), payload, wgm.signalCandidate); err != nil {
|
|
errCh <- err
|
|
return
|
|
}
|
|
case string(HOSTED_SQUAD_WEBRTC_ANSWER):
|
|
if err := validateRequest(payload, SDP); err != nil {
|
|
errCh <- err
|
|
return
|
|
}
|
|
if err := wgm.Manager.HandleAnswer(ctx, req.GetFrom(), req.GetTo(), payload); err != nil {
|
|
errCh <- err
|
|
return
|
|
}
|
|
case string(HOSTED_SQUAD_WEBRTC_COUNTER_OFFER):
|
|
if err := wgm.Manager.HandleCounterOffer(ctx, req.GetFrom(), req.GetTo(), payload); err != nil {
|
|
errCh <- err
|
|
return
|
|
}
|
|
case string(HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_ANSWER):
|
|
logger.Println("received negotiation answer")
|
|
if err := validateRequest(payload, SDP); err != nil {
|
|
errCh <- err
|
|
return
|
|
}
|
|
if err := wgm.Manager.HandleRennegotiationAnswer(req.GetFrom(), payload[SDP]); err != nil {
|
|
errCh <- err
|
|
return
|
|
}
|
|
case string(HOSTED_SQUAD_WEBRTC_RENNEGOTIATION_OFFER):
|
|
logger.Println("received negotiation offer")
|
|
if err := validateRequest(payload, SDP); err != nil {
|
|
errCh <- err
|
|
return
|
|
}
|
|
if err := wgm.Manager.HandleRennegotiationOffer(req.GetFrom(), payload[SDP]); err != nil {
|
|
errCh <- err
|
|
return
|
|
}
|
|
case string(HOSTED_SQUAD_WEBRTC_CANDIDATE):
|
|
if err := validateRequest(payload, "candidate", "sdpMLineIndex", "sdpMid"); err != nil {
|
|
errCh <- err
|
|
return
|
|
}
|
|
logger.Println(payload)
|
|
i, err := strconv.Atoi(payload["sdpMLineIndex"])
|
|
if err != nil {
|
|
errCh <- err
|
|
return
|
|
}
|
|
SDPMLineIndex := uint16(i)
|
|
sdpMid := payload["sdpMid"]
|
|
logger.Println(sdpMid, SDPMLineIndex)
|
|
if err := wgm.Manager.AddCandidate(&webrtc.ICECandidateInit{
|
|
Candidate: payload["candidate"],
|
|
SDPMid: &sdpMid,
|
|
SDPMLineIndex: &SDPMLineIndex,
|
|
}, req.GetFrom()); err != nil {
|
|
errCh <- err
|
|
return
|
|
}
|
|
default:
|
|
}
|
|
}()
|
|
select {
|
|
case <-ctx.Done():
|
|
err = ctx.Err()
|
|
return
|
|
case <-done:
|
|
return
|
|
case err = <-errCh:
|
|
return
|
|
}
|
|
}
|