mirror of
https://github.com/jech/galene.git
synced 2024-11-10 02:35:58 +01:00
240 lines
4 KiB
Go
240 lines
4 KiB
Go
|
// Copyright (c) 2020 by Juliusz Chroboczek.
|
||
|
|
||
|
// This is not open source software. Copy it, and I'll break into your
|
||
|
// house and tell your three year-old that Santa doesn't exist.
|
||
|
|
||
|
package main
|
||
|
|
||
|
import (
|
||
|
"log"
|
||
|
"sync"
|
||
|
|
||
|
"github.com/pion/webrtc/v2"
|
||
|
)
|
||
|
|
||
|
type trackPair struct {
|
||
|
remote, local *webrtc.Track
|
||
|
}
|
||
|
|
||
|
type upConnection struct {
|
||
|
id string
|
||
|
label string
|
||
|
pc *webrtc.PeerConnection
|
||
|
maxAudioBitrate uint32
|
||
|
maxVideoBitrate uint32
|
||
|
streamCount int
|
||
|
pairs []trackPair
|
||
|
}
|
||
|
|
||
|
type downConnection struct {
|
||
|
id string
|
||
|
pc *webrtc.PeerConnection
|
||
|
remote *upConnection
|
||
|
maxBitrate uint32
|
||
|
}
|
||
|
|
||
|
type client struct {
|
||
|
group *group
|
||
|
id string
|
||
|
username string
|
||
|
done chan struct{}
|
||
|
writeCh chan interface{}
|
||
|
writerDone chan struct{}
|
||
|
actionCh chan interface{}
|
||
|
down map[string]*downConnection
|
||
|
up map[string]*upConnection
|
||
|
}
|
||
|
|
||
|
type group struct {
|
||
|
name string
|
||
|
public bool
|
||
|
|
||
|
mu sync.Mutex
|
||
|
clients []*client
|
||
|
}
|
||
|
|
||
|
type delPCAction struct {
|
||
|
id string
|
||
|
}
|
||
|
|
||
|
type addTrackAction struct {
|
||
|
id string
|
||
|
track *webrtc.Track
|
||
|
remote *upConnection
|
||
|
done bool
|
||
|
}
|
||
|
|
||
|
type addLabelAction struct {
|
||
|
id string
|
||
|
label string
|
||
|
}
|
||
|
|
||
|
type getUpAction struct {
|
||
|
ch chan<- string
|
||
|
}
|
||
|
|
||
|
type pushTracksAction struct {
|
||
|
c *client
|
||
|
}
|
||
|
|
||
|
var groups struct {
|
||
|
mu sync.Mutex
|
||
|
groups map[string]*group
|
||
|
api *webrtc.API
|
||
|
}
|
||
|
|
||
|
func addGroup(name string) (*group, error) {
|
||
|
groups.mu.Lock()
|
||
|
defer groups.mu.Unlock()
|
||
|
|
||
|
if groups.groups == nil {
|
||
|
groups.groups = make(map[string]*group)
|
||
|
m := webrtc.MediaEngine{}
|
||
|
m.RegisterCodec(webrtc.NewRTPVP8Codec(
|
||
|
webrtc.DefaultPayloadTypeVP8, 90000))
|
||
|
m.RegisterCodec(webrtc.NewRTPOpusCodec(
|
||
|
webrtc.DefaultPayloadTypeOpus, 48000))
|
||
|
groups.api = webrtc.NewAPI(
|
||
|
webrtc.WithMediaEngine(m),
|
||
|
)
|
||
|
}
|
||
|
|
||
|
g := groups.groups[name]
|
||
|
|
||
|
if g == nil {
|
||
|
g = &group{
|
||
|
name: name,
|
||
|
}
|
||
|
groups.groups[name] = g
|
||
|
}
|
||
|
|
||
|
return g, nil
|
||
|
}
|
||
|
|
||
|
func delGroup(name string) bool {
|
||
|
groups.mu.Lock()
|
||
|
defer groups.mu.Unlock()
|
||
|
|
||
|
g := groups.groups[name]
|
||
|
if g == nil {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
if len(g.clients) != 0 {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
delete(groups.groups, name)
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
type userid struct {
|
||
|
id string
|
||
|
username string
|
||
|
}
|
||
|
|
||
|
func addClient(name string, client *client) (*group, []userid, error) {
|
||
|
g, err := addGroup(name)
|
||
|
if err != nil {
|
||
|
return nil, nil, err
|
||
|
}
|
||
|
|
||
|
var users []userid
|
||
|
g.mu.Lock()
|
||
|
defer g.mu.Unlock()
|
||
|
for _, c := range g.clients {
|
||
|
users = append(users, userid{c.id, c.username})
|
||
|
}
|
||
|
g.clients = append(g.clients, client)
|
||
|
return g, users, nil
|
||
|
}
|
||
|
|
||
|
func delClient(c *client) {
|
||
|
c.group.mu.Lock()
|
||
|
defer c.group.mu.Unlock()
|
||
|
g := c.group
|
||
|
for i, cc := range g.clients {
|
||
|
if cc == c {
|
||
|
g.clients =
|
||
|
append(g.clients[:i], g.clients[i+1:]...)
|
||
|
c.group = nil
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
log.Printf("Deleting unknown client")
|
||
|
c.group = nil
|
||
|
}
|
||
|
|
||
|
func (g *group) getClients(except *client) []*client {
|
||
|
g.mu.Lock()
|
||
|
defer g.mu.Unlock()
|
||
|
clients := make([]*client, 0, len(g.clients))
|
||
|
for _, c := range g.clients {
|
||
|
if c != except {
|
||
|
clients = append(clients, c)
|
||
|
}
|
||
|
}
|
||
|
return clients
|
||
|
}
|
||
|
|
||
|
func (g *group) Range(f func(c *client) bool) {
|
||
|
g.mu.Lock()
|
||
|
defer g.mu.Unlock()
|
||
|
for _, c := range g.clients {
|
||
|
ok := f(c)
|
||
|
if(!ok){
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type writerDeadError int
|
||
|
|
||
|
func (err writerDeadError) Error() string {
|
||
|
return "client writer died"
|
||
|
}
|
||
|
|
||
|
func (c *client) write(m clientMessage) error {
|
||
|
select {
|
||
|
case c.writeCh <- m:
|
||
|
return nil
|
||
|
case <-c.writerDone:
|
||
|
return writerDeadError(0)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type clientDeadError int
|
||
|
|
||
|
func (err clientDeadError) Error() string {
|
||
|
return "client dead"
|
||
|
}
|
||
|
|
||
|
func (c *client) action(m interface{}) error {
|
||
|
select {
|
||
|
case c.actionCh <- m:
|
||
|
return nil
|
||
|
case <-c.done:
|
||
|
return clientDeadError(0)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type publicGroup struct {
|
||
|
Name string `json:"name"`
|
||
|
ClientCount int `json:"clientCount"`
|
||
|
}
|
||
|
|
||
|
func getPublicGroups() []publicGroup {
|
||
|
gs := make([]publicGroup, 0)
|
||
|
groups.mu.Lock()
|
||
|
defer groups.mu.Unlock()
|
||
|
for _, g := range groups.groups {
|
||
|
if g.public {
|
||
|
gs = append(gs, publicGroup{
|
||
|
Name: g.name,
|
||
|
ClientCount: len(g.clients),
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
return gs
|
||
|
}
|