api: decode durations from strings instead of numbers

This allows to use human-readable durations with the API,
for instance: "5s" instead of 5000000000
This commit is contained in:
aler9
2021-09-26 23:06:40 +02:00
parent 64808863ed
commit ca9645c2f9
19 changed files with 242 additions and 147 deletions

View File

@@ -26,9 +26,9 @@ components:
logFile: logFile:
type: string type: string
readTimeout: readTimeout:
type: integer type: string
writeTimeout: writeTimeout:
type: integer type: string
readBufferCount: readBufferCount:
type: integer type: integer
api: api:
@@ -98,7 +98,7 @@ components:
hlsSegmentCount: hlsSegmentCount:
type: integer type: integer
hlsSegmentDuration: hlsSegmentDuration:
type: integer type: string
hlsAllowOrigin: hlsAllowOrigin:
type: string type: string
@@ -122,9 +122,9 @@ components:
sourceOnDemand: sourceOnDemand:
type: boolean type: boolean
sourceOnDemandStartTimeout: sourceOnDemandStartTimeout:
type: integer type: string
sourceOnDemandCloseAfter: sourceOnDemandCloseAfter:
type: integer type: string
sourceRedirect: sourceRedirect:
type: string type: string
disablePublisherOverride: disablePublisherOverride:
@@ -160,9 +160,9 @@ components:
runOnDemandRestart: runOnDemandRestart:
type: boolean type: boolean
runOnDemandStartTimeout: runOnDemandStartTimeout:
type: integer type: string
runOnDemandCloseAfter: runOnDemandCloseAfter:
type: integer type: string
runOnPublish: runOnPublish:
type: string type: string
runOnPublishRestart: runOnPublishRestart:

View File

@@ -61,8 +61,8 @@ type Conf struct {
LogDestinations []string `yaml:"logDestinations" json:"logDestinations"` LogDestinations []string `yaml:"logDestinations" json:"logDestinations"`
LogDestinationsParsed map[logger.Destination]struct{} `yaml:"-" json:"-"` LogDestinationsParsed map[logger.Destination]struct{} `yaml:"-" json:"-"`
LogFile string `yaml:"logFile" json:"logFile"` LogFile string `yaml:"logFile" json:"logFile"`
ReadTimeout time.Duration `yaml:"readTimeout" json:"readTimeout"` ReadTimeout StringDuration `yaml:"readTimeout" json:"readTimeout"`
WriteTimeout time.Duration `yaml:"writeTimeout" json:"writeTimeout"` WriteTimeout StringDuration `yaml:"writeTimeout" json:"writeTimeout"`
ReadBufferCount int `yaml:"readBufferCount" json:"readBufferCount"` ReadBufferCount int `yaml:"readBufferCount" json:"readBufferCount"`
API bool `yaml:"api" json:"api"` API bool `yaml:"api" json:"api"`
APIAddress string `yaml:"apiAddress" json:"apiAddress"` APIAddress string `yaml:"apiAddress" json:"apiAddress"`
@@ -101,7 +101,7 @@ type Conf struct {
HLSAddress string `yaml:"hlsAddress" json:"hlsAddress"` HLSAddress string `yaml:"hlsAddress" json:"hlsAddress"`
HLSAlwaysRemux bool `yaml:"hlsAlwaysRemux" json:"hlsAlwaysRemux"` HLSAlwaysRemux bool `yaml:"hlsAlwaysRemux" json:"hlsAlwaysRemux"`
HLSSegmentCount int `yaml:"hlsSegmentCount" json:"hlsSegmentCount"` HLSSegmentCount int `yaml:"hlsSegmentCount" json:"hlsSegmentCount"`
HLSSegmentDuration time.Duration `yaml:"hlsSegmentDuration" json:"hlsSegmentDuration"` HLSSegmentDuration StringDuration `yaml:"hlsSegmentDuration" json:"hlsSegmentDuration"`
HLSAllowOrigin string `yaml:"hlsAllowOrigin" json:"hlsAllowOrigin"` HLSAllowOrigin string `yaml:"hlsAllowOrigin" json:"hlsAllowOrigin"`
// paths // paths
@@ -201,10 +201,10 @@ func (conf *Conf) CheckAndFillMissing() error {
conf.LogFile = "rtsp-simple-server.log" conf.LogFile = "rtsp-simple-server.log"
} }
if conf.ReadTimeout == 0 { if conf.ReadTimeout == 0 {
conf.ReadTimeout = 10 * time.Second conf.ReadTimeout = 10 * StringDuration(time.Second)
} }
if conf.WriteTimeout == 0 { if conf.WriteTimeout == 0 {
conf.WriteTimeout = 10 * time.Second conf.WriteTimeout = 10 * StringDuration(time.Second)
} }
if conf.ReadBufferCount == 0 { if conf.ReadBufferCount == 0 {
conf.ReadBufferCount = 512 conf.ReadBufferCount = 512
@@ -322,7 +322,7 @@ func (conf *Conf) CheckAndFillMissing() error {
conf.HLSSegmentCount = 3 conf.HLSSegmentCount = 3
} }
if conf.HLSSegmentDuration == 0 { if conf.HLSSegmentDuration == 0 {
conf.HLSSegmentDuration = 1 * time.Second conf.HLSSegmentDuration = 1 * StringDuration(time.Second)
} }
if conf.HLSAllowOrigin == "" { if conf.HLSAllowOrigin == "" {
conf.HLSAllowOrigin = "*" conf.HLSAllowOrigin = "*"

View File

@@ -28,7 +28,32 @@ func writeTempFile(byts []byte) (string, error) {
return tmpf.Name(), nil return tmpf.Name(), nil
} }
func TestWithFileAndEnv(t *testing.T) { func TestConfFromFile(t *testing.T) {
tmpf, err := writeTempFile([]byte(`
paths:
cam1:
runOnDemandStartTimeout: 5s
`))
require.NoError(t, err)
defer os.Remove(tmpf)
conf, hasFile, err := Load(tmpf)
require.NoError(t, err)
require.Equal(t, true, hasFile)
pa, ok := conf.Paths["cam1"]
require.Equal(t, true, ok)
require.Equal(t, &PathConf{
Source: "publisher",
SourceProtocol: "",
SourceOnDemandStartTimeout: 10 * StringDuration(time.Second),
SourceOnDemandCloseAfter: 10 * StringDuration(time.Second),
RunOnDemandStartTimeout: 5 * StringDuration(time.Second),
RunOnDemandCloseAfter: 10 * StringDuration(time.Second),
}, pa)
}
func TestConfFromFileAndEnv(t *testing.T) {
os.Setenv("RTSP_PATHS_CAM1_SOURCE", "rtsp://testing") os.Setenv("RTSP_PATHS_CAM1_SOURCE", "rtsp://testing")
defer os.Unsetenv("RTSP_PATHS_CAM1_SOURCE") defer os.Unsetenv("RTSP_PATHS_CAM1_SOURCE")
@@ -45,14 +70,14 @@ func TestWithFileAndEnv(t *testing.T) {
require.Equal(t, &PathConf{ require.Equal(t, &PathConf{
Source: "rtsp://testing", Source: "rtsp://testing",
SourceProtocol: "automatic", SourceProtocol: "automatic",
SourceOnDemandStartTimeout: 10 * time.Second, SourceOnDemandStartTimeout: 10 * StringDuration(time.Second),
SourceOnDemandCloseAfter: 10 * time.Second, SourceOnDemandCloseAfter: 10 * StringDuration(time.Second),
RunOnDemandStartTimeout: 10 * time.Second, RunOnDemandStartTimeout: 10 * StringDuration(time.Second),
RunOnDemandCloseAfter: 10 * time.Second, RunOnDemandCloseAfter: 10 * StringDuration(time.Second),
}, pa) }, pa)
} }
func TestWithEnvOnly(t *testing.T) { func TestConfFromEnvOnly(t *testing.T) {
os.Setenv("RTSP_PATHS_CAM1_SOURCE", "rtsp://testing") os.Setenv("RTSP_PATHS_CAM1_SOURCE", "rtsp://testing")
defer os.Unsetenv("RTSP_PATHS_CAM1_SOURCE") defer os.Unsetenv("RTSP_PATHS_CAM1_SOURCE")
@@ -65,14 +90,14 @@ func TestWithEnvOnly(t *testing.T) {
require.Equal(t, &PathConf{ require.Equal(t, &PathConf{
Source: "rtsp://testing", Source: "rtsp://testing",
SourceProtocol: "automatic", SourceProtocol: "automatic",
SourceOnDemandStartTimeout: 10 * time.Second, SourceOnDemandStartTimeout: 10 * StringDuration(time.Second),
SourceOnDemandCloseAfter: 10 * time.Second, SourceOnDemandCloseAfter: 10 * StringDuration(time.Second),
RunOnDemandStartTimeout: 10 * time.Second, RunOnDemandStartTimeout: 10 * StringDuration(time.Second),
RunOnDemandCloseAfter: 10 * time.Second, RunOnDemandCloseAfter: 10 * StringDuration(time.Second),
}, pa) }, pa)
} }
func TestEncryption(t *testing.T) { func TestConfEncryption(t *testing.T) {
key := "testing123testin" key := "testing123testin"
plaintext := ` plaintext := `
paths: paths:

View File

@@ -12,13 +12,13 @@ import (
func loadEnvInternal(env map[string]string, prefix string, rv reflect.Value) error { func loadEnvInternal(env map[string]string, prefix string, rv reflect.Value) error {
rt := rv.Type() rt := rv.Type()
if rt == reflect.TypeOf(time.Duration(0)) { if rt == reflect.TypeOf(StringDuration(0)) {
if ev, ok := env[prefix]; ok { if ev, ok := env[prefix]; ok {
d, err := time.ParseDuration(ev) d, err := time.ParseDuration(ev)
if err != nil { if err != nil {
return fmt.Errorf("%s: %s", prefix, err) return fmt.Errorf("%s: %s", prefix, err)
} }
rv.Set(reflect.ValueOf(d)) rv.Set(reflect.ValueOf(StringDuration(d)))
} }
return nil return nil
} }

View File

@@ -23,7 +23,7 @@ type testStruct struct {
MyBool bool MyBool bool
// duration // duration
MyDuration time.Duration MyDuration StringDuration
// slice // slice
MySlice []string MySlice []string
@@ -61,7 +61,7 @@ func TestEnvironment(t *testing.T) {
require.Equal(t, "testcontent", s.MyString) require.Equal(t, "testcontent", s.MyString)
require.Equal(t, 123, s.MyInt) require.Equal(t, 123, s.MyInt)
require.Equal(t, true, s.MyBool) require.Equal(t, true, s.MyBool)
require.Equal(t, 22*time.Second, s.MyDuration) require.Equal(t, 22*StringDuration(time.Second), s.MyDuration)
require.Equal(t, []string{"el1", "el2"}, s.MySlice) require.Equal(t, []string{"el1", "el2"}, s.MySlice)
_, ok := s.MyMap["mykey"] _, ok := s.MyMap["mykey"]

View File

@@ -75,8 +75,8 @@ type PathConf struct {
SourceAnyPortEnable bool `yaml:"sourceAnyPortEnable" json:"sourceAnyPortEnable"` SourceAnyPortEnable bool `yaml:"sourceAnyPortEnable" json:"sourceAnyPortEnable"`
SourceFingerprint string `yaml:"sourceFingerprint" json:"sourceFingerprint"` SourceFingerprint string `yaml:"sourceFingerprint" json:"sourceFingerprint"`
SourceOnDemand bool `yaml:"sourceOnDemand" json:"sourceOnDemand"` SourceOnDemand bool `yaml:"sourceOnDemand" json:"sourceOnDemand"`
SourceOnDemandStartTimeout time.Duration `yaml:"sourceOnDemandStartTimeout" json:"sourceOnDemandStartTimeout"` //nolint:lll SourceOnDemandStartTimeout StringDuration `yaml:"sourceOnDemandStartTimeout" json:"sourceOnDemandStartTimeout"` //nolint:lll
SourceOnDemandCloseAfter time.Duration `yaml:"sourceOnDemandCloseAfter" json:"sourceOnDemandCloseAfter"` SourceOnDemandCloseAfter StringDuration `yaml:"sourceOnDemandCloseAfter" json:"sourceOnDemandCloseAfter"`
SourceRedirect string `yaml:"sourceRedirect" json:"sourceRedirect"` SourceRedirect string `yaml:"sourceRedirect" json:"sourceRedirect"`
DisablePublisherOverride bool `yaml:"disablePublisherOverride" json:"disablePublisherOverride"` DisablePublisherOverride bool `yaml:"disablePublisherOverride" json:"disablePublisherOverride"`
Fallback string `yaml:"fallback" json:"fallback"` Fallback string `yaml:"fallback" json:"fallback"`
@@ -96,8 +96,8 @@ type PathConf struct {
RunOnInitRestart bool `yaml:"runOnInitRestart" json:"runOnInitRestart"` RunOnInitRestart bool `yaml:"runOnInitRestart" json:"runOnInitRestart"`
RunOnDemand string `yaml:"runOnDemand" json:"runOnDemand"` RunOnDemand string `yaml:"runOnDemand" json:"runOnDemand"`
RunOnDemandRestart bool `yaml:"runOnDemandRestart" json:"runOnDemandRestart"` RunOnDemandRestart bool `yaml:"runOnDemandRestart" json:"runOnDemandRestart"`
RunOnDemandStartTimeout time.Duration `yaml:"runOnDemandStartTimeout" json:"runOnDemandStartTimeout"` RunOnDemandStartTimeout StringDuration `yaml:"runOnDemandStartTimeout" json:"runOnDemandStartTimeout"`
RunOnDemandCloseAfter time.Duration `yaml:"runOnDemandCloseAfter" json:"runOnDemandCloseAfter"` RunOnDemandCloseAfter StringDuration `yaml:"runOnDemandCloseAfter" json:"runOnDemandCloseAfter"`
RunOnPublish string `yaml:"runOnPublish" json:"runOnPublish"` RunOnPublish string `yaml:"runOnPublish" json:"runOnPublish"`
RunOnPublishRestart bool `yaml:"runOnPublishRestart" json:"runOnPublishRestart"` RunOnPublishRestart bool `yaml:"runOnPublishRestart" json:"runOnPublishRestart"`
RunOnRead string `yaml:"runOnRead" json:"runOnRead"` RunOnRead string `yaml:"runOnRead" json:"runOnRead"`
@@ -236,11 +236,11 @@ func (pconf *PathConf) checkAndFillMissing(name string) error {
} }
if pconf.SourceOnDemandStartTimeout == 0 { if pconf.SourceOnDemandStartTimeout == 0 {
pconf.SourceOnDemandStartTimeout = 10 * time.Second pconf.SourceOnDemandStartTimeout = 10 * StringDuration(time.Second)
} }
if pconf.SourceOnDemandCloseAfter == 0 { if pconf.SourceOnDemandCloseAfter == 0 {
pconf.SourceOnDemandCloseAfter = 10 * time.Second pconf.SourceOnDemandCloseAfter = 10 * StringDuration(time.Second)
} }
if pconf.Fallback != "" { if pconf.Fallback != "" {
@@ -337,11 +337,11 @@ func (pconf *PathConf) checkAndFillMissing(name string) error {
} }
if pconf.RunOnDemandStartTimeout == 0 { if pconf.RunOnDemandStartTimeout == 0 {
pconf.RunOnDemandStartTimeout = 10 * time.Second pconf.RunOnDemandStartTimeout = 10 * StringDuration(time.Second)
} }
if pconf.RunOnDemandCloseAfter == 0 { if pconf.RunOnDemandCloseAfter == 0 {
pconf.RunOnDemandCloseAfter = 10 * time.Second pconf.RunOnDemandCloseAfter = 10 * StringDuration(time.Second)
} }
return nil return nil

View File

@@ -0,0 +1,65 @@
package conf
import (
"encoding/json"
"errors"
"time"
"gopkg.in/yaml.v2"
)
// StringDuration is a duration that is unmarshaled from a string.
// Durations are normally unmarshaled from numbers.
type StringDuration time.Duration
// MarshalJSON marshals a StringDuration into a string.
func (d StringDuration) MarshalJSON() ([]byte, error) {
return json.Marshal(time.Duration(d).String())
}
// UnmarshalJSON unmarshals a StringDuration from a string.
func (d *StringDuration) UnmarshalJSON(b []byte) error {
var v interface{}
if err := json.Unmarshal(b, &v); err != nil {
return err
}
value, ok := v.(string)
if !ok {
return errors.New("invalid duration")
}
du, err := time.ParseDuration(value)
if err != nil {
return err
}
*d = StringDuration(du)
return nil
}
// MarshalYAML marshals a StringDuration into a string.
func (d StringDuration) MarshalYAML() ([]byte, error) {
return yaml.Marshal(time.Duration(d).String())
}
// UnmarshalYAML unmarshals a StringDuration from a string.
func (d *StringDuration) UnmarshalYAML(unmarshal func(interface{}) error) error {
var v interface{}
if err := unmarshal(&v); err != nil {
return err
}
value, ok := v.(string)
if !ok {
return errors.New("invalid duration")
}
du, err := time.ParseDuration(value)
if err != nil {
return err
}
*d = StringDuration(du)
return nil
}

View File

@@ -10,7 +10,6 @@ import (
"net/http/httputil" "net/http/httputil"
"reflect" "reflect"
"sync" "sync"
"time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@@ -50,8 +49,8 @@ func loadConfData(ctx *gin.Context) (interface{}, error) {
LogLevel *string `json:"logLevel"` LogLevel *string `json:"logLevel"`
LogDestinations *[]string `json:"logDestinations"` LogDestinations *[]string `json:"logDestinations"`
LogFile *string `json:"logFile"` LogFile *string `json:"logFile"`
ReadTimeout *time.Duration `json:"readTimeout"` ReadTimeout *conf.StringDuration `json:"readTimeout"`
WriteTimeout *time.Duration `json:"writeTimeout"` WriteTimeout *conf.StringDuration `json:"writeTimeout"`
ReadBufferCount *int `json:"readBufferCount"` ReadBufferCount *int `json:"readBufferCount"`
API *bool `json:"api"` API *bool `json:"api"`
APIAddress *string `json:"apiAddress"` APIAddress *string `json:"apiAddress"`
@@ -87,7 +86,7 @@ func loadConfData(ctx *gin.Context) (interface{}, error) {
HLSAddress *string `json:"hlsAddress"` HLSAddress *string `json:"hlsAddress"`
HLSAlwaysRemux *bool `json:"hlsAlwaysRemux"` HLSAlwaysRemux *bool `json:"hlsAlwaysRemux"`
HLSSegmentCount *int `json:"hlsSegmentCount"` HLSSegmentCount *int `json:"hlsSegmentCount"`
HLSSegmentDuration *time.Duration `json:"hlsSegmentDuration"` HLSSegmentDuration *conf.StringDuration `json:"hlsSegmentDuration"`
HLSAllowOrigin *string `json:"hlsAllowOrigin"` HLSAllowOrigin *string `json:"hlsAllowOrigin"`
} }
err := json.NewDecoder(ctx.Request.Body).Decode(&in) err := json.NewDecoder(ctx.Request.Body).Decode(&in)
@@ -106,8 +105,8 @@ func loadConfPathData(ctx *gin.Context) (interface{}, error) {
SourceAnyPortEnable *bool `json:"sourceAnyPortEnable"` SourceAnyPortEnable *bool `json:"sourceAnyPortEnable"`
SourceFingerprint *string `json:"sourceFingerprint"` SourceFingerprint *string `json:"sourceFingerprint"`
SourceOnDemand *bool `json:"sourceOnDemand"` SourceOnDemand *bool `json:"sourceOnDemand"`
SourceOnDemandStartTimeout *time.Duration `json:"sourceOnDemandStartTimeout"` SourceOnDemandStartTimeout *conf.StringDuration `json:"sourceOnDemandStartTimeout"`
SourceOnDemandCloseAfter *time.Duration `json:"sourceOnDemandCloseAfter"` SourceOnDemandCloseAfter *conf.StringDuration `json:"sourceOnDemandCloseAfter"`
SourceRedirect *string `json:"sourceRedirect"` SourceRedirect *string `json:"sourceRedirect"`
DisablePublisherOverride *bool `json:"disablePublisherOverride"` DisablePublisherOverride *bool `json:"disablePublisherOverride"`
Fallback *string `json:"fallback"` Fallback *string `json:"fallback"`
@@ -125,8 +124,8 @@ func loadConfPathData(ctx *gin.Context) (interface{}, error) {
RunOnInitRestart *bool `json:"runOnInitRestart"` RunOnInitRestart *bool `json:"runOnInitRestart"`
RunOnDemand *string `json:"runOnDemand"` RunOnDemand *string `json:"runOnDemand"`
RunOnDemandRestart *bool `json:"runOnDemandRestart"` RunOnDemandRestart *bool `json:"runOnDemandRestart"`
RunOnDemandStartTimeout *time.Duration `json:"runOnDemandStartTimeout"` RunOnDemandStartTimeout *conf.StringDuration `json:"runOnDemandStartTimeout"`
RunOnDemandCloseAfter *time.Duration `json:"runOnDemandCloseAfter"` RunOnDemandCloseAfter *conf.StringDuration `json:"runOnDemandCloseAfter"`
RunOnPublish *string `json:"runOnPublish"` RunOnPublish *string `json:"runOnPublish"`
RunOnPublishRestart *bool `json:"runOnPublishRestart"` RunOnPublishRestart *bool `json:"runOnPublishRestart"`
RunOnRead *string `json:"runOnRead"` RunOnRead *string `json:"runOnRead"`

View File

@@ -71,6 +71,7 @@ func TestAPIConfigSet(t *testing.T) {
err := httpRequest(http.MethodPost, "http://localhost:9997/v1/config/set", map[string]interface{}{ err := httpRequest(http.MethodPost, "http://localhost:9997/v1/config/set", map[string]interface{}{
"rtmpDisable": true, "rtmpDisable": true,
"readTimeout": "7s",
}, nil) }, nil)
require.NoError(t, err) require.NoError(t, err)
@@ -80,6 +81,7 @@ func TestAPIConfigSet(t *testing.T) {
err = httpRequest(http.MethodGet, "http://localhost:9997/v1/config/get", nil, &out) err = httpRequest(http.MethodGet, "http://localhost:9997/v1/config/get", nil, &out)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, true, out["rtmpDisable"]) require.Equal(t, true, out["rtmpDisable"])
require.Equal(t, "7s", out["readTimeout"])
} }
func TestAPIConfigPathsAdd(t *testing.T) { func TestAPIConfigPathsAdd(t *testing.T) {

View File

@@ -18,6 +18,7 @@ import (
"github.com/aler9/gortsplib/pkg/rtph264" "github.com/aler9/gortsplib/pkg/rtph264"
"github.com/pion/rtp" "github.com/pion/rtp"
"github.com/aler9/rtsp-simple-server/internal/conf"
"github.com/aler9/rtsp-simple-server/internal/hls" "github.com/aler9/rtsp-simple-server/internal/hls"
"github.com/aler9/rtsp-simple-server/internal/logger" "github.com/aler9/rtsp-simple-server/internal/logger"
) )
@@ -117,7 +118,7 @@ type hlsMuxerParent interface {
type hlsMuxer struct { type hlsMuxer struct {
hlsAlwaysRemux bool hlsAlwaysRemux bool
hlsSegmentCount int hlsSegmentCount int
hlsSegmentDuration time.Duration hlsSegmentDuration conf.StringDuration
readBufferCount int readBufferCount int
wg *sync.WaitGroup wg *sync.WaitGroup
pathName string pathName string
@@ -140,7 +141,7 @@ func newHLSMuxer(
parentCtx context.Context, parentCtx context.Context,
hlsAlwaysRemux bool, hlsAlwaysRemux bool,
hlsSegmentCount int, hlsSegmentCount int,
hlsSegmentDuration time.Duration, hlsSegmentDuration conf.StringDuration,
readBufferCount int, readBufferCount int,
wg *sync.WaitGroup, wg *sync.WaitGroup,
pathName string, pathName string,
@@ -300,7 +301,7 @@ func (r *hlsMuxer) runInner(innerCtx context.Context, innerReady chan struct{})
var err error var err error
r.muxer, err = hls.NewMuxer( r.muxer, err = hls.NewMuxer(
r.hlsSegmentCount, r.hlsSegmentCount,
r.hlsSegmentDuration, time.Duration(r.hlsSegmentDuration),
videoTrack, videoTrack,
audioTrack, audioTrack,
) )

View File

@@ -8,8 +8,8 @@ import (
gopath "path" gopath "path"
"strings" "strings"
"sync" "sync"
"time"
"github.com/aler9/rtsp-simple-server/internal/conf"
"github.com/aler9/rtsp-simple-server/internal/logger" "github.com/aler9/rtsp-simple-server/internal/logger"
) )
@@ -20,7 +20,7 @@ type hlsServerParent interface {
type hlsServer struct { type hlsServer struct {
hlsAlwaysRemux bool hlsAlwaysRemux bool
hlsSegmentCount int hlsSegmentCount int
hlsSegmentDuration time.Duration hlsSegmentDuration conf.StringDuration
hlsAllowOrigin string hlsAllowOrigin string
readBufferCount int readBufferCount int
pathManager *pathManager pathManager *pathManager
@@ -43,7 +43,7 @@ func newHLSServer(
address string, address string,
hlsAlwaysRemux bool, hlsAlwaysRemux bool,
hlsSegmentCount int, hlsSegmentCount int,
hlsSegmentDuration time.Duration, hlsSegmentDuration conf.StringDuration,
hlsAllowOrigin string, hlsAllowOrigin string,
readBufferCount int, readBufferCount int,
pathManager *pathManager, pathManager *pathManager,

View File

@@ -182,8 +182,8 @@ type pathPublisherPauseReq struct {
type path struct { type path struct {
rtspAddress string rtspAddress string
readTimeout time.Duration readTimeout conf.StringDuration
writeTimeout time.Duration writeTimeout conf.StringDuration
readBufferCount int readBufferCount int
readBufferSize int readBufferSize int
confName string confName string
@@ -226,8 +226,8 @@ type path struct {
func newPath( func newPath(
parentCtx context.Context, parentCtx context.Context,
rtspAddress string, rtspAddress string,
readTimeout time.Duration, readTimeout conf.StringDuration,
writeTimeout time.Duration, writeTimeout conf.StringDuration,
readBufferCount int, readBufferCount int,
readBufferSize int, readBufferSize int,
confName string, confName string,
@@ -478,7 +478,7 @@ func (pa *path) onDemandStartSource() {
pa.onDemandReadyTimer.Stop() pa.onDemandReadyTimer.Stop()
if pa.hasStaticSource() { if pa.hasStaticSource() {
pa.staticSourceCreate() pa.staticSourceCreate()
pa.onDemandReadyTimer = time.NewTimer(pa.conf.SourceOnDemandStartTimeout) pa.onDemandReadyTimer = time.NewTimer(time.Duration(pa.conf.SourceOnDemandStartTimeout))
} else { } else {
pa.Log(logger.Info, "on demand command started") pa.Log(logger.Info, "on demand command started")
@@ -487,7 +487,7 @@ func (pa *path) onDemandStartSource() {
Path: pa.name, Path: pa.name,
Port: port, Port: port,
}) })
pa.onDemandReadyTimer = time.NewTimer(pa.conf.RunOnDemandStartTimeout) pa.onDemandReadyTimer = time.NewTimer(time.Duration(pa.conf.RunOnDemandStartTimeout))
} }
pa.onDemandState = pathOnDemandStateWaitingReady pa.onDemandState = pathOnDemandStateWaitingReady
@@ -496,9 +496,9 @@ func (pa *path) onDemandStartSource() {
func (pa *path) onDemandScheduleClose() { func (pa *path) onDemandScheduleClose() {
pa.onDemandCloseTimer.Stop() pa.onDemandCloseTimer.Stop()
if pa.hasStaticSource() { if pa.hasStaticSource() {
pa.onDemandCloseTimer = time.NewTimer(pa.conf.SourceOnDemandCloseAfter) pa.onDemandCloseTimer = time.NewTimer(time.Duration(pa.conf.SourceOnDemandCloseAfter))
} else { } else {
pa.onDemandCloseTimer = time.NewTimer(pa.conf.RunOnDemandCloseAfter) pa.onDemandCloseTimer = time.NewTimer(time.Duration(pa.conf.RunOnDemandCloseAfter))
} }
pa.onDemandState = pathOnDemandStateClosing pa.onDemandState = pathOnDemandStateClosing

View File

@@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"net" "net"
"sync" "sync"
"time"
"github.com/aler9/gortsplib/pkg/base" "github.com/aler9/gortsplib/pkg/base"
@@ -23,8 +22,8 @@ type pathManagerParent interface {
type pathManager struct { type pathManager struct {
rtspAddress string rtspAddress string
readTimeout time.Duration readTimeout conf.StringDuration
writeTimeout time.Duration writeTimeout conf.StringDuration
readBufferCount int readBufferCount int
readBufferSize int readBufferSize int
pathConfs map[string]*conf.PathConf pathConfs map[string]*conf.PathConf
@@ -52,8 +51,8 @@ type pathManager struct {
func newPathManager( func newPathManager(
parentCtx context.Context, parentCtx context.Context,
rtspAddress string, rtspAddress string,
readTimeout time.Duration, readTimeout conf.StringDuration,
writeTimeout time.Duration, writeTimeout conf.StringDuration,
readBufferCount int, readBufferCount int,
readBufferSize int, readBufferSize int,
pathConfs map[string]*conf.PathConf, pathConfs map[string]*conf.PathConf,

View File

@@ -19,6 +19,7 @@ import (
"github.com/notedit/rtmp/av" "github.com/notedit/rtmp/av"
"github.com/pion/rtp" "github.com/pion/rtp"
"github.com/aler9/rtsp-simple-server/internal/conf"
"github.com/aler9/rtsp-simple-server/internal/externalcmd" "github.com/aler9/rtsp-simple-server/internal/externalcmd"
"github.com/aler9/rtsp-simple-server/internal/logger" "github.com/aler9/rtsp-simple-server/internal/logger"
"github.com/aler9/rtsp-simple-server/internal/rtcpsenderset" "github.com/aler9/rtsp-simple-server/internal/rtcpsenderset"
@@ -55,8 +56,8 @@ type rtmpConnParent interface {
type rtmpConn struct { type rtmpConn struct {
id string id string
rtspAddress string rtspAddress string
readTimeout time.Duration readTimeout conf.StringDuration
writeTimeout time.Duration writeTimeout conf.StringDuration
readBufferCount int readBufferCount int
runOnConnect string runOnConnect string
runOnConnectRestart bool runOnConnectRestart bool
@@ -77,8 +78,8 @@ func newRTMPConn(
parentCtx context.Context, parentCtx context.Context,
id string, id string,
rtspAddress string, rtspAddress string,
readTimeout time.Duration, readTimeout conf.StringDuration,
writeTimeout time.Duration, writeTimeout conf.StringDuration,
readBufferCount int, readBufferCount int,
runOnConnect string, runOnConnect string,
runOnConnectRestart bool, runOnConnectRestart bool,
@@ -184,8 +185,8 @@ func (c *rtmpConn) runInner(ctx context.Context) error {
c.conn.NetConn().Close() c.conn.NetConn().Close()
}() }()
c.conn.NetConn().SetReadDeadline(time.Now().Add(c.readTimeout)) c.conn.NetConn().SetReadDeadline(time.Now().Add(time.Duration(c.readTimeout)))
c.conn.NetConn().SetWriteDeadline(time.Now().Add(c.writeTimeout)) c.conn.NetConn().SetWriteDeadline(time.Now().Add(time.Duration(c.writeTimeout)))
err := c.conn.ServerHandshake() err := c.conn.ServerHandshake()
if err != nil { if err != nil {
return err return err
@@ -262,7 +263,7 @@ func (c *rtmpConn) runRead(ctx context.Context) error {
return fmt.Errorf("the stream doesn't contain an H264 track or an AAC track") return fmt.Errorf("the stream doesn't contain an H264 track or an AAC track")
} }
c.conn.NetConn().SetWriteDeadline(time.Now().Add(c.writeTimeout)) c.conn.NetConn().SetWriteDeadline(time.Now().Add(time.Duration(c.writeTimeout)))
c.conn.WriteMetadata(videoTrack, audioTrack) c.conn.WriteMetadata(videoTrack, audioTrack)
c.ringBuffer = ringbuffer.New(uint64(c.readBufferCount)) c.ringBuffer = ringbuffer.New(uint64(c.readBufferCount))
@@ -351,7 +352,7 @@ func (c *rtmpConn) runRead(ctx context.Context) error {
pts -= videoStartPTS pts -= videoStartPTS
dts := videoDTSEst.Feed(pts) dts := videoDTSEst.Feed(pts)
c.conn.NetConn().SetWriteDeadline(time.Now().Add(c.writeTimeout)) c.conn.NetConn().SetWriteDeadline(time.Now().Add(time.Duration(c.writeTimeout)))
err = c.conn.WritePacket(av.Packet{ err = c.conn.WritePacket(av.Packet{
Type: av.H264, Type: av.H264,
Data: data, Data: data,
@@ -391,7 +392,7 @@ func (c *rtmpConn) runRead(ctx context.Context) error {
} }
for _, au := range aus { for _, au := range aus {
c.conn.NetConn().SetWriteDeadline(time.Now().Add(c.writeTimeout)) c.conn.NetConn().SetWriteDeadline(time.Now().Add(time.Duration(c.writeTimeout)))
err := c.conn.WritePacket(av.Packet{ err := c.conn.WritePacket(av.Packet{
Type: av.AAC, Type: av.AAC,
Data: au, Data: au,
@@ -408,7 +409,7 @@ func (c *rtmpConn) runRead(ctx context.Context) error {
} }
func (c *rtmpConn) runPublish(ctx context.Context) error { func (c *rtmpConn) runPublish(ctx context.Context) error {
c.conn.NetConn().SetReadDeadline(time.Now().Add(c.readTimeout)) c.conn.NetConn().SetReadDeadline(time.Now().Add(time.Duration(c.readTimeout)))
videoTrack, audioTrack, err := c.conn.ReadMetadata() videoTrack, audioTrack, err := c.conn.ReadMetadata()
if err != nil { if err != nil {
return err return err
@@ -483,7 +484,7 @@ func (c *rtmpConn) runPublish(ctx context.Context) error {
} }
for { for {
c.conn.NetConn().SetReadDeadline(time.Now().Add(c.readTimeout)) c.conn.NetConn().SetReadDeadline(time.Now().Add(time.Duration(c.readTimeout)))
pkt, err := c.conn.ReadPacket() pkt, err := c.conn.ReadPacket()
if err != nil { if err != nil {
return err return err

View File

@@ -8,10 +8,10 @@ import (
"net" "net"
"strconv" "strconv"
"sync" "sync"
"time"
"github.com/aler9/gortsplib" "github.com/aler9/gortsplib"
"github.com/aler9/rtsp-simple-server/internal/conf"
"github.com/aler9/rtsp-simple-server/internal/logger" "github.com/aler9/rtsp-simple-server/internal/logger"
) )
@@ -20,8 +20,8 @@ type rtmpServerParent interface {
} }
type rtmpServer struct { type rtmpServer struct {
readTimeout time.Duration readTimeout conf.StringDuration
writeTimeout time.Duration writeTimeout conf.StringDuration
readBufferCount int readBufferCount int
rtspAddress string rtspAddress string
runOnConnect string runOnConnect string
@@ -45,8 +45,8 @@ type rtmpServer struct {
func newRTMPServer( func newRTMPServer(
parentCtx context.Context, parentCtx context.Context,
address string, address string,
readTimeout time.Duration, readTimeout conf.StringDuration,
writeTimeout time.Duration, writeTimeout conf.StringDuration,
readBufferCount int, readBufferCount int,
rtspAddress string, rtspAddress string,
runOnConnect string, runOnConnect string,

View File

@@ -12,6 +12,7 @@ import (
"github.com/aler9/gortsplib/pkg/rtph264" "github.com/aler9/gortsplib/pkg/rtph264"
"github.com/notedit/rtmp/av" "github.com/notedit/rtmp/av"
"github.com/aler9/rtsp-simple-server/internal/conf"
"github.com/aler9/rtsp-simple-server/internal/logger" "github.com/aler9/rtsp-simple-server/internal/logger"
"github.com/aler9/rtsp-simple-server/internal/rtcpsenderset" "github.com/aler9/rtsp-simple-server/internal/rtcpsenderset"
"github.com/aler9/rtsp-simple-server/internal/rtmp" "github.com/aler9/rtsp-simple-server/internal/rtmp"
@@ -29,8 +30,8 @@ type rtmpSourceParent interface {
type rtmpSource struct { type rtmpSource struct {
ur string ur string
readTimeout time.Duration readTimeout conf.StringDuration
writeTimeout time.Duration writeTimeout conf.StringDuration
wg *sync.WaitGroup wg *sync.WaitGroup
parent rtmpSourceParent parent rtmpSourceParent
@@ -41,8 +42,8 @@ type rtmpSource struct {
func newRTMPSource( func newRTMPSource(
parentCtx context.Context, parentCtx context.Context,
ur string, ur string,
readTimeout time.Duration, readTimeout conf.StringDuration,
writeTimeout time.Duration, writeTimeout conf.StringDuration,
wg *sync.WaitGroup, wg *sync.WaitGroup,
parent rtmpSourceParent) *rtmpSource { parent rtmpSourceParent) *rtmpSource {
ctx, ctxCancel := context.WithCancel(parentCtx) ctx, ctxCancel := context.WithCancel(parentCtx)
@@ -103,7 +104,7 @@ func (s *rtmpSource) runInner() bool {
runErr <- func() error { runErr <- func() error {
s.log(logger.Debug, "connecting") s.log(logger.Debug, "connecting")
ctx2, cancel2 := context.WithTimeout(innerCtx, s.readTimeout) ctx2, cancel2 := context.WithTimeout(innerCtx, time.Duration(s.readTimeout))
defer cancel2() defer cancel2()
conn, err := rtmp.DialContext(ctx2, s.ur) conn, err := rtmp.DialContext(ctx2, s.ur)
@@ -114,8 +115,8 @@ func (s *rtmpSource) runInner() bool {
readDone := make(chan error) readDone := make(chan error)
go func() { go func() {
readDone <- func() error { readDone <- func() error {
conn.NetConn().SetReadDeadline(time.Now().Add(s.readTimeout)) conn.NetConn().SetReadDeadline(time.Now().Add(time.Duration(s.readTimeout)))
conn.NetConn().SetWriteDeadline(time.Now().Add(s.writeTimeout)) conn.NetConn().SetWriteDeadline(time.Now().Add(time.Duration(s.writeTimeout)))
err = conn.ClientHandshake() err = conn.ClientHandshake()
if err != nil { if err != nil {
return err return err
@@ -123,7 +124,7 @@ func (s *rtmpSource) runInner() bool {
conn.NetConn().SetWriteDeadline(time.Time{}) conn.NetConn().SetWriteDeadline(time.Time{})
conn.NetConn().SetReadDeadline(time.Now().Add(s.readTimeout)) conn.NetConn().SetReadDeadline(time.Now().Add(time.Duration(s.readTimeout)))
videoTrack, audioTrack, err := conn.ReadMetadata() videoTrack, audioTrack, err := conn.ReadMetadata()
if err != nil { if err != nil {
return err return err
@@ -171,7 +172,7 @@ func (s *rtmpSource) runInner() bool {
} }
for { for {
conn.NetConn().SetReadDeadline(time.Now().Add(s.readTimeout)) conn.NetConn().SetReadDeadline(time.Now().Add(time.Duration(s.readTimeout)))
pkt, err := conn.ReadPacket() pkt, err := conn.ReadPacket()
if err != nil { if err != nil {
return err return err

View File

@@ -12,6 +12,7 @@ import (
"github.com/aler9/gortsplib/pkg/headers" "github.com/aler9/gortsplib/pkg/headers"
"github.com/aler9/gortsplib/pkg/liberrors" "github.com/aler9/gortsplib/pkg/liberrors"
"github.com/aler9/rtsp-simple-server/internal/conf"
"github.com/aler9/rtsp-simple-server/internal/externalcmd" "github.com/aler9/rtsp-simple-server/internal/externalcmd"
"github.com/aler9/rtsp-simple-server/internal/logger" "github.com/aler9/rtsp-simple-server/internal/logger"
) )
@@ -37,7 +38,7 @@ type rtspConnParent interface {
type rtspConn struct { type rtspConn struct {
rtspAddress string rtspAddress string
authMethods []headers.AuthMethod authMethods []headers.AuthMethod
readTimeout time.Duration readTimeout conf.StringDuration
runOnConnect string runOnConnect string
runOnConnectRestart bool runOnConnectRestart bool
pathManager *pathManager pathManager *pathManager
@@ -54,7 +55,7 @@ type rtspConn struct {
func newRTSPConn( func newRTSPConn(
rtspAddress string, rtspAddress string,
authMethods []headers.AuthMethod, authMethods []headers.AuthMethod,
readTimeout time.Duration, readTimeout conf.StringDuration,
runOnConnect string, runOnConnect string,
runOnConnectRestart bool, runOnConnectRestart bool,
pathManager *pathManager, pathManager *pathManager,

View File

@@ -24,7 +24,7 @@ type rtspServerParent interface {
type rtspServer struct { type rtspServer struct {
authMethods []headers.AuthMethod authMethods []headers.AuthMethod
readTimeout time.Duration readTimeout conf.StringDuration
isTLS bool isTLS bool
rtspAddress string rtspAddress string
protocols map[conf.Protocol]struct{} protocols map[conf.Protocol]struct{}
@@ -47,8 +47,8 @@ func newRTSPServer(
parentCtx context.Context, parentCtx context.Context,
address string, address string,
authMethods []headers.AuthMethod, authMethods []headers.AuthMethod,
readTimeout time.Duration, readTimeout conf.StringDuration,
writeTimeout time.Duration, writeTimeout conf.StringDuration,
readBufferCount int, readBufferCount int,
readBufferSize int, readBufferSize int,
useUDP bool, useUDP bool,
@@ -87,8 +87,8 @@ func newRTSPServer(
s.srv = &gortsplib.Server{ s.srv = &gortsplib.Server{
Handler: s, Handler: s,
ReadTimeout: readTimeout, ReadTimeout: time.Duration(readTimeout),
WriteTimeout: writeTimeout, WriteTimeout: time.Duration(writeTimeout),
ReadBufferCount: readBufferCount, ReadBufferCount: readBufferCount,
ReadBufferSize: readBufferSize, ReadBufferSize: readBufferSize,
} }

View File

@@ -13,6 +13,7 @@ import (
"github.com/aler9/gortsplib" "github.com/aler9/gortsplib"
"github.com/aler9/gortsplib/pkg/base" "github.com/aler9/gortsplib/pkg/base"
"github.com/aler9/rtsp-simple-server/internal/conf"
"github.com/aler9/rtsp-simple-server/internal/logger" "github.com/aler9/rtsp-simple-server/internal/logger"
) )
@@ -31,8 +32,8 @@ type rtspSource struct {
proto *gortsplib.ClientProtocol proto *gortsplib.ClientProtocol
anyPortEnable bool anyPortEnable bool
fingerprint string fingerprint string
readTimeout time.Duration readTimeout conf.StringDuration
writeTimeout time.Duration writeTimeout conf.StringDuration
readBufferCount int readBufferCount int
readBufferSize int readBufferSize int
wg *sync.WaitGroup wg *sync.WaitGroup
@@ -48,8 +49,8 @@ func newRTSPSource(
proto *gortsplib.ClientProtocol, proto *gortsplib.ClientProtocol,
anyPortEnable bool, anyPortEnable bool,
fingerprint string, fingerprint string,
readTimeout time.Duration, readTimeout conf.StringDuration,
writeTimeout time.Duration, writeTimeout conf.StringDuration,
readBufferCount int, readBufferCount int,
readBufferSize int, readBufferSize int,
wg *sync.WaitGroup, wg *sync.WaitGroup,
@@ -134,8 +135,8 @@ func (s *rtspSource) runInner() bool {
return nil return nil
}, },
}, },
ReadTimeout: s.readTimeout, ReadTimeout: time.Duration(s.readTimeout),
WriteTimeout: s.writeTimeout, WriteTimeout: time.Duration(s.writeTimeout),
ReadBufferCount: s.readBufferCount, ReadBufferCount: s.readBufferCount,
ReadBufferSize: s.readBufferSize, ReadBufferSize: s.readBufferSize,
AnyPortEnable: s.anyPortEnable, AnyPortEnable: s.anyPortEnable,