Skip to content

Commit

Permalink
rpicamera: fix restarting camera when component crashes
Browse files Browse the repository at this point in the history
  • Loading branch information
aler9 committed Nov 30, 2024
1 parent e6fa56d commit b8d0b43
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 59 deletions.
134 changes: 77 additions & 57 deletions internal/staticsources/rpicamera/camera.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ type camera struct {
Params params
OnData func(time.Duration, [][]byte)

cmd *exec.Cmd
pipeOut *pipe
pipeIn *pipe
cmd *exec.Cmd
pipeOut *pipe
pipeIn *pipe
finalErr error

waitDone chan error
readerDone chan error
terminate chan struct{}
done chan struct{}
}

func (c *camera) initialize() error {
Expand Down Expand Up @@ -64,78 +65,92 @@ func (c *camera) initialize() error {
return err
}

c.terminate = make(chan struct{})
c.done = make(chan struct{})

go c.run()

c.pipeOut.write(append([]byte{'c'}, c.Params.serialize()...))

c.waitDone = make(chan error)
return nil
}

func (c *camera) close() {
close(c.terminate)
<-c.done
freeComponent()
}

func (c *camera) run() {
defer close(c.done)
c.finalErr = c.runInner()
}

func (c *camera) runInner() error {
cmdDone := make(chan error)
go func() {
c.waitDone <- c.cmd.Wait()
cmdDone <- c.cmd.Wait()
}()

c.readerDone = make(chan error)
readDone := make(chan error)
go func() {
c.readerDone <- c.readReady()
readDone <- c.runReader()
}()

select {
case err := <-c.waitDone:
c.pipeOut.close()
c.pipeIn.close()
<-c.readerDone
freeComponent()
return fmt.Errorf("process exited unexpectedly: %v", err)
for {
select {
case err := <-cmdDone:
c.pipeIn.close()
c.pipeOut.close()

<-readDone

return err

case err := <-readDone:
c.pipeIn.close()

case err := <-c.readerDone:
if err != nil {
c.pipeOut.write([]byte{'e'})
<-c.waitDone
c.pipeOut.close()
c.pipeIn.close()
freeComponent()

<-cmdDone

return err
}
}

c.readerDone = make(chan error)
go func() {
c.readerDone <- c.readData()
close(c.readerDone)
}()
case <-c.terminate:
c.pipeIn.close()
<-readDone

return nil
}
c.pipeOut.write([]byte{'e'})
c.pipeOut.close()

func (c *camera) close() {
c.pipeOut.write([]byte{'e'})
<-c.waitDone
c.pipeOut.close()
c.pipeIn.close()
<-c.readerDone
freeComponent()
}
<-cmdDone

func (c *camera) reloadParams(params params) {
c.pipeOut.write(append([]byte{'c'}, params.serialize()...))
return fmt.Errorf("terminated")
}
}
}

func (c *camera) readReady() error {
buf, err := c.pipeIn.read()
if err != nil {
return err
}
func (c *camera) runReader() error {
outer:
for {
buf, err := c.pipeIn.read()
if err != nil {
return err
}

switch buf[0] {
case 'e':
return fmt.Errorf(string(buf[1:]))
switch buf[0] {
case 'e':
return fmt.Errorf(string(buf[1:]))

case 'r':
return nil
case 'r':
break outer

default:
return fmt.Errorf("unexpected output from video pipe: '0x%.2x'", buf[0])
default:
return fmt.Errorf("unexpected data from pipe: '0x%.2x'", buf[0])
}
}
}

func (c *camera) readData() error {
for {
buf, err := c.pipeIn.read()
if err != nil {
Expand All @@ -159,11 +174,16 @@ func (c *camera) readData() error {
c.OnData(dts, nalus)

default:
return fmt.Errorf("unexpected output from pipe (%c)", buf[0])
return fmt.Errorf("unexpected data from pipe: '0x%.2x'", buf[0])
}
}
}

func (c *camera) error() chan error {
return c.readerDone
func (c *camera) reloadParams(params params) {
c.pipeOut.write(append([]byte{'c'}, params.serialize()...))
}

func (c *camera) wait() error {
<-c.done
return c.finalErr
}
2 changes: 1 addition & 1 deletion internal/staticsources/rpicamera/camera_disabled.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ func (c *camera) close() {
func (c *camera) reloadParams(_ params) {
}

func (c *camera) error() chan error {
func (c *camera) wait() error {

Check warning on line 25 in internal/staticsources/rpicamera/camera_disabled.go

View check run for this annotation

Codecov / codecov/patch

internal/staticsources/rpicamera/camera_disabled.go#L25

Added line #L25 was not covered by tests
return nil
}
7 changes: 6 additions & 1 deletion internal/staticsources/rpicamera/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,14 @@ func (s *Source) Run(params defs.StaticSourceRunParams) error {
}
}()

cameraErr := make(chan error)
go func() {
cameraErr <- cam.wait()
}()

Check warning on line 139 in internal/staticsources/rpicamera/source.go

View check run for this annotation

Codecov / codecov/patch

internal/staticsources/rpicamera/source.go#L136-L139

Added lines #L136 - L139 were not covered by tests

for {
select {
case err := <-cam.error():
case err := <-cameraErr:

Check warning on line 143 in internal/staticsources/rpicamera/source.go

View check run for this annotation

Codecov / codecov/patch

internal/staticsources/rpicamera/source.go#L143

Added line #L143 was not covered by tests
return err

case cnf := <-params.ReloadConf:
Expand Down

0 comments on commit b8d0b43

Please sign in to comment.