mirror of
https://github.com/giongto35/cloud-game.git
synced 2026-07-21 17:18:47 +00:00
SDP Exchanging
This commit is contained in:
parent
73a6a0fe61
commit
80ca5bdd97
4 changed files with 163 additions and 27 deletions
95
main.go
95
main.go
|
|
@ -168,9 +168,10 @@ func startSession(webRTC *webrtc.WebRTC, gameName string, roomID string, playerI
|
|||
|
||||
// Session represents a session connected from the browser to the current server
|
||||
type Session struct {
|
||||
client *Client
|
||||
oclient *Client
|
||||
ServerID string
|
||||
client *Client
|
||||
oclient *Client
|
||||
peerconnection *webrtc.WebRTC
|
||||
ServerID string
|
||||
}
|
||||
|
||||
// Handle normal traffic (from browser to host)
|
||||
|
|
@ -186,10 +187,11 @@ func ws(w http.ResponseWriter, r *http.Request) {
|
|||
var playerIndex int
|
||||
|
||||
// Create connection to overlord
|
||||
client := NewClient(c, webrtc.NewWebRTC())
|
||||
client := NewClient(c)
|
||||
|
||||
wssession := &Session{
|
||||
client: client,
|
||||
client: client,
|
||||
peerconnection: webrtc.NewWebRTC(),
|
||||
// The server session is maintaining
|
||||
}
|
||||
|
||||
|
|
@ -199,7 +201,7 @@ func ws(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
client.receive("initwebrtc", func(resp WSPacket) WSPacket {
|
||||
log.Println("Received user SDP")
|
||||
localSession, err := client.peerconnection.StartClient(resp.Data, width, height)
|
||||
localSession, err := wssession.peerconnection.StartClient(resp.Data, width, height)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
|
@ -252,15 +254,15 @@ func ws(w http.ResponseWriter, r *http.Request) {
|
|||
//log.Println("Ping from server with game:", gameName)
|
||||
//res.ID = "pong"
|
||||
log.Println("Starting game")
|
||||
roomServerID := GetServerIDOfRoom(wssession.oclient, roomID)
|
||||
roomServerID := getServerIDOfRoom(wssession.oclient, roomID)
|
||||
log.Println("Server of RoomID ", roomID, " is ", roomServerID)
|
||||
if roomServerID != "" && wssession.ServerID != roomServerID {
|
||||
// TODO: Re -register
|
||||
bridgeConnection(wssession, roomServerID)
|
||||
go bridgeConnection(wssession, roomServerID, gameName, roomID, playerIndex)
|
||||
return
|
||||
}
|
||||
|
||||
roomID, isNewRoom = startSession(client.peerconnection, gameName, roomID, playerIndex)
|
||||
roomID, isNewRoom = startSession(wssession.peerconnection, gameName, roomID, playerIndex)
|
||||
if isNewRoom {
|
||||
wssession.oclient.send(WSPacket{
|
||||
ID: "registerRoom",
|
||||
|
|
@ -383,7 +385,7 @@ func removeSession(w *webrtc.WebRTC, room *Room) {
|
|||
}
|
||||
}
|
||||
|
||||
func GetServerIDOfRoom(oc *Client, roomID string) string {
|
||||
func getServerIDOfRoom(oc *Client, roomID string) string {
|
||||
packet := oc.syncSend(
|
||||
WSPacket{
|
||||
ID: "getRoom",
|
||||
|
|
@ -394,8 +396,37 @@ func GetServerIDOfRoom(oc *Client, roomID string) string {
|
|||
return packet.Data
|
||||
}
|
||||
|
||||
func bridgeConnection(session *Session, serverID string) {
|
||||
func bridgeConnection(session *Session, serverID string, gameName string, roomID string, playerIndex int) {
|
||||
log.Println("Bridging connection to other Host ", serverID)
|
||||
client := session.client
|
||||
oclient := session.oclient
|
||||
// Ask client to init
|
||||
|
||||
log.Println("Requesting offer to browser", serverID)
|
||||
resp := client.syncSend(WSPacket{
|
||||
ID: "requestOffer",
|
||||
Data: "",
|
||||
})
|
||||
|
||||
log.Println("Sending offer to overlord to relay message to target host", resp.TargetHostID)
|
||||
// Ask overlord to relay SDP packet to serverID
|
||||
resp.TargetHostID = serverID
|
||||
remoteTargetSDP := oclient.syncSend(resp)
|
||||
log.Println("Got back remote host SDP, sending to browser", remoteTargetSDP.Data)
|
||||
// Send back remote SDP of remote server to browser
|
||||
client.syncSend(WSPacket{
|
||||
ID: "sdp",
|
||||
Data: remoteTargetSDP.Data,
|
||||
})
|
||||
log.Println("Init session done, start game on target host")
|
||||
|
||||
oclient.syncSend(WSPacket{
|
||||
ID: "start",
|
||||
Data: gameName,
|
||||
RoomID: roomID,
|
||||
PlayerIndex: playerIndex,
|
||||
})
|
||||
log.Println("Game is started on remote host")
|
||||
}
|
||||
|
||||
const overlordHost = "ws://localhost:9000/wso"
|
||||
|
|
@ -415,7 +446,7 @@ func (s *Session) NewOverlordClient() {
|
|||
if err != nil {
|
||||
log.Println("Cannot connect to overlord")
|
||||
}
|
||||
oclient := NewClient(oc, webrtc.NewWebRTC())
|
||||
oclient := NewClient(oc)
|
||||
oclient.send(
|
||||
WSPacket{
|
||||
ID: "ping",
|
||||
|
|
@ -437,6 +468,46 @@ func (s *Session) NewOverlordClient() {
|
|||
},
|
||||
)
|
||||
|
||||
// Received from overlord the sdp. This is happens when bridging
|
||||
// TODO: refactor
|
||||
oclient.receive(
|
||||
"initwebrtc",
|
||||
func(resp WSPacket) (req WSPacket) {
|
||||
log.Println("Received a sdp request from overlord")
|
||||
log.Println("Start peerconnection from the sdp")
|
||||
|
||||
localSession, err := s.peerconnection.StartClient(resp.Data, width, height)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
return WSPacket{
|
||||
ID: "sdp",
|
||||
Data: localSession,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
// Received start from overlord. This is happens when bridging
|
||||
// TODO: refactor
|
||||
oclient.receive(
|
||||
"start",
|
||||
func(resp WSPacket) (req WSPacket) {
|
||||
log.Println("Received a start request from overlord")
|
||||
log.Println("Add the connection to current room on the host")
|
||||
|
||||
roomID, isNewRoom := startSession(s.peerconnection, resp.Data, resp.RoomID, resp.PlayerIndex)
|
||||
// Bridge always access to old room
|
||||
// TODO: log warn
|
||||
if isNewRoom == true {
|
||||
log.Fatal("Bridge should not spawn new room")
|
||||
}
|
||||
|
||||
req.ID = "start"
|
||||
req.RoomID = roomID
|
||||
return req
|
||||
},
|
||||
)
|
||||
go oclient.listen()
|
||||
|
||||
s.oclient = oclient
|
||||
|
|
|
|||
68
overlord.go
68
overlord.go
|
|
@ -13,7 +13,7 @@ import (
|
|||
var roomToServer = map[string]string{}
|
||||
|
||||
// servers are the map serverID to server Client
|
||||
var servers = map[string]Client{}
|
||||
var servers = map[string]*Client{}
|
||||
|
||||
// If it's overlord, handle overlord connection (from host to overlord)
|
||||
func wso(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -29,7 +29,14 @@ func wso(w http.ResponseWriter, r *http.Request) {
|
|||
serverID := strconv.Itoa(rand.Int())
|
||||
log.Println("A new server connected ", serverID)
|
||||
|
||||
client := NewClient(c, webrtc.NewWebRTC())
|
||||
client := NewClient(c)
|
||||
servers[serverID] = client
|
||||
|
||||
wssession := &Session{
|
||||
client: client,
|
||||
peerconnection: webrtc.NewWebRTC(),
|
||||
// The server session is maintaining
|
||||
}
|
||||
|
||||
client.send(
|
||||
WSPacket{
|
||||
|
|
@ -61,5 +68,62 @@ func wso(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
})
|
||||
|
||||
client.receive("initwebrtc", func(resp WSPacket) WSPacket {
|
||||
log.Println("Received a relay sdp request from a host")
|
||||
// TODO: Abstract
|
||||
if resp.TargetHostID != serverID {
|
||||
log.Println("sending relay sdp to target host", resp.TargetHostID)
|
||||
// relay SDP to target host and get back sdp
|
||||
// TODO: Async
|
||||
sdp := servers[resp.TargetHostID].syncSend(
|
||||
resp,
|
||||
)
|
||||
|
||||
return sdp
|
||||
}
|
||||
log.Println("Target host is overlord itself: start peerconnection")
|
||||
// If the target is in master
|
||||
// start by its old
|
||||
localSession, err := wssession.peerconnection.StartClient(resp.Data, width, height)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
return WSPacket{
|
||||
ID: "sdp",
|
||||
Data: localSession,
|
||||
}
|
||||
})
|
||||
|
||||
// TODO: use relay ID type
|
||||
// TODO: Merge sdp and start
|
||||
client.receive("start", func(resp WSPacket) WSPacket {
|
||||
log.Println("Received a relay start request from a host")
|
||||
// TODO: Abstract
|
||||
if resp.TargetHostID != serverID {
|
||||
// relay SDP to target host and get back sdp
|
||||
// TODO: Async
|
||||
resp := servers[resp.TargetHostID].syncSend(
|
||||
resp,
|
||||
)
|
||||
|
||||
return resp
|
||||
}
|
||||
log.Println("Target host is overlord itself: start game")
|
||||
// If the target is in master
|
||||
// start by its old
|
||||
roomID, isNewRoom := startSession(wssession.peerconnection, resp.Data, resp.RoomID, resp.PlayerIndex)
|
||||
// Bridge always access to old room
|
||||
// TODO: log warn
|
||||
if isNewRoom == true {
|
||||
log.Fatal("Bridge should not spawn new room")
|
||||
}
|
||||
|
||||
return WSPacket{
|
||||
ID: "start",
|
||||
RoomID: roomID,
|
||||
}
|
||||
})
|
||||
|
||||
client.listen()
|
||||
}
|
||||
|
|
|
|||
12
static/js/ws.js
vendored
12
static/js/ws.js
vendored
|
|
@ -1,4 +1,5 @@
|
|||
var pc;
|
||||
var curPacketID = "";
|
||||
// web socket
|
||||
|
||||
conn = new WebSocket(`ws://${location.host}/ws`);
|
||||
|
|
@ -27,10 +28,10 @@ conn.onmessage = e => {
|
|||
log("Got remote sdp");
|
||||
pc.setRemoteDescription(new RTCSessionDescription(JSON.parse(atob(d["data"]))));
|
||||
break;
|
||||
//case "requestOffer":
|
||||
//pc.createOffer({offerToReceiveVideo: true, offerToReceiveAudio: false}).then(d => {
|
||||
//pc.setLocalDescription(d).catch(log);
|
||||
//})
|
||||
case "requestOffer":
|
||||
curPacketID = d["packet_id"];
|
||||
log("Received request offer ", curPacketID)
|
||||
startWebRTC();
|
||||
|
||||
//case "sdpremote":
|
||||
//log("Got remote sdp");
|
||||
|
|
@ -108,7 +109,8 @@ function startWebRTC() {
|
|||
session = btoa(JSON.stringify(pc.localDescription));
|
||||
localSessionDescription = session;
|
||||
log("Send SDP to remote peer");
|
||||
conn.send(JSON.stringify({"id": "initwebrtc", "data": session}));
|
||||
// TODO: Fix curPacketID
|
||||
conn.send(JSON.stringify({"id": "initwebrtc", "data": session, "packet_id": curPacketID}));
|
||||
} else {
|
||||
console.log(JSON.stringify(event.candidate));
|
||||
}
|
||||
|
|
|
|||
15
ws.go
15
ws.go
|
|
@ -7,15 +7,12 @@ import (
|
|||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/giongto35/cloud-game/webrtc"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
conn *websocket.Conn
|
||||
|
||||
peerconnection *webrtc.WebRTC
|
||||
|
||||
// sendCallback is callback based on packetID
|
||||
sendCallback map[string]func(req WSPacket)
|
||||
// recvCallback is callback when receive based on ID of the packet
|
||||
|
|
@ -30,20 +27,19 @@ type WSPacket struct {
|
|||
PlayerIndex int `json:"player_index"`
|
||||
|
||||
TargetHostID string `json:"target_id"`
|
||||
PacketID string
|
||||
PacketID string `json:"packet_id"`
|
||||
}
|
||||
|
||||
var EmptyPacket = WSPacket{}
|
||||
|
||||
func NewClient(conn *websocket.Conn, webrtc *webrtc.WebRTC) *Client {
|
||||
func NewClient(conn *websocket.Conn) *Client {
|
||||
sendCallback := map[string]func(WSPacket){}
|
||||
recvCallback := map[string]func(WSPacket){}
|
||||
return &Client{
|
||||
conn: conn,
|
||||
|
||||
peerconnection: webrtc,
|
||||
sendCallback: sendCallback,
|
||||
recvCallback: recvCallback,
|
||||
sendCallback: sendCallback,
|
||||
recvCallback: recvCallback,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -94,6 +90,7 @@ func (c *Client) syncSend(request WSPacket) (response WSPacket) {
|
|||
|
||||
func (c *Client) listen() {
|
||||
for {
|
||||
log.Println("Waiting for message")
|
||||
_, rawMsg, err := c.conn.ReadMessage()
|
||||
if err != nil {
|
||||
log.Println("[!] read:", err)
|
||||
|
|
@ -109,6 +106,8 @@ func (c *Client) listen() {
|
|||
if callback, ok := c.sendCallback[wspacket.PacketID]; ok {
|
||||
callback(wspacket)
|
||||
delete(c.sendCallback, wspacket.PacketID)
|
||||
// Skip receiveCallback to avoid duplication
|
||||
continue
|
||||
}
|
||||
// Check if some receiver with the ID is registered
|
||||
if callback, ok := c.recvCallback[wspacket.ID]; ok {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue