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 24 Jun 2018 03:16:31 -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 24 Jun 2018 03:16:32 -0000 @@ -182,7 +182,6 @@ __KERNEL_RCSID(0, "$NetBSD: audio.c,v 1. #include #include #include -#include #include #include @@ -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; @@ -2072,7 +2072,8 @@ audio_initbufs(struct audio_softc *sc, s DPRINTF(("audio_initbufs: mode=0x%x\n", vc->sc_mode)); hw = sc->hw_if; if (audio_can_capture(sc) && - ((vc->sc_open & AUOPEN_READ) || vc == sc->sc_hwvc)) { + ((vc->sc_open & AUOPEN_READ) || (vc == sc->sc_hwvc && + sc->sc_recopens == 0))) { audio_init_ringbuffer(sc, &vc->sc_mrr, AUMODE_RECORD); if (sc->sc_recopens == 0 && (vc->sc_open & AUOPEN_READ)) { @@ -2087,7 +2088,8 @@ audio_initbufs(struct audio_softc *sc, s } if (audio_can_playback(sc) && - ((vc->sc_open & AUOPEN_WRITE) || vc == sc->sc_hwvc)) { + ((vc->sc_open & AUOPEN_WRITE) || (vc == sc->sc_hwvc && + sc->sc_opens == 0))) { audio_init_ringbuffer(sc, &vc->sc_mpr, AUMODE_PLAY); if (sc->sc_opens == 0 && (vc->sc_open & AUOPEN_WRITE)) { @@ -2272,7 +2274,6 @@ audio_open(dev_t dev, struct audio_softc goto bad; } } - audio_initbufs(sc, NULL); if (sc->sc_usemixer && audio_can_playback(sc)) audio_init_ringbuffer(sc, &sc->sc_mixring.sc_mpr, AUMODE_PLAY); @@ -2295,6 +2296,7 @@ audio_open(dev_t dev, struct audio_softc goto bad; } } + audio_initbufs(sc, NULL); mutex_enter(sc->sc_intr_lock); vc->sc_full_duplex = @@ -2450,36 +2452,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; - } + } else if (hw == true && !sc->sc_trigger_started) { + 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 +2492,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 +2788,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; @@ -3603,13 +3609,13 @@ audiostartr(struct audio_softc *sc, stru return 0; error = 0; + mutex_enter(sc->sc_intr_lock); if (sc->sc_rec_started == false) { - mutex_enter(sc->sc_intr_lock); error = mix_read(sc); if (sc->sc_usemixer) - cv_broadcast(&sc->sc_rcondvar); - mutex_exit(sc->sc_intr_lock); + AUDIO_SOFTINT(sc->sc_recmix_ih); } + mutex_exit(sc->sc_intr_lock); vc->sc_rbus = true; return error; @@ -3646,27 +3652,23 @@ audiostartp(struct audio_softc *sc, stru } vc->sc_pbus = true; + mutex_enter(sc->sc_intr_lock); if (sc->sc_trigger_started == false) { if (sc->sc_usemixer) { audio_mix(sc); audio_mix(sc); audio_mix(sc); } - mutex_enter(sc->sc_intr_lock); error = mix_write(sc); - if (error) - goto done; - if (sc->sc_usemixer) { + if (!error && sc->sc_usemixer) { vc = sc->sc_hwvc; vc->sc_mpr.s.outp = 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); } + mutex_exit(sc->sc_intr_lock); return error; } @@ -3723,20 +3725,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 +3754,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 +3780,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 +3798,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,18 +3816,28 @@ 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); continue; } @@ -3861,7 +3883,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 +3898,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,32 +3912,36 @@ 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)); - mutex_enter(sc->sc_intr_lock); - mix_func(sc, cb, vc); - mutex_exit(sc->sc_intr_lock); + + /* + * 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. + */ + 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); DPRINTFN(2, ("audio_pint: vc=%p mode=%d pause=%d used=%d " @@ -3929,31 +3956,18 @@ audio_mix(void *v) if (!vc->sc_full_duplex && vc->sc_mode & AUMODE_RECORD) sc->schedule_rih = true; } - 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); - mutex_exit(sc->sc_intr_lock); + hwstream->inp = audio_stream_add_inp(hwstream, inp, cc); + } kpreempt_disable(); if (sc->schedule_wih == true) @@ -3989,7 +4003,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); } @@ -4029,7 +4043,6 @@ audio_upmix(void *v) cc = blksize; if (cb->s.inp + blksize > cb->s.end) cc = cb->s.end - cb->s.inp; - mutex_enter(sc->sc_intr_lock); memcpy(cb->s.inp, sc->sc_mixring.sc_mrr.s.start, cc); if (cc < blksize && cc != 0) { cc1 = cc; @@ -4037,7 +4050,6 @@ audio_upmix(void *v) memcpy(cb->s.start, sc->sc_mixring.sc_mrr.s.start + cc1, cc); } - mutex_exit(sc->sc_intr_lock); cc = blksize; recswvol_func(sc, cb, blksize, vc); @@ -4114,9 +4126,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 +4253,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; @@ -5390,8 +5402,10 @@ audio_resume(device_t dv, const pmf_qual struct virtual_channel *vc; mutex_enter(sc->sc_lock); + mutex_enter(sc->sc_intr_lock); sc->sc_trigger_started = false; sc->sc_rec_started = false; + mutex_exit(sc->sc_intr_lock); audio_set_vchan_defaults(sc, AUMODE_PLAY | AUMODE_PLAY_ALL | AUMODE_RECORD); @@ -5586,19 +5600,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,12 +5640,11 @@ 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); } if (vc->sc_npfilters > 0 && @@ -5635,21 +5653,21 @@ mix_write(void *arg) 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); } + blksize = vc->sc_mpr.blksize; 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 +5684,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 +5713,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 +5743,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 +5986,47 @@ 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; + } + + mutex_enter(sc->sc_intr_lock); + 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_intr_lock); + 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; } + mutex_enter(sc->sc_intr_lock); + audio_upmix(sc); + mutex_exit(sc->sc_intr_lock); + mutex_exit(sc->sc_lock); }