]> git.alsa-project.org Git - alsa-lib.git/commitdiff
Fix CPU hog with combination of rate plugin
authorTakashi Iwai <tiwai@suse.de>
Fri, 22 Apr 2005 16:36:13 +0000 (16:36 +0000)
committerTakashi Iwai <tiwai@suse.de>
Fri, 22 Apr 2005 16:36:13 +0000 (16:36 +0000)
Fix CPU hog with some apps (e.g. artsd) when rate plugin is used
together with dmix (or possible hw).

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

index 5ec13e73bb9f9d75640f4ce679a8255808b201c5..e49df24c303b115f6dc2c0dc23ecf5e5cade2a1d 100644 (file)
@@ -447,7 +447,7 @@ int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned in
        events = pfds[0].revents;
        if (events & POLLIN) {
                snd_pcm_uframes_t avail;
-               int empty = 0;
+               int empty;
                snd_pcm_avail_update(pcm);
                if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
                        events |= POLLOUT;
@@ -457,10 +457,10 @@ int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned in
                        avail = snd_pcm_mmap_capture_avail(pcm);
                }
                empty = avail < pcm->avail_min;
-               if (empty)
+               if (empty) {
                        snd_pcm_direct_clear_timer_queue(dmix);
-               if (empty)
                        events &= ~(POLLOUT|POLLIN);
+               }
        }
        switch (snd_pcm_state(dmix->spcm)) {
        case SND_PCM_STATE_XRUN:
index 88cf5d1d98dba1f70a225e8eec330ff3a48f7a6d..4813b8a256f48f0d079e02e10e664545f4b0451c 100644 (file)
@@ -627,6 +627,9 @@ static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm,
                /* ok, we commit the changes after the validation of area */
                /* it's intended, although the result might be crappy */
                snd_pcm_dmix_sync_area(pcm, size);
+               /* clear timer queue to avoid a bogus return from poll */
+               if (snd_pcm_mmap_playback_avail(pcm) < pcm->avail_min)
+                       snd_pcm_direct_clear_timer_queue(dmix);
        }
        return size;
 }
index 4c8fb2e0873595f202185eeaff8eb0126793ee54..77f96b04f5494b7b3fdab60f3ec7a441bf98951f 100644 (file)
@@ -69,6 +69,7 @@ struct _snd_pcm_rate {
        snd_pcm_generic_t gen;
        snd_atomic_write_t watom;
        snd_pcm_uframes_t appl_ptr, hw_ptr;
+       snd_pcm_uframes_t last_commit_ptr;
        snd_pcm_uframes_t orig_avail_min;
        snd_pcm_sw_params_t sw_params;
        enum rate_type type;
@@ -759,6 +760,7 @@ static int snd_pcm_rate_init(snd_pcm_t *pcm)
        default:
                assert(0);
        }
+       rate->last_commit_ptr = 0;
        return 0;
 }
 
@@ -831,7 +833,10 @@ static inline snd_pcm_sframes_t snd_pcm_rate_move_applptr(snd_pcm_t *pcm, snd_pc
                diff = -((slave->boundary - orig_appl_ptr) + rate->appl_ptr);
        }
        if (frames < 0)
-               return -diff;
+               diff = -diff;
+
+       rate->last_commit_ptr = rate->appl_ptr - rate->appl_ptr % pcm->period_size;
+
        return diff;
 }
 
@@ -842,6 +847,9 @@ static inline void snd_pcm_rate_sync_hwptr(snd_pcm_t *pcm)
 
        if (pcm->stream != SND_PCM_STREAM_PLAYBACK)
                return;
+       /* FIXME: boundary overlap of slave hw_ptr isn't evaluated here!
+        *        e.g. if slave rate is small... 
+        */
        rate->hw_ptr =
                (slave_hw_ptr / rate->gen.slave->period_size) * pcm->period_size +
                snd_pcm_rate_client_frames(pcm, slave_hw_ptr % rate->gen.slave->period_size);
@@ -1168,82 +1176,56 @@ static int snd_pcm_rate_grab_next_period(snd_pcm_t *pcm, snd_pcm_uframes_t hw_of
        return 1;
 }
 
-static snd_pcm_sframes_t snd_pcm_rate_mmap_commit(snd_pcm_t *pcm,
-                                                 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
-                                                 snd_pcm_uframes_t size)
+static int snd_pcm_rate_sync_playback_area(snd_pcm_t *pcm, snd_pcm_uframes_t appl_ptr)
 {
        snd_pcm_rate_t *rate = pcm->private_data;
        snd_pcm_t *slave = rate->gen.slave;
-       snd_pcm_uframes_t appl_offset, xfer;
+       snd_pcm_uframes_t xfer;
        snd_pcm_sframes_t slave_size;
        int err;
 
-       if (size == 0)
-               return 0;
-       if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
-               snd_atomic_write_begin(&rate->watom);
-               snd_pcm_mmap_appl_forward(pcm, size);
-               snd_atomic_write_end(&rate->watom);
-               return size;
-       }
        slave_size = snd_pcm_avail_update(slave);
        if (slave_size < 0)
                return slave_size;
-       xfer = rate->appl_ptr % pcm->period_size;
-       appl_offset = (rate->appl_ptr - xfer) % pcm->buffer_size;
-       xfer = pcm->period_size - xfer;
-       if (xfer >= size) {
-               if (xfer == size && (snd_pcm_uframes_t)slave_size >= rate->gen.slave->period_size) {
-                       err = snd_pcm_rate_commit_next_period(pcm, appl_offset);
-                       if (err < 0)
-                               return err;
-                       if (err == 0)
-                               return 0;
-               }
-               snd_atomic_write_begin(&rate->watom);
-               snd_pcm_mmap_appl_forward(pcm, size);
-               snd_atomic_write_end(&rate->watom);
-               return size;
-       } else {
-               if ((snd_pcm_uframes_t)slave_size >= rate->gen.slave->period_size) {
-                       err = snd_pcm_rate_commit_next_period(pcm, appl_offset);
-                       if (err < 0)
-                               return err;
-                       if (err == 0)
-                               return 0;
-               }
-               snd_atomic_write_begin(&rate->watom);
-               snd_pcm_mmap_appl_forward(pcm, xfer);
-               snd_atomic_write_end(&rate->watom);
-               appl_offset += pcm->period_size;
-               appl_offset %= pcm->buffer_size;
-               size -= xfer;
-               slave_size -= rate->gen.slave->period_size;
-       }
-       while ((snd_pcm_uframes_t)size >= pcm->period_size &&
+
+       if (appl_ptr < rate->last_commit_ptr)
+               xfer = appl_ptr - rate->last_commit_ptr + pcm->boundary;
+       else
+               xfer = appl_ptr - rate->last_commit_ptr;
+       while (xfer >= pcm->period_size &&
               (snd_pcm_uframes_t)slave_size >= rate->gen.slave->period_size) {
-               err = snd_pcm_rate_commit_next_period(pcm, appl_offset);
+               err = snd_pcm_rate_commit_next_period(pcm, rate->last_commit_ptr % pcm->buffer_size);
                if (err == 0)
-                       return xfer;
+                       break;
                if (err < 0)
-                       return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
-               xfer += pcm->period_size;
-               size -= pcm->period_size;
+                       return err;
+               xfer -= pcm->period_size;
                slave_size -= rate->gen.slave->period_size;
-               appl_offset += pcm->period_size;
-               appl_offset %= pcm->buffer_size;
-               snd_atomic_write_begin(&rate->watom);
-               snd_pcm_mmap_appl_forward(pcm, pcm->period_size);
-               snd_atomic_write_end(&rate->watom);
+               rate->last_commit_ptr += pcm->period_size;
+               if (rate->last_commit_ptr >= pcm->boundary)
+                       rate->last_commit_ptr = 0;
        }
-       size %= pcm->period_size;
-       if (size > 0) {
-               snd_atomic_write_begin(&rate->watom);
-               snd_pcm_mmap_appl_forward(pcm, size);
-               snd_atomic_write_end(&rate->watom);
-               xfer += size;
+       return 0;
+}
+
+static snd_pcm_sframes_t snd_pcm_rate_mmap_commit(snd_pcm_t *pcm,
+                                                 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
+                                                 snd_pcm_uframes_t size)
+{
+       snd_pcm_rate_t *rate = pcm->private_data;
+       int err;
+
+       if (size == 0)
+               return 0;
+       if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
+               err = snd_pcm_rate_sync_playback_area(pcm, rate->appl_ptr + size);
+               if (err < 0)
+                       return err;
        }
-       return xfer;
+       snd_atomic_write_begin(&rate->watom);
+       snd_pcm_mmap_appl_forward(pcm, size);
+       snd_atomic_write_end(&rate->watom);
+       return size;
 }
 
 static snd_pcm_sframes_t snd_pcm_rate_avail_update(snd_pcm_t *pcm)
@@ -1258,6 +1240,7 @@ static snd_pcm_sframes_t snd_pcm_rate_avail_update(snd_pcm_t *pcm)
        snd_atomic_write_begin(&rate->watom);
        snd_pcm_rate_sync_hwptr(pcm);
        snd_atomic_write_end(&rate->watom);
+       snd_pcm_rate_sync_playback_area(pcm, rate->appl_ptr);
        return snd_pcm_mmap_avail(pcm);
  _capture: {
        snd_pcm_uframes_t xfer, hw_offset, size;