prevent using alwaysAvailableFile and alwaysAvailableTracks together (#5529)

This commit is contained in:
Alessandro Ros
2026-02-28 18:31:41 +01:00
committed by GitHub
parent 2fcefb7093
commit 549300cbd4
6 changed files with 37 additions and 30 deletions
+2 -2
View File
@@ -382,12 +382,12 @@ components:
# Always available # Always available
alwaysAvailable: alwaysAvailable:
type: boolean type: boolean
alwaysAvailableFile:
type: string
alwaysAvailableTracks: alwaysAvailableTracks:
type: array type: array
items: items:
$ref: '#/components/schemas/AlwaysAvailableTrack' $ref: '#/components/schemas/AlwaysAvailableTrack'
alwaysAvailableFile:
type: string
# Record # Record
record: record:
+18 -10
View File
@@ -48,14 +48,12 @@ func TestConfFromFile(t *testing.T) {
pa, ok := conf.Paths["cam1"] pa, ok := conf.Paths["cam1"]
require.Equal(t, true, ok) require.Equal(t, true, ok)
require.Equal(t, &Path{ require.Equal(t, &Path{
Name: "cam1", Name: "cam1",
Source: "publisher", Source: "publisher",
SourceOnDemandStartTimeout: 10 * Duration(time.Second), SourceOnDemandStartTimeout: 10 * Duration(time.Second),
SourceOnDemandCloseAfter: 10 * Duration(time.Second), SourceOnDemandCloseAfter: 10 * Duration(time.Second),
OverridePublisher: true, OverridePublisher: true,
AlwaysAvailableTracks: []AlwaysAvailableTrack{ AlwaysAvailableTracks: []AlwaysAvailableTrack{},
{Codec: "H264"},
},
RecordPath: "./recordings/%path/%Y-%m-%d_%H-%M-%S-%f", RecordPath: "./recordings/%path/%Y-%m-%d_%H-%M-%S-%f",
RecordFormat: RecordFormatFMP4, RecordFormat: RecordFormatFMP4,
RecordPartDuration: Duration(1 * time.Second), RecordPartDuration: Duration(1 * time.Second),
@@ -739,6 +737,16 @@ func TestConfErrors(t *testing.T) {
"playbackAddress: ''\n", "playbackAddress: ''\n",
"'playbackAddress' must be set when playback is enabled", "'playbackAddress' must be set when playback is enabled",
}, },
{
"alwaysAvailableTracks and alwaysAvailableFile together",
"paths:\n" +
" mypath:\n" +
" alwaysAvailable: yes\n" +
" alwaysAvailableTracks:\n" +
" - codec: H264\n" +
" alwaysAvailableFile: /path/to/file.mp4\n",
"'alwaysAvailableFile' and 'alwaysAvailableTracks' cannot be used together",
},
} { } {
t.Run(ca.name, func(t *testing.T) { t.Run(ca.name, func(t *testing.T) {
tmpf, err := createTempFile([]byte(ca.conf)) tmpf, err := createTempFile([]byte(ca.conf))
@@ -752,7 +760,7 @@ func TestConfErrors(t *testing.T) {
} }
func TestAlwaysAvailableFileErrorMagicBytes(t *testing.T) { func TestAlwaysAvailableFileErrorMagicBytes(t *testing.T) {
tmpf, err := createTempFile([]byte("not an mp4 file")) tmpf, err := createTempFile([]byte("ABCDEFGHI"))
require.NoError(t, err) require.NoError(t, err)
defer os.Remove(tmpf) defer os.Remove(tmpf)
@@ -764,7 +772,7 @@ func TestAlwaysAvailableFileErrorMagicBytes(t *testing.T) {
defer os.Remove(tmpConf) defer os.Remove(tmpConf)
_, _, err = Load(tmpConf, nil, nil) _, _, err = Load(tmpConf, nil, nil)
require.EqualError(t, err, "invalid 'alwaysAvailableFile': file is not MP4, magic bytes are '[97 110 32 109]'") require.EqualError(t, err, "invalid 'alwaysAvailableFile': file is not MP4, magic bytes are [69 70 71 72]")
} }
func TestSampleConfFile(t *testing.T) { func TestSampleConfFile(t *testing.T) {
+6 -7
View File
@@ -82,7 +82,7 @@ func checkMP4MagicBytes(f io.ReadSeeker) error {
} }
if !bytes.Equal(magicBytes, []byte("ftyp")) { if !bytes.Equal(magicBytes, []byte("ftyp")) {
return fmt.Errorf("file is not MP4, magic bytes are '%v'", magicBytes) return fmt.Errorf("file is not MP4, magic bytes are %v", magicBytes)
} }
_, err = f.Seek(0, io.SeekStart) _, err = f.Seek(0, io.SeekStart)
@@ -185,8 +185,8 @@ type Path struct {
// Always available // Always available
AlwaysAvailable bool `json:"alwaysAvailable"` AlwaysAvailable bool `json:"alwaysAvailable"`
AlwaysAvailableFile string `json:"alwaysAvailableFile"`
AlwaysAvailableTracks []AlwaysAvailableTrack `json:"alwaysAvailableTracks"` AlwaysAvailableTracks []AlwaysAvailableTrack `json:"alwaysAvailableTracks"`
AlwaysAvailableFile string `json:"alwaysAvailableFile"`
// Record // Record
Record bool `json:"record"` Record bool `json:"record"`
@@ -310,11 +310,6 @@ func (pconf *Path) setDefaults() {
pconf.SourceOnDemandStartTimeout = 10 * Duration(time.Second) pconf.SourceOnDemandStartTimeout = 10 * Duration(time.Second)
pconf.SourceOnDemandCloseAfter = 10 * Duration(time.Second) pconf.SourceOnDemandCloseAfter = 10 * Duration(time.Second)
// Always available
pconf.AlwaysAvailableTracks = []AlwaysAvailableTrack{
{Codec: "H264"},
}
// Record // Record
pconf.RecordPath = "./recordings/%path/%Y-%m-%d_%H-%M-%S-%f" pconf.RecordPath = "./recordings/%path/%Y-%m-%d_%H-%M-%S-%f"
pconf.RecordFormat = RecordFormatFMP4 pconf.RecordFormat = RecordFormatFMP4
@@ -734,6 +729,10 @@ func (pconf *Path) validate(
} }
if pconf.AlwaysAvailableFile != "" { if pconf.AlwaysAvailableFile != "" {
if len(pconf.AlwaysAvailableTracks) != 0 {
return fmt.Errorf("'alwaysAvailableFile' and 'alwaysAvailableTracks' cannot be used together")
}
err := checkAlwaysAvailableFile(pconf.AlwaysAvailableFile) err := checkAlwaysAvailableFile(pconf.AlwaysAvailableFile)
if err != nil { if err != nil {
return fmt.Errorf("invalid 'alwaysAvailableFile': %w", err) return fmt.Errorf("invalid 'alwaysAvailableFile': %w", err)
+1 -1
View File
@@ -788,8 +788,8 @@ func (pa *path) setAvailable(desc *description.Session, replaceNTP bool) error {
pa.stream = &stream.Stream{ pa.stream = &stream.Stream{
Desc: desc, Desc: desc,
AlwaysAvailable: pa.conf.AlwaysAvailable, AlwaysAvailable: pa.conf.AlwaysAvailable,
AlwaysAvailableFile: pa.conf.AlwaysAvailableFile,
AlwaysAvailableTracks: pa.conf.AlwaysAvailableTracks, AlwaysAvailableTracks: pa.conf.AlwaysAvailableTracks,
AlwaysAvailableFile: pa.conf.AlwaysAvailableFile,
WriteQueueSize: pa.writeQueueSize, WriteQueueSize: pa.writeQueueSize,
RTPMaxPayloadSize: pa.rtpMaxPayloadSize, RTPMaxPayloadSize: pa.rtpMaxPayloadSize,
ReplaceNTP: replaceNTP, ReplaceNTP: replaceNTP,
+1 -1
View File
@@ -221,8 +221,8 @@ func mediasFromAlwaysAvailableTracks(alwaysAvailableTracks []conf.AlwaysAvailabl
type Stream struct { type Stream struct {
Desc *description.Session Desc *description.Session
AlwaysAvailable bool AlwaysAvailable bool
AlwaysAvailableFile string
AlwaysAvailableTracks []conf.AlwaysAvailableTrack AlwaysAvailableTracks []conf.AlwaysAvailableTrack
AlwaysAvailableFile string
WriteQueueSize int WriteQueueSize int
RTPMaxPayloadSize int RTPMaxPayloadSize int
ReplaceNTP bool ReplaceNTP bool
+9 -9
View File
@@ -498,17 +498,17 @@ pathDefaults:
# Enable always-available mode, in which a offline segment is played on repeat when the stream is not available. # Enable always-available mode, in which a offline segment is played on repeat when the stream is not available.
alwaysAvailable: false alwaysAvailable: false
# An MP4 file can be used instead of the default offline segment.
alwaysAvailableFile: ''
# Tracks of the default offline segment. # Tracks of the default offline segment.
alwaysAvailableTracks: alwaysAvailableTracks: []
# Available values are: AV1, VP9, H265, H264, Opus, MPEG4Audio, G711, LPCM # Available values are: AV1, VP9, H265, H264, Opus, MPEG4Audio, G711, LPCM
- codec: H264 # - codec: H264
# in case of MPEG4Audio, G711, LPCM, sampleRate and ChannelCount must be provided too. # # in case of MPEG4Audio, G711, LPCM, sampleRate and ChannelCount must be provided too.
# sampleRate: 48000 # sampleRate: 48000
# channelCount: 2 # channelCount: 2
# in case of G711, muLaw must be provided too. # # in case of G711, muLaw must be provided too.
# muLaw: false # muLaw: false
# A MP4 file can be used instead of the default offline segment.
alwaysAvailableFile: ''
############################################### ###############################################
# Default path settings -> Record # Default path settings -> Record