alsa.go: Add chunkingRead function to abstract reading from the alsa buffer (#440)

The chunkingRead function allows the record period to not impact on the recording buffer size of the audio. This should allow for less issues related to alsa buffer reading.
This commit is contained in:
David Sutton 2024-04-04 12:56:24 +10:30
parent 9f56bee095
commit ee6046cab0
1 changed files with 23 additions and 2 deletions

View File

@ -147,8 +147,8 @@ func (d *ALSA) Setup(c config.Config) error {
return fmt.Errorf("failed to open device: %w", err) return fmt.Errorf("failed to open device: %w", err)
} }
// Setup the device to record with desired period. // Create a buffer of 1 minute for continuous recordings.
ab := d.dev.NewBufferDuration(time.Duration(d.RecPeriod * float64(time.Second))) ab := d.dev.NewBufferDuration(time.Minute)
sf, err := pcm.SFFromString(ab.Format.SampleFormat.String()) sf, err := pcm.SFFromString(ab.Format.SampleFormat.String())
if err != nil { if err != nil {
return fmt.Errorf("unable to get sample format from string: %w", err) 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. // input continously records audio and writes it to the ringbuffer.
// Re-opens the device and tries again if the ASLA device returns an error. // Re-opens the device and tries again if the ASLA device returns an error.
func (d *ALSA) input() { 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 { for {
// Check mode. // Check mode.
d.mu.Lock() 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. // Read reads from the ringbuffer, returning the number of bytes read upon success.
func (d *ALSA) Read(p []byte) (int, error) { func (d *ALSA) Read(p []byte) (int, error) {
// Ready ringbuffer for read. // Ready ringbuffer for read.