tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Call for testers - Audio improvements for NetBSD 8.1



Hi,

I have made changes to audio that improve it's performance and I'd like these 
changes to be in 8.1.

Please test and report back with any problems.  Please cc me as I am not 
subscribed to the list.

The patch is also available at:

ftp://ftp.netbsd.org/pub/NetBSD/misc/nat/audio-intr-final-v3.diff

Summary of changes / improvements:

It removes the complication of kthreads and conditional variables by turning 
the play/rec threads into softints.

It also does not copy stream silence as there is already silence in the 
mixring - speed up should benefit older computers.

It steadily caches three blocks of audio keeping the latency within spec as 
repoted via the sysctl latency variable.

With this I was able to have stutter free playback on the x68k emulator even 
at 12 mhz (at 12mhz the mixing format had to be 8bit 1 ch 8000hz as to 
reduce the amount of data handled).

It treats the second, third, to n number of streams differently mixing them 
into the mix rings output pointer signifinicantly reducing latency now that 
more data is cached.  It should perform as good as mmapped audio.

This patch should work better for slower computers slightly better 
performance, less stutter (even when switching from X11 to a text vt) due to 
better buffer utiliziation and near perfect negligable latency even though more 
data is buffered.

Please test as I intend to commit this change in two weeks and it should make 
NetBSD 8.1.

Best regards,

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


Home | Main Index | Thread Index | Old Index