diff options
Diffstat (limited to 'firmware/target/hosted/pcm-alsa.c')
-rw-r--r-- | firmware/target/hosted/pcm-alsa.c | 65 |
1 files changed, 53 insertions, 12 deletions
diff --git a/firmware/target/hosted/pcm-alsa.c b/firmware/target/hosted/pcm-alsa.c index 14e1c4cd3e..1854f67ba0 100644 --- a/firmware/target/hosted/pcm-alsa.c +++ b/firmware/target/hosted/pcm-alsa.c | |||
@@ -62,6 +62,12 @@ | |||
62 | #define DEFAULT_PLAYBACK_DEVICE "plughw:0,0" | 62 | #define DEFAULT_PLAYBACK_DEVICE "plughw:0,0" |
63 | #define DEFAULT_CAPTURE_DEVICE "default" | 63 | #define DEFAULT_CAPTURE_DEVICE "default" |
64 | 64 | ||
65 | #if MIX_FRAME_SAMPLES < 512 | ||
66 | #error "MIX_FRAME_SAMPLES needs to be at least 512!" | ||
67 | #elif MIX_FRAME_SAMPLES < 1024 | ||
68 | #warning "MIX_FRAME_SAMPLES <1024 may cause dropouts!" | ||
69 | #endif | ||
70 | |||
65 | static const snd_pcm_access_t access_ = SND_PCM_ACCESS_RW_INTERLEAVED; /* access mode */ | 71 | static const snd_pcm_access_t access_ = SND_PCM_ACCESS_RW_INTERLEAVED; /* access mode */ |
66 | #if defined(SONY_NWZ_LINUX) || defined(HAVE_FIIO_LINUX_CODEC) | 72 | #if defined(SONY_NWZ_LINUX) || defined(HAVE_FIIO_LINUX_CODEC) |
67 | /* Sony NWZ must use 32-bit per sample */ | 73 | /* Sony NWZ must use 32-bit per sample */ |
@@ -83,6 +89,8 @@ static sample_t *frames = NULL; | |||
83 | static const void *pcm_data = 0; | 89 | static const void *pcm_data = 0; |
84 | static size_t pcm_size = 0; | 90 | static size_t pcm_size = 0; |
85 | 91 | ||
92 | static unsigned int xruns = 0; | ||
93 | |||
86 | static snd_async_handler_t *ahandler = NULL; | 94 | static snd_async_handler_t *ahandler = NULL; |
87 | static pthread_mutex_t pcm_mtx; | 95 | static pthread_mutex_t pcm_mtx; |
88 | static char signal_stack[SIGSTKSZ]; | 96 | static char signal_stack[SIGSTKSZ]; |
@@ -117,17 +125,21 @@ static int set_hwparams(snd_pcm_t *handle) | |||
117 | snd_pcm_hw_params_malloc(¶ms); | 125 | snd_pcm_hw_params_malloc(¶ms); |
118 | 126 | ||
119 | /* Size playback buffers based on sample rate. | 127 | /* Size playback buffers based on sample rate. |
120 | Note these are in FRAMES, and are sized to be about 10ms | 128 | |
121 | for the buffer and 2.5ms for the period */ | 129 | Buffer size must be at least 4x period size! |
130 | |||
131 | Note these are in FRAMES, and are sized to be about 8.5ms | ||
132 | for the buffer and 2.1ms for the period | ||
133 | */ | ||
122 | if (pcm_sampr > SAMPR_96) { | 134 | if (pcm_sampr > SAMPR_96) { |
123 | buffer_size = MIX_FRAME_SAMPLES * 16 * 4; /* 32k */ | 135 | buffer_size = MIX_FRAME_SAMPLES * 4 * 4; |
124 | period_size = MIX_FRAME_SAMPLES * 4 * 4; /* 4k */ | 136 | period_size = MIX_FRAME_SAMPLES * 4; |
125 | } else if (pcm_sampr > SAMPR_48) { | 137 | } else if (pcm_sampr > SAMPR_48) { |
126 | buffer_size = MIX_FRAME_SAMPLES * 16 * 2; /* 16k */ | 138 | buffer_size = MIX_FRAME_SAMPLES * 2 * 4; |
127 | period_size = MIX_FRAME_SAMPLES * 4 * 2; /* 2k */ | 139 | period_size = MIX_FRAME_SAMPLES * 2; |
128 | } else { | 140 | } else { |
129 | buffer_size = MIX_FRAME_SAMPLES * 16; /* 4k */ | 141 | buffer_size = MIX_FRAME_SAMPLES * 4; |
130 | period_size = MIX_FRAME_SAMPLES * 4; /* 1k */ | 142 | period_size = MIX_FRAME_SAMPLES; |
131 | } | 143 | } |
132 | 144 | ||
133 | /* choose all parameters */ | 145 | /* choose all parameters */ |
@@ -407,7 +419,8 @@ static void async_callback(snd_async_handler_t *ahandler) | |||
407 | 419 | ||
408 | if (state == SND_PCM_STATE_XRUN) | 420 | if (state == SND_PCM_STATE_XRUN) |
409 | { | 421 | { |
410 | logf("underrun!"); | 422 | xruns++; |
423 | logf("initial underrun!"); | ||
411 | err = snd_pcm_recover(handle, -EPIPE, 0); | 424 | err = snd_pcm_recover(handle, -EPIPE, 0); |
412 | if (err < 0) { | 425 | if (err < 0) { |
413 | logf("XRUN Recovery error: %s", snd_strerror(err)); | 426 | logf("XRUN Recovery error: %s", snd_strerror(err)); |
@@ -432,8 +445,20 @@ static void async_callback(snd_async_handler_t *ahandler) | |||
432 | { | 445 | { |
433 | if (copy_frames(false)) | 446 | if (copy_frames(false)) |
434 | { | 447 | { |
448 | retry: | ||
435 | err = snd_pcm_writei(handle, frames, period_size); | 449 | err = snd_pcm_writei(handle, frames, period_size); |
436 | if (err < 0 && err != period_size && err != -EAGAIN) | 450 | if (err == -EPIPE) |
451 | { | ||
452 | logf("mid underrun!"); | ||
453 | xruns++; | ||
454 | err = snd_pcm_recover(handle, -EPIPE, 0); | ||
455 | if (err < 0) { | ||
456 | logf("XRUN Recovery error: %s", snd_strerror(err)); | ||
457 | goto abort; | ||
458 | } | ||
459 | goto retry; | ||
460 | } | ||
461 | else if (err != period_size) | ||
437 | { | 462 | { |
438 | logf("Write error: written %i expected %li", err, period_size); | 463 | logf("Write error: written %i expected %li", err, period_size); |
439 | break; | 464 | break; |
@@ -452,7 +477,18 @@ static void async_callback(snd_async_handler_t *ahandler) | |||
452 | while (snd_pcm_avail_update(handle) >= period_size) | 477 | while (snd_pcm_avail_update(handle) >= period_size) |
453 | { | 478 | { |
454 | int err = snd_pcm_readi(handle, frames, period_size); | 479 | int err = snd_pcm_readi(handle, frames, period_size); |
455 | if (err < 0 && err != period_size && err != -EAGAIN) | 480 | if (err == -EPIPE) |
481 | { | ||
482 | logf("rec mid underrun!"); | ||
483 | xruns++; | ||
484 | err = snd_pcm_recover(handle, -EPIPE, 0); | ||
485 | if (err < 0) { | ||
486 | logf("XRUN Recovery error: %s", snd_strerror(err)); | ||
487 | goto abort; | ||
488 | } | ||
489 | continue; /* buffer contents trashed, no sense in trying to copy */ | ||
490 | } | ||
491 | else if (err != period_size) | ||
456 | { | 492 | { |
457 | logf("Read error: read %i expected %li", err, period_size); | 493 | logf("Read error: read %i expected %li", err, period_size); |
458 | break; | 494 | break; |
@@ -751,11 +787,16 @@ void pcm_play_dma_postinit(void) | |||
751 | #endif | 787 | #endif |
752 | } | 788 | } |
753 | 789 | ||
754 | int pcm_alsa_get_rate(void) | 790 | unsigned int pcm_alsa_get_rate(void) |
755 | { | 791 | { |
756 | return real_sample_rate; | 792 | return real_sample_rate; |
757 | } | 793 | } |
758 | 794 | ||
795 | unsigned int pcm_alsa_get_xruns(void) | ||
796 | { | ||
797 | return xruns; | ||
798 | } | ||
799 | |||
759 | #ifdef HAVE_RECORDING | 800 | #ifdef HAVE_RECORDING |
760 | void pcm_rec_lock(void) | 801 | void pcm_rec_lock(void) |
761 | { | 802 | { |