Add speakerMode checking for treatment.

This commit is contained in:
David Sutton 2023-05-19 12:05:31 +09:30
parent ee7cb57fe5
commit 701b1f6c3a
1 changed files with 78 additions and 72 deletions

View File

@ -35,7 +35,6 @@ import (
"io" "io"
"os/exec" "os/exec"
"strconv" "strconv"
"sync"
"time" "time"
"bitbucket.org/ausocean/av/container/mts" "bitbucket.org/ausocean/av/container/mts"
@ -78,16 +77,17 @@ const (
i2cPort = 1 i2cPort = 1
) )
// Treatment modes. // Channel modes.
const ( const (
modePaused = "Paused" modeStereo = "Stereo"
modeTreatment = "Play" modeLeft = "LeftMono"
modeCheck = "Check" modeRight = "RightMono"
modeMute = "Mute"
) )
// Variable map to send to netreceiver/vidgrind. // Variable map to send to netreceiver/vidgrind.
var varMap = map[string]string{ var varMap = map[string]string{
"mode": "enum:Paused,Play,Check", "speakerMode": "enum:Stereo,LeftMono,RightMono,Mute",
"AudioFilePath": "string", "AudioFilePath": "string",
} }
@ -131,6 +131,10 @@ func main() {
log.Fatal("could not initialise revid", "error", err) log.Fatal("could not initialise revid", "error", err)
} }
// Play the audio (audio will play even whilst muted).
log.Debug("Playing the audio")
go playAudio(filePtr, log)
// Start the control loop. // Start the control loop.
log.Debug("starting control loop") log.Debug("starting control loop")
run(rv, ns, filePtr, log, netLog) run(rv, ns, filePtr, log, netLog)
@ -140,9 +144,6 @@ func main() {
// if var changes, changes current mode (paused,audio playback or soundcheck) // if var changes, changes current mode (paused,audio playback or soundcheck)
func run(rv *revid.Revid, ns *netsender.Sender, file *string, l logging.Logger, nl *netlogger.Logger) { func run(rv *revid.Revid, ns *netsender.Sender, file *string, l logging.Logger, nl *netlogger.Logger) {
var ( var (
wg sync.WaitGroup
audioQuit chan struct{}
treating bool
vs int vs int
) )
@ -207,50 +208,76 @@ func run(rv *revid.Revid, ns *netsender.Sender, file *string, l logging.Logger,
} }
l.Debug("checking mode") l.Debug("checking mode")
switch ns.Mode() { setChannels(vars["speakerMode"], l)
case modePaused: // l.Info("revid updated with new mode")
stopAudio(&wg, &treating, audioQuit)
l.Info("mode is Paused, stopping revid")
rv.Stop()
case modeTreatment:
l.Debug("checking audio file path")
f := vars["AudioFilePath"]
if f != "" && *file != f {
file = &f
l.Info("updated audio file path, stopping audio", "AudioFilePath", f)
stopAudio(&wg, &treating, audioQuit)
}
if !treating {
l.Info("starting audio treatment")
rv.Stop()
audioQuit = make(chan struct{})
treating = true
wg.Add(1)
go playAudio(file, audioQuit, &wg, l)
}
case modeCheck:
stopAudio(&wg, &treating, audioQuit)
l.Info("sound checking")
err = rv.Start()
if err != nil {
l.Error("could not start revid", "error", err)
ns.SetMode(modePaused, &vs)
sleep(ns, l) sleep(ns, l)
continue
} }
}
// setChannels handles the muting of one, both, or neither of the channels. It takes in speakerMode
// and sets the relevant volumes.
func setChannels(mode string, l logging.Logger) {
vols := ""
l.Info("mode is", "mode", mode)
// Set the volume of each channel.
switch mode {
case modeStereo:
vols = "100%,100%"
case modeLeft:
vols = "0%,100%"
case modeRight:
vols = "100%,0%"
case modeMute:
vols = "0%,0%"
default: default:
l.Warning("mode is not valid", "mode", ns.Mode()) // If an invalid option has been chosen, keep the previous setting.
return
}
l.Info("revid updated with new mode")
sleep(ns, l)
}
} }
// playAudio is intended to be run as a routine. It will repeatedly play an audio file until // Create the command to change the channel volumes.
// a signal is received to return. The entire audio file is played before the termination cmd := exec.Command("amixer", "sset", "Speaker", vols)
// signal chan is checked.
func playAudio(file *string, quit chan struct{}, wg *sync.WaitGroup, l logging.Logger) { // Pipe the output to stdout and stderr.
outPipe, err := cmd.StdoutPipe()
if err != nil {
l.Error("failed to pipe stdout", "error", err)
}
errPipe, err := cmd.StderrPipe()
if err != nil {
l.Error("failed to pipe stderr", "error", err)
}
// Execute the channel setting command.
err = cmd.Start()
if err != nil {
l.Error("channel setting failed", "error", err)
}
// Copy any std out to a buffer for logging.
var outBuff bytes.Buffer
go func() {
_, err = io.Copy(&outBuff, outPipe)
if err != nil {
l.Error("failed to copy out pipe", "error", err)
}
}()
// Copy any std error to a buffer for logging.
var errBuff bytes.Buffer
go func() {
_, err = io.Copy(&errBuff, errPipe)
if err != nil {
l.Error("failed to copy error pipe", "error", err)
}
}()
l.Info("mode set to", "mode", mode)
}
// playAudio is intended to be run as a routine. It will continuously run even whilst muted.
func playAudio(file *string, l logging.Logger) {
var numPlays int var numPlays int
for { for {
cmd := exec.Command(audioCmd, *file) cmd := exec.Command(audioCmd, *file)
@ -303,29 +330,8 @@ func playAudio(file *string, quit chan struct{}, wg *sync.WaitGroup, l logging.L
if errBuff.Len() != 0 { if errBuff.Len() != 0 {
l.Error("errors from stderr", "stderr", string(errBuff.Bytes())) l.Error("errors from stderr", "stderr", string(errBuff.Bytes()))
} }
// Check for audio signal halt.
// TODO: work out better way to do this. Doing it this way means we have to wait for
// the audio file to finish playing.
select {
case <-quit:
wg.Done()
return
default:
} }
} }
}
// stopAudio signals to the playAudio routine to terminate and then waits for it to
// do so.
func stopAudio(wg *sync.WaitGroup, treating *bool, signal chan struct{}) {
if !*treating {
return
}
close(signal)
wg.Wait()
*treating = false
}
// 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.