Index: audiovar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/audiovar.h,v
retrieving revision 1.68
diff -u -p -r1.68 audiovar.h
--- audiovar.h  15 Nov 2017 04:28:45 -0000      1.68
+++ audiovar.h  23 Jun 2018 01:39:02 -0000
@@ -279,10 +279,8 @@ struct audio_softc {
       bool            schedule_wih;
       bool            schedule_rih;

-       lwp_t           *sc_playthread;
-       kcondvar_t      sc_condvar;
-       lwp_t           *sc_recthread;
-       kcondvar_t      sc_rcondvar;
+       void            *sc_playmix_ih;
+       void            *sc_recmix_ih;

       /* These are changeable by sysctl to set the vchan common format */
       struct sysctllog        *sc_log;        /* sysctl log */
Index: audio.c
===================================================================
RCS file: /cvsroot/src/sys/dev/audio.c,v
retrieving revision 1.457
diff -u -p -r1.457 audio.c
--- audio.c     22 May 2018 01:35:49 -0000      1.457
+++ audio.c     23 Jun 2018 01:39:03 -0000
@@ -182,7 +182,6 @@ __KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.
#include <sys/audioio.h>
#include <sys/device.h>
#include <sys/intr.h>
-#include <sys/kthread.h>
#include <sys/cpu.h>
#include <sys/mman.h>

@@ -227,6 +226,12 @@ int        audio_idle_timeout = 30;
               mutex_exit(sc->sc_intr_lock); \
} while (0)

+#define AUDIO_SOFTINT(x) do { \
+       kpreempt_disable(); \
+       softint_schedule(x); \
+       kpreempt_enable(); \
+} while (0)
+
int    audio_blk_ms = AUDIO_BLK_MS;

int    audiosetinfo(struct audio_softc *, struct audio_info *, bool,
@@ -270,12 +275,12 @@ void      audio_rint(void *);
void   audio_pint(void *);
void   audio_mix(void *);
void   audio_upmix(void *);
-void   audio_play_thread(void *);
-void   audio_rec_thread(void *);
+void   audio_play_mix(void *);
+void   audio_rec_mix(void *);
void   recswvol_func(struct audio_softc *, struct audio_ringbuffer *,
                     size_t, struct virtual_channel *);
void   mix_func(struct audio_softc *, struct audio_ringbuffer *,
-                struct virtual_channel *);
+                struct virtual_channel *, uint8_t *, size_t, bool);
int    mix_write(void *);
int    mix_read(void *);
int    audio_check_params(struct audio_params *);
@@ -285,6 +290,7 @@ static void audio_setblksize(struct audi
                                struct virtual_channel *, int, int);
int    audio_calc_blksize(struct audio_softc *, const audio_params_t *);
void   audio_fill_silence(const struct audio_params *, uint8_t *, int);
+void   audio_wrap_silence(audio_stream_t *, int, int);
int    audio_silence_copyout(struct audio_softc *, int, struct uio *);

static int     audio_allocbufs(struct audio_softc *);
@@ -546,8 +552,6 @@ audioattach(device_t parent, device_t se
       cv_init(&sc->sc_rchan, "audiord");
       cv_init(&sc->sc_wchan, "audiowr");
       cv_init(&sc->sc_lchan, "audiolk");
-       cv_init(&sc->sc_condvar,"play");
-       cv_init(&sc->sc_rcondvar,"record");

       if (hwp == NULL || hwp->get_locks == NULL) {
               aprint_error(": missing method\n");
@@ -855,10 +859,10 @@ audioattach(device_t parent, device_t se
#ifdef AUDIO_PM_IDLE
       callout_schedule(&sc->sc_idle_counter, audio_idle_timeout * hz);
#endif
-       kthread_create(PRI_SOFTSERIAL, KTHREAD_MPSAFE | KTHREAD_MUSTJOIN, NULL,
-           audio_rec_thread, sc, &sc->sc_recthread, "audiorec");
-       kthread_create(PRI_SOFTSERIAL, KTHREAD_MPSAFE | KTHREAD_MUSTJOIN, NULL,
-           audio_play_thread, sc, &sc->sc_playthread, "audiomix");
+       sc->sc_recmix_ih = softint_establish(SOFTINT_SERIAL | SOFTINT_MPSAFE,
+           audio_rec_mix, sc);
+       sc->sc_playmix_ih = softint_establish(SOFTINT_SERIAL | SOFTINT_MPSAFE,
+           audio_play_mix, sc);
       audiorescan(self, "audio", NULL);
}

@@ -872,8 +876,6 @@ audioactivate(device_t self, enum devact
               mutex_enter(sc->sc_lock);
               sc->sc_dying = true;
               mutex_enter(sc->sc_intr_lock);
-               cv_broadcast(&sc->sc_condvar);
-               cv_broadcast(&sc->sc_rcondvar);
               cv_broadcast(&sc->sc_wchan);
               cv_broadcast(&sc->sc_rchan);
               cv_broadcast(&sc->sc_lchan);
@@ -902,16 +904,6 @@ audiodetach(device_t self, int flags)
       sc->sc_dying = true;
       cv_broadcast(&sc->sc_wchan);
       cv_broadcast(&sc->sc_rchan);
-       mutex_enter(sc->sc_intr_lock);
-       cv_broadcast(&sc->sc_condvar);
-       cv_broadcast(&sc->sc_rcondvar);
-       mutex_exit(sc->sc_intr_lock);
-       mutex_exit(sc->sc_lock);
-       kthread_join(sc->sc_playthread);
-       kthread_join(sc->sc_recthread);
-       mutex_enter(sc->sc_lock);
-       cv_destroy(&sc->sc_condvar);
-       cv_destroy(&sc->sc_rcondvar);
       mutex_exit(sc->sc_lock);

       /* delete sysctl nodes */
@@ -967,6 +959,14 @@ audiodetach(device_t self, int flags)

       auconv_delete_encodings(sc->sc_encodings);

+       if (sc->sc_recmix_ih) {
+               softint_disestablish(sc->sc_recmix_ih);
+               sc->sc_recmix_ih = NULL;
+       }
+       if (sc->sc_playmix_ih) {
+               softint_disestablish(sc->sc_playmix_ih);
+               sc->sc_playmix_ih = NULL;
+       }
       if (sc->sc_sih_rd) {
               softint_disestablish(sc->sc_sih_rd);
               sc->sc_sih_rd = NULL;
@@ -2450,36 +2450,29 @@ audio_drain(struct audio_softc *sc, stru
       if (used <= 0)
               return 0;

+       int blksize;
+       if (sc->sc_usemixer)
+               blksize = sc->sc_mixring.sc_mpr.blksize;
+       else
+               blksize = cb->blksize;
+
       if (hw == false && !vc->sc_pbus) {
               /* We've never started playing, probably because the
                * block was too short.  Pad it and start now.
                */
               uint8_t *inp = cb->s.inp;
-               int blksize = sc->sc_mixring.sc_mpr.blksize;

               cc = blksize - (inp - cb->s.start) % blksize;
-               audio_fill_silence(&cb->s.param, inp, cc);
-               cb->s.inp = audio_stream_add_inp(&cb->s, inp, cc);
+               audio_wrap_silence(&cb->s, blksize, cc);
               mutex_exit(sc->sc_intr_lock);
               error = audiostartp(sc, vc);
               mutex_enter(sc->sc_intr_lock);
               if (error)
                       return error;
       } else if (hw == true) {
-               used = cb->blksize - (sc->sc_mixring.sc_mpr.s.inp -
-                   sc->sc_mixring.sc_mpr.s.start) % cb->blksize;
-               while (used > 0) {
-                       cc = sc->sc_mixring.sc_mpr.s.end -
-                           sc->sc_mixring.sc_mpr.s.inp;
-                       if (cc > used)
-                               cc = used;
-                       audio_fill_silence(&cb->s.param,
-                           sc->sc_mixring.sc_mpr.s.inp, cc);
-                       sc->sc_mixring.sc_mpr.s.inp =
-                           audio_stream_add_inp(&sc->sc_mixring.sc_mpr.s,
-                               sc->sc_mixring.sc_mpr.s.inp, cc);
-                       used -= cc;
-               }
+               cc = blksize - (sc->sc_mixring.sc_mpr.s.inp -
+                   sc->sc_mixring.sc_mpr.s.start) % blksize;
+               audio_wrap_silence(&sc->sc_mixring.sc_mpr.s, blksize, cc);
               mix_write(sc);
       }
       /*
@@ -2497,13 +2490,8 @@ audio_drain(struct audio_softc *sc, stru
       vc->sc_draining = true;

       drops = cb->drops;
-       if (vc == sc->sc_hwvc)
-               drops += cb->blksize;
-       else if (sc->sc_usemixer)
-               drops += sc->sc_mixring.sc_mpr.blksize * PREFILL_BLOCKS;
-
       error = 0;
-       while (cb->drops <= drops && !error) {
+       while (cb->drops == drops && !error) {
               DPRINTF(("audio_drain: vc=%p used=%d, drops=%ld\n",
                       vc,
                       audio_stream_get_used(&vc->sc_mpr.s),
@@ -2798,6 +2786,22 @@ audio_calc_blksize(struct audio_softc *s
}

void
+audio_wrap_silence(audio_stream_t *stream, int blksize, int n)
+{
+       int cc, total;
+
+       total = n;
+       while (total > 0) {
+               cc = stream->end - stream->inp;
+               if (cc > total)
+                       cc = total;
+               audio_fill_silence(&stream->param, stream->inp, cc);
+               stream->inp = audio_stream_add_inp(stream, stream->inp, cc);
+               total -= cc;
+       }
+};
+
+void
audio_fill_silence(const struct audio_params *params, uint8_t *p, int n)
{
       uint8_t auzero0, auzero1;
@@ -3607,7 +3611,7 @@ audiostartr(struct audio_softc *sc, stru
               mutex_enter(sc->sc_intr_lock);
               error = mix_read(sc);
               if (sc->sc_usemixer)
-                       cv_broadcast(&sc->sc_rcondvar);
+                       AUDIO_SOFTINT(sc->sc_recmix_ih);
               mutex_exit(sc->sc_intr_lock);
       }
       vc->sc_rbus = true;
@@ -3662,7 +3666,6 @@ audiostartp(struct audio_softc *sc, stru
                           audio_stream_add_outp(&vc->sc_mpr.s,
                             vc->sc_mpr.s.outp, vc->sc_mpr.blksize);
                       error = mix_write(sc);
-                       cv_broadcast(&sc->sc_condvar);
               }
done:
               mutex_exit(sc->sc_intr_lock);
@@ -3723,20 +3726,25 @@ audio_pint(void *v)
       struct audio_softc *sc;
       struct audio_ringbuffer *cb;
       struct virtual_channel *vc;
-       int blksize, cc, used;
+       audio_stream_t *stream;
+       int blksize, cc, silblksize, used;

       sc = v;
       vc = sc->sc_hwvc;
       blksize = vc->sc_mpr.blksize;
+       if (sc->sc_usemixer) {
+               stream = &sc->sc_mixring.sc_mpr.s;
+               silblksize = sc->sc_mixring.sc_mpr.blksize;
+               cb = &sc->sc_mixring.sc_mpr;
+        } else {
+               stream = vc->sc_pustream;
+               silblksize = blksize;
+               cb = &vc->sc_mpr;
+       }

       if (sc->sc_dying == true || sc->sc_trigger_started == false)
               return;

-       if (sc->sc_usemixer)
-               cb = &sc->sc_mixring.sc_mpr;
-       else
-               cb = &vc->sc_mpr;
-
       if (vc->sc_draining && cb->drops != sc->sc_last_drops) {
               vc->sc_mpr.drops += blksize;
               cv_broadcast(&sc->sc_wchan);
@@ -3747,27 +3755,22 @@ audio_pint(void *v)
       vc->sc_mpr.s.outp = audio_stream_add_outp(&vc->sc_mpr.s,
           vc->sc_mpr.s.outp, blksize);

-       if (audio_stream_get_used(&cb->s) < blksize) {
+       used = audio_stream_get_used(stream);
+
+       if (used < silblksize) {
               DPRINTFN(3, ("HW RING - INSERT SILENCE\n"));
-               used = blksize;
-               while (used > 0) {
-                       cc = cb->s.end - cb->s.inp;
-                       if (cc > used)
-                               cc = used;
-                       audio_fill_silence(&cb->s.param, cb->s.inp, cc);
-                       cb->s.inp =
-                           audio_stream_add_inp(&cb->s, cb->s.inp, cc);
-                       used -= cc;
-               }
-               vc->sc_mpr.drops += blksize;
+               cc = silblksize - used;
+               audio_wrap_silence(stream, silblksize, cc);
+               cb->drops += silblksize;
       }

       mix_write(sc);

-       if (sc->sc_usemixer)
-               cv_broadcast(&sc->sc_condvar);
-       else
+       if (!sc->sc_usemixer)
               cv_broadcast(&sc->sc_wchan);
+       else if (!vc->sc_draining)
+               AUDIO_SOFTINT(sc->sc_playmix_ih);
+
}

void
@@ -3778,9 +3781,13 @@ audio_mix(void *v)
       struct audio_chan *chan;
       struct virtual_channel *vc;
       struct audio_ringbuffer *cb;
+       audio_stream_t *hwstream;
       stream_fetcher_t *fetcher;
       uint8_t *inp;
-       int cc, cc1, used, blksize;
+       int cc, used, blksize;
+       size_t total;
+       unsigned int chancount;
+       bool first;

       sc = v;

@@ -3792,7 +3799,13 @@ audio_mix(void *v)
       if (sc->sc_dying == true)
               return;

+       chancount = 0;
       blksize = sc->sc_mixring.sc_mpr.blksize;
+       hwstream = &sc->sc_mixring.sc_mpr.s;
+
+       if (audio_stream_get_used(hwstream) > sc->sc_hwvc->sc_mpr.usedlow)
+               return;
+
       SIMPLEQ_FOREACH(chan, &sc->sc_audiochan, entries) {
               vc = chan->vc;

@@ -3804,15 +3817,27 @@ audio_mix(void *v)
               cb = &vc->sc_mpr;

               sc->sc_writeme = true;
+               chancount++;
+               if (chancount == 1)
+                       first = true;
+               else
+                       first = false;

               inp = cb->s.inp;
               cb->stamp += blksize;
+               total = blksize;
+
               if (cb->mmapped) {
                       DPRINTF(("audio_pint: vc=%p mmapped outp=%p cc=%d "
                                "inp=%p\n", vc, cb->s.outp, blksize,
                                 cb->s.inp));
                       mutex_enter(sc->sc_intr_lock);
-                       mix_func(sc, cb, vc);
+                       if (first)
+                               mix_func(sc, cb, vc, hwstream->inp, total,
+                                   first);
+                       else
+                               mix_func(sc, cb, vc, __UNCONST(hwstream->outp),
+                                   total, first);
                       cb->s.outp = audio_stream_add_outp(&cb->s, cb->s.outp,
                           blksize);
                       mutex_exit(sc->sc_intr_lock);
@@ -3861,7 +3886,7 @@ audio_mix(void *v)
                * at accurate timing.  If used < blksize, uaudio(4) already
                * request transfer of garbage data.
                */
-               if (used <= sc->sc_hwvc->sc_mpr.usedlow && !cb->copying &&
+               if (used <= cb->usedlow && !cb->copying &&
                   vc->sc_npfilters > 0) {
                       /* we might have data in filter pipeline */
                       null_fetcher.fetch_to = null_fetcher_fetch_to;
@@ -3876,6 +3901,7 @@ audio_mix(void *v)
                       cb->fstamp += used -
                           audio_stream_get_used(vc->sc_pustream);
                       used = audio_stream_get_used(&cb->s);
+                       sc->schedule_wih = true;
               }
               if (used < blksize) {
                       /* we don't have a full block to use */
@@ -3889,31 +3915,37 @@ audio_mix(void *v)
                                         "used=%d blksize=%d\n", vc, used,
                                         blksize));
                               inp = cb->s.inp;
-                               cc = blksize - (inp - cb->s.start) % blksize;
+                               cc = blksize - used;
                               if (cb->pause)
                                       cb->pdrops += cc;
                               else {
                                       cb->drops += cc;
                                       vc->sc_playdrop += cc;
                               }
-
-                               audio_fill_silence(&cb->s.param, inp, cc);
-                               cb->s.inp = audio_stream_add_inp(&cb->s, inp,
-                                   cc);
-
-                               /* Clear next block to keep ahead of the DMA. */
-                               used = audio_stream_get_used(&cb->s);
-                               if (used + blksize < cb->s.end - cb->s.start) {
-                                       audio_fill_silence(&cb->s.param, cb->s.inp,
-                                           blksize);
+                               if (first)
+                                       audio_wrap_silence(&cb->s, blksize, cc);
+                               else {
+                                       total = blksize - cc;
+                                       cb->s.inp = audio_stream_add_inp(&cb->s,
+                                           inp, cc);
                               }
                       }
               }

               DPRINTFN(5, ("audio_pint: vc=%p outp=%p used=%d cc=%d\n", vc,
                        cb->s.outp, used, blksize));
+
+               /*
+                * Mix at the tail of the ringbuffer if it's the first vc
+                * otherwize mix at the current playback position in the
+                * mix ring.  This imroves latency for virtual channels
+                * greater than 1.
+                */
               mutex_enter(sc->sc_intr_lock);
-               mix_func(sc, cb, vc);
+               if (first)
+                       mix_func(sc, cb, vc, hwstream->inp, total, first);
+               else
+                       mix_func(sc, cb, vc, __UNCONST(hwstream->outp), total, first);
               mutex_exit(sc->sc_intr_lock);
               cb->s.outp = audio_stream_add_outp(&cb->s, cb->s.outp, blksize);

@@ -3932,27 +3964,16 @@ audio_mix(void *v)
       mutex_enter(sc->sc_intr_lock);

       vc = sc->sc_hwvc;
-       cb = &sc->sc_mixring.sc_mpr;
-       inp = cb->s.inp;
-       cc = blksize - (inp - cb->s.start) % blksize;
+       inp = hwstream->inp;
       if (sc->sc_writeme == false) {
+               cc = blksize - audio_stream_get_used(hwstream);
               DPRINTFN(3, ("MIX RING EMPTY - INSERT SILENCE\n"));
-               audio_fill_silence(&vc->sc_pustream->param, inp, cc);
-               sc->sc_mixring.sc_mpr.drops += cc;
-       } else
+               audio_wrap_silence(hwstream, blksize, cc);
+               vc->sc_mpr.drops += cc;
+       } else {
               cc = blksize;
-       cb->s.inp = audio_stream_add_inp(&cb->s, cb->s.inp, cc);
-       cc = blksize;
-       cc1 = sc->sc_mixring.sc_mpr.s.end - sc->sc_mixring.sc_mpr.s.inp;
-       if (cc1 < cc) {
-               audio_fill_silence(&vc->sc_pustream->param,
-                   sc->sc_mixring.sc_mpr.s.inp, cc1);
-               cc -= cc1;
-               audio_fill_silence(&vc->sc_pustream->param,
-                   sc->sc_mixring.sc_mpr.s.start, cc);
-       } else
-               audio_fill_silence(&vc->sc_pustream->param,
-                   sc->sc_mixring.sc_mpr.s.inp, cc);
+               hwstream->inp = audio_stream_add_inp(hwstream, inp, cc);
+       }
       mutex_exit(sc->sc_intr_lock);

       kpreempt_disable();
@@ -3989,7 +4010,7 @@ audio_rint(void *v)
       mix_read(sc);

       if (sc->sc_usemixer)
-               cv_broadcast(&sc->sc_rcondvar);
+               AUDIO_SOFTINT(sc->sc_recmix_ih);
       else
               cv_broadcast(&sc->sc_rchan);
}
@@ -4114,9 +4135,7 @@ audio_upmix(void *v)
                           blksize);
               }
       }
-       kpreempt_disable();
-       softint_schedule(sc->sc_sih_rd);
-       kpreempt_enable();
+       AUDIO_SOFTINT(sc->sc_sih_rd);
}

int
@@ -4243,6 +4262,8 @@ audio_set_vchan_defaults(struct audio_so

               vc->sc_rparams = sc->sc_vchan_params;
               vc->sc_pparams = sc->sc_vchan_params;
+               vc->sc_pustream = &vc->sc_mpr.s;
+               vc->sc_rustream = &vc->sc_mrr.s;
       }

       return error;
@@ -5586,19 +5607,24 @@ mix_write(void *arg)
       stream_filter_t *filter;
       stream_fetcher_t *fetcher;
       stream_fetcher_t null_fetcher;
-       int cc, cc1, cc2, error, used;
+       int blksize, cc, cc1, cc2, error, used;
       const uint8_t *orig;
       uint8_t *tocopy;

       vc = sc->sc_hwvc;
       error = 0;

+       if (sc->sc_usemixer)
+               blksize = sc->sc_mixring.sc_mpr.blksize;
+       else
+               blksize = vc->sc_mpr.blksize;
+
       if (sc->sc_usemixer &&
-           audio_stream_get_used(vc->sc_pustream) <=
-                               sc->sc_mixring.sc_mpr.blksize) {
+           audio_stream_get_used(vc->sc_pustream) <
+                               vc->sc_mpr.usedlow) {
               tocopy = vc->sc_pustream->inp;
               orig = sc->sc_mixring.sc_mpr.s.outp;
-               used = sc->sc_mixring.sc_mpr.blksize;
+               used = blksize;

               while (used > 0) {
                       cc = used;
@@ -5621,35 +5647,34 @@ mix_write(void *arg)
               }

               vc->sc_pustream->inp = audio_stream_add_inp(vc->sc_pustream,
-                   vc->sc_pustream->inp, sc->sc_mixring.sc_mpr.blksize);
+                   vc->sc_pustream->inp, blksize);

               sc->sc_mixring.sc_mpr.s.outp =
                   audio_stream_add_outp(&sc->sc_mixring.sc_mpr.s,
-                       sc->sc_mixring.sc_mpr.s.outp,
-                       sc->sc_mixring.sc_mpr.blksize);
+                       sc->sc_mixring.sc_mpr.s.outp, blksize);
       }

+       blksize = vc->sc_mpr.blksize;
       if (vc->sc_npfilters > 0 &&
           (sc->sc_usemixer || sc->sc_trigger_started)) {
               null_fetcher.fetch_to = null_fetcher_fetch_to;
               filter = vc->sc_pfilters[0];
               filter->set_fetcher(filter, &null_fetcher);
               fetcher = &vc->sc_pfilters[vc->sc_npfilters - 1]->base;
-               fetcher->fetch_to(sc, fetcher, &vc->sc_mpr.s,
-                   vc->sc_mpr.blksize * 2);
+               fetcher->fetch_to(sc, fetcher, &vc->sc_mpr.s, blksize * 2);
       }

       if (sc->hw_if->trigger_output && sc->sc_trigger_started == false) {
               DPRINTF(("%s: call trigger_output\n", __func__));
               sc->sc_trigger_started = true;
               error = sc->hw_if->trigger_output(sc->hw_hdl,
-                   vc->sc_mpr.s.start, vc->sc_mpr.s.end, vc->sc_mpr.blksize,
+                   vc->sc_mpr.s.start, vc->sc_mpr.s.end, blksize,
                   audio_pint, (void *)sc, &vc->sc_mpr.s.param);
       } else if (sc->hw_if->start_output) {
               DPRINTF(("%s: call start_output\n", __func__));
               sc->sc_trigger_started = true;
               error = sc->hw_if->start_output(sc->hw_hdl,
-                   __UNCONST(vc->sc_mpr.s.outp), vc->sc_mpr.blksize,
+                   __UNCONST(vc->sc_mpr.s.outp), blksize,
                   audio_pint, (void *)sc);
       }

@@ -5666,18 +5691,18 @@ mix_write(void *arg)
#define DEF_MIX_FUNC(bits, type, bigger_type, MINVAL, MAXVAL)          \
       static void                                                     \
       mix_func##bits(struct audio_softc *sc, struct audio_ringbuffer *cb, \
-                 struct virtual_channel *vc)                           \
+                 struct virtual_channel *vc, uint8_t *target,          \
+                 size_t bytes, bool first)                              \
       {                                                               \
-               int blksize, cc, cc1, cc2, m, resid;                    \
+               int cc, cc1, cc2, m, resid;                             \
               bigger_type product;                                    \
               bigger_type result;                                     \
               type *orig, *tomix;                                     \
                                                                       \
-               blksize = sc->sc_mixring.sc_mpr.blksize;                \
-               resid = blksize;                                        \
+               resid = bytes;                                          \
                                                                       \
               tomix = __UNCONST(cb->s.outp);                          \
-               orig = (type *)(sc->sc_mixring.sc_mpr.s.inp);           \
+               orig = (type *)(target);                                \
                                                                       \
               while (resid > 0) {                                     \
                       cc = resid;                                     \
@@ -5695,22 +5720,23 @@ mix_write(void *arg)
                               tomix[m] = (bigger_type)tomix[m] *      \
                                   (bigger_type)(vc->sc_swvol) / 255;  \
vol_done:                                                              \
+                               if (first) {                            \
+                                       orig[m] = tomix[m];             \
+                                       continue;                       \
+                               }                                       \
                               result = (bigger_type)orig[m] + tomix[m]; \
-                               if (sc->sc_opens == 1)                  \
-                                       goto adj_done;                  \
                               product = (bigger_type)orig[m] * tomix[m]; \
                               if (orig[m] > 0 && tomix[m] > 0)        \
                                       result -= product / MAXVAL;     \
                               else if (orig[m] < 0 && tomix[m] < 0)   \
                                       result -= product / MINVAL;     \
-adj_done:                                                              \
                               orig[m] = result;                       \
                       }                                               \
                                                                       \
                       if (&orig[m] >=                                 \
                           (type *)sc->sc_mixring.sc_mpr.s.end)        \
                               orig =                                  \
-                                (type *)sc->sc_mixring.sc_mpr.s.start; \
+                                (type *)sc->sc_mixring.sc_mpr.s.start; \
                       if (&tomix[m] >= (type *)cb->s.end)             \
                               tomix = (type *)cb->s.start;            \
                                                                       \
@@ -5724,18 +5750,18 @@ DEF_MIX_FUNC(32, int32_t, int64_t, INT32

void
mix_func(struct audio_softc *sc, struct audio_ringbuffer *cb,
-        struct virtual_channel *vc)
+        struct virtual_channel *vc, uint8_t *target, size_t used, bool first)
{
       switch (sc->sc_vchan_params.precision) {
       case 8:
-               mix_func8(sc, cb, vc);
+               mix_func8(sc, cb, vc, target, used, first);
               break;
       case 16:
-               mix_func16(sc, cb, vc);
+               mix_func16(sc, cb, vc, target, used, first);
               break;
       case 24:
       case 32:
-               mix_func32(sc, cb, vc);
+               mix_func32(sc, cb, vc, target, used, first);
               break;
       default:
               break;
@@ -5967,59 +5993,43 @@ audio_query_encoding(struct audio_softc
}

void
-audio_play_thread(void *v)
+audio_play_mix(void *v)
{
       struct audio_softc *sc;

       sc = (struct audio_softc *)v;

-       for (;;) {
-               mutex_enter(sc->sc_lock);
-               if (sc->sc_dying) {
-                       mutex_exit(sc->sc_lock);
-                       kthread_exit(0);
-               }
-               if (!sc->sc_trigger_started)
-                       goto play_wait;
-
-               while (!sc->sc_dying && sc->sc_usemixer &&
-                   audio_stream_get_used(&sc->sc_mixring.sc_mpr.s) <
-                                               sc->sc_mixring.sc_mpr.blksize)
-                       audio_mix(sc);
-
-play_wait:
+       mutex_enter(sc->sc_lock);
+       if (sc->sc_dying) {
               mutex_exit(sc->sc_lock);
-
-               mutex_enter(sc->sc_intr_lock);
-               cv_wait_sig(&sc->sc_condvar, sc->sc_intr_lock);
-               mutex_exit(sc->sc_intr_lock);
+               return;
+       }
+
+       int i;
+       for (i = 0; i < PREFILL_BLOCKS; i++) {
+               int used = audio_stream_get_used(&sc->sc_mixring.sc_mpr.s);
+               if (!sc->sc_dying && !sc->sc_hwvc->sc_draining &&
+                   sc->sc_usemixer && used < sc->sc_mixring.sc_mpr.blksize *
+                   PREFILL_BLOCKS)
+                       audio_mix(sc);
       }
+       mutex_exit(sc->sc_lock);
}

void
-audio_rec_thread(void *v)
+audio_rec_mix(void *v)
{
       struct audio_softc *sc;

       sc = (struct audio_softc *)v;

-       for (;;) {
-               mutex_enter(sc->sc_lock);
-               if (sc->sc_dying) {
-                       mutex_exit(sc->sc_lock);
-                       kthread_exit(0);
-               }
-               if (!sc->sc_rec_started)
-                       goto rec_wait;
-
-               audio_upmix(sc);
-rec_wait:
+       mutex_enter(sc->sc_lock);
+       if (sc->sc_dying) {
               mutex_exit(sc->sc_lock);
-
-               mutex_enter(sc->sc_intr_lock);
-               cv_wait_sig(&sc->sc_rcondvar, sc->sc_intr_lock);
-               mutex_exit(sc->sc_intr_lock);
+               return;
       }
+       audio_upmix(sc);
+       mutex_exit(sc->sc_lock);

}