mirror of https://bitbucket.org/ausocean/av.git
Merged in improve-logging (pull request #389)
Improve debug and info logging quality and frequency * cmd/rv: added some more debug and info logging * revid: improving logging in revid.go * revid: improved logging in senders.go * revid: don't need to set log level as netsender does it * added some extract log messages Approved-by: Trek Hopton <trek.hopton@gmail.com>
This commit is contained in:
parent
fc3c89231d
commit
0fa50d1a46
|
@ -129,20 +129,24 @@ func main() {
|
||||||
if canProfile {
|
if canProfile {
|
||||||
profile(log)
|
profile(log)
|
||||||
defer pprof.StopCPUProfile()
|
defer pprof.StopCPUProfile()
|
||||||
|
log.Log(logger.Info, "profiling started")
|
||||||
}
|
}
|
||||||
|
|
||||||
var rv *revid.Revid
|
var rv *revid.Revid
|
||||||
|
|
||||||
|
log.Log(logger.Debug, "initialising netsender client")
|
||||||
ns, err := netsender.New(log, nil, readPin(rv), nil, config.TypeData)
|
ns, err := netsender.New(log, nil, readPin(rv), nil, config.TypeData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log(logger.Fatal, pkg+"could not initialise netsender client: "+err.Error())
|
log.Log(logger.Fatal, pkg+"could not initialise netsender client: "+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Log(logger.Debug, "initialising revid")
|
||||||
rv, err = revid.New(config.Config{Logger: log}, ns)
|
rv, err = revid.New(config.Config{Logger: log}, ns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log(logger.Fatal, pkg+"could not initialise revid", "error", err.Error())
|
log.Log(logger.Fatal, pkg+"could not initialise revid", "error", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Log(logger.Debug, "beginning main loop")
|
||||||
run(rv, ns, log, netLog)
|
run(rv, ns, log, netLog)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,6 +155,7 @@ func main() {
|
||||||
func run(rv *revid.Revid, ns *netsender.Sender, l *logger.Logger, nl *netlogger.Logger) {
|
func run(rv *revid.Revid, ns *netsender.Sender, l *logger.Logger, nl *netlogger.Logger) {
|
||||||
var vs int
|
var vs int
|
||||||
for {
|
for {
|
||||||
|
l.Log(logger.Debug, "running netsender")
|
||||||
err := ns.Run()
|
err := ns.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Log(logger.Warning, pkg+"Run Failed. Retrying...", "error", err.Error())
|
l.Log(logger.Warning, pkg+"Run Failed. Retrying...", "error", err.Error())
|
||||||
|
@ -158,38 +163,47 @@ func run(rv *revid.Revid, ns *netsender.Sender, l *logger.Logger, nl *netlogger.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
l.Log(logger.Debug, "sending logs")
|
||||||
err = nl.Send(ns)
|
err = nl.Send(ns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Log(logger.Warning, pkg+"Logs could not be sent", "error", err.Error())
|
l.Log(logger.Warning, pkg+"Logs could not be sent", "error", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// If var sum hasn't changed we skip rest of loop.
|
l.Log(logger.Debug, "checking varsum")
|
||||||
newVs := ns.VarSum()
|
newVs := ns.VarSum()
|
||||||
if vs == newVs {
|
if vs == newVs {
|
||||||
sleep(ns, l)
|
sleep(ns, l)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
vs = newVs
|
vs = newVs
|
||||||
|
l.Log(logger.Info, "varsum changed", "vs", vs)
|
||||||
|
|
||||||
|
l.Log(logger.Debug, "getting new vars")
|
||||||
vars, err := ns.Vars()
|
vars, err := ns.Vars()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Log(logger.Error, pkg+"netSender failed to get vars", "error", err.Error())
|
l.Log(logger.Error, pkg+"netSender failed to get vars", "error", err.Error())
|
||||||
time.Sleep(netSendRetryTime)
|
time.Sleep(netSendRetryTime)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
l.Log(logger.Debug, "got new vars", "vars", vars)
|
||||||
|
|
||||||
// Configure revid based on the vars.
|
// Configure revid based on the vars.
|
||||||
|
l.Log(logger.Debug, "updating revid's configuration")
|
||||||
err = rv.Update(vars)
|
err = rv.Update(vars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Log(logger.Warning, pkg+"Couldn't update revid", "error", err.Error())
|
l.Log(logger.Warning, pkg+"couldn't update revid", "error", err.Error())
|
||||||
sleep(ns, l)
|
sleep(ns, l)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
l.Log(logger.Info, "revid successfully reconfigured")
|
||||||
|
|
||||||
|
l.Log(logger.Debug, "checking mode")
|
||||||
switch ns.Mode() {
|
switch ns.Mode() {
|
||||||
case modePaused:
|
case modePaused:
|
||||||
|
l.Log(logger.Debug, "mode is Paused, stopping revid")
|
||||||
rv.Stop()
|
rv.Stop()
|
||||||
case modeNormal, modeLoop:
|
case modeNormal, modeLoop:
|
||||||
|
l.Log(logger.Debug, "mode is Normal or Loop, starting revid")
|
||||||
err = rv.Start()
|
err = rv.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Log(logger.Error, pkg+"could not start revid", "error", err.Error())
|
l.Log(logger.Error, pkg+"could not start revid", "error", err.Error())
|
||||||
|
@ -198,6 +212,7 @@ func run(rv *revid.Revid, ns *netsender.Sender, l *logger.Logger, nl *netlogger.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
case modeBurst:
|
case modeBurst:
|
||||||
|
l.Log(logger.Debug, "mode is Burst, bursting revid")
|
||||||
err = rv.Burst()
|
err = rv.Burst()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Log(logger.Warning, pkg+"could not start burst", "error", err.Error())
|
l.Log(logger.Warning, pkg+"could not start burst", "error", err.Error())
|
||||||
|
@ -207,6 +222,7 @@ func run(rv *revid.Revid, ns *netsender.Sender, l *logger.Logger, nl *netlogger.
|
||||||
}
|
}
|
||||||
ns.SetMode(modePaused, &vs)
|
ns.SetMode(modePaused, &vs)
|
||||||
}
|
}
|
||||||
|
l.Log(logger.Info, "revid updated with new mode")
|
||||||
|
|
||||||
sleep(ns, l)
|
sleep(ns, l)
|
||||||
}
|
}
|
||||||
|
@ -227,12 +243,14 @@ func profile(l *logger.Logger) {
|
||||||
// sleep uses a delay to halt the program based on the monitoring period
|
// sleep uses a delay to halt the program based on the monitoring period
|
||||||
// netsender parameter (mp) defined in the netsender.conf config.
|
// netsender parameter (mp) defined in the netsender.conf config.
|
||||||
func sleep(ns *netsender.Sender, l *logger.Logger) {
|
func sleep(ns *netsender.Sender, l *logger.Logger) {
|
||||||
|
l.Log(logger.Debug, "sleeping")
|
||||||
t, err := strconv.Atoi(ns.Param("mp"))
|
t, err := strconv.Atoi(ns.Param("mp"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Log(logger.Error, pkg+"could not get sleep time, using default", "error", err)
|
l.Log(logger.Error, pkg+"could not get sleep time, using default", "error", err)
|
||||||
t = defaultSleepTime
|
t = defaultSleepTime
|
||||||
}
|
}
|
||||||
time.Sleep(time.Duration(t) * time.Second)
|
time.Sleep(time.Duration(t) * time.Second)
|
||||||
|
l.Log(logger.Debug, "finished sleeping")
|
||||||
}
|
}
|
||||||
|
|
||||||
// readPin provides a callback function of consistent signature for use by
|
// readPin provides a callback function of consistent signature for use by
|
||||||
|
|
133
revid/revid.go
133
revid/revid.go
|
@ -154,13 +154,14 @@ func (r *Revid) Bitrate() int {
|
||||||
// configuration; checking validity and returning errors if not valid. It then
|
// configuration; checking validity and returning errors if not valid. It then
|
||||||
// sets up the data pipeline accordingly to this configuration.
|
// sets up the data pipeline accordingly to this configuration.
|
||||||
func (r *Revid) reset(c config.Config) error {
|
func (r *Revid) reset(c config.Config) error {
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "setting config")
|
||||||
err := r.setConfig(c)
|
err := r.setConfig(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
r.cfg.Logger.Log(logger.Info, "config set")
|
||||||
|
|
||||||
r.cfg.Logger.SetLevel(c.LogLevel)
|
r.cfg.Logger.Log(logger.Debug, "setting up revid pipeline")
|
||||||
|
|
||||||
err = r.setupPipeline(
|
err = r.setupPipeline(
|
||||||
func(dst io.WriteCloser, fps float64) (io.WriteCloser, error) {
|
func(dst io.WriteCloser, fps float64) (io.WriteCloser, error) {
|
||||||
var st int
|
var st int
|
||||||
|
@ -215,6 +216,7 @@ func (r *Revid) reset(c config.Config) error {
|
||||||
},
|
},
|
||||||
ioext.MultiWriteCloser,
|
ioext.MultiWriteCloser,
|
||||||
)
|
)
|
||||||
|
r.cfg.Logger.Log(logger.Info, "finished setting pipeline")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -227,10 +229,12 @@ func (r *Revid) reset(c config.Config) error {
|
||||||
// revid config.
|
// revid config.
|
||||||
func (r *Revid) setConfig(config config.Config) error {
|
func (r *Revid) setConfig(config config.Config) error {
|
||||||
r.cfg.Logger = config.Logger
|
r.cfg.Logger = config.Logger
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "validating config")
|
||||||
err := config.Validate()
|
err := config.Validate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("Config struct is bad: " + err.Error())
|
return errors.New("Config struct is bad: " + err.Error())
|
||||||
}
|
}
|
||||||
|
r.cfg.Logger.Log(logger.Info, "config validated")
|
||||||
r.cfg = config
|
r.cfg = config
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -257,6 +261,7 @@ func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate float64) (io.
|
||||||
for _, out := range r.cfg.Outputs {
|
for _, out := range r.cfg.Outputs {
|
||||||
switch out {
|
switch out {
|
||||||
case config.OutputHTTP:
|
case config.OutputHTTP:
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "using HTTP output")
|
||||||
rb, err := vring.NewBuffer(r.cfg.RBMaxElements, r.cfg.RBCapacity, time.Duration(r.cfg.RBWriteTimeout)*time.Second)
|
rb, err := vring.NewBuffer(r.cfg.RBMaxElements, r.cfg.RBCapacity, time.Duration(r.cfg.RBWriteTimeout)*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not initialise MTS ring buffer: %w", err)
|
return fmt.Errorf("could not initialise MTS ring buffer: %w", err)
|
||||||
|
@ -269,18 +274,21 @@ func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate float64) (io.
|
||||||
)
|
)
|
||||||
mtsSenders = append(mtsSenders, w)
|
mtsSenders = append(mtsSenders, w)
|
||||||
case config.OutputRTP:
|
case config.OutputRTP:
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "using RTP output")
|
||||||
w, err := newRtpSender(r.cfg.RTPAddress, r.cfg.Logger.Log, r.cfg.FrameRate, r.bitrate.Report)
|
w, err := newRtpSender(r.cfg.RTPAddress, r.cfg.Logger.Log, r.cfg.FrameRate, r.bitrate.Report)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.cfg.Logger.Log(logger.Warning, pkg+"rtp connect error", "error", err.Error())
|
r.cfg.Logger.Log(logger.Warning, pkg+"rtp connect error", "error", err.Error())
|
||||||
}
|
}
|
||||||
mtsSenders = append(mtsSenders, w)
|
mtsSenders = append(mtsSenders, w)
|
||||||
case config.OutputFile:
|
case config.OutputFile:
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "using File output")
|
||||||
w, err := newFileSender(r.cfg.OutputPath)
|
w, err := newFileSender(r.cfg.OutputPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
mtsSenders = append(mtsSenders, w)
|
mtsSenders = append(mtsSenders, w)
|
||||||
case config.OutputRTMP:
|
case config.OutputRTMP:
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "using RTMP output")
|
||||||
rb, err := vring.NewBuffer(r.cfg.RBMaxElements, r.cfg.RBCapacity, time.Duration(r.cfg.RBWriteTimeout)*time.Second)
|
rb, err := vring.NewBuffer(r.cfg.RBMaxElements, r.cfg.RBCapacity, time.Duration(r.cfg.RBWriteTimeout)*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not initialise RTMP ring buffer: %w", err)
|
return fmt.Errorf("could not initialise RTMP ring buffer: %w", err)
|
||||||
|
@ -326,73 +334,61 @@ func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate float64) (io.
|
||||||
l := len(r.cfg.Filters)
|
l := len(r.cfg.Filters)
|
||||||
r.filters = []filter.Filter{filter.NewNoOp(r.encoders)}
|
r.filters = []filter.Filter{filter.NewNoOp(r.encoders)}
|
||||||
if l != 0 {
|
if l != 0 {
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "setting up filters", "filters", r.cfg.Filters)
|
||||||
r.filters = make([]filter.Filter, l)
|
r.filters = make([]filter.Filter, l)
|
||||||
dst := r.encoders
|
dst := r.encoders
|
||||||
|
|
||||||
for i := l - 1; i >= 0; i-- {
|
for i := l - 1; i >= 0; i-- {
|
||||||
switch r.cfg.Filters[i] {
|
switch r.cfg.Filters[i] {
|
||||||
case config.FilterNoOp:
|
case config.FilterNoOp:
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "using NoOp filter")
|
||||||
r.filters[i] = filter.NewNoOp(dst)
|
r.filters[i] = filter.NewNoOp(dst)
|
||||||
case config.FilterMOG:
|
case config.FilterMOG:
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "using MOG filter")
|
||||||
r.filters[i] = filter.NewMOG(dst, r.cfg)
|
r.filters[i] = filter.NewMOG(dst, r.cfg)
|
||||||
case config.FilterVariableFPS:
|
case config.FilterVariableFPS:
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "using Variable FPS MOG filter")
|
||||||
r.filters[i] = filter.NewVariableFPS(dst, r.cfg.MinFPS, filter.NewMOG(dst, r.cfg))
|
r.filters[i] = filter.NewVariableFPS(dst, r.cfg.MinFPS, filter.NewMOG(dst, r.cfg))
|
||||||
case config.FilterKNN:
|
case config.FilterKNN:
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "using KNN filter")
|
||||||
r.filters[i] = filter.NewKNN(dst, r.cfg)
|
r.filters[i] = filter.NewKNN(dst, r.cfg)
|
||||||
case config.FilterDiff:
|
case config.FilterDiff:
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "using gocv difference filter")
|
||||||
r.filters[i] = filter.NewDiff(dst, r.cfg)
|
r.filters[i] = filter.NewDiff(dst, r.cfg)
|
||||||
case config.FilterBasic:
|
case config.FilterBasic:
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "using go difference filter")
|
||||||
r.filters[i] = filter.NewBasic(dst, r.cfg)
|
r.filters[i] = filter.NewBasic(dst, r.cfg)
|
||||||
default:
|
default:
|
||||||
panic("Undefined Filter")
|
panic("Undefined Filter")
|
||||||
}
|
}
|
||||||
dst = r.filters[i]
|
dst = r.filters[i]
|
||||||
}
|
}
|
||||||
|
r.cfg.Logger.Log(logger.Info, "filters set up")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch r.cfg.Input {
|
switch r.cfg.Input {
|
||||||
case config.InputRaspivid:
|
case config.InputRaspivid:
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "using raspivid input")
|
||||||
r.input = raspivid.New(r.cfg.Logger)
|
r.input = raspivid.New(r.cfg.Logger)
|
||||||
|
r.setLexer(r.cfg.InputCodec, false)
|
||||||
switch r.cfg.InputCodec {
|
|
||||||
case codecutil.H264:
|
|
||||||
r.lexTo = h264.Lex
|
|
||||||
case codecutil.MJPEG:
|
|
||||||
r.lexTo = mjpeg.Lex
|
|
||||||
}
|
|
||||||
|
|
||||||
case config.InputV4L:
|
case config.InputV4L:
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "using V4L input")
|
||||||
r.input = webcam.New(r.cfg.Logger)
|
r.input = webcam.New(r.cfg.Logger)
|
||||||
switch r.cfg.InputCodec {
|
r.setLexer(r.cfg.InputCodec, false)
|
||||||
case codecutil.H264:
|
|
||||||
r.lexTo = h264.Lex
|
|
||||||
case codecutil.MJPEG:
|
|
||||||
r.lexTo = mjpeg.Lex
|
|
||||||
}
|
|
||||||
|
|
||||||
case config.InputFile:
|
case config.InputFile:
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "using file input")
|
||||||
r.input = file.New()
|
r.input = file.New()
|
||||||
switch r.cfg.InputCodec {
|
r.setLexer(r.cfg.InputCodec, false)
|
||||||
case codecutil.H264:
|
|
||||||
r.lexTo = h264.Lex
|
|
||||||
case codecutil.MJPEG:
|
|
||||||
r.lexTo = mjpeg.Lex
|
|
||||||
}
|
|
||||||
|
|
||||||
case config.InputRTSP:
|
case config.InputRTSP:
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "using RTSP input")
|
||||||
r.input = geovision.New(r.cfg.Logger)
|
r.input = geovision.New(r.cfg.Logger)
|
||||||
|
r.setLexer(r.cfg.InputCodec, true)
|
||||||
switch r.cfg.InputCodec {
|
|
||||||
case codecutil.H264:
|
|
||||||
r.lexTo = h264.NewExtractor().Extract
|
|
||||||
case codecutil.H265:
|
|
||||||
r.lexTo = h265.NewLexer(false).Lex
|
|
||||||
case codecutil.MJPEG:
|
|
||||||
r.lexTo = mjpeg.NewExtractor().Extract
|
|
||||||
}
|
|
||||||
|
|
||||||
case config.InputAudio:
|
case config.InputAudio:
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "using audio input")
|
||||||
err := r.setupAudio()
|
err := r.setupAudio()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -401,14 +397,43 @@ func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate float64) (io.
|
||||||
|
|
||||||
// Configure the input device. We know that defaults are set, so no need to
|
// Configure the input device. We know that defaults are set, so no need to
|
||||||
// return error, but we should log.
|
// return error, but we should log.
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "configuring input device")
|
||||||
err := r.input.Set(r.cfg)
|
err := r.input.Set(r.cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.cfg.Logger.Log(logger.Warning, pkg+"errors from configuring input device", "errors", err)
|
r.cfg.Logger.Log(logger.Warning, pkg+"errors from configuring input device", "errors", err)
|
||||||
}
|
}
|
||||||
|
r.cfg.Logger.Log(logger.Info, "input device configured")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setLexer sets the revid input lexer based on input codec and whether input
|
||||||
|
// is RTSP or not, in which case an RTP/<codec> extractor is used.
|
||||||
|
func (r *Revid) setLexer(c uint8, isRTSP bool) {
|
||||||
|
switch c {
|
||||||
|
case codecutil.H264:
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "using H.264 codec")
|
||||||
|
r.lexTo = h264.Lex
|
||||||
|
if isRTSP {
|
||||||
|
r.lexTo = h264.NewExtractor().Extract
|
||||||
|
}
|
||||||
|
case codecutil.H265:
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "using H.265 codec")
|
||||||
|
r.lexTo = h265.NewLexer(false).Lex
|
||||||
|
if !isRTSP {
|
||||||
|
panic("byte stream H.265 lexing not implemented")
|
||||||
|
}
|
||||||
|
case codecutil.MJPEG:
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "using MJPEG codec")
|
||||||
|
r.lexTo = mjpeg.Lex
|
||||||
|
if isRTSP {
|
||||||
|
r.lexTo = mjpeg.NewExtractor().Extract
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic("unrecognised codec")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Start invokes a Revid to start processing video from a defined input
|
// Start invokes a Revid to start processing video from a defined input
|
||||||
// and packetising (if theres packetization) to a defined output.
|
// and packetising (if theres packetization) to a defined output.
|
||||||
//
|
//
|
||||||
|
@ -422,18 +447,21 @@ func (r *Revid) Start() error {
|
||||||
r.mu.Lock()
|
r.mu.Lock()
|
||||||
defer r.mu.Unlock()
|
defer r.mu.Unlock()
|
||||||
|
|
||||||
r.cfg.Logger.Log(logger.Info, pkg+"starting Revid")
|
r.cfg.Logger.Log(logger.Debug, pkg+"resetting revid")
|
||||||
err := r.reset(r.cfg)
|
err := r.reset(r.cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Stop()
|
r.Stop()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
r.cfg.Logger.Log(logger.Info, "revid reset")
|
||||||
|
|
||||||
// Calculate delay between frames based on FileFPS.
|
// Calculate delay between frames based on FileFPS.
|
||||||
d := time.Duration(0)
|
d := time.Duration(0)
|
||||||
if r.cfg.FileFPS != 0 {
|
if r.cfg.FileFPS != 0 {
|
||||||
d = time.Duration(1000/r.cfg.FileFPS) * time.Millisecond
|
d = time.Duration(1000/r.cfg.FileFPS) * time.Millisecond
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "starting input processing routine")
|
||||||
r.wg.Add(1)
|
r.wg.Add(1)
|
||||||
go r.processFrom(r.input, d)
|
go r.processFrom(r.input, d)
|
||||||
|
|
||||||
|
@ -454,48 +482,54 @@ func (r *Revid) Stop() {
|
||||||
r.mu.Lock()
|
r.mu.Lock()
|
||||||
defer r.mu.Unlock()
|
defer r.mu.Unlock()
|
||||||
|
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "stopping input")
|
||||||
err := r.input.Stop()
|
err := r.input.Stop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.cfg.Logger.Log(logger.Error, pkg+"could not stop input", "error", err.Error())
|
r.cfg.Logger.Log(logger.Error, pkg+"could not stop input", "error", err.Error())
|
||||||
|
} else {
|
||||||
|
r.cfg.Logger.Log(logger.Info, "input stopped")
|
||||||
}
|
}
|
||||||
|
|
||||||
r.cfg.Logger.Log(logger.Info, pkg+"closing pid peline")
|
r.cfg.Logger.Log(logger.Debug, "closing pipeline")
|
||||||
err = r.encoders.Close()
|
err = r.encoders.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.cfg.Logger.Log(logger.Error, pkg+"failed to close pipeline", "error", err.Error())
|
r.cfg.Logger.Log(logger.Error, pkg+"failed to close pipeline", "error", err.Error())
|
||||||
|
} else {
|
||||||
|
r.cfg.Logger.Log(logger.Info, "pipeline closed")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, filter := range r.filters {
|
for _, filter := range r.filters {
|
||||||
err = filter.Close()
|
err = filter.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.cfg.Logger.Log(logger.Error, pkg+"failed to close pipeline", "error", err.Error())
|
r.cfg.Logger.Log(logger.Error, pkg+"failed to close filters", "error", err.Error())
|
||||||
|
} else {
|
||||||
|
r.cfg.Logger.Log(logger.Info, "filters closed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r.cfg.Logger.Log(logger.Info, pkg+"closed pipeline")
|
r.cfg.Logger.Log(logger.Debug, "waiting for routines to finish")
|
||||||
|
|
||||||
r.cfg.Logger.Log(logger.Info, pkg+"waiting for routines to close")
|
|
||||||
|
|
||||||
r.wg.Wait()
|
r.wg.Wait()
|
||||||
|
r.cfg.Logger.Log(logger.Info, "routines finished")
|
||||||
|
|
||||||
r.cfg.Logger.Log(logger.Info, pkg+"revid stopped")
|
|
||||||
r.running = false
|
r.running = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Burst starts revid, waits for time specified, and then stops revid.
|
// Burst starts revid, waits for time specified, and then stops revid.
|
||||||
func (r *Revid) Burst() error {
|
func (r *Revid) Burst() error {
|
||||||
r.cfg.Logger.Log(logger.Info, pkg+"starting burst")
|
r.cfg.Logger.Log(logger.Debug, "starting revid")
|
||||||
|
|
||||||
err := r.Start()
|
err := r.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not start revid: %w", err)
|
return fmt.Errorf("could not start revid: %w", err)
|
||||||
}
|
}
|
||||||
|
r.cfg.Logger.Log(logger.Info, "revid started")
|
||||||
|
|
||||||
dur := time.Duration(r.cfg.BurstPeriod) * time.Second
|
dur := time.Duration(r.cfg.BurstPeriod) * time.Second
|
||||||
time.Sleep(dur)
|
time.Sleep(dur)
|
||||||
|
|
||||||
r.cfg.Logger.Log(logger.Info, pkg+"stopping burst")
|
r.cfg.Logger.Log(logger.Debug, "stopping revid")
|
||||||
r.Stop()
|
r.Stop()
|
||||||
|
r.cfg.Logger.Log(logger.Info, "revid stopped")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -511,12 +545,15 @@ func (r *Revid) IsRunning() bool {
|
||||||
// Update is safe for concurrent use.
|
// Update is safe for concurrent use.
|
||||||
func (r *Revid) Update(vars map[string]string) error {
|
func (r *Revid) Update(vars map[string]string) error {
|
||||||
if r.IsRunning() {
|
if r.IsRunning() {
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "revid running; stopping for re-config")
|
||||||
r.Stop()
|
r.Stop()
|
||||||
|
r.cfg.Logger.Log(logger.Info, "revid was running; stopped for re-config")
|
||||||
}
|
}
|
||||||
|
|
||||||
r.mu.Lock()
|
r.mu.Lock()
|
||||||
defer r.mu.Unlock()
|
defer r.mu.Unlock()
|
||||||
//look through the vars and update revid where needed
|
//look through the vars and update revid where needed
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "checking vars from server", "vars", vars)
|
||||||
for key, value := range vars {
|
for key, value := range vars {
|
||||||
switch key {
|
switch key {
|
||||||
case "Input":
|
case "Input":
|
||||||
|
@ -863,7 +900,8 @@ func (r *Revid) Update(vars map[string]string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r.cfg.Logger.Log(logger.Info, pkg+"revid config changed", "config", fmt.Sprintf("%+v", r.cfg))
|
r.cfg.Logger.Log(logger.Info, "finished reconfig")
|
||||||
|
r.cfg.Logger.Log(logger.Debug, pkg+"config changed", "config", r.cfg)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -882,21 +920,24 @@ func (r *Revid) processFrom(in device.AVDevice, delay time.Duration) {
|
||||||
// Lex data from input device, in, until finished or an error is encountered.
|
// Lex data from input device, in, until finished or an error is encountered.
|
||||||
// For a continuous source e.g. a camera or microphone, we should remain
|
// For a continuous source e.g. a camera or microphone, we should remain
|
||||||
// in this call indefinitely unless in.Stop() is called and an io.EOF is forced.
|
// in this call indefinitely unless in.Stop() is called and an io.EOF is forced.
|
||||||
r.cfg.Logger.Log(logger.Info, pkg+"lexing")
|
r.cfg.Logger.Log(logger.Debug, pkg+"lexing")
|
||||||
err = r.lexTo(r.filters[0], in, delay)
|
err = r.lexTo(r.filters[0], in, delay)
|
||||||
switch err {
|
switch err {
|
||||||
case nil, io.EOF:
|
case nil, io.EOF:
|
||||||
|
r.cfg.Logger.Log(logger.Info, "end of file")
|
||||||
case io.ErrUnexpectedEOF:
|
case io.ErrUnexpectedEOF:
|
||||||
r.cfg.Logger.Log(logger.Info, pkg+"unexpected EOF from input")
|
r.cfg.Logger.Log(logger.Info, pkg+"unexpected EOF from input")
|
||||||
default:
|
default:
|
||||||
r.err <- err
|
r.err <- err
|
||||||
}
|
}
|
||||||
|
r.cfg.Logger.Log(logger.Info, "finished reading input")
|
||||||
|
|
||||||
|
r.cfg.Logger.Log(logger.Debug, "stopping input")
|
||||||
err = in.Stop()
|
err = in.Stop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.err <- fmt.Errorf("could not stop input source: %w", err)
|
r.err <- fmt.Errorf("could not stop input source: %w", err)
|
||||||
|
} else {
|
||||||
|
r.cfg.Logger.Log(logger.Info, "input stopped")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r.cfg.Logger.Log(logger.Info, pkg+"finished lexing")
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,9 +75,13 @@ func newHttpSender(ns *netsender.Sender, log func(lvl int8, msg string, args ...
|
||||||
|
|
||||||
// Write implements io.Writer.
|
// Write implements io.Writer.
|
||||||
func (s *httpSender) Write(d []byte) (int, error) {
|
func (s *httpSender) Write(d []byte) (int, error) {
|
||||||
|
s.log(logger.Debug, "HTTP sending")
|
||||||
err := httpSend(d, s.client, s.log)
|
err := httpSend(d, s.client, s.log)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
s.log(logger.Debug, "good send", "len", len(d))
|
||||||
s.report(len(d))
|
s.report(len(d))
|
||||||
|
} else {
|
||||||
|
s.log(logger.Debug, "bad send", "error", err)
|
||||||
}
|
}
|
||||||
return len(d), err
|
return len(d), err
|
||||||
}
|
}
|
||||||
|
@ -88,6 +92,7 @@ func httpSend(d []byte, client *netsender.Sender, log func(lvl int8, msg string,
|
||||||
// Only send if "V0" is configured as an input.
|
// Only send if "V0" is configured as an input.
|
||||||
send := false
|
send := false
|
||||||
ip := client.Param("ip")
|
ip := client.Param("ip")
|
||||||
|
log(logger.Debug, "making pins, and sending recv request", "ip", ip)
|
||||||
pins := netsender.MakePins(ip, "V")
|
pins := netsender.MakePins(ip, "V")
|
||||||
for i, pin := range pins {
|
for i, pin := range pins {
|
||||||
if pin.Name == "V0" {
|
if pin.Name == "V0" {
|
||||||
|
@ -108,6 +113,7 @@ func httpSend(d []byte, client *netsender.Sender, log func(lvl int8, msg string,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
log(logger.Debug, "good request", "reply", reply)
|
||||||
return extractMeta(reply, log)
|
return extractMeta(reply, log)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +206,7 @@ func (s *mtsSender) output() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-s.done:
|
case <-s.done:
|
||||||
s.log(logger.Info, pkg+"mtsSender: got done signal, terminating output routine")
|
s.log(logger.Info, pkg+"terminating sender output routine")
|
||||||
defer s.wg.Done()
|
defer s.wg.Done()
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
|
@ -212,10 +218,10 @@ func (s *mtsSender) output() {
|
||||||
case nil, io.EOF:
|
case nil, io.EOF:
|
||||||
continue
|
continue
|
||||||
case vring.ErrNextTimeout:
|
case vring.ErrNextTimeout:
|
||||||
s.log(logger.Debug, pkg+"mtsSender: ring buffer read timeout")
|
s.log(logger.Debug, pkg+"ring buffer read timeout")
|
||||||
continue
|
continue
|
||||||
default:
|
default:
|
||||||
s.log(logger.Error, pkg+"mtsSender: unexpected error", "error", err.Error())
|
s.log(logger.Error, pkg+"unexpected error", "error", err.Error())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -225,11 +231,14 @@ func (s *mtsSender) output() {
|
||||||
elem = nil
|
elem = nil
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
s.log(logger.Debug, pkg+"mtsSender: writing")
|
s.log(logger.Debug, pkg+"writing")
|
||||||
_, err = s.dst.Write(elem.Bytes())
|
_, err = s.dst.Write(elem.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.log(logger.Debug, "failed write, repairing MTS", "error", err)
|
||||||
s.repairer.Failed()
|
s.repairer.Failed()
|
||||||
continue
|
continue
|
||||||
|
} else {
|
||||||
|
s.log(logger.Debug, "good write")
|
||||||
}
|
}
|
||||||
elem.Close()
|
elem.Close()
|
||||||
elem = nil
|
elem = nil
|
||||||
|
@ -258,7 +267,7 @@ func (s *mtsSender) Write(d []byte) (int, error) {
|
||||||
s.ring.Flush()
|
s.ring.Flush()
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log(logger.Warning, pkg+"mtsSender: ringBuffer write error", "error", err.Error(), "n", n, "size", len(s.buf))
|
s.log(logger.Warning, pkg+"ringBuffer write error", "error", err.Error(), "n", n, "size", len(s.buf))
|
||||||
}
|
}
|
||||||
s.buf = s.buf[:0]
|
s.buf = s.buf[:0]
|
||||||
}
|
}
|
||||||
|
@ -267,8 +276,10 @@ func (s *mtsSender) Write(d []byte) (int, error) {
|
||||||
|
|
||||||
// Close implements io.Closer.
|
// Close implements io.Closer.
|
||||||
func (s *mtsSender) Close() error {
|
func (s *mtsSender) Close() error {
|
||||||
|
s.log(logger.Debug, "closing sender output routine")
|
||||||
close(s.done)
|
close(s.done)
|
||||||
s.wg.Wait()
|
s.wg.Wait()
|
||||||
|
s.log(logger.Info, "sender output routine closed")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,9 +304,9 @@ func newRtmpSender(url string, timeout uint, retries int, rb *vring.Buffer, log
|
||||||
if err == nil {
|
if err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
log(logger.Error, err.Error())
|
log(logger.Error, "dial error", "error", err)
|
||||||
if n < retries-1 {
|
if n < retries-1 {
|
||||||
log(logger.Info, pkg+"retry rtmp connection")
|
log(logger.Info, pkg+"retrying dial")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s := &rtmpSender{
|
s := &rtmpSender{
|
||||||
|
@ -319,7 +330,7 @@ func (s *rtmpSender) output() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-s.done:
|
case <-s.done:
|
||||||
s.log(logger.Info, pkg+"rtmpSender: got done signal, terminating output routine")
|
s.log(logger.Info, pkg+"terminating sender output routine")
|
||||||
defer s.wg.Done()
|
defer s.wg.Done()
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
|
@ -331,29 +342,32 @@ func (s *rtmpSender) output() {
|
||||||
case nil, io.EOF:
|
case nil, io.EOF:
|
||||||
continue
|
continue
|
||||||
case vring.ErrNextTimeout:
|
case vring.ErrNextTimeout:
|
||||||
s.log(logger.Debug, pkg+"rtmpSender: ring buffer read timeout")
|
s.log(logger.Debug, pkg+"ring buffer read timeout")
|
||||||
continue
|
continue
|
||||||
default:
|
default:
|
||||||
s.log(logger.Error, pkg+"rtmpSender: unexpected error", "error", err.Error())
|
s.log(logger.Error, pkg+"unexpected error", "error", err.Error())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if s.conn == nil {
|
if s.conn == nil {
|
||||||
s.log(logger.Warning, pkg+"rtmpSender: no rtmp connection, going to restart...")
|
s.log(logger.Warning, pkg+"no rtmp connection, re-dialing")
|
||||||
err := s.restart()
|
err := s.restart()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log(logger.Warning, pkg+"rtmpSender: could not restart connection", "error", err.Error())
|
s.log(logger.Warning, pkg+"could not restart connection", "error", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_, err := s.conn.Write(elem.Bytes())
|
b := elem.Bytes()
|
||||||
|
s.log(logger.Debug, "writing to conn", "len", len(b))
|
||||||
|
_, err := s.conn.Write(b)
|
||||||
switch err {
|
switch err {
|
||||||
case nil, rtmp.ErrInvalidFlvTag:
|
case nil, rtmp.ErrInvalidFlvTag:
|
||||||
|
s.log(logger.Debug, "good write to conn")
|
||||||
default:
|
default:
|
||||||
s.log(logger.Warning, pkg+"rtmpSender: send error, restarting...", "error", err.Error())
|
s.log(logger.Warning, pkg+"send error, re-dialing", "error", err)
|
||||||
err = s.restart()
|
err = s.restart()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log(logger.Warning, pkg+"rtmpSender: could not restart connection", "error", err.Error())
|
s.log(logger.Warning, pkg+"could not restart connection", "error", err)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -365,12 +379,13 @@ func (s *rtmpSender) output() {
|
||||||
|
|
||||||
// Write implements io.Writer.
|
// Write implements io.Writer.
|
||||||
func (s *rtmpSender) Write(d []byte) (int, error) {
|
func (s *rtmpSender) Write(d []byte) (int, error) {
|
||||||
|
s.log(logger.Debug, "writing to ring buffer")
|
||||||
_, err := s.ring.Write(d)
|
_, err := s.ring.Write(d)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
s.ring.Flush()
|
s.ring.Flush()
|
||||||
}
|
s.log(logger.Debug, "good ring buffer write", "len", len(d))
|
||||||
if err != nil {
|
} else {
|
||||||
s.log(logger.Warning, pkg+"rtmpSender: ring buffer write error", "error", err.Error())
|
s.log(logger.Warning, pkg+"ring buffer write error", "error", err.Error())
|
||||||
}
|
}
|
||||||
s.report(len(d))
|
s.report(len(d))
|
||||||
return len(d), nil
|
return len(d), nil
|
||||||
|
@ -380,11 +395,12 @@ func (s *rtmpSender) restart() error {
|
||||||
s.close()
|
s.close()
|
||||||
var err error
|
var err error
|
||||||
for n := 0; n < s.retries; n++ {
|
for n := 0; n < s.retries; n++ {
|
||||||
|
s.log(logger.Debug, "dialing", "dials", n)
|
||||||
s.conn, err = rtmp.Dial(s.url, s.timeout, s.log)
|
s.conn, err = rtmp.Dial(s.url, s.timeout, s.log)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
s.log(logger.Error, err.Error())
|
s.log(logger.Error, "dial error", "error", err)
|
||||||
if n < s.retries-1 {
|
if n < s.retries-1 {
|
||||||
s.log(logger.Info, pkg+"retry rtmp connection")
|
s.log(logger.Info, pkg+"retry rtmp connection")
|
||||||
}
|
}
|
||||||
|
@ -393,14 +409,17 @@ func (s *rtmpSender) restart() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *rtmpSender) Close() error {
|
func (s *rtmpSender) Close() error {
|
||||||
|
s.log(logger.Debug, "closing output routine")
|
||||||
if s.done != nil {
|
if s.done != nil {
|
||||||
close(s.done)
|
close(s.done)
|
||||||
}
|
}
|
||||||
s.wg.Wait()
|
s.wg.Wait()
|
||||||
|
s.log(logger.Info, "output routine closed")
|
||||||
return s.close()
|
return s.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *rtmpSender) close() error {
|
func (s *rtmpSender) close() error {
|
||||||
|
s.log(logger.Debug, "closing connection")
|
||||||
if s.conn == nil {
|
if s.conn == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue