diff --git a/cmd/treatment/main.go b/cmd/treatment/main.go index 8a6e30b9..31287927 100644 --- a/cmd/treatment/main.go +++ b/cmd/treatment/main.go @@ -35,7 +35,6 @@ import ( "io" "os/exec" "strconv" - "sync" "time" "bitbucket.org/ausocean/av/container/mts" @@ -78,17 +77,18 @@ const ( i2cPort = 1 ) -// Treatment modes. +// Channel modes. const ( - modePaused = "Paused" - modeTreatment = "Play" - modeCheck = "Check" + modeStereo = "Stereo" + modeLeft = "LeftMono" + modeRight = "RightMono" + modeMute = "Mute" ) // Variable map to send to netreceiver/vidgrind. var varMap = map[string]string{ - "mode": "enum:Paused,Play,Check", - "AudioFilePath": "string", + "speakerMode": "enum:Stereo,LeftMono,RightMono,Mute", + "AudioFilePath": "string", } func main() { @@ -131,6 +131,10 @@ func main() { 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. log.Debug("starting control loop") run(rv, ns, filePtr, log, netLog) @@ -140,10 +144,7 @@ func main() { // 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) { var ( - wg sync.WaitGroup - audioQuit chan struct{} - treating bool - vs int + vs int ) for { @@ -207,50 +208,76 @@ func run(rv *revid.Revid, ns *netsender.Sender, file *string, l logging.Logger, } l.Debug("checking mode") - switch ns.Mode() { - case modePaused: - 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) - continue - } - default: - l.Warning("mode is not valid", "mode", ns.Mode()) - - } - l.Info("revid updated with new mode") + setChannels(vars["speakerMode"], l) + // 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 -// a signal is received to return. The entire audio file is played before the termination -// signal chan is checked. -func playAudio(file *string, quit chan struct{}, wg *sync.WaitGroup, l logging.Logger) { +// 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: + // If an invalid option has been chosen, keep the previous setting. + return + } + + // Create the command to change the channel volumes. + cmd := exec.Command("amixer", "sset", "Speaker", vols) + + // 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 for { cmd := exec.Command(audioCmd, *file) @@ -303,30 +330,9 @@ func playAudio(file *string, quit chan struct{}, wg *sync.WaitGroup, l logging.L if errBuff.Len() != 0 { 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 // netsender parameter (mp) defined in the netsender.conf config. func sleep(ns *netsender.Sender, l logging.Logger) {