diff --git a/device/alsa/alsa.go b/device/alsa/alsa.go index 815d885d..0078b146 100644 --- a/device/alsa/alsa.go +++ b/device/alsa/alsa.go @@ -147,8 +147,8 @@ func (d *ALSA) Setup(c config.Config) error { return fmt.Errorf("failed to open device: %w", err) } - // Setup the device to record with desired period. - ab := d.dev.NewBufferDuration(time.Duration(d.RecPeriod * float64(time.Second))) + // Create a buffer of 1 minute for continuous recordings. + ab := d.dev.NewBufferDuration(time.Minute) sf, err := pcm.SFFromString(ab.Format.SampleFormat.String()) if err != nil { return fmt.Errorf("unable to get sample format from string: %w", err) @@ -355,6 +355,13 @@ func (d *ALSA) open() error { // input continously records audio and writes it to the ringbuffer. // Re-opens the device and tries again if the ASLA device returns an error. func (d *ALSA) input() { + // Make a channel to communicate betwen continuous recording and processing. + // The channel has a capacity of 5 minutes of audio, which it should never reach. + ch := make(chan []byte, int(5*60/d.RecPeriod)) + + // Read audio in 1 minute sections. + go chunkingRead(d, ch) + for { // Check mode. d.mu.Lock() @@ -407,6 +414,20 @@ func (d *ALSA) input() { } } +// chunkingRead reads continuously from the ALSA buffer in 1 minute sections. The +// audio is then chunked into the recording period set by d.RecPeriod and sent over +// the channel. +func chunkingRead(d *ALSA, ch chan []byte) { + // Read audio in 1 minute sections. + d.dev.Read(d.pb.Data) + + // Chunk the audio into length of RecPeriod. + bytesPerRecPeriod := d.dev.BytesPerFrame() * d.dev.BufferFormat().Rate * int(d.RecPeriod) + for i := 0; i < len(d.pb.Data); i += bytesPerRecPeriod { + ch <- d.pb.Data[i:i+bytesPerRecPeriod-1] + } +} + // Read reads from the ringbuffer, returning the number of bytes read upon success. func (d *ALSA) Read(p []byte) (int, error) { // Ready ringbuffer for read.