hosted: Improve buffer underrun handling in the ALSA driver
* Bump internal mix buffer size by 4x, to 1K frames (matching ALSA period) * Handle an underrun that occurs when filling the audio buffer * Log underruns and make them available in the debug info Change-Id: I28d56dd35d88851fa167ad92368a5882937a758f
This commit is contained in:
parent
473aa615de
commit
3027cead01
4 changed files with 66 additions and 19 deletions
|
@ -40,6 +40,10 @@
|
||||||
/* iBasso Devices: Match Rockbox PCM buffer size to ALSA PCM buffer size
|
/* iBasso Devices: Match Rockbox PCM buffer size to ALSA PCM buffer size
|
||||||
to minimize memory transfers. */
|
to minimize memory transfers. */
|
||||||
#define MIX_FRAME_SAMPLES 2048
|
#define MIX_FRAME_SAMPLES 2048
|
||||||
|
#elif (CONFIG_PLATFORM & PLATFORM_HOSTED)
|
||||||
|
/* Hosted targets need larger buffers for decent performance due to
|
||||||
|
OS locking/scheduling overhead */
|
||||||
|
#define MIX_FRAME_SAMPLES 1024
|
||||||
#else
|
#else
|
||||||
/* Assume HW DMA engine is available or sufficient latency exists in the
|
/* Assume HW DMA engine is available or sufficient latency exists in the
|
||||||
PCM pathway */
|
PCM pathway */
|
||||||
|
|
|
@ -62,6 +62,7 @@ bool dbg_hw_info(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
lcd_putsf(0, line++, "pcm srate: %d", pcm_alsa_get_rate());
|
lcd_putsf(0, line++, "pcm srate: %d", pcm_alsa_get_rate());
|
||||||
|
lcd_putsf(0, line++, "pcm xruns: %d", pcm_alsa_get_xruns());
|
||||||
#ifdef HAVE_HEADPHONE_DETECTION
|
#ifdef HAVE_HEADPHONE_DETECTION
|
||||||
lcd_putsf(0, line++, "hp: %d", headphones_inserted());
|
lcd_putsf(0, line++, "hp: %d", headphones_inserted());
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -62,6 +62,12 @@
|
||||||
#define DEFAULT_PLAYBACK_DEVICE "plughw:0,0"
|
#define DEFAULT_PLAYBACK_DEVICE "plughw:0,0"
|
||||||
#define DEFAULT_CAPTURE_DEVICE "default"
|
#define DEFAULT_CAPTURE_DEVICE "default"
|
||||||
|
|
||||||
|
#if MIX_FRAME_SAMPLES < 512
|
||||||
|
#error "MIX_FRAME_SAMPLES needs to be at least 512!"
|
||||||
|
#elif MIX_FRAME_SAMPLES < 1024
|
||||||
|
#warning "MIX_FRAME_SAMPLES <1024 may cause dropouts!"
|
||||||
|
#endif
|
||||||
|
|
||||||
static const snd_pcm_access_t access_ = SND_PCM_ACCESS_RW_INTERLEAVED; /* access mode */
|
static const snd_pcm_access_t access_ = SND_PCM_ACCESS_RW_INTERLEAVED; /* access mode */
|
||||||
#if defined(SONY_NWZ_LINUX) || defined(HAVE_FIIO_LINUX_CODEC)
|
#if defined(SONY_NWZ_LINUX) || defined(HAVE_FIIO_LINUX_CODEC)
|
||||||
/* Sony NWZ must use 32-bit per sample */
|
/* Sony NWZ must use 32-bit per sample */
|
||||||
|
@ -83,6 +89,8 @@ static sample_t *frames = NULL;
|
||||||
static const void *pcm_data = 0;
|
static const void *pcm_data = 0;
|
||||||
static size_t pcm_size = 0;
|
static size_t pcm_size = 0;
|
||||||
|
|
||||||
|
static unsigned int xruns = 0;
|
||||||
|
|
||||||
static snd_async_handler_t *ahandler = NULL;
|
static snd_async_handler_t *ahandler = NULL;
|
||||||
static pthread_mutex_t pcm_mtx;
|
static pthread_mutex_t pcm_mtx;
|
||||||
static char signal_stack[SIGSTKSZ];
|
static char signal_stack[SIGSTKSZ];
|
||||||
|
@ -117,17 +125,21 @@ static int set_hwparams(snd_pcm_t *handle)
|
||||||
snd_pcm_hw_params_malloc(¶ms);
|
snd_pcm_hw_params_malloc(¶ms);
|
||||||
|
|
||||||
/* Size playback buffers based on sample rate.
|
/* Size playback buffers based on sample rate.
|
||||||
Note these are in FRAMES, and are sized to be about 10ms
|
|
||||||
for the buffer and 2.5ms for the period */
|
Buffer size must be at least 4x period size!
|
||||||
|
|
||||||
|
Note these are in FRAMES, and are sized to be about 8.5ms
|
||||||
|
for the buffer and 2.1ms for the period
|
||||||
|
*/
|
||||||
if (pcm_sampr > SAMPR_96) {
|
if (pcm_sampr > SAMPR_96) {
|
||||||
buffer_size = MIX_FRAME_SAMPLES * 16 * 4; /* 32k */
|
buffer_size = MIX_FRAME_SAMPLES * 4 * 4;
|
||||||
period_size = MIX_FRAME_SAMPLES * 4 * 4; /* 4k */
|
period_size = MIX_FRAME_SAMPLES * 4;
|
||||||
} else if (pcm_sampr > SAMPR_48) {
|
} else if (pcm_sampr > SAMPR_48) {
|
||||||
buffer_size = MIX_FRAME_SAMPLES * 16 * 2; /* 16k */
|
buffer_size = MIX_FRAME_SAMPLES * 2 * 4;
|
||||||
period_size = MIX_FRAME_SAMPLES * 4 * 2; /* 2k */
|
period_size = MIX_FRAME_SAMPLES * 2;
|
||||||
} else {
|
} else {
|
||||||
buffer_size = MIX_FRAME_SAMPLES * 16; /* 4k */
|
buffer_size = MIX_FRAME_SAMPLES * 4;
|
||||||
period_size = MIX_FRAME_SAMPLES * 4; /* 1k */
|
period_size = MIX_FRAME_SAMPLES;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* choose all parameters */
|
/* choose all parameters */
|
||||||
|
@ -407,7 +419,8 @@ static void async_callback(snd_async_handler_t *ahandler)
|
||||||
|
|
||||||
if (state == SND_PCM_STATE_XRUN)
|
if (state == SND_PCM_STATE_XRUN)
|
||||||
{
|
{
|
||||||
logf("underrun!");
|
xruns++;
|
||||||
|
logf("initial underrun!");
|
||||||
err = snd_pcm_recover(handle, -EPIPE, 0);
|
err = snd_pcm_recover(handle, -EPIPE, 0);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
logf("XRUN Recovery error: %s", snd_strerror(err));
|
logf("XRUN Recovery error: %s", snd_strerror(err));
|
||||||
|
@ -432,8 +445,20 @@ static void async_callback(snd_async_handler_t *ahandler)
|
||||||
{
|
{
|
||||||
if (copy_frames(false))
|
if (copy_frames(false))
|
||||||
{
|
{
|
||||||
|
retry:
|
||||||
err = snd_pcm_writei(handle, frames, period_size);
|
err = snd_pcm_writei(handle, frames, period_size);
|
||||||
if (err < 0 && err != period_size && err != -EAGAIN)
|
if (err == -EPIPE)
|
||||||
|
{
|
||||||
|
logf("mid underrun!");
|
||||||
|
xruns++;
|
||||||
|
err = snd_pcm_recover(handle, -EPIPE, 0);
|
||||||
|
if (err < 0) {
|
||||||
|
logf("XRUN Recovery error: %s", snd_strerror(err));
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
else if (err != period_size)
|
||||||
{
|
{
|
||||||
logf("Write error: written %i expected %li", err, period_size);
|
logf("Write error: written %i expected %li", err, period_size);
|
||||||
break;
|
break;
|
||||||
|
@ -452,7 +477,18 @@ static void async_callback(snd_async_handler_t *ahandler)
|
||||||
while (snd_pcm_avail_update(handle) >= period_size)
|
while (snd_pcm_avail_update(handle) >= period_size)
|
||||||
{
|
{
|
||||||
int err = snd_pcm_readi(handle, frames, period_size);
|
int err = snd_pcm_readi(handle, frames, period_size);
|
||||||
if (err < 0 && err != period_size && err != -EAGAIN)
|
if (err == -EPIPE)
|
||||||
|
{
|
||||||
|
logf("rec mid underrun!");
|
||||||
|
xruns++;
|
||||||
|
err = snd_pcm_recover(handle, -EPIPE, 0);
|
||||||
|
if (err < 0) {
|
||||||
|
logf("XRUN Recovery error: %s", snd_strerror(err));
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
continue; /* buffer contents trashed, no sense in trying to copy */
|
||||||
|
}
|
||||||
|
else if (err != period_size)
|
||||||
{
|
{
|
||||||
logf("Read error: read %i expected %li", err, period_size);
|
logf("Read error: read %i expected %li", err, period_size);
|
||||||
break;
|
break;
|
||||||
|
@ -751,11 +787,16 @@ void pcm_play_dma_postinit(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int pcm_alsa_get_rate(void)
|
unsigned int pcm_alsa_get_rate(void)
|
||||||
{
|
{
|
||||||
return real_sample_rate;
|
return real_sample_rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int pcm_alsa_get_xruns(void)
|
||||||
|
{
|
||||||
|
return xruns;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_RECORDING
|
#ifdef HAVE_RECORDING
|
||||||
void pcm_rec_lock(void)
|
void pcm_rec_lock(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* __________ __ ___.
|
* __________ __ ___.
|
||||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
* \/ \/ \/ \/ \/
|
* \/ \/ \/ \/ \/
|
||||||
*
|
*
|
||||||
* Copyright (C) 2016 Amaury Pouly
|
* Copyright (C) 2016 Amaury Pouly
|
||||||
*
|
*
|
||||||
|
@ -34,6 +34,7 @@ void pcm_alsa_set_playback_device(const char *device);
|
||||||
void pcm_alsa_set_capture_device(const char *device);
|
void pcm_alsa_set_capture_device(const char *device);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int pcm_alsa_get_rate(void);
|
unsigned int pcm_alsa_get_rate(void);
|
||||||
|
unsigned int pcm_alsa_get_xruns(void);
|
||||||
|
|
||||||
#endif /* __PCM_ALSA_RB_H__ */
|
#endif /* __PCM_ALSA_RB_H__ */
|
||||||
|
|
Loading…
Reference in a new issue