Reputation: 5943
I'm building a small audio application for personal use and need to pipe to some external tools.
I want to structure my program around io.ReadCloser
s that I transform and pipe in to PulseAudios paplay
command.
A simplified example:
package main
import (
"os/exec"
)
func main () {
speech, err := Say("Hello world!")
if err != nil {
log.Fatal(err)
}
err = Play(speech)
if err != nil {
log.Fatal(err)
}
}
// Say creates a stream containing text as a text-to-speech wav audio stream.
func Say(text string) (io.ReadCloser, error) {
speak := exec.Command("espeak", "--stdout", text)
out, err := speak.StdoutPipe()
if err != nil {
return nil, err
}
return out, speak.Start()
}
// Play a wav audio stream.
func Play(s io.ReadCloser) error {
play := exec.Command("paplay")
play.Stdin = s
play.Stderr = os.Stderr
return play.Run()
}
This is a simplified example, but I'd like to create wav streams using different commands, concatenate them and pipe them to paplay
.
The go docs on exec.Cmd
specify that I need to call Wait
on each command to ensure the resources allocated for running the command are cleared:
Wait releases any resources associated with the Cmd.
But at the same time it is unclear if I need to call this when using StdoutPipe
.
Will go clean up the command after the stdout pipe is exhausted and the command has exited or do I need to rethink my abstractions here?
Upvotes: 2
Views: 823
Reputation:
But at the same time it is unclear if I need to call this when using StdoutPipe.
Yes you still need to Wait()
to consider cmd instances ended completely.
However, to pipe the stdout stream, its close signal suffices to detect the end of copy.
The doc says
StdoutPipe returns a pipe that will be connected to the command's standard output when the command starts.
Wait will close the pipe after seeing the command exit, so most callers need not close the pipe themselves; however, an implication is that it is incorrect to call Wait before all reads from the pipe have completed. For the same reason, it is incorrect to call Run when using StdoutPipe. See the example for idiomatic usage.
Will go clean up the command after the stdout pipe is exhausted and the command has exited or
yes.
do I need to rethink my abstractions here?
no.
your code is ok.
Upvotes: 1