From 96aeb1e6037196e51c6142096b1a96fcccf9c740 Mon Sep 17 00:00:00 2001 From: Alessandro Ros Date: Sat, 18 Jul 2026 17:58:16 +0200 Subject: [PATCH] rename runOnReady into runOnAvailable, runOnNotReady into runOnUnavailable (#5957) --- api/openapi.yaml | 12 ++++++ .../07-remuxing-reencoding-compression.md | 4 +- docs/2-features/11-forward.md | 6 +-- docs/2-features/13-extract-snapshots.md | 4 +- docs/2-features/21-hooks.md | 18 ++++----- internal/conf/conf_test.go | 19 ++++++++++ internal/conf/path.go | 24 ++++++++++-- internal/core/path.go | 6 +-- internal/core/path_test.go | 20 +++++----- .../hooks/{on_ready.go => on_available.go} | 38 +++++++++---------- mediamtx.yml | 10 ++--- 11 files changed, 105 insertions(+), 56 deletions(-) rename internal/hooks/{on_ready.go => on_available.go} (50%) diff --git a/api/openapi.yaml b/api/openapi.yaml index efecc6e4..20540cf5 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -1124,6 +1124,10 @@ components: items: type: integer format: uint64 + runOnAvailable: + type: string + runOnAvailableRestart: + type: boolean runOnDemand: type: string runOnDemandCloseAfter: @@ -1139,6 +1143,8 @@ components: type: boolean runOnNotReady: type: string + nullable: true + deprecated: true runOnOffline: type: string runOnOnline: @@ -1151,14 +1157,20 @@ components: type: boolean runOnReady: type: string + nullable: true + deprecated: true runOnReadyRestart: type: boolean + nullable: true + deprecated: true runOnRecordSegmentComplete: type: string runOnRecordSegmentCreate: type: string runOnUnDemand: type: string + runOnUnavailable: + type: string runOnUnread: type: string source: diff --git a/docs/2-features/07-remuxing-reencoding-compression.md b/docs/2-features/07-remuxing-reencoding-compression.md index b7c5612c..92942f83 100644 --- a/docs/2-features/07-remuxing-reencoding-compression.md +++ b/docs/2-features/07-remuxing-reencoding-compression.md @@ -6,9 +6,9 @@ To change the format, codec or compression of a stream, use _FFmpeg_ or _GStream paths: compressed: original: - runOnReady: > + runOnAvailable: > ffmpeg -i rtsp://localhost:$RTSP_PORT/$MTX_PATH -c:v libx264 -pix_fmt yuv420p -preset ultrafast -b:v 600k -max_muxing_queue_size 1024 -f rtsp rtsp://localhost:$RTSP_PORT/compressed - runOnReadyRestart: yes + runOnAvailableRestart: yes ``` diff --git a/docs/2-features/11-forward.md b/docs/2-features/11-forward.md index 753a2a7b..b0fe0bf1 100644 --- a/docs/2-features/11-forward.md +++ b/docs/2-features/11-forward.md @@ -1,12 +1,12 @@ # Forward -To forward incoming streams to another server, use _FFmpeg_ inside the `runOnReady` parameter: +To forward incoming streams to another server, use _FFmpeg_ inside the `runOnAvailable` parameter: ```yml pathDefaults: - runOnReady: > + runOnAvailable: > ffmpeg -i rtsp://localhost:$RTSP_PORT/$MTX_PATH -c copy -f rtsp rtsp://other-server:8554/another-path - runOnReadyRestart: yes + runOnAvailableRestart: yes ``` diff --git a/docs/2-features/13-extract-snapshots.md b/docs/2-features/13-extract-snapshots.md index 3532d980..b81f5f55 100644 --- a/docs/2-features/13-extract-snapshots.md +++ b/docs/2-features/13-extract-snapshots.md @@ -1,10 +1,10 @@ # Extract snapshots -You can periodically extract snapshots from available streams by using FFmpeg inside the `runOnReady` hook: +You can periodically extract snapshots from available streams by using FFmpeg inside the `runOnAvailable` hook: ```yml pathDefaults: - runOnReady: | + runOnAvailable: | bash -c " while true; do mkdir -p $(dirname snapshots/$MTX_PATH) diff --git a/docs/2-features/21-hooks.md b/docs/2-features/21-hooks.md index 581e782b..8c443b0b 100644 --- a/docs/2-features/21-hooks.md +++ b/docs/2-features/21-hooks.md @@ -80,14 +80,14 @@ pathDefaults: runOnUnDemand: ``` -## runOnReady +## runOnAvailable -`runOnReady` allows to run a command when a stream is available to be read: +`runOnAvailable` allows to run a command when a stream is available to be read: ```yml pathDefaults: # Command to run when the stream is available to be read. - # This is terminated with SIGINT when the stream is not ready anymore. + # This is terminated with SIGINT when the stream is not available anymore. # The following environment variables are available: # * MTX_PATH: path name # * MTX_QUERY: query parameters (passed by publisher) (url-encoded) @@ -96,20 +96,20 @@ pathDefaults: # * RTSP_PORT: RTSP server port # * G1, G2, ...: regular expression groups, if path name is # a regular expression. - runOnReady: curl http://my-custom-server/webhook?path=$MTX_PATH&source_type=$MTX_SOURCE_TYPE&source_id=$MTX_SOURCE_ID + runOnAvailable: curl http://my-custom-server/webhook?path=$MTX_PATH&source_type=$MTX_SOURCE_TYPE&source_id=$MTX_SOURCE_ID # Restart the command if it exits. - runOnReadyRestart: no + runOnAvailableRestart: no ``` -## runOnNotReady +## runOnUnavailable -`runOnNotReady` allows to run a command when a stream is not available anymore: +`runOnUnavailable` allows to run a command when a stream is not available anymore: ```yml pathDefaults: # Command to run when the stream is not available anymore. - # Environment variables are the same as runOnReady. - runOnNotReady: curl http://my-custom-server/webhook?path=$MTX_PATH&source_type=$MTX_SOURCE_TYPE&source_id=$MTX_SOURCE_ID + # Environment variables are the same as runOnAvailable. + runOnUnavailable: curl http://my-custom-server/webhook?path=$MTX_PATH&source_type=$MTX_SOURCE_TYPE&source_id=$MTX_SOURCE_ID ``` ## runOnOnline diff --git a/internal/conf/conf_test.go b/internal/conf/conf_test.go index 049d8beb..54e23630 100644 --- a/internal/conf/conf_test.go +++ b/internal/conf/conf_test.go @@ -853,6 +853,25 @@ func TestConfErrors(t *testing.T) { } } +func TestDeprecatedAvailabilityHooks(t *testing.T) { + tmpf := createTempFile(t, []byte("paths:\n"+ + " mypath:\n"+ + " runOnReady: command1\n"+ + " runOnReadyRestart: yes\n"+ + " runOnNotReady: command2\n")) + + conf, _, err := Load(tmpf, nil, nil) + require.NoError(t, err) + + pa := conf.Paths["mypath"] + require.Equal(t, "command1", pa.RunOnAvailable) + require.Equal(t, true, pa.RunOnAvailableRestart) + require.Equal(t, "command2", pa.RunOnUnavailable) + require.Equal(t, "command1", *pa.RunOnReady) + require.Equal(t, true, *pa.RunOnReadyRestart) + require.Equal(t, "command2", *pa.RunOnNotReady) +} + func TestAlwaysAvailableFileErrorMagicBytes(t *testing.T) { tmpf := createTempFile(t, []byte("ABCDEFGHI")) diff --git a/internal/conf/path.go b/internal/conf/path.go index 538329ec..c8a5fb0f 100644 --- a/internal/conf/path.go +++ b/internal/conf/path.go @@ -341,9 +341,12 @@ type Path struct { RunOnDemandStartTimeout Duration `json:"runOnDemandStartTimeout"` RunOnDemandCloseAfter Duration `json:"runOnDemandCloseAfter"` RunOnUnDemand string `json:"runOnUnDemand"` - RunOnReady string `json:"runOnReady"` - RunOnReadyRestart bool `json:"runOnReadyRestart"` - RunOnNotReady string `json:"runOnNotReady"` + RunOnAvailable string `json:"runOnAvailable"` + RunOnAvailableRestart bool `json:"runOnAvailableRestart"` + RunOnUnavailable string `json:"runOnUnavailable"` + RunOnReady *string `json:"runOnReady,omitempty" deprecated:"true"` + RunOnReadyRestart *bool `json:"runOnReadyRestart,omitempty" deprecated:"true"` + RunOnNotReady *string `json:"runOnNotReady,omitempty" deprecated:"true"` RunOnOnline string `json:"runOnOnline"` RunOnOnlineRestart bool `json:"runOnOnlineRestart"` RunOnOffline string `json:"runOnOffline"` @@ -930,6 +933,21 @@ func (pconf *Path) validate( " does not support option 'runOnInit'; use another path") } + if pconf.RunOnReady != nil { + l.Log(logger.Warn, "parameter 'runOnReady' is deprecated and has been replaced with 'runOnAvailable'") + pconf.RunOnAvailable = *pconf.RunOnReady + } + + if pconf.RunOnReadyRestart != nil { + l.Log(logger.Warn, "parameter 'runOnReadyRestart' is deprecated and has been replaced with 'runOnAvailableRestart'") + pconf.RunOnAvailableRestart = *pconf.RunOnReadyRestart + } + + if pconf.RunOnNotReady != nil { + l.Log(logger.Warn, "parameter 'runOnNotReady' is deprecated and has been replaced with 'runOnUnavailable'") + pconf.RunOnUnavailable = *pconf.RunOnNotReady + } + if (pconf.RunOnDemand != "" || pconf.RunOnUnDemand != "") && pconf.Source != "publisher" { return fmt.Errorf("'runOnDemand' and 'runOnUnDemand' can be used only when source is 'publisher'") } diff --git a/internal/core/path.go b/internal/core/path.go index 9b835a7d..51af92d2 100644 --- a/internal/core/path.go +++ b/internal/core/path.go @@ -98,7 +98,7 @@ type path struct { availableTime time.Time onlineTime time.Time onUnDemandHook func(string) - onNotReadyHook func() + onUnavailableHook func() onOfflineHook func() readers map[defs.Reader]struct{} describeRequestsOnHold []defs.PathDescribeReq @@ -881,7 +881,7 @@ func (pa *path) setAvailable( sourceDesc = source.APISourceDescribe() } - pa.onNotReadyHook = hooks.OnReady(hooks.OnReadyParams{ + pa.onUnavailableHook = hooks.OnAvailable(hooks.OnAvailableParams{ Logger: pa, ExternalCmdPool: pa.externalCmdPool, Conf: pa.conf, @@ -928,7 +928,7 @@ func (pa *path) setNotAvailable() { r.Close() } - pa.onNotReadyHook() + pa.onUnavailableHook() if pa.recorder != nil { pa.recorder.Close() diff --git a/internal/core/path_test.go b/internal/core/path_test.go index 64c4632e..07be6d83 100644 --- a/internal/core/path_test.go +++ b/internal/core/path_test.go @@ -267,9 +267,9 @@ func TestPathRunOnConnect(t *testing.T) { } } -func TestPathRunOnReady(t *testing.T) { - onReady := filepath.Join(t.TempDir(), "on_ready") - onNotReady := filepath.Join(t.TempDir(), "on_unready") +func TestPathRunOnAvailable(t *testing.T) { + onAvailable := filepath.Join(t.TempDir(), "on_available") + onUnavailable := filepath.Join(t.TempDir(), "on_unavailable") func() { p, ok := newInstance(t, fmt.Sprintf("rtmp: no\n"+ @@ -277,9 +277,9 @@ func TestPathRunOnReady(t *testing.T) { "webrtc: no\n"+ "paths:\n"+ " ~te(st):\n"+ - " runOnReady: sh -c 'echo \"$MTX_PATH $MTX_QUERY $MTX_SOURCE_TYPE $MTX_SOURCE_ID $RTSP_PORT $G1\" > %s'\n"+ - " runOnNotReady: sh -c 'echo \"$MTX_PATH $MTX_QUERY $MTX_SOURCE_TYPE $MTX_SOURCE_ID $RTSP_PORT $G1\" > %s'\n", - onReady, onNotReady)) + " runOnAvailable: sh -c 'echo \"$MTX_PATH $MTX_QUERY $MTX_SOURCE_TYPE $MTX_SOURCE_ID $RTSP_PORT $G1\" > %s'\n"+ + " runOnUnavailable: sh -c 'echo \"$MTX_PATH $MTX_QUERY $MTX_SOURCE_TYPE $MTX_SOURCE_ID $RTSP_PORT $G1\" > %s'\n", + onAvailable, onUnavailable)) require.Equal(t, true, ok) defer p.Close() @@ -294,7 +294,7 @@ func TestPathRunOnReady(t *testing.T) { time.Sleep(500 * time.Millisecond) }() - byts, err := os.ReadFile(onReady) + byts, err := os.ReadFile(onAvailable) require.NoError(t, err) fields := strings.Split(string(byts[:len(byts)-1]), " ") require.Equal(t, "test", fields[0]) @@ -304,7 +304,7 @@ func TestPathRunOnReady(t *testing.T) { require.Equal(t, "8554", fields[4]) require.Equal(t, "st", fields[5]) - byts, err = os.ReadFile(onNotReady) + byts, err = os.ReadFile(onUnavailable) require.NoError(t, err) fields = strings.Split(string(byts[:len(byts)-1]), " ") require.Equal(t, "test", fields[0]) @@ -315,7 +315,7 @@ func TestPathRunOnReady(t *testing.T) { require.Equal(t, "st", fields[5]) } -func TestPathRunOnReadyQueryInjection(t *testing.T) { +func TestPathRunOnAvailableQueryInjection(t *testing.T) { sentinel := filepath.Join(t.TempDir(), "mediamtx_test_query_injection_sentinel") for _, ca := range []struct { @@ -346,7 +346,7 @@ func TestPathRunOnReadyQueryInjection(t *testing.T) { } { t.Run(ca.name, func(t *testing.T) { p, ok := newInstance(t, fmt.Sprintf( - "rtmp: no\nhls: no\nwebrtc: no\npaths:\n test:\n runOnReady: %s\n", + "rtmp: no\nhls: no\nwebrtc: no\npaths:\n test:\n runOnAvailable: %s\n", ca.cmdstr)) require.Equal(t, true, ok) defer p.Close() diff --git a/internal/hooks/on_ready.go b/internal/hooks/on_available.go similarity index 50% rename from internal/hooks/on_ready.go rename to internal/hooks/on_available.go index 0cf24792..68e4a787 100644 --- a/internal/hooks/on_ready.go +++ b/internal/hooks/on_available.go @@ -9,8 +9,8 @@ import ( "github.com/bluenviron/mediamtx/internal/logger" ) -// OnReadyParams are the parameters of OnReady. -type OnReadyParams struct { +// OnAvailableParams are the parameters of OnAvailable. +type OnAvailableParams struct { Logger logger.Writer ExternalCmdPool *externalcmd.Pool Conf *conf.Path @@ -19,12 +19,12 @@ type OnReadyParams struct { Query string } -// OnReady is the OnReady hook. -func OnReady(params OnReadyParams) func() { +// OnAvailable is the OnAvailable hook. +func OnAvailable(params OnAvailableParams) func() { var env externalcmd.Environment - var onReadyCmd *externalcmd.Cmd + var onAvailableCmd *externalcmd.Cmd - if params.Conf.RunOnReady != "" || params.Conf.RunOnNotReady != "" { + if params.Conf.RunOnAvailable != "" || params.Conf.RunOnUnavailable != "" { env = params.ExternalCmdEnv env["MTX_QUERY"] = url.QueryEscape(params.Query) if params.Desc != nil { @@ -33,31 +33,31 @@ func OnReady(params OnReadyParams) func() { } } - if params.Conf.RunOnReady != "" { - params.Logger.Log(logger.Info, "runOnReady command started") - onReadyCmd = &externalcmd.Cmd{ + if params.Conf.RunOnAvailable != "" { + params.Logger.Log(logger.Info, "runOnAvailable command started") + onAvailableCmd = &externalcmd.Cmd{ Pool: params.ExternalCmdPool, - Cmdstr: params.Conf.RunOnReady, - Restart: params.Conf.RunOnReadyRestart, + Cmdstr: params.Conf.RunOnAvailable, + Restart: params.Conf.RunOnAvailableRestart, Env: env, OnExit: func(err error) { - params.Logger.Log(logger.Info, "runOnReady command exited: %v", err) + params.Logger.Log(logger.Info, "runOnAvailable command exited: %v", err) }, } - onReadyCmd.Start() + onAvailableCmd.Start() } return func() { - if onReadyCmd != nil { - onReadyCmd.Close() - params.Logger.Log(logger.Info, "runOnReady command stopped") + if onAvailableCmd != nil { + onAvailableCmd.Close() + params.Logger.Log(logger.Info, "runOnAvailable command stopped") } - if params.Conf.RunOnNotReady != "" { - params.Logger.Log(logger.Info, "runOnNotReady command launched") + if params.Conf.RunOnUnavailable != "" { + params.Logger.Log(logger.Info, "runOnUnavailable command launched") cmd := &externalcmd.Cmd{ Pool: params.ExternalCmdPool, - Cmdstr: params.Conf.RunOnNotReady, + Cmdstr: params.Conf.RunOnUnavailable, Restart: false, Env: env, } diff --git a/mediamtx.yml b/mediamtx.yml index 0b871ff6..e1d3903c 100644 --- a/mediamtx.yml +++ b/mediamtx.yml @@ -759,7 +759,7 @@ pathDefaults: runOnUnDemand: # Command to run when the stream is available to be read. - # This is terminated with SIGINT when the stream is not ready anymore. + # This is terminated with SIGINT when the stream is not available anymore. # The following environment variables are available: # * MTX_PATH: path name # * MTX_QUERY: query parameters (passed by publisher) (url-encoded) @@ -768,12 +768,12 @@ pathDefaults: # * RTSP_PORT: RTSP server port # * G1, G2, ...: regular expression groups, if path name is # a regular expression. - runOnReady: + runOnAvailable: # Restart the command if it exits. - runOnReadyRestart: false + runOnAvailableRestart: false # Command to run when the stream is not available anymore. - # Environment variables are the same as runOnReady. - runOnNotReady: + # Environment variables are the same as runOnAvailable. + runOnUnavailable: # Command to run when the stream is online, which means # that the stream is available and provided by a online source (not an offline segment).