romeovs
romeovs

Reputation: 5943

Should I wait on command when using StdoutPipe when using exec.Command?

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.ReadClosers 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

Answers (1)

user4466350
user4466350

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

Related Questions