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