diff --git a/README.md b/README.md index 06b3d326..f8b6dfae 100644 --- a/README.md +++ b/README.md @@ -548,7 +548,7 @@ _rtsp-simple-server_ natively support the Raspberry Pi Camera, enabling high-qua 2. Make sure that the legacy camera stack is disabled. Type `sudo raspi-config`, then go to `Interfacing options`, `enable/disable legacy camera support`, choose `no`. Reboot the system. -3. Make sure that the `libcamera0` package version is at least `0.0.2`, otherwise upgrade it with `sudo apt update && sudo apt upgrade`. +3. Make sure that the `libcamera0` package version is at least `0.0.2`, otherwise upgrade it with `sudo apt update && sudo apt install libcamera0`. If you want to run the standard (non-dockerized) version of the server, just download the server executable and make sure to pick the `arm64` variant if you're using the 64-bit version of the operative system. Then edit `rtsp-simple-server.yml` and replace everything inside section `paths` with the following content: diff --git a/internal/conf/conf.go b/internal/conf/conf.go index 9841b1dd..ccf1a4df 100644 --- a/internal/conf/conf.go +++ b/internal/conf/conf.go @@ -7,6 +7,7 @@ import ( "fmt" "os" "reflect" + "sort" "strings" "time" @@ -422,10 +423,19 @@ func (conf *Conf) CheckAndFillMissing() error { delete(conf.Paths, "all") } - for name, pconf := range conf.Paths { + sortedNames := make([]string, len(conf.Paths)) + i := 0 + for name := range conf.Paths { + sortedNames[i] = name + i++ + } + sort.Strings(sortedNames) + + for _, name := range sortedNames { + pconf := conf.Paths[name] if pconf == nil { - conf.Paths[name] = &PathConf{} - pconf = conf.Paths[name] + pconf = &PathConf{} + conf.Paths[name] = pconf } err := pconf.checkAndFillMissing(conf, name) diff --git a/internal/conf/conf_test.go b/internal/conf/conf_test.go index 15f78248..de5bb924 100644 --- a/internal/conf/conf_test.go +++ b/internal/conf/conf_test.go @@ -170,24 +170,48 @@ func TestConfEncryption(t *testing.T) { require.Equal(t, true, ok) } -func TestConfErrorNonExistentParameter(t *testing.T) { - func() { - tmpf, err := writeTempFile([]byte(`invalid: param`)) - require.NoError(t, err) - defer os.Remove(tmpf) +func TestConfErrors(t *testing.T) { + for _, ca := range []struct { + name string + conf string + err string + }{ + { + "non existent parameter 1", + `invalid: param`, + "non-existent parameter: 'invalid'", + }, + { + "non existent parameter 2", + "paths:\n" + + " mypath:\n" + + " invalid: parameter\n", + "parameter paths, key mypath: non-existent parameter: 'invalid'", + }, + { + "invalid path name", + "paths:\n" + + " '':\n" + + " source: publisher\n", + "invalid path name '': cannot be empty", + }, + { + "double raspberry pi camera", + "paths:\n" + + " cam1:\n" + + " source: rpiCamera\n" + + " cam2:\n" + + " source: rpiCamera\n", + "'rpiCamera' is used as source in two paths ('cam1' and 'cam2')", + }, + } { + t.Run(ca.name, func(t *testing.T) { + tmpf, err := writeTempFile([]byte(ca.conf)) + require.NoError(t, err) + defer os.Remove(tmpf) - _, _, err = Load(tmpf) - require.EqualError(t, err, "non-existent parameter: 'invalid'") - }() - - func() { - tmpf, err := writeTempFile([]byte("paths:\n" + - " mypath:\n" + - " invalid: parameter\n")) - require.NoError(t, err) - defer os.Remove(tmpf) - - _, _, err = Load(tmpf) - require.EqualError(t, err, "parameter paths, key mypath: non-existent parameter: 'invalid'") - }() + _, _, err = Load(tmpf) + require.EqualError(t, err, ca.err) + }) + } } diff --git a/internal/conf/path.go b/internal/conf/path.go index e56d3301..4bc35c1a 100644 --- a/internal/conf/path.go +++ b/internal/conf/path.go @@ -96,15 +96,11 @@ type PathConf struct { } func (pconf *PathConf) checkAndFillMissing(conf *Conf, name string) error { - if name == "" { - return fmt.Errorf("path name can not be empty") - } - // normal path - if name[0] != '~' { + if name == "" || name[0] != '~' { err := IsValidPathName(name) if err != nil { - return fmt.Errorf("invalid path name: %s (%s)", err, name) + return fmt.Errorf("invalid path name '%s': %s", name, err) } // regular expression path @@ -193,6 +189,12 @@ func (pconf *PathConf) checkAndFillMissing(conf *Conf, name string) error { "a path with a regular expression (or path 'all') cannot have 'rpiCamera' as source. use another path") } + for otherName, otherPath := range conf.Paths { + if otherPath != pconf && otherPath != nil && otherPath.Source == "rpiCamera" { + return fmt.Errorf("'rpiCamera' is used as source in two paths ('%s' and '%s')", name, otherName) + } + } + if pconf.RPICameraWidth == 0 { pconf.RPICameraWidth = 1920 }