diff options
author | Takashi Yano <takashi.yano@nifty.ne.jp> | 2023-09-01 11:41:10 +0300 |
---|---|---|
committer | Takashi Yano <takashi.yano@nifty.ne.jp> | 2023-09-01 15:33:38 +0300 |
commit | 2a4af36614705e5499683aa2f63dfe499edce6b7 (patch) | |
tree | 17defa71a6450e7d62210b39d017f109831e2559 /winsup/cygwin/fhandler | |
parent | 3daedf267d5b4940355fd370538d3036016efeda (diff) |
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>
Diffstat (limited to 'winsup/cygwin/fhandler')
-rw-r--r-- | winsup/cygwin/fhandler/mixer.cc | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/winsup/cygwin/fhandler/mixer.cc b/winsup/cygwin/fhandler/mixer.cc new file mode 100644 index 000000000..fabd397b7 --- /dev/null +++ b/winsup/cygwin/fhandler/mixer.cc @@ -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; +} |