Cygwin: Implement sound mixer device.

This patch adds implementation of OSS-based sound mixer device. This
allows applications to change the sound playing volume.

NOTE: Currently, the recording volume cannot be changed.

Reviewed-by: Corinna Vinschen <corinna@vinschen.de>
Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
This commit is contained in:
Takashi Yano 2023-09-01 17:41:10 +09:00
parent 3daedf267d
commit 2a4af36614
8 changed files with 892 additions and 687 deletions

View File

@ -89,6 +89,7 @@ FHANDLER_FILES= \
fhandler/dsp.cc \
fhandler/fifo.cc \
fhandler/floppy.cc \
fhandler/mixer.cc \
fhandler/mqueue.cc \
fhandler/netdrive.cc \
fhandler/nodevice.cc \

File diff suppressed because it is too large Load Diff

View File

@ -180,6 +180,7 @@ const _device dev_error_storage =
"/dev/console", BRACK(FH_CONSOLE), "/dev/console", exists_console, S_IFCHR, =console_dev
"/dev/ptmx", BRACK(FH_PTMX), "/dev/ptmx", exists, S_IFCHR
"/dev/windows", BRACK(FH_WINDOWS), "\\Device\\Null", exists_ntdev, S_IFCHR
"/dev/mixer", BRACK(FH_OSS_MIXER), "\\Device\\Null", exists_ntdev, S_IFCHR
"/dev/dsp", BRACK(FH_OSS_DSP), "\\Device\\Null", exists_ntdev, S_IFCHR
"/dev/conin", BRACK(FH_CONIN), "/dev/conin", exists_console, S_IFCHR
"/dev/conout", BRACK(FH_CONOUT), "/dev/conout", exists_console, S_IFCHR

View File

@ -552,6 +552,9 @@ fh_alloc (path_conv& pc)
case FH_CLIPBOARD:
fh = cnew (fhandler_dev_clipboard);
break;
case FH_OSS_MIXER:
fh = cnew (fhandler_dev_mixer);
break;
case FH_OSS_DSP:
fh = cnew (fhandler_dev_dsp);
break;

View File

@ -0,0 +1,152 @@
/* fhandler_dev_mixer: code to emulate OSS sound model /dev/mixer
Written by Takashi Yano <takashi.yano@nifty.ne.jp>
This file is part of Cygwin.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
#include <sys/soundcard.h>
#include "cygerrno.h"
#include "path.h"
#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
ssize_t
fhandler_dev_mixer::write (const void *ptr, size_t len)
{
set_errno (EINVAL);
return -1;
}
void
fhandler_dev_mixer::read (void *ptr, size_t& len)
{
len = -1;
set_errno (EINVAL);
}
int
fhandler_dev_mixer::open (int flags, mode_t)
{
int ret = -1, err = 0;
switch (flags & O_ACCMODE)
{
case O_RDWR:
case O_WRONLY:
case O_RDONLY:
if (waveInGetNumDevs () == 0 && waveOutGetNumDevs () == 0)
err = ENXIO;
break;
default:
err = EINVAL;
}
if (err)
set_errno (err);
else
{
ret = open_null (flags);
rec_source = SOUND_MIXER_MIC;
}
return ret;
}
static DWORD
volume_oss_to_winmm (int vol_oss)
{
unsigned int vol_l, vol_r;
DWORD vol_winmm;
vol_l = ((unsigned int) vol_oss) & 0xff;
vol_r = ((unsigned int) vol_oss) >> 8;
vol_l = min ((vol_l * 65535 + 50) / 100, 65535);
vol_r = min ((vol_r * 65535 + 50) / 100, 65535);
vol_winmm = (vol_r << 16) | vol_l;
return vol_winmm;
}
static int
volume_winmm_to_oss (DWORD vol_winmm)
{
int vol_l, vol_r;
vol_l = vol_winmm & 0xffff;
vol_r = vol_winmm >> 16;
vol_l = min ((vol_l * 100 + 32768) / 65535, 100);
vol_r = min ((vol_r * 100 + 32768) / 65535, 100);
return (vol_r << 8) | vol_l;
}
int
fhandler_dev_mixer::ioctl (unsigned int cmd, void *buf)
{
int ret = 0;
DWORD vol;
switch (cmd)
{
case SOUND_MIXER_READ_DEVMASK:
*(int *) buf = SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_LINE;
break;
case SOUND_MIXER_READ_RECMASK:
*(int *) buf = SOUND_MASK_MIC | SOUND_MASK_LINE;
break;
case SOUND_MIXER_READ_STEREODEVS:
*(int *) buf = SOUND_MASK_VOLUME | SOUND_MASK_LINE;
break;
case SOUND_MIXER_READ_CAPS:
*(int *) buf = SOUND_CAP_EXCL_INPUT;
break;
case MIXER_WRITE (SOUND_MIXER_RECSRC):
/* Dummy implementation */
if (*(int *) buf == 0 || ((*(int *) buf) & SOUND_MASK_MIC))
rec_source = SOUND_MIXER_MIC;
else if ((*(int *) buf) & SOUND_MASK_LINE)
rec_source = SOUND_MIXER_LINE;
break;
case MIXER_READ (SOUND_MIXER_RECSRC):
/* Dummy implementation */
*(int *) buf = 1 << rec_source;
break;
case MIXER_WRITE (SOUND_MIXER_VOLUME):
vol = volume_oss_to_winmm (*(int *) buf);
if (waveOutSetVolume ((HWAVEOUT)WAVE_MAPPER, vol) != MMSYSERR_NOERROR)
{
set_errno (EINVAL);
ret = -1;
}
break;
case MIXER_READ (SOUND_MIXER_VOLUME):
DWORD vol;
if (waveOutGetVolume ((HWAVEOUT)WAVE_MAPPER, &vol) != MMSYSERR_NOERROR)
{
set_errno (EINVAL);
ret = -1;
break;
}
*(int *) buf = volume_winmm_to_oss (vol);
break;
default:
for (int i = 0; i < SOUND_MIXER_NRDEVICES; i++)
{
if (cmd == (unsigned int) MIXER_WRITE (i))
goto out;
if (cmd == (unsigned int) MIXER_READ (i))
{
*(int *) buf = 0;
goto out;
}
}
set_errno (EINVAL);
ret = -1;
break;
}
out:
return ret;
}

View File

@ -242,6 +242,7 @@ enum fh_devices
FH_URANDOM = FHDEV (DEV_MEM_MAJOR, 9),
DEV_SOUND_MAJOR = 14,
FH_OSS_MIXER = FHDEV (DEV_SOUND_MAJOR, 0),
FH_OSS_DSP = FHDEV (DEV_SOUND_MAJOR, 3),
DEV_SOCK_MAJOR = 30,

View File

@ -2777,6 +2777,35 @@ class fhandler_windows: public fhandler_base
}
};
class fhandler_dev_mixer: public fhandler_base
{
private:
int rec_source;
public:
fhandler_dev_mixer () {}
int open (int, mode_t mode = 0);
ssize_t write (const void *, size_t);
void read (void *, size_t&);
int ioctl (unsigned int, void *);
fhandler_dev_mixer (void *) {}
void copy_from (fhandler_base *x)
{
pc.free_strings ();
*this = *reinterpret_cast<fhandler_dev_mixer *> (x);
_copy_from_reset_helper ();
}
fhandler_dev_mixer *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_dev_mixer));
fhandler_dev_mixer *fh = new (ptr) fhandler_dev_mixer (ptr);
fh->copy_from (this);
return fh;
}
};
class fhandler_dev_dsp: public fhandler_base
{
public:

View File

@ -31,6 +31,8 @@ What's new:
- New API calls: c8rtomb, c16rtomb, c32rtomb, mbrtoc8, mbrtoc16, mbrtoc32.
- Implement OSS-based sound mixer device (/dev/mixer).
What changed:
-------------