diff --git a/src/stt.zig b/src/stt.zig index 3e690c0..0911db8 100644 --- a/src/stt.zig +++ b/src/stt.zig @@ -454,19 +454,56 @@ pub const AlsaCapture = struct { self.sample_rate = actual_rate; } - // Set buffer size + // Get hardware constraints for buffer size + // SAFETY: this is set immediately as an out parameter in c API + var min_buffer: c.snd_pcm_uframes_t = undefined; + // SAFETY: this is set immediately as an out parameter in c API + var max_buffer: c.snd_pcm_uframes_t = undefined; + _ = c.snd_pcm_hw_params_get_buffer_size_min(hw_params, &min_buffer); + _ = c.snd_pcm_hw_params_get_buffer_size_max(hw_params, &max_buffer); + + // Calculate minimum buffer size for ~40ms of audio + const calculated_min: u32 = @intCast((self.sample_rate * 40) / 1000); + const target_buffer = @max(self.buffer_size, calculated_min); + if (target_buffer < min_buffer) { + std.log.info("Buffer size {} too small, using minimum {}", .{ target_buffer, min_buffer }); + self.buffer_size = @intCast(min_buffer); + } else if (target_buffer > max_buffer) { + std.log.info("Buffer size {} too large, using maximum {}", .{ target_buffer, max_buffer }); + self.buffer_size = @intCast(max_buffer); + } else { + self.buffer_size = @intCast(target_buffer); + } + + // Set buffer size first var actual_buffer_size: c.snd_pcm_uframes_t = self.buffer_size; err = c.snd_pcm_hw_params_set_buffer_size_near(self.pcm_handle, hw_params, &actual_buffer_size); if (err < 0) return Error.SetBufferSizeError; + self.buffer_size = @intCast(actual_buffer_size); - // Set period size - var actual_period_size: c.snd_pcm_uframes_t = self.period_size; - err = c.snd_pcm_hw_params_set_period_size_near(self.pcm_handle, hw_params, &actual_period_size, null); + // Set period time (in microseconds) instead of period size for better compatibility + // Target ~10ms periods (10000 microseconds) + var period_time: c_uint = std.time.us_per_ms * 10; + var dir: c_int = 0; + err = c.snd_pcm_hw_params_set_period_time_near(self.pcm_handle, hw_params, &period_time, &dir); if (err < 0) return Error.SetPeriodSizeError; + // Get the actual period size that was set + // SAFETY: this is set immediately as an out parameter in c API + var actual_period_size: c.snd_pcm_uframes_t = undefined; + err = c.snd_pcm_hw_params_get_period_size(hw_params, &actual_period_size, null); + if (err >= 0) { + self.period_size = @intCast(actual_period_size); + } + + std.log.debug("ALSA params: rate={}, channels={}, buffer={}, period={}", .{ self.sample_rate, self.channels, actual_buffer_size, self.period_size }); + // Apply hardware parameters err = c.snd_pcm_hw_params(self.pcm_handle, hw_params); - if (err < 0) return Error.ApplyParametersError; + if (err < 0) { + std.log.err("snd_pcm_hw_params failed with error code: {}", .{err}); + return Error.ApplyParametersError; + } // Prepare the PCM for use err = c.snd_pcm_prepare(self.pcm_handle);