mirror of
https://github.com/jech/galene.git
synced 2024-11-22 16:45:58 +01:00
Send RTC configuration with joined message.
This avoids one HTTP request, and is potentially more flexible.
This commit is contained in:
parent
d09c0f0a80
commit
a0418d26ec
8 changed files with 121 additions and 101 deletions
|
@ -1 +0,0 @@
|
||||||
[]
|
|
|
@ -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()
|
go group.ReadPublicGroups()
|
||||||
|
|
||||||
|
|
|
@ -50,34 +50,6 @@ func (err ProtocolError) Error() string {
|
||||||
return string(err)
|
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 {
|
type ChatHistoryEntry struct {
|
||||||
Id string
|
Id string
|
||||||
User string
|
User string
|
||||||
|
|
78
group/ice.go
Normal file
78
group/ice.go
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
|
@ -138,7 +138,9 @@ type rtpDownConnection struct {
|
||||||
|
|
||||||
func newDownConn(c group.Client, id string, remote conn.Up) (*rtpDownConnection, error) {
|
func newDownConn(c group.Client, id string, remote conn.Up) (*rtpDownConnection, error) {
|
||||||
api := group.APIFromCodecs(remote.Codecs())
|
api := group.APIFromCodecs(remote.Codecs())
|
||||||
pc, err := api.NewPeerConnection(group.IceConfiguration())
|
pc, err := api.NewPeerConnection(
|
||||||
|
group.ToConfiguration(group.ICEConfiguration()),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,22 +161,23 @@ func (v rateMap) MarshalJSON() ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type clientMessage struct {
|
type clientMessage struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Kind string `json:"kind,omitempty"`
|
Kind string `json:"kind,omitempty"`
|
||||||
Id string `json:"id,omitempty"`
|
Id string `json:"id,omitempty"`
|
||||||
Dest string `json:"dest,omitempty"`
|
Dest string `json:"dest,omitempty"`
|
||||||
Username string `json:"username,omitempty"`
|
Username string `json:"username,omitempty"`
|
||||||
Password string `json:"password,omitempty"`
|
Password string `json:"password,omitempty"`
|
||||||
Privileged bool `json:"privileged,omitempty"`
|
Privileged bool `json:"privileged,omitempty"`
|
||||||
Permissions *group.ClientPermissions `json:"permissions,omitempty"`
|
Permissions *group.ClientPermissions `json:"permissions,omitempty"`
|
||||||
Group string `json:"group,omitempty"`
|
Group string `json:"group,omitempty"`
|
||||||
Value interface{} `json:"value,omitempty"`
|
Value interface{} `json:"value,omitempty"`
|
||||||
Time int64 `json:"time,omitempty"`
|
Time int64 `json:"time,omitempty"`
|
||||||
Offer *webrtc.SessionDescription `json:"offer,omitempty"`
|
Offer *webrtc.SessionDescription `json:"offer,omitempty"`
|
||||||
Answer *webrtc.SessionDescription `json:"answer,omitempty"`
|
Answer *webrtc.SessionDescription `json:"answer,omitempty"`
|
||||||
Candidate *webrtc.ICECandidateInit `json:"candidate,omitempty"`
|
Candidate *webrtc.ICECandidateInit `json:"candidate,omitempty"`
|
||||||
Labels map[string]string `json:"labels,omitempty"`
|
Labels map[string]string `json:"labels,omitempty"`
|
||||||
Request rateMap `json:"request,omitempty"`
|
Request rateMap `json:"request,omitempty"`
|
||||||
|
RTCConfiguration *group.RTCConfiguration `json:"rtcConfiguration,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type closeMessage struct {
|
type closeMessage struct {
|
||||||
|
@ -866,16 +867,17 @@ func clientLoop(c *webClient, ws *websocket.Conn) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
case permissionsChangedAction:
|
case permissionsChangedAction:
|
||||||
group := c.Group()
|
g := c.Group()
|
||||||
if group == nil {
|
if g == nil {
|
||||||
return errors.New("Permissions changed in no group")
|
return errors.New("Permissions changed in no group")
|
||||||
}
|
}
|
||||||
perms := c.permissions
|
perms := c.permissions
|
||||||
c.write(clientMessage{
|
c.write(clientMessage{
|
||||||
Type: "joined",
|
Type: "joined",
|
||||||
Kind: "change",
|
Kind: "change",
|
||||||
Group: group.Name(),
|
Group: g.Name(),
|
||||||
Permissions: &perms,
|
Permissions: &perms,
|
||||||
|
RTCConfiguration: group.ICEConfiguration(),
|
||||||
})
|
})
|
||||||
if !c.permissions.Present {
|
if !c.permissions.Present {
|
||||||
up := getUpConns(c)
|
up := getUpConns(c)
|
||||||
|
@ -1078,10 +1080,11 @@ func handleClientMessage(c *webClient, m clientMessage) error {
|
||||||
c.group = g
|
c.group = g
|
||||||
perms := c.permissions
|
perms := c.permissions
|
||||||
err = c.write(clientMessage{
|
err = c.write(clientMessage{
|
||||||
Type: "joined",
|
Type: "joined",
|
||||||
Kind: "join",
|
Kind: "join",
|
||||||
Group: m.Group,
|
Group: m.Group,
|
||||||
Permissions: &perms,
|
Permissions: &perms,
|
||||||
|
RTCConfiguration: group.ICEConfiguration(),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -85,9 +85,9 @@ function ServerConnection() {
|
||||||
/**
|
/**
|
||||||
* The ICE configuration used by all associated streams.
|
* The ICE configuration used by all associated streams.
|
||||||
*
|
*
|
||||||
* @type {RTCIceServer[]}
|
* @type {RTCConfiguration}
|
||||||
*/
|
*/
|
||||||
this.iceServers = null;
|
this.rtcConfiguration = null;
|
||||||
/**
|
/**
|
||||||
* The permissions granted to this connection.
|
* The permissions granted to this connection.
|
||||||
*
|
*
|
||||||
|
@ -183,6 +183,7 @@ function ServerConnection() {
|
||||||
* @property {RTCIceCandidate} [candidate]
|
* @property {RTCIceCandidate} [candidate]
|
||||||
* @property {Object<string,string>} [labels]
|
* @property {Object<string,string>} [labels]
|
||||||
* @property {Object<string,(boolean|number)>} [request]
|
* @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));
|
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.
|
* connect connects to the server.
|
||||||
*
|
*
|
||||||
|
@ -240,14 +221,6 @@ ServerConnection.prototype.connect = async function(url) {
|
||||||
sc.socket = null;
|
sc.socket = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!sc.iceServers) {
|
|
||||||
try {
|
|
||||||
await sc.getIceServers();
|
|
||||||
} catch(e) {
|
|
||||||
console.warn(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sc.socket = new WebSocket(url);
|
sc.socket = new WebSocket(url);
|
||||||
|
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
|
@ -311,7 +284,8 @@ ServerConnection.prototype.connect = async function(url) {
|
||||||
} else {
|
} else {
|
||||||
sc.group = m.group;
|
sc.group = m.group;
|
||||||
}
|
}
|
||||||
sc.permissions = m.permissions;
|
sc.permissions = m.permissions || [];
|
||||||
|
sc.rtcConfiguration = m.rtcConfiguration || null;
|
||||||
if(sc.onjoined)
|
if(sc.onjoined)
|
||||||
sc.onjoined.call(sc, m.kind, m.group,
|
sc.onjoined.call(sc, m.kind, m.group,
|
||||||
m.permissions || {},
|
m.permissions || {},
|
||||||
|
@ -432,9 +406,7 @@ ServerConnection.prototype.newUpStream = function(id) {
|
||||||
if(sc.up[id])
|
if(sc.up[id])
|
||||||
throw new Error('Eek!');
|
throw new Error('Eek!');
|
||||||
}
|
}
|
||||||
let pc = new RTCPeerConnection({
|
let pc = new RTCPeerConnection(sc.rtcConfiguration);
|
||||||
iceServers: sc.iceServers || [],
|
|
||||||
});
|
|
||||||
if(!pc)
|
if(!pc)
|
||||||
throw new Error("Couldn't create peer connection");
|
throw new Error("Couldn't create peer connection");
|
||||||
if(sc.up[id]) {
|
if(sc.up[id]) {
|
||||||
|
@ -568,9 +540,7 @@ ServerConnection.prototype.gotOffer = async function(id, labels, offer, renegoti
|
||||||
throw new Error('Duplicate connection id');
|
throw new Error('Duplicate connection id');
|
||||||
|
|
||||||
if(!c) {
|
if(!c) {
|
||||||
let pc = new RTCPeerConnection({
|
let pc = new RTCPeerConnection(sc.rtcConfiguration);
|
||||||
iceServers: this.iceServers,
|
|
||||||
});
|
|
||||||
c = new Stream(this, id, pc, false);
|
c = new Stream(this, id, pc, false);
|
||||||
sc.down[id] = c;
|
sc.down[id] = c;
|
||||||
|
|
||||||
|
|
|
@ -45,12 +45,6 @@ func Serve(address string, dataDir string) error {
|
||||||
})
|
})
|
||||||
http.HandleFunc("/recordings/", recordingsHandler)
|
http.HandleFunc("/recordings/", recordingsHandler)
|
||||||
http.HandleFunc("/ws", wsHandler)
|
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("/public-groups.json", publicHandler)
|
||||||
http.HandleFunc("/stats", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/stats", func(w http.ResponseWriter, r *http.Request) {
|
||||||
statsHandler(w, r, dataDir)
|
statsHandler(w, r, dataDir)
|
||||||
|
|
Loading…
Reference in a new issue