]> git.alsa-project.org Git - alsa-lib.git/commitdiff
Fix noisy output of dmix with two periods
authorTakashi Iwai <tiwai@suse.de>
Fri, 24 Mar 2006 14:53:41 +0000 (14:53 +0000)
committerTakashi Iwai <tiwai@suse.de>
Fri, 24 Mar 2006 14:53:41 +0000 (14:53 +0000)
Fixed the noisy output of dmix with two (or less) periods.
The dmix tends to give noise or XRUN when running with two periods
because of its implementation nature.  To avoid this, the start
position is aligned to the period size, so that the updates are synced
with interrupts of slave PCM.

src/pcm/pcm_direct.c
src/pcm/pcm_dmix.c

index 815448896d41b7cb19abce0e8b2a70c2f3ae937e..744757078ef3a00c2748580c809a1efd733a1ec7 100644 (file)
@@ -713,8 +713,11 @@ int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
                int changed;
                do {
                        changed = 0;
+                       /* Set min/max size to [2:1024] since INT_MAX as the
+                        * upper-limit results in a too big buffer on some apps.
+                        */
                        err = hw_param_interval_refine_minmax(params, SND_PCM_HW_PARAM_PERIODS,
-                                                     2, INT_MAX);
+                                                             2, 1024);
                        if (err < 0)
                                return err;
                        changed |= err;
index 54706af08a92f3915c330f54caba6f32f1051460..e3f4aa06d269896195b6522fe5ee873191175955 100644 (file)
@@ -484,21 +484,35 @@ static int snd_pcm_dmix_prepare(snd_pcm_t *pcm)
        return snd_pcm_direct_set_timer_params(dmix);
 }
 
+static void reset_slave_ptr(snd_pcm_t *pcm, snd_pcm_direct_t *dmix)
+{
+       dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
+       if (! dmix->variable_buffer_size ||
+           pcm->buffer_size > pcm->period_size * 2)
+               return;
+       /* If we have too litte periods, better to align the start position
+        * to the period boundary so that the interrupt can be handled properly
+        * at the right time.
+        */
+       dmix->slave_appl_ptr = ((dmix->slave_appl_ptr + dmix->slave_period_size - 1)
+                               / dmix->slave_period_size) * dmix->slave_period_size;
+}
+
 static int snd_pcm_dmix_reset(snd_pcm_t *pcm)
 {
        snd_pcm_direct_t *dmix = pcm->private_data;
        dmix->hw_ptr %= pcm->period_size;
        dmix->appl_ptr = dmix->last_appl_ptr = dmix->hw_ptr;
-       dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
+       reset_slave_ptr(pcm, dmix);
        return 0;
 }
 
-static int snd_pcm_dmix_start_timer(snd_pcm_direct_t *dmix)
+static int snd_pcm_dmix_start_timer(snd_pcm_t *pcm, snd_pcm_direct_t *dmix)
 {
        int err;
 
        snd_pcm_hwsync(dmix->spcm);
-       dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
+       reset_slave_ptr(pcm, dmix);
        err = snd_timer_start(dmix->timer);
        if (err < 0)
                return err;
@@ -521,7 +535,7 @@ static int snd_pcm_dmix_start(snd_pcm_t *pcm)
        else if (avail < 0)
                return 0;
        else {
-               if ((err = snd_pcm_dmix_start_timer(dmix)) < 0)
+               if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0)
                        return err;
                snd_pcm_dmix_sync_area(pcm);
        }
@@ -664,7 +678,7 @@ static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm,
                return 0;
        snd_pcm_mmap_appl_forward(pcm, size);
        if (dmix->state == STATE_RUN_PENDING) {
-               if ((err = snd_pcm_dmix_start_timer(dmix)) < 0)
+               if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0)
                        return err;
        } else if (dmix->state == SND_PCM_STATE_RUNNING ||
                   dmix->state == SND_PCM_STATE_DRAINING)