diff --git a/api/openapi.yaml b/api/openapi.yaml index 855cffd4..7a12d3f4 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -589,6 +589,16 @@ components: readyTime: type: string nullable: true + available: + type: boolean + availableTime: + type: string + nullable: true + online: + type: boolean + onlineTime: + type: string + nullable: true tracks: type: array items: diff --git a/docs/2-usage/07-always-available.md b/docs/2-usage/07-always-available.md index fecaac9c..8231ff9e 100644 --- a/docs/2-usage/07-always-available.md +++ b/docs/2-usage/07-always-available.md @@ -1,6 +1,6 @@ # Always-available streams -When the publisher or source of a stream is offline, the server can be configured to fill gaps in the stream with a video that is played on repeat until a publisher comes back online. This allows readers to stay connected regardless of the state of the stream. The offline video and any future online stream are concatenated without decoding or re-encoding packets, using the original codec. +When the publisher or source of a stream is offline, the server can be configured to fill gaps in the stream with an offline segment that is played on repeat until a publisher comes back online. This allows readers to stay connected regardless of the state of the stream. The offline segment and any future online stream are concatenated without decoding or re-encoding packets, using the original codec. This feature can be enabled by toggling the `alwaysAvailable` flag and filling `alwaysAvailableTracks`: @@ -18,12 +18,11 @@ paths: # muLaw: false ``` -By default, the server uses a default offline video with the text "STREAM IS OFFLINE". This can be changed by importing the video from a MP4 file: +By default, the server uses a default offline segment with the text "STREAM IS OFFLINE". The segment can be replaced with an external MP4 file: ```yml paths: mypath: alwaysAvailable: true - # Path to the MP4 file that is played on repeat. If not provided, a default video will be used instead. alwaysAvailableFile: "./h264.mp4" ``` diff --git a/internal/core/path.go b/internal/core/path.go index b482f51f..f2609eaf 100644 --- a/internal/core/path.go +++ b/internal/core/path.go @@ -163,6 +163,10 @@ func (pa *path) isAvailable() bool { return pa.stream != nil } +func (pa *path) isOnline() bool { + return pa.source != nil +} + func (pa *path) run() { defer close(pa.done) defer pa.wg.Done() @@ -613,6 +617,22 @@ func (pa *path) doAPIPathsGet(req pathAPIPathsGetReq) { v := pa.availableTime return &v }(), + Available: pa.isAvailable(), + AvailableTime: func() *time.Time { + if !pa.isAvailable() { + return nil + } + v := pa.availableTime + return &v + }(), + Online: pa.isOnline(), + OnlineTime: func() *time.Time { + if !pa.isOnline() { + return nil + } + v := pa.onlineTime + return &v + }(), Source: func() *defs.APIPathSource { if pa.source == nil { return nil diff --git a/internal/defs/api.go b/internal/defs/api.go index 80fe7ac2..924bd2da 100644 --- a/internal/defs/api.go +++ b/internal/defs/api.go @@ -90,9 +90,13 @@ type APIPathReader struct { type APIPath struct { Name string `json:"name"` ConfName string `json:"confName"` + Ready bool `json:"ready"` // deprecated + ReadyTime *time.Time `json:"readyTime"` // deprecated + Available bool `json:"available"` + AvailableTime *time.Time `json:"availableTime"` + Online bool `json:"online"` + OnlineTime *time.Time `json:"onlineTime"` Source *APIPathSource `json:"source"` - Ready bool `json:"ready"` - ReadyTime *time.Time `json:"readyTime"` Tracks []string `json:"tracks"` BytesReceived uint64 `json:"bytesReceived"` BytesSent uint64 `json:"bytesSent"` diff --git a/mediamtx.yml b/mediamtx.yml index fd9d7b13..d618c547 100644 --- a/mediamtx.yml +++ b/mediamtx.yml @@ -489,11 +489,11 @@ pathDefaults: ############################################### # Default path settings -> Always available - # Enable always-available mode, in which a file 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 - # Path to the MP4 file that is played on repeat. If not provided, a default file will be used. + # An MP4 file can be used instead of the default offline segment. alwaysAvailableFile: '' - # If alwaysAvailableFile is not provided, these are the tracks of the default file. + # Tracks of the offline segment. alwaysAvailableTracks: # Available values are: AV1, VP9, H265, H264, Opus, MPEG4Audio, G711, LPCM - codec: H264