1
Fork 0

Send RTC configuration with joined message.

This avoids one HTTP request, and is potentially more flexible.
This commit is contained in:
Juliusz Chroboczek 2020-12-28 02:25:46 +01:00
parent d09c0f0a80
commit a0418d26ec
8 changed files with 121 additions and 101 deletions

View File

@ -1 +0,0 @@
[]

View File

@ -79,7 +79,7 @@ func main() {
}()
}
group.IceFilename = filepath.Join(dataDir, "ice-servers.json")
group.ICEFilename = filepath.Join(dataDir, "ice-servers.json")
go group.ReadPublicGroups()

View File

@ -50,34 +50,6 @@ func (err ProtocolError) Error() string {
return string(err)
}
var IceFilename string
var iceConf webrtc.Configuration
var iceOnce sync.Once
func IceConfiguration() webrtc.Configuration {
iceOnce.Do(func() {
var iceServers []webrtc.ICEServer
file, err := os.Open(IceFilename)
if err != nil {
log.Printf("Open %v: %v", IceFilename, err)
return
}
defer file.Close()
d := json.NewDecoder(file)
err = d.Decode(&iceServers)
if err != nil {
log.Printf("Get ICE configuration: %v", err)
return
}
iceConf = webrtc.Configuration{
ICEServers: iceServers,
}
})
return iceConf
}
type ChatHistoryEntry struct {
Id string
User string

78
group/ice.go Normal file
View File

@ -0,0 +1,78 @@
package group
import (
"encoding/json"
"log"
"os"
"sync"
"github.com/pion/webrtc/v3"
)
type ICEServer struct {
URLs []string `json:"urls"`
Username string `json:"username,omitempty"`
Credential interface{} `json:"credential,omitempty"`
CredentialType string `json:"credentialType,omitempty"`
}
type RTCConfiguration struct {
ICEServers []ICEServer `json:"iceServers,omitempty"`
ICETransportPolicy string `json:"iceTransportPolicy,omitempty"`
}
var ICEFilename string
var iceConf RTCConfiguration
var iceOnce sync.Once
func ICEConfiguration() *RTCConfiguration {
iceOnce.Do(func() {
var iceServers []ICEServer
file, err := os.Open(ICEFilename)
if err != nil {
log.Printf("Open %v: %v", ICEFilename, err)
return
}
defer file.Close()
d := json.NewDecoder(file)
err = d.Decode(&iceServers)
if err != nil {
log.Printf("Get ICE configuration: %v", err)
return
}
iceConf = RTCConfiguration{
ICEServers: iceServers,
}
})
return &iceConf
}
func ToConfiguration(conf *RTCConfiguration) webrtc.Configuration {
var iceServers []webrtc.ICEServer
for _, s := range conf.ICEServers {
tpe := webrtc.ICECredentialTypePassword
if s.CredentialType == "oauth" {
tpe = webrtc.ICECredentialTypeOauth
}
iceServers = append(iceServers,
webrtc.ICEServer{
URLs: s.URLs,
Username: s.Username,
Credential: s.Credential,
CredentialType: tpe,
},
)
}
policy := webrtc.ICETransportPolicyAll
if conf.ICETransportPolicy == "relay" {
policy = webrtc.ICETransportPolicyRelay
}
return webrtc.Configuration{
ICEServers: iceServers,
ICETransportPolicy: policy,
}
}

View File

@ -138,7 +138,9 @@ type rtpDownConnection struct {
func newDownConn(c group.Client, id string, remote conn.Up) (*rtpDownConnection, error) {
api := group.APIFromCodecs(remote.Codecs())
pc, err := api.NewPeerConnection(group.IceConfiguration())
pc, err := api.NewPeerConnection(
group.ToConfiguration(group.ICEConfiguration()),
)
if err != nil {
return nil, err
}
@ -457,7 +459,9 @@ func pushConn(up *rtpUpConnection, g *group.Group, cs []group.Client) {
}
func newUpConn(c group.Client, id string, labels map[string]string) (*rtpUpConnection, error) {
pc, err := c.Group().API().NewPeerConnection(group.IceConfiguration())
pc, err := c.Group().API().NewPeerConnection(
group.ToConfiguration(group.ICEConfiguration()),
)
if err != nil {
return nil, err
}

View File

@ -161,22 +161,23 @@ func (v rateMap) MarshalJSON() ([]byte, error) {
}
type clientMessage struct {
Type string `json:"type"`
Kind string `json:"kind,omitempty"`
Id string `json:"id,omitempty"`
Dest string `json:"dest,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
Privileged bool `json:"privileged,omitempty"`
Permissions *group.ClientPermissions `json:"permissions,omitempty"`
Group string `json:"group,omitempty"`
Value interface{} `json:"value,omitempty"`
Time int64 `json:"time,omitempty"`
Offer *webrtc.SessionDescription `json:"offer,omitempty"`
Answer *webrtc.SessionDescription `json:"answer,omitempty"`
Candidate *webrtc.ICECandidateInit `json:"candidate,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
Request rateMap `json:"request,omitempty"`
Type string `json:"type"`
Kind string `json:"kind,omitempty"`
Id string `json:"id,omitempty"`
Dest string `json:"dest,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
Privileged bool `json:"privileged,omitempty"`
Permissions *group.ClientPermissions `json:"permissions,omitempty"`
Group string `json:"group,omitempty"`
Value interface{} `json:"value,omitempty"`
Time int64 `json:"time,omitempty"`
Offer *webrtc.SessionDescription `json:"offer,omitempty"`
Answer *webrtc.SessionDescription `json:"answer,omitempty"`
Candidate *webrtc.ICECandidateInit `json:"candidate,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
Request rateMap `json:"request,omitempty"`
RTCConfiguration *group.RTCConfiguration `json:"rtcConfiguration,omitempty"`
}
type closeMessage struct {
@ -866,16 +867,17 @@ func clientLoop(c *webClient, ws *websocket.Conn) error {
}
case permissionsChangedAction:
group := c.Group()
if group == nil {
g := c.Group()
if g == nil {
return errors.New("Permissions changed in no group")
}
perms := c.permissions
c.write(clientMessage{
Type: "joined",
Kind: "change",
Group: group.Name(),
Permissions: &perms,
Type: "joined",
Kind: "change",
Group: g.Name(),
Permissions: &perms,
RTCConfiguration: group.ICEConfiguration(),
})
if !c.permissions.Present {
up := getUpConns(c)
@ -1078,10 +1080,11 @@ func handleClientMessage(c *webClient, m clientMessage) error {
c.group = g
perms := c.permissions
err = c.write(clientMessage{
Type: "joined",
Kind: "join",
Group: m.Group,
Permissions: &perms,
Type: "joined",
Kind: "join",
Group: m.Group,
Permissions: &perms,
RTCConfiguration: group.ICEConfiguration(),
})
if err != nil {
return err

View File

@ -85,9 +85,9 @@ function ServerConnection() {
/**
* The ICE configuration used by all associated streams.
*
* @type {RTCIceServer[]}
* @type {RTCConfiguration}
*/
this.iceServers = null;
this.rtcConfiguration = null;
/**
* The permissions granted to this connection.
*
@ -183,6 +183,7 @@ function ServerConnection() {
* @property {RTCIceCandidate} [candidate]
* @property {Object<string,string>} [labels]
* @property {Object<string,(boolean|number)>} [request]
* @property {Object<string,any>} [rtcConfiguration]
*/
/**
@ -206,26 +207,6 @@ ServerConnection.prototype.send = function(m) {
return this.socket.send(JSON.stringify(m));
}
/**
* getIceServers fetches an ICE configuration from the server and
* populates the iceServers field of a ServerConnection. It is called
* lazily by connect.
*
* @returns {Promise<RTCIceServer[]>}
* @function
*/
ServerConnection.prototype.getIceServers = async function() {
let r = await fetch('/ice-servers.json');
if(!r.ok)
throw new Error("Couldn't fetch ICE servers: " +
r.status + ' ' + r.statusText);
let servers = await r.json();
if(!(servers instanceof Array))
throw new Error("couldn't parse ICE servers");
this.iceServers = servers;
return servers;
}
/**
* connect connects to the server.
*
@ -240,14 +221,6 @@ ServerConnection.prototype.connect = async function(url) {
sc.socket = null;
}
if(!sc.iceServers) {
try {
await sc.getIceServers();
} catch(e) {
console.warn(e);
}
}
sc.socket = new WebSocket(url);
return await new Promise((resolve, reject) => {
@ -311,7 +284,8 @@ ServerConnection.prototype.connect = async function(url) {
} else {
sc.group = m.group;
}
sc.permissions = m.permissions;
sc.permissions = m.permissions || [];
sc.rtcConfiguration = m.rtcConfiguration || null;
if(sc.onjoined)
sc.onjoined.call(sc, m.kind, m.group,
m.permissions || {},
@ -432,9 +406,7 @@ ServerConnection.prototype.newUpStream = function(id) {
if(sc.up[id])
throw new Error('Eek!');
}
let pc = new RTCPeerConnection({
iceServers: sc.iceServers || [],
});
let pc = new RTCPeerConnection(sc.rtcConfiguration);
if(!pc)
throw new Error("Couldn't create peer connection");
if(sc.up[id]) {
@ -568,9 +540,7 @@ ServerConnection.prototype.gotOffer = async function(id, labels, offer, renegoti
throw new Error('Duplicate connection id');
if(!c) {
let pc = new RTCPeerConnection({
iceServers: this.iceServers,
});
let pc = new RTCPeerConnection(sc.rtcConfiguration);
c = new Stream(this, id, pc, false);
sc.down[id] = c;

View File

@ -45,12 +45,6 @@ func Serve(address string, dataDir string) error {
})
http.HandleFunc("/recordings/", recordingsHandler)
http.HandleFunc("/ws", wsHandler)
http.HandleFunc("/ice-servers.json",
func(w http.ResponseWriter, r *http.Request) {
mungeHeader(w)
serveFile(w, r,
filepath.Join(dataDir, "ice-servers.json"))
})
http.HandleFunc("/public-groups.json", publicHandler)
http.HandleFunc("/stats", func(w http.ResponseWriter, r *http.Request) {
statsHandler(w, r, dataDir)