input/alsa: set period_size=buffer_size/4
This way, we have four periods instead of the default of two. With only two periods, we don't get woken up often enough, and we frequently encounter buffer overruns. With four periods, we have more time to breathe, and the buffer overruns magically disappear.
This commit is contained in:
parent
d1f3a87c08
commit
7e8b448985
1
NEWS
1
NEWS
@ -1,6 +1,7 @@
|
|||||||
ver 0.20.2 (not yet released)
|
ver 0.20.2 (not yet released)
|
||||||
* input
|
* input
|
||||||
- alsa: fix crash bug
|
- alsa: fix crash bug
|
||||||
|
- alsa: fix buffer overruns
|
||||||
* decoder
|
* decoder
|
||||||
- flac: add options "probesize" and "analyzeduration"
|
- flac: add options "probesize" and "analyzeduration"
|
||||||
* resampler
|
* resampler
|
||||||
|
@ -57,15 +57,6 @@ static constexpr unsigned int default_rate = 44100; // cd quality
|
|||||||
static constexpr size_t ALSA_MAX_BUFFERED = default_rate * default_channels * 2;
|
static constexpr size_t ALSA_MAX_BUFFERED = default_rate * default_channels * 2;
|
||||||
static constexpr size_t ALSA_RESUME_AT = ALSA_MAX_BUFFERED / 2;
|
static constexpr size_t ALSA_RESUME_AT = ALSA_MAX_BUFFERED / 2;
|
||||||
|
|
||||||
/**
|
|
||||||
* This value should be the same as the read buffer size defined in
|
|
||||||
* PcmDecoderPlugin.cxx:pcm_stream_decode().
|
|
||||||
* We use it to calculate how many audio frames to buffer in the alsa driver
|
|
||||||
* before reading from the device. snd_pcm_readi() blocks until that many
|
|
||||||
* frames are ready.
|
|
||||||
*/
|
|
||||||
static constexpr size_t read_buffer_size = 4096;
|
|
||||||
|
|
||||||
class AlsaInputStream final
|
class AlsaInputStream final
|
||||||
: public AsyncInputStream,
|
: public AsyncInputStream,
|
||||||
MultiSocketMonitor, DeferredMonitor {
|
MultiSocketMonitor, DeferredMonitor {
|
||||||
@ -344,18 +335,22 @@ ConfigureCapture(snd_pcm_t *capture_handle,
|
|||||||
(unsigned)period_size_min, (unsigned)period_size_max,
|
(unsigned)period_size_min, (unsigned)period_size_max,
|
||||||
period_time_min, period_time_max);
|
period_time_min, period_time_max);
|
||||||
|
|
||||||
/* period needs to be big enough so that poll() doesn't fire too often,
|
/* choose the maximum possible buffer_size ... */
|
||||||
* but small enough that buffer overruns don't occur if Read() is not
|
snd_pcm_hw_params_set_buffer_size(capture_handle, hw_params,
|
||||||
* invoked often enough.
|
buffer_size_max);
|
||||||
* the calculation here is empirical; however all measurements were
|
|
||||||
* done using 44100:16:2. When we extend this plugin to support
|
/* ... and calculate the period_size to have four periods in
|
||||||
* other audio formats then this may need to be revisited */
|
one buffer; this way, we get woken up often enough to avoid
|
||||||
snd_pcm_uframes_t period = read_buffer_size * 2;
|
buffer overruns, but not too often */
|
||||||
int direction = -1;
|
snd_pcm_uframes_t buffer_size;
|
||||||
if ((err = snd_pcm_hw_params_set_period_size_near(capture_handle, hw_params,
|
if (snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size) == 0) {
|
||||||
&period, &direction)) < 0)
|
snd_pcm_uframes_t period_size = buffer_size / 4;
|
||||||
throw FormatRuntimeError("Cannot set period size (%s)",
|
int direction = -1;
|
||||||
snd_strerror(err));
|
if ((err = snd_pcm_hw_params_set_period_size_near(capture_handle, hw_params,
|
||||||
|
&period_size, &direction)) < 0)
|
||||||
|
throw FormatRuntimeError("Cannot set period size (%s)",
|
||||||
|
snd_strerror(err));
|
||||||
|
}
|
||||||
|
|
||||||
if ((err = snd_pcm_hw_params(capture_handle, hw_params)) < 0)
|
if ((err = snd_pcm_hw_params(capture_handle, hw_params)) < 0)
|
||||||
throw FormatRuntimeError("Cannot set parameters (%s)",
|
throw FormatRuntimeError("Cannot set parameters (%s)",
|
||||||
|
Loading…
Reference in New Issue
Block a user