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);
 
 }
 
