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

     1  package catnip
     2  
     3  import (
     4  	"context"
     5  	"sync"
     6  
     7  	"github.com/noriah/catnip/input"
     8  	"github.com/noriah/catnip/processor"
     9  
    10  	"github.com/pkg/errors"
    11  )
    12  
    13  const MaxChannelCount = 2
    14  const MaxSampleSize = 2048
    15  
    16  type SetupFunc func() error
    17  type StartFunc func(ctx context.Context) (context.Context, error)
    18  type CleanupFunc func() error
    19  
    20  func Run(cfg *Config, ctx context.Context) error {
    21  	if err := cfg.Validate(); err != nil {
    22  		return err
    23  	}
    24  
    25  	inputBuffers := input.MakeBuffers(cfg.ChannelCount, cfg.SampleSize)
    26  
    27  	procConfig := processor.Config{
    28  		SampleRate:   cfg.SampleRate,
    29  		SampleSize:   cfg.SampleSize,
    30  		ChannelCount: cfg.ChannelCount,
    31  		ProcessRate:  cfg.ProcessRate,
    32  		Buffers:      inputBuffers,
    33  		Analyzer:     cfg.Analyzer,
    34  		Output:       cfg.Output,
    35  		Smoother:     cfg.Smoother,
    36  		Windower:     cfg.Windower,
    37  	}
    38  
    39  	var vis processor.Processor
    40  
    41  	if cfg.UseThreaded {
    42  		vis = processor.NewThreaded(procConfig)
    43  	} else {
    44  		vis = processor.New(procConfig)
    45  	}
    46  
    47  	backend, err := input.InitBackend(cfg.Backend)
    48  	if err != nil {
    49  		return err
    50  	}
    51  
    52  	sessConfig := input.SessionConfig{
    53  		FrameSize:  cfg.ChannelCount,
    54  		SampleSize: cfg.SampleSize,
    55  		SampleRate: cfg.SampleRate,
    56  	}
    57  
    58  	if sessConfig.Device, err = input.GetDevice(backend, cfg.Device); err != nil {
    59  		return err
    60  	}
    61  
    62  	audio, err := backend.Start(sessConfig)
    63  	defer backend.Close()
    64  
    65  	if err != nil {
    66  		return errors.Wrap(err, "failed to start the input backend")
    67  	}
    68  
    69  	if cfg.SetupFunc != nil {
    70  		if err := cfg.SetupFunc(); err != nil {
    71  			return err
    72  		}
    73  	}
    74  
    75  	if cfg.CleanupFunc != nil {
    76  		defer cfg.CleanupFunc()
    77  	}
    78  
    79  	if cfg.StartFunc != nil {
    80  		if ctx, err = cfg.StartFunc(ctx); err != nil {
    81  			return err
    82  		}
    83  	}
    84  
    85  	kickChan := make(chan bool, 1)
    86  	mu := &sync.Mutex{}
    87  
    88  	ctx = vis.Start(ctx, kickChan, mu)
    89  	defer vis.Stop()
    90  
    91  	if err := audio.Start(ctx, inputBuffers, kickChan, mu); err != nil {
    92  		if !errors.Is(ctx.Err(), context.Canceled) {
    93  			return errors.Wrap(err, "failed to start input session")
    94  		}
    95  	}
    96  
    97  	return nil
    98  }