Checkpoint audio-only Skald fork work
This commit is contained in:
+22
-22
@@ -151,7 +151,7 @@ func (u UserDescription) MarshalJSON() ([]byte, error) {
|
||||
// about the JSON file it was deserialised from.
|
||||
type Description struct {
|
||||
// The file this was deserialised from. This is not necessarily
|
||||
// the name of the hall, for example in case of a subgroup.
|
||||
// the name of the hall, for example in case of a subhall.
|
||||
FileName string `json:"-"`
|
||||
|
||||
// The modtime and size of the file. These are used to detect
|
||||
@@ -159,8 +159,8 @@ type Description struct {
|
||||
modTime time.Time `json:"-"`
|
||||
fileSize int64 `json:"-"`
|
||||
|
||||
// Whether this is an automatically generated subgroup
|
||||
isSubgroup bool `json:"-"`
|
||||
// Whether this is an automatically generated subhall
|
||||
isSubhall bool `json:"-"`
|
||||
|
||||
// The user-friendly hall name
|
||||
DisplayName string `json:"displayName,omitempty"`
|
||||
@@ -199,8 +199,8 @@ type Description struct {
|
||||
// Whether creating tokens is allowed
|
||||
UnrestrictedTokens bool `json:"unrestricted-tokens,omitempty"`
|
||||
|
||||
// Whether subgroups are created on the fly.
|
||||
AutoSubgroups bool `json:"auto-subgroups,omitempty"`
|
||||
// Whether subhalls are created on the fly.
|
||||
AutoSubhalls bool `json:"auto-subhalls,omitempty"`
|
||||
|
||||
// Whether to lock the hall when the last op logs out.
|
||||
Autolock bool `json:"autolock,omitempty"`
|
||||
@@ -231,7 +231,7 @@ type Description struct {
|
||||
Op []ClientPattern `json:"op,omitempty"`
|
||||
Presenter []ClientPattern `json:"presenter,omitempty"`
|
||||
Other []ClientPattern `json:"other,omitempty"`
|
||||
AllowSubgroups bool `json:"allow-subgroups,omitempty"`
|
||||
AllowSubhalls bool `json:"allow-subhalls,omitempty"`
|
||||
AllowAnonymous bool `json:"allow-anonymous,omitempty"`
|
||||
}
|
||||
|
||||
@@ -244,20 +244,20 @@ func maxHistoryAge(desc *Description) time.Duration {
|
||||
return DefaultMaxHistoryAge
|
||||
}
|
||||
|
||||
func getDescriptionFile[T any](name string, allowSubgroups bool, get func(string) (T, error)) (T, string, bool, error) {
|
||||
isSubgroup := false
|
||||
func getDescriptionFile[T any](name string, allowSubhalls bool, get func(string) (T, error)) (T, string, bool, error) {
|
||||
isSubhall := false
|
||||
for name != "" {
|
||||
fileName := filepath.Join(
|
||||
Directory, path.Clean("/"+name)+".json",
|
||||
)
|
||||
r, err := get(fileName)
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
return r, fileName, isSubgroup, err
|
||||
return r, fileName, isSubhall, err
|
||||
}
|
||||
if !allowSubgroups {
|
||||
if !allowSubhalls {
|
||||
break
|
||||
}
|
||||
isSubgroup = true
|
||||
isSubhall = true
|
||||
name, _ = path.Split(name)
|
||||
name = strings.TrimRight(name, "/")
|
||||
}
|
||||
@@ -311,7 +311,7 @@ func GetSanitisedDescription(name string) (*Description, string, error) {
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if d.isSubgroup {
|
||||
if d.isSubhall {
|
||||
return nil, "", os.ErrNotExist
|
||||
}
|
||||
|
||||
@@ -395,7 +395,7 @@ func rewriteDescriptionFile(filename string, desc *Description) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !conf.WritableGroups {
|
||||
if !conf.WritableHalls {
|
||||
return ErrDescriptionsNotWritable
|
||||
}
|
||||
|
||||
@@ -439,9 +439,9 @@ func rewriteDescriptionFile(filename string, desc *Description) error {
|
||||
}
|
||||
|
||||
// readDescription reads a hall's description from disk
|
||||
func readDescription(name string, allowSubgroups bool) (*Description, error) {
|
||||
r, fileName, isSubgroup, err :=
|
||||
getDescriptionFile(name, allowSubgroups, os.Open)
|
||||
func readDescription(name string, allowSubhalls bool) (*Description, error) {
|
||||
r, fileName, isSubhall, err :=
|
||||
getDescriptionFile(name, allowSubhalls, os.Open)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -469,11 +469,11 @@ func readDescription(name string, allowSubgroups bool) (*Description, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if isSubgroup {
|
||||
if !desc.AutoSubgroups {
|
||||
if isSubhall {
|
||||
if !desc.AutoSubhalls {
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
desc.isSubgroup = true
|
||||
desc.isSubhall = true
|
||||
desc.Public = false
|
||||
desc.Description = ""
|
||||
}
|
||||
@@ -490,9 +490,9 @@ func upgradeDescription(desc *Description) error {
|
||||
desc.AllowAnonymous = false
|
||||
}
|
||||
|
||||
if desc.AllowSubgroups {
|
||||
desc.AutoSubgroups = true
|
||||
desc.AllowSubgroups = false
|
||||
if desc.AllowSubhalls {
|
||||
desc.AutoSubhalls = true
|
||||
desc.AllowSubhalls = false
|
||||
}
|
||||
|
||||
upgradePassword := func(pw *Password) Password {
|
||||
|
||||
+19
-19
@@ -59,12 +59,12 @@ func TestEmptyJSON(t *testing.T) {
|
||||
var descJSON = `
|
||||
{
|
||||
"max-history-age": 10,
|
||||
"auto-subgroups": true,
|
||||
"auto-subhalls": true,
|
||||
"users": {
|
||||
"jch": {"password": "topsecret", "permissions": "op"},
|
||||
"john": {"password": "secret", "permissions": "present"},
|
||||
"james": {"password": "secret2", "permissions": "message"},
|
||||
"peter": {"password": "secret4"}
|
||||
"user1": {"password": "topsecret", "permissions": "op"},
|
||||
"user2": {"password": "secret", "permissions": "present"},
|
||||
"user3": {"password": "secret2", "permissions": "message"},
|
||||
"user4": {"password": "secret4"}
|
||||
},
|
||||
"wildcard-user":
|
||||
{"permissions": "message", "password": {"type":"wildcard"}}
|
||||
@@ -95,15 +95,15 @@ func TestDescriptionJSON(t *testing.T) {
|
||||
|
||||
var obsoleteJSON = `
|
||||
{
|
||||
"op": [{"username": "jch","password": "topsecret"}],
|
||||
"op": [{"username": "user1","password": "topsecret"}],
|
||||
"max-history-age": 10,
|
||||
"allow-subgroups": true,
|
||||
"allow-subhalls": true,
|
||||
"presenter": [
|
||||
{"username": "john", "password": "secret"}
|
||||
{"username": "user2", "password": "secret"}
|
||||
],
|
||||
"other": [
|
||||
{"username": "james", "password": "secret2"},
|
||||
{"username": "peter", "password": "secret4"},
|
||||
{"username": "user3", "password": "secret2"},
|
||||
{"username": "user4", "password": "secret4"},
|
||||
{}
|
||||
]
|
||||
}`
|
||||
@@ -124,9 +124,9 @@ func TestUpgradeDescription(t *testing.T) {
|
||||
t.Fatalf("upgradeDescription: %v", err)
|
||||
}
|
||||
|
||||
if d1.AutoSubgroups != d2.AutoSubgroups ||
|
||||
d1.AllowSubgroups != d2.AllowSubgroups {
|
||||
t.Errorf("AllowSubgroups not upgraded correctly")
|
||||
if d1.AutoSubhalls != d2.AutoSubhalls ||
|
||||
d1.AllowSubhalls != d2.AllowSubhalls {
|
||||
t.Errorf("AllowSubhalls not upgraded correctly")
|
||||
}
|
||||
|
||||
if d2.Op != nil || d2.Presenter != nil || d2.Other != nil {
|
||||
@@ -139,7 +139,7 @@ func TestUpgradeDescription(t *testing.T) {
|
||||
}
|
||||
|
||||
for k, v1 := range d1.Users {
|
||||
if k == "peter" {
|
||||
if k == "user4" {
|
||||
// not representable in the old format
|
||||
continue
|
||||
}
|
||||
@@ -176,13 +176,13 @@ func setupTest(dir, datadir string, writable bool) error {
|
||||
defer f.Close()
|
||||
conf := `{}`
|
||||
if writable {
|
||||
conf = `{"writableGroups": true}`
|
||||
conf = `{"writableHalls": true}`
|
||||
}
|
||||
_, err = f.WriteString(conf)
|
||||
return err
|
||||
}
|
||||
|
||||
func TestNonWritableGroups(t *testing.T) {
|
||||
func TestNonWritableHalls(t *testing.T) {
|
||||
err := setupTest(t.TempDir(), t.TempDir(), false)
|
||||
if err != nil {
|
||||
t.Fatalf("setupTest: %v", err)
|
||||
@@ -200,7 +200,7 @@ func TestNonWritableGroups(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestWritableGroups(t *testing.T) {
|
||||
func TestWritableHalls(t *testing.T) {
|
||||
err := setupTest(t.TempDir(), t.TempDir(), true)
|
||||
if err != nil {
|
||||
t.Fatalf("setupTest: %v", err)
|
||||
@@ -259,7 +259,7 @@ func TestWritableGroups(t *testing.T) {
|
||||
nil, "Test", err, desc.AllowAnonymous,
|
||||
)
|
||||
}
|
||||
testUser(t, "jch", false)
|
||||
testUser(t, "user1", false)
|
||||
testUser(t, "", true)
|
||||
}
|
||||
|
||||
@@ -308,7 +308,7 @@ func testUser(t *testing.T, username string, wildcard bool) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubGroup(t *testing.T) {
|
||||
func TestSubHall(t *testing.T) {
|
||||
err := setupTest(t.TempDir(), t.TempDir(), true)
|
||||
if err != nil {
|
||||
t.Fatalf("setupTest: %v", err)
|
||||
|
||||
+28
-111
@@ -216,39 +216,6 @@ func fmtpValue(fmtp, key string) string {
|
||||
|
||||
func CodecPayloadType(codec webrtc.RTPCodecCapability) (webrtc.PayloadType, error) {
|
||||
switch strings.ToLower(codec.MimeType) {
|
||||
case "video/vp8":
|
||||
return 96, nil
|
||||
case "video/vp9":
|
||||
profile := fmtpValue(codec.SDPFmtpLine, "profile-id")
|
||||
switch profile {
|
||||
case "", "0":
|
||||
return 98, nil
|
||||
case "2":
|
||||
return 100, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("unknown VP9 profile %v", profile)
|
||||
|
||||
}
|
||||
case "video/av1":
|
||||
return 35, nil
|
||||
case "video/h264":
|
||||
profile := fmtpValue(codec.SDPFmtpLine, "profile-level-id")
|
||||
if profile == "" {
|
||||
return 102, nil
|
||||
}
|
||||
if len(profile) < 4 {
|
||||
return 0, errors.New("malforned H.264 profile")
|
||||
}
|
||||
switch strings.ToLower(profile[:4]) {
|
||||
case "4200":
|
||||
return 102, nil
|
||||
case "42e0":
|
||||
return 108, nil
|
||||
default:
|
||||
return 0, fmt.Errorf(
|
||||
"unknown H.264 profile %v", profile,
|
||||
)
|
||||
}
|
||||
case "audio/opus":
|
||||
return 111, nil
|
||||
case "audio/g722":
|
||||
@@ -262,89 +229,48 @@ func CodecPayloadType(codec webrtc.RTPCodecCapability) (webrtc.PayloadType, erro
|
||||
}
|
||||
}
|
||||
|
||||
// VideoRTCPFeedback are the RTCP feedback types that we expect for video
|
||||
// tracks.
|
||||
var VideoRTCPFeedback = []webrtc.RTCPFeedback{
|
||||
{"goog-remb", ""},
|
||||
{"nack", ""},
|
||||
{"nack", "pli"},
|
||||
{"ccm", "fir"},
|
||||
}
|
||||
|
||||
// AudioRTCPFeedback is like VideoRTCPFeedback but for audio tracks.
|
||||
// AudioRTCPFeedback is the RTCP feedback for audio tracks.
|
||||
var AudioRTCPFeedback = []webrtc.RTCPFeedback(nil)
|
||||
|
||||
func codecsFromName(name string) ([]webrtc.RTPCodecParameters, error) {
|
||||
var codecs []webrtc.RTPCodecCapability
|
||||
|
||||
switch name {
|
||||
case "vp8":
|
||||
codecs = []webrtc.RTPCodecCapability{
|
||||
{
|
||||
"video/VP8", 90000, 0,
|
||||
"",
|
||||
VideoRTCPFeedback,
|
||||
},
|
||||
}
|
||||
case "vp9":
|
||||
codecs = []webrtc.RTPCodecCapability{
|
||||
{
|
||||
"video/VP9", 90000, 0,
|
||||
"profile-id=0",
|
||||
VideoRTCPFeedback,
|
||||
},
|
||||
{
|
||||
"video/VP9", 90000, 0,
|
||||
"profile-id=2",
|
||||
VideoRTCPFeedback,
|
||||
},
|
||||
}
|
||||
case "av1":
|
||||
codecs = []webrtc.RTPCodecCapability{
|
||||
{
|
||||
"video/AV1", 90000, 0,
|
||||
"",
|
||||
VideoRTCPFeedback,
|
||||
},
|
||||
}
|
||||
case "h264":
|
||||
codecs = []webrtc.RTPCodecCapability{
|
||||
{
|
||||
"video/H264", 90000, 0,
|
||||
"level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f",
|
||||
VideoRTCPFeedback,
|
||||
},
|
||||
}
|
||||
case "opus":
|
||||
codecs = []webrtc.RTPCodecCapability{
|
||||
{
|
||||
"audio/opus", 48000, 2,
|
||||
"minptime=10;useinbandfec=1;stereo=1;sprop-stereo=1",
|
||||
AudioRTCPFeedback,
|
||||
MimeType: "audio/opus",
|
||||
ClockRate: 48000,
|
||||
Channels: 2,
|
||||
SDPFmtpLine: "minptime=10;useinbandfec=1;stereo=1;sprop-stereo=1",
|
||||
RTCPFeedback: AudioRTCPFeedback,
|
||||
},
|
||||
}
|
||||
case "g722":
|
||||
codecs = []webrtc.RTPCodecCapability{
|
||||
{
|
||||
"audio/G722", 8000, 1,
|
||||
"",
|
||||
AudioRTCPFeedback,
|
||||
MimeType: "audio/G722",
|
||||
ClockRate: 8000,
|
||||
Channels: 1,
|
||||
RTCPFeedback: AudioRTCPFeedback,
|
||||
},
|
||||
}
|
||||
case "pcmu":
|
||||
codecs = []webrtc.RTPCodecCapability{
|
||||
{
|
||||
"audio/PCMU", 8000, 1,
|
||||
"",
|
||||
AudioRTCPFeedback,
|
||||
MimeType: "audio/PCMU",
|
||||
ClockRate: 8000,
|
||||
Channels: 1,
|
||||
RTCPFeedback: AudioRTCPFeedback,
|
||||
},
|
||||
}
|
||||
case "pcma":
|
||||
codecs = []webrtc.RTPCodecCapability{
|
||||
{
|
||||
"audio/PCMA", 8000, 1,
|
||||
"",
|
||||
AudioRTCPFeedback,
|
||||
MimeType: "audio/PCMA",
|
||||
ClockRate: 8000,
|
||||
Channels: 1,
|
||||
RTCPFeedback: AudioRTCPFeedback,
|
||||
},
|
||||
}
|
||||
default:
|
||||
@@ -384,11 +310,7 @@ func APIFromCodecs(codecs []webrtc.RTPCodecParameters) (*webrtc.API, error) {
|
||||
m := webrtc.MediaEngine{}
|
||||
|
||||
for _, codec := range codecs {
|
||||
tpe := webrtc.RTPCodecTypeVideo
|
||||
if strings.HasPrefix(strings.ToLower(codec.MimeType), "audio/") {
|
||||
tpe = webrtc.RTPCodecTypeAudio
|
||||
}
|
||||
err := m.RegisterCodec(codec, tpe)
|
||||
err := m.RegisterCodec(codec, webrtc.RTPCodecTypeAudio)
|
||||
if err != nil {
|
||||
log.Printf("%v", err)
|
||||
continue
|
||||
@@ -401,11 +323,6 @@ func APIFromCodecs(codecs []webrtc.RTPCodecParameters) (*webrtc.API, error) {
|
||||
s.SetEphemeralUDPPortRange(UDPMin, UDPMax)
|
||||
}
|
||||
|
||||
err := webrtc.ConfigureSimulcastExtensionHeaders(&m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ir := interceptor.Registry{}
|
||||
|
||||
return webrtc.NewAPI(
|
||||
@@ -417,7 +334,7 @@ func APIFromCodecs(codecs []webrtc.RTPCodecParameters) (*webrtc.API, error) {
|
||||
|
||||
func APIFromNames(names []string) (*webrtc.API, error) {
|
||||
if len(names) == 0 {
|
||||
names = []string{"vp8", "opus"}
|
||||
names = []string{"opus"}
|
||||
}
|
||||
var codecs []webrtc.RTPCodecParameters
|
||||
for _, n := range names {
|
||||
@@ -543,14 +460,14 @@ func GetNames() []string {
|
||||
return names
|
||||
}
|
||||
|
||||
type SubGroup struct {
|
||||
type SubHall struct {
|
||||
Name string
|
||||
Clients int
|
||||
}
|
||||
|
||||
func GetSubGroups(parent string) []SubGroup {
|
||||
func GetSubHalls(parent string) []SubHall {
|
||||
prefix := parent + "/"
|
||||
subgroups := make([]SubGroup, 0)
|
||||
subhalls := make([]SubHall, 0)
|
||||
|
||||
Range(func(g *Hall) bool {
|
||||
if strings.HasPrefix(g.name, prefix) {
|
||||
@@ -558,13 +475,13 @@ func GetSubGroups(parent string) []SubGroup {
|
||||
count := len(g.clients)
|
||||
g.mu.Unlock()
|
||||
if count > 0 {
|
||||
subgroups = append(subgroups,
|
||||
SubGroup{g.name, count})
|
||||
subhalls = append(subhalls,
|
||||
SubHall{g.name, count})
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
return subgroups
|
||||
return subhalls
|
||||
}
|
||||
|
||||
func Get(name string) *Hall {
|
||||
@@ -929,7 +846,7 @@ type Configuration struct {
|
||||
AllowOrigin []string `json:"allowOrigin,omitempty"`
|
||||
AllowAdminOrigin []string `json:"allowAdminOrigin,omitempty"`
|
||||
ProxyURL string `json:"proxyURL,omitempty"`
|
||||
WritableGroups bool `json:"writableGroups,omitempty"`
|
||||
WritableHalls bool `json:"writableHalls,omitempty"`
|
||||
Users map[string]UserDescription `json:"users,omitempty"`
|
||||
|
||||
// obsolete fields
|
||||
@@ -1173,7 +1090,7 @@ func (g *Hall) Status(authentified bool, base *url.URL) Status {
|
||||
if authentified {
|
||||
conf, err := GetConfiguration()
|
||||
if err == nil {
|
||||
d.CanChangePassword = conf.WritableGroups
|
||||
d.CanChangePassword = conf.WritableHalls
|
||||
}
|
||||
}
|
||||
return d
|
||||
|
||||
+9
-10
@@ -34,23 +34,23 @@ func TestConstantTimeCompare(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGroup(t *testing.T) {
|
||||
func TestHall(t *testing.T) {
|
||||
halls.halls = nil
|
||||
Add("hall", &Description{})
|
||||
Add("hall/subgroup", &Description{Public: true})
|
||||
Add("hall/subhall", &Description{Public: true})
|
||||
if len(halls.halls) != 2 {
|
||||
t.Errorf("Expected 2, got %v", len(halls.halls))
|
||||
}
|
||||
g := Get("hall")
|
||||
g2 := Get("hall/subgroup")
|
||||
g2 := Get("hall/subhall")
|
||||
if g == nil {
|
||||
t.Fatalf("Couldn't get hall")
|
||||
}
|
||||
if g2 == nil {
|
||||
t.Fatalf("Couldn't get hall/subgroup")
|
||||
t.Fatalf("Couldn't get hall/subhall")
|
||||
}
|
||||
if name := g.Name(); name != "hall" {
|
||||
t.Errorf("Name: expected group1, got %v", name)
|
||||
t.Errorf("Name: expected hall, got %v", name)
|
||||
}
|
||||
if locked, _ := g.Locked(); locked {
|
||||
t.Errorf("Locked: expected false, got %v", locked)
|
||||
@@ -64,12 +64,12 @@ func TestGroup(t *testing.T) {
|
||||
t.Errorf("Expected 2, got %v", names)
|
||||
}
|
||||
|
||||
if subs := GetSubGroups("hall"); len(subs) != 0 {
|
||||
if subs := GetSubHalls("hall"); len(subs) != 0 {
|
||||
t.Errorf("Expected [], got %v", subs)
|
||||
}
|
||||
|
||||
if public := GetPublic(nil); len(public) != 1 || public[0].Name != "hall/subgroup" {
|
||||
t.Errorf("Expected hall/subgroup, got %v", public)
|
||||
if public := GetPublic(nil); len(public) != 1 || public[0].Name != "hall/subhall" {
|
||||
t.Errorf("Expected hall/subhall, got %v", public)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ type credPerm struct {
|
||||
var desc2JSON = `
|
||||
{
|
||||
"max-history-age": 10,
|
||||
"auto-subgroups": true,
|
||||
"auto-subhalls": true,
|
||||
"users": {
|
||||
"jch": {"password": "topsecret", "permissions": "op"},
|
||||
"john": {"password": "secret", "permissions": "present"},
|
||||
@@ -377,7 +377,6 @@ func TestValidHallName(t *testing.T) {
|
||||
|
||||
func TestPayloadTypeDistinct(t *testing.T) {
|
||||
names := []string{
|
||||
"vp8", "vp9", "av1", "h264",
|
||||
"opus", "g722", "pcmu", "pcma",
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user