From 34e3e97f5b33f6ce58a682336a8c705db5c5514b Mon Sep 17 00:00:00 2001 From: Simon Schubert Date: Thu, 14 Jun 2007 21:48:36 +0000 Subject: [PATCH] Allow vchans to have their own volume control. This means you can use two processes producing audio and change their volume independently (if they implement mixer controls themselves). --- sys/dev/sound/pcm/channel.c | 8 +++-- sys/dev/sound/pcm/dsp.c | 55 +++++++++++++++++++++------------ sys/dev/sound/pcm/dsp.h | 4 ++- sys/dev/sound/pcm/mixer.c | 61 +++++++++++++++++++++++++++++++++++-- sys/dev/sound/pcm/sound.c | 20 ++++++++++-- sys/dev/sound/pcm/sound.h | 3 +- sys/dev/sound/pcm/vchan.c | 23 +++++++++++--- 7 files changed, 141 insertions(+), 33 deletions(-) diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c index 56d7d363d6..f75bc03027 100644 --- a/sys/dev/sound/pcm/channel.c +++ b/sys/dev/sound/pcm/channel.c @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/dev/sound/pcm/channel.c,v 1.99.2.4 2006/04/04 17:37:51 ariff Exp $ - * $DragonFly: src/sys/dev/sound/pcm/channel.c,v 1.11 2007/01/04 21:47:03 corecode Exp $ + * $DragonFly: src/sys/dev/sound/pcm/channel.c,v 1.12 2007/06/14 21:48:36 corecode Exp $ */ #include "use_isa.h" @@ -35,7 +35,7 @@ #include "feeder_if.h" -SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/channel.c,v 1.11 2007/01/04 21:47:03 corecode Exp $"); +SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/channel.c,v 1.12 2007/06/14 21:48:36 corecode Exp $"); #define MIN_CHUNK_SIZE 256 /* for uiomove etc. */ #if 0 @@ -861,6 +861,10 @@ chn_init(struct pcm_channel *c, void *devinfo, int dir, int direction) if (ret) goto out; + ret = chn_setvolume(c, 100, 100); + if (ret) + goto out; + out: CHN_UNLOCK(c); diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c index 66c61eaa1e..df1ce48a37 100644 --- a/sys/dev/sound/pcm/dsp.c +++ b/sys/dev/sound/pcm/dsp.c @@ -24,15 +24,16 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/dev/sound/pcm/dsp.c,v 1.80.2.6 2006/04/04 17:43:48 ariff Exp $ - * $DragonFly: src/sys/dev/sound/pcm/dsp.c,v 1.14 2007/01/04 21:47:03 corecode Exp $ + * $DragonFly: src/sys/dev/sound/pcm/dsp.c,v 1.15 2007/06/14 21:48:36 corecode Exp $ */ #include #include +#include #include -SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/dsp.c,v 1.14 2007/01/04 21:47:03 corecode Exp $"); +SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/dsp.c,v 1.15 2007/06/14 21:48:36 corecode Exp $"); #define OLDPCM_IOCTL @@ -60,7 +61,7 @@ struct dev_ops dsp_cdevsw = { static eventhandler_tag dsp_ehtag; #endif -static struct snddev_info * +struct snddev_info * dsp_get_info(struct cdev *dev) { struct snddev_info *d; @@ -423,24 +424,7 @@ dsp_ioctl(struct dev_ioctl_args *ap) int kill; int ret = 0, *arg_i = (int *)arg, tmp; - /* - * this is an evil hack to allow broken apps to perform mixer ioctls - * on dsp devices. - */ - d = dsp_get_info(i_dev); - if (IOCGROUP(cmd) == 'M') { - /* - * This is at least, a bug to bug compatible with OSS. - */ - if (d->mixer_dev != NULL) { - ap->a_head.a_dev = d->mixer_dev; - return mixer_ioctl(ap); - } else { - return EBADF; - } - } - getchns(i_dev, &rdch, &wrch, 0); kill = 0; @@ -456,6 +440,37 @@ dsp_ioctl(struct dev_ioctl_args *ap) wrch = NULL; if (kill & 2) rdch = NULL; + + /* + * 4Front OSS specifies that dsp devices allow mixer controls to + * control PCM == their volume. + */ + if (IOCGROUP(cmd) == 'M') { + /* + * For now only set the channel volume for vchans, pass + * all others to the mixer. + */ + if (wrch != NULL && wrch->flags & CHN_F_VIRTUAL && + (cmd & 0xff) == SOUND_MIXER_PCM) { + if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) { + int vol_raw = *(int *)arg; + int vol_left, vol_right; + + vol_left = min(vol_raw & 0x00ff, 100); + vol_right = min((vol_raw & 0xff00) >> 8, 100); + ret = chn_setvolume(wrch, vol_left, vol_right); + } else { + *(int *)arg = wrch->volume; + } + } else { + ap->a_head.a_dev = d->mixer_dev; + ret = mixer_ioctl(ap); + } + + relchns(i_dev, rdch, wrch, 0); + crit_exit(); + return ret; + } switch(cmd) { #ifdef OLDPCM_IOCTL diff --git a/sys/dev/sound/pcm/dsp.h b/sys/dev/sound/pcm/dsp.h index a068a34650..600217adf8 100644 --- a/sys/dev/sound/pcm/dsp.h +++ b/sys/dev/sound/pcm/dsp.h @@ -24,7 +24,9 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/dev/sound/pcm/dsp.h,v 1.9 2005/01/06 01:43:20 imp Exp $ - * $DragonFly: src/sys/dev/sound/pcm/dsp.h,v 1.3 2007/01/04 21:47:03 corecode Exp $ + * $DragonFly: src/sys/dev/sound/pcm/dsp.h,v 1.4 2007/06/14 21:48:36 corecode Exp $ */ extern struct dev_ops dsp_cdevsw; + +struct snddev_info *dsp_get_info(struct cdev *dev); diff --git a/sys/dev/sound/pcm/mixer.c b/sys/dev/sound/pcm/mixer.c index dfe5668575..6b75c5d60b 100644 --- a/sys/dev/sound/pcm/mixer.c +++ b/sys/dev/sound/pcm/mixer.c @@ -24,14 +24,15 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/dev/sound/pcm/mixer.c,v 1.43.2.4 2006/04/04 17:43:48 ariff Exp $ - * $DragonFly: src/sys/dev/sound/pcm/mixer.c,v 1.14 2007/01/04 21:47:03 corecode Exp $ + * $DragonFly: src/sys/dev/sound/pcm/mixer.c,v 1.15 2007/06/14 21:48:36 corecode Exp $ */ #include +#include #include "mixer_if.h" -SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/mixer.c,v 1.14 2007/01/04 21:47:03 corecode Exp $"); +SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/mixer.c,v 1.15 2007/06/14 21:48:36 corecode Exp $"); MALLOC_DEFINE(M_MIXER, "mixer", "mixer"); @@ -436,6 +437,48 @@ mixer_hwvol_step(device_t dev, int left_step, int right_step) /* ----------------------------------------------------------------------- */ +static int +vchanvolume(cdev_t i_dev, int write, int *volume, int *ret, + struct thread *td) +{ + struct snddev_info *d; + void *cookie; + struct pcm_channel *ch; + int vol_left, vol_right; + + crit_enter(); + d = dsp_get_info(i_dev); + if (d == NULL) { + crit_exit(); + return 0; + } + /* + * We search for a vchan which is owned by the current process. + */ + for (cookie = NULL; (ch = pcm_chn_iterate(d, &cookie)) != NULL;) + if (ch->flags & CHN_F_VIRTUAL && + ch->pid == td->td_proc->p_pid) + break; + + if (ch == NULL) { + crit_exit(); + return 0; + } + + if (write) { + vol_left = min(*volume & 0x00ff, 100); + vol_right = min((*volume & 0xff00) >> 8, 100); + *ret = chn_setvolume(ch, vol_left, vol_right); + } else { + *volume = ch->volume; + *ret = 0; + } + crit_exit(); + return 1; +} + +/* ----------------------------------------------------------------------- */ + static int mixer_open(struct dev_open_args *ap) { @@ -486,6 +529,20 @@ mixer_ioctl(struct dev_ioctl_args *ap) if (m == NULL) return EBADF; + /* + * If we are handling PCM, maybe the app really wants to + * set its vchan, and fails to use the correct fd. + */ + if (j == SOUND_MIXER_PCM) { + cdev_t pdev; + + if (vchanvolume(i_dev, + (cmd & MIXER_WRITE(0)) == MIXER_WRITE(0), + (int *)arg, &ret, curthread)) + return ret; + /* else proceed as usual */ + } + snd_mtxlock(m->lock); if (mode != -1 && !m->busy) { snd_mtxunlock(m->lock); diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c index 2622f9fd2b..d949f97f00 100644 --- a/sys/dev/sound/pcm/sound.c +++ b/sys/dev/sound/pcm/sound.c @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/dev/sound/pcm/sound.c,v 1.93.2.3 2006/04/04 17:43:48 ariff Exp $ - * $DragonFly: src/sys/dev/sound/pcm/sound.c,v 1.8 2007/01/04 21:47:03 corecode Exp $ + * $DragonFly: src/sys/dev/sound/pcm/sound.c,v 1.9 2007/06/14 21:48:36 corecode Exp $ */ #include @@ -35,7 +35,7 @@ #include "feeder_if.h" -SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/sound.c,v 1.8 2007/01/04 21:47:03 corecode Exp $"); +SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/sound.c,v 1.9 2007/06/14 21:48:36 corecode Exp $"); devclass_t pcm_devclass; @@ -521,6 +521,22 @@ retry_num_search_out: return ch; } +struct pcm_channel * +pcm_chn_iterate(struct snddev_info *d, void **cookie) +{ + struct snddev_channel **last = (struct snddev_channel **)cookie; + + if (*last == NULL) + *last = SLIST_FIRST(&d->channels); + else + *last = SLIST_NEXT(*last, link); + + if (*last == NULL) + return NULL; + else + return (*last)->channel; +} + int pcm_chn_destroy(struct pcm_channel *ch) { diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h index 9c3d1f4789..b64d75d1e4 100644 --- a/sys/dev/sound/pcm/sound.h +++ b/sys/dev/sound/pcm/sound.h @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/dev/sound/pcm/sound.h,v 1.63.2.2 2006/04/04 17:43:48 ariff Exp $ - * $DragonFly: src/sys/dev/sound/pcm/sound.h,v 1.10 2007/01/04 21:47:03 corecode Exp $ + * $DragonFly: src/sys/dev/sound/pcm/sound.h,v 1.11 2007/06/14 21:48:36 corecode Exp $ */ /* @@ -221,6 +221,7 @@ int pcm_chnref(struct pcm_channel *c, int ref); int pcm_inprog(struct snddev_info *d, int delta); struct pcm_channel *pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls, int dir, void *devinfo); +struct pcm_channel *pcm_chn_iterate(struct snddev_info *d, void **cookie); int pcm_chn_destroy(struct pcm_channel *ch); int pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch); int pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch); diff --git a/sys/dev/sound/pcm/vchan.c b/sys/dev/sound/pcm/vchan.c index 8f8201812e..fc148b961e 100644 --- a/sys/dev/sound/pcm/vchan.c +++ b/sys/dev/sound/pcm/vchan.c @@ -24,14 +24,14 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/dev/sound/pcm/vchan.c,v 1.17.2.4 2006/04/04 17:43:49 ariff Exp $ - * $DragonFly: src/sys/dev/sound/pcm/vchan.c,v 1.5 2007/01/04 21:47:03 corecode Exp $ + * $DragonFly: src/sys/dev/sound/pcm/vchan.c,v 1.6 2007/06/14 21:48:36 corecode Exp $ */ #include #include #include "feeder_if.h" -SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/vchan.c,v 1.5 2007/01/04 21:47:03 corecode Exp $"); +SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/vchan.c,v 1.6 2007/06/14 21:48:36 corecode Exp $"); /* * Default speed @@ -53,18 +53,27 @@ static u_int32_t vchan_fmt[] = { }; static int -vchan_mix_s16(int16_t *to, int16_t *tmp, unsigned int count) +vchan_mix_s16(int16_t *to, int16_t *tmp, unsigned int count, int volume) { /* * to is the output buffer, tmp is the input buffer * count is the number of 16bit samples to mix + * volume is in range 0-100 */ int i; int x; + int scale; + int doscale; + + scale = (volume << 16) / 100; + doscale = volume != 100; for(i = 0; i < count; i++) { x = to[i]; - x += tmp[i]; + if (doscale) + x += ((int)tmp[i] * scale) >> 16; + else + x += tmp[i]; if (x < -32768) { /* kprintf("%d + %d = %d (u)\n", to[i], tmp[i], x); */ x = -32768; @@ -88,6 +97,7 @@ feed_vchan_s16(struct pcm_feeder *f, struct pcm_channel *c, u_int8_t *b, u_int32 uint32_t sz; int16_t *tmp, *dst; unsigned int cnt, rcnt = 0; + int volume; #if 0 if (sndbuf_getsize(src) < count) @@ -118,7 +128,10 @@ feed_vchan_s16(struct pcm_feeder *f, struct pcm_channel *c, u_int8_t *b, u_int32 if (ch->flags & CHN_F_MAPPED) sndbuf_acquire(ch->bufsoft, NULL, sndbuf_getfree(ch->bufsoft)); cnt = FEEDER_FEED(ch->feeder, ch, (u_int8_t *)tmp, count, ch->bufsoft); - vchan_mix_s16(dst, tmp, cnt >> 1); + volume = ch->volume & 0xff; /* XXX do special stereo processing? */ + volume += (ch->volume >> 8) & 0xff; + volume >>= 1; + vchan_mix_s16(dst, tmp, cnt >> 1, volume); if (cnt > rcnt) rcnt = cnt; } -- 2.41.0