snd_pcm seperate vchan pcm volume mixing
Simon 'corecode' Schubert
corecode at fs.ei.tum.de
Thu Jan 19 06:03:35 PST 2006
Simon 'corecode' Schubert wrote:
hey,
attached patch lets (when using vchans) applications change their own
vchan volume instead of changing the master pcm.
opinions?
patch is for dragonfly, but maybe it's of use for freebsd as well (thus
cc'ed)
cheers
simon
once again with patch. didn't thunderbird ask for forgotten attachments
at some point?
--
Serve - BSD +++ RENT this banner advert +++ ASCII Ribbon /"\
Work - Mac +++ space for low â¬â¬â¬ NOW!1 +++ Campaign \ /
Party Enjoy Relax | http://dragonflybsd.org Against HTML \
Dude 2c 2 the max ! http://golden-apple.biz Mail + News / \
diff -r 04ea340a2ccb -r 14cba75cc990 sys/dev/sound/pcm/channel.c
--- a/sys/dev/sound/pcm/channel.c Wed Jan 18 09:59:34 2006 +0000
+++ b/sys/dev/sound/pcm/channel.c Thu Jan 19 04:29:25 2006 +0100
@@ -724,6 +724,9 @@
if (ret)
goto out;
+ ret = chn_setvolume(c, 100, 100);
+ if (ret)
+ goto out;
out:
if (ret) {
@@ -783,7 +786,7 @@
{
CHN_LOCKASSERT(c);
/* could add a feeder for volume changing if channel returns -1 */
- c->volume = (left << 8) | right;
+ c->volume = (right << 8) | left;
return 0;
}
diff -r 04ea340a2ccb -r 14cba75cc990 sys/dev/sound/pcm/dsp.c
--- a/sys/dev/sound/pcm/dsp.c Wed Jan 18 09:59:34 2006 +0000
+++ b/sys/dev/sound/pcm/dsp.c Thu Jan 19 04:29:25 2006 +0100
@@ -432,6 +432,46 @@
return ret;
}
+int
+dsp_vchanvolume(dev_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
dsp_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
{
@@ -439,19 +479,6 @@
struct snddev_info *d;
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.
- */
-
- if (IOCGROUP(cmd) == 'M') {
- dev_t pdev;
-
- pdev = make_adhoc_dev(&dsp_cdevsw,
- PCMMKMINOR(PCMUNIT(i_dev), SND_DEV_CTL, 0));
- return mixer_ioctl(pdev, cmd, arg, mode, td);
- }
crit_enter();
d = dsp_get_info(i_dev);
@@ -471,6 +498,40 @@
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') {
+ dev_t pdev;
+
+ /*
+ * 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 {
+ pdev = make_adhoc_dev(&dsp_cdevsw,
+ PCMMKMINOR(PCMUNIT(i_dev), SND_DEV_CTL, 0));
+ ret = mixer_ioctl(pdev, cmd, arg, mode, td);
+ }
+
+ relchns(i_dev, rdch, wrch, 0);
+ crit_exit();
+ return ret;
+ }
switch(cmd) {
#ifdef OLDPCM_IOCTL
diff -r 04ea340a2ccb -r 14cba75cc990 sys/dev/sound/pcm/dsp.h
--- a/sys/dev/sound/pcm/dsp.h Wed Jan 18 09:59:34 2006 +0000
+++ b/sys/dev/sound/pcm/dsp.h Thu Jan 19 04:29:25 2006 +0100
@@ -31,3 +31,5 @@
int dsp_registerrec(int unit, int channel);
int dsp_unregister(int unit, int channel);
int dsp_unregisterrec(int unit, int channel);
+int dsp_vchanvolume(dev_t i_dev, int write, int *volume, int *ret,
+ struct thread *td);
diff -r 04ea340a2ccb -r 14cba75cc990 sys/dev/sound/pcm/mixer.c
--- a/sys/dev/sound/pcm/mixer.c Wed Jan 18 09:59:34 2006 +0000
+++ b/sys/dev/sound/pcm/mixer.c Thu Jan 19 04:29:25 2006 +0100
@@ -451,6 +451,23 @@
if (!m->busy)
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) {
+ dev_t pdev;
+
+ pdev = make_adhoc_dev(&mixer_cdevsw,
+ PCMMKMINOR(PCMUNIT(i_dev), SND_DEV_DSP, 0));
+
+ if (dsp_vchanvolume(pdev,
+ (cmd & MIXER_WRITE(0)) == MIXER_WRITE(0),
+ arg_i, &ret, td))
+ return ret;
+ /* else proceed as usual */
+ }
+
crit_enter();
snd_mtxlock(m->lock);
if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) {
diff -r 04ea340a2ccb -r 14cba75cc990 sys/dev/sound/pcm/sound.c
--- a/sys/dev/sound/pcm/sound.c Wed Jan 18 09:59:34 2006 +0000
+++ b/sys/dev/sound/pcm/sound.c Thu Jan 19 04:29:25 2006 +0100
@@ -402,6 +402,22 @@
}
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
diff -r 04ea340a2ccb -r 14cba75cc990 sys/dev/sound/pcm/sound.h
--- a/sys/dev/sound/pcm/sound.h Wed Jan 18 09:59:34 2006 +0000
+++ b/sys/dev/sound/pcm/sound.h Thu Jan 19 04:29:25 2006 +0100
@@ -222,6 +222,7 @@
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 mkdev);
int pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch, int rmdev);
diff -r 04ea340a2ccb -r 14cba75cc990 sys/dev/sound/pcm/vchan.c
--- a/sys/dev/sound/pcm/vchan.c Wed Jan 18 09:59:34 2006 +0000
+++ b/sys/dev/sound/pcm/vchan.c Thu Jan 19 04:29:25 2006 +0100
@@ -45,18 +45,19 @@
};
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;
for(i = 0; i < count; i++) {
x = to[i];
- x += tmp[i];
+ x += (int)tmp[i] * volume / 100;
if (x < -32768) {
/* printf("%d + %d = %d (u)\n", to[i], tmp[i], x); */
x = -32768;
@@ -79,6 +80,7 @@
struct pcm_channel *ch;
int16_t *tmp, *dst;
unsigned int cnt;
+ int volume;
KASSERT(sndbuf_getsize(src) >= count, ("bad bufsize"));
count &= ~1;
@@ -99,7 +101,10 @@
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 / 2);
+ volume = ch->volume & 0xff; /* XXX do special stereo processing? */
+ volume += (ch->volume >> 8) & 0xff;
+ volume /= 2;
+ vchan_mix_s16(dst, tmp, cnt / 2, volume);
}
}
More information about the Kernel
mailing list