github.com/noriah/catnip@v1.8.5/input/parec/parec.go (about)

     1  package parec
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/noisetorch/pulseaudio"
     7  	"github.com/noriah/catnip/input"
     8  	"github.com/noriah/catnip/input/common/execread"
     9  	"github.com/pkg/errors"
    10  )
    11  
    12  func init() {
    13  	input.RegisterBackend("parec", Backend{})
    14  }
    15  
    16  type Backend struct{}
    17  
    18  func (p Backend) Init() error {
    19  	return nil
    20  }
    21  
    22  func (p Backend) Close() error {
    23  	return nil
    24  }
    25  
    26  func (p Backend) Devices() ([]input.Device, error) {
    27  	c, err := pulseaudio.NewClient()
    28  	if err != nil {
    29  		return nil, errors.Wrap(err, "failed to create client")
    30  	}
    31  	defer c.Close()
    32  
    33  	s, err := c.Sources()
    34  	if err != nil {
    35  		return nil, errors.Wrap(err, "failed to get sources")
    36  	}
    37  
    38  	devices := make([]input.Device, len(s))
    39  	for i, source := range s {
    40  		devices[i] = PulseDevice(source.Name)
    41  	}
    42  
    43  	return devices, nil
    44  }
    45  
    46  func (p Backend) DefaultDevice() (input.Device, error) {
    47  	return PulseDevice(""), nil
    48  }
    49  
    50  func (p Backend) Start(cfg input.SessionConfig) (input.Session, error) {
    51  	return NewSession(cfg)
    52  }
    53  
    54  type PulseDevice string
    55  
    56  // InputArgs is used for FFmpeg only.
    57  func (d PulseDevice) InputArgs() []string {
    58  	return []string{"-f", "pulse", "-i", string(d)}
    59  }
    60  
    61  func (d PulseDevice) String() string {
    62  	return string(d)
    63  }
    64  
    65  func NewSession(cfg input.SessionConfig) (*execread.Session, error) {
    66  	dv, ok := cfg.Device.(PulseDevice)
    67  	if !ok {
    68  		return nil, fmt.Errorf("invalid device type %T", cfg.Device)
    69  	}
    70  
    71  	if cfg.FrameSize > 2 {
    72  		return nil, errors.New("channel count not supported, mono/stereo only")
    73  	}
    74  
    75  	args := []string{
    76  		"parec",
    77  		"--format=float32le",
    78  		fmt.Sprintf("--rate=%.0f", cfg.SampleRate),
    79  		fmt.Sprintf("--channels=%d", cfg.FrameSize),
    80  	}
    81  
    82  	if dv != "" {
    83  		args = append(args, "-d", dv.String())
    84  	}
    85  
    86  	return execread.NewSession(args, true, cfg), nil
    87  }