⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mixer.c

📁 Wine-20031016
💻 C
📖 第 1 页 / 共 3 页
字号:
/* -*- tab-width: 8; c-basic-offset: 4 -*- *//* * Sample MIXER Wine Driver for Linux * * Copyright 	1997 Marcus Meissner * 		1999,2001 Eric Pouech * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include "config.h"#include <stdlib.h>#include <stdarg.h>#include <stdio.h>#include <string.h>#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#include <fcntl.h>#include <errno.h>#include <assert.h>#ifdef HAVE_SYS_IOCTL_H# include <sys/ioctl.h>#endif#define NONAMELESSUNION#define NONAMELESSSTRUCT#include "windef.h"#include "winbase.h"#include "mmddk.h"#include "oss.h"#include "wine/debug.h"WINE_DEFAULT_DEBUG_CHANNEL(mmaux);#ifdef HAVE_OSS#define	WINE_MIXER_MANUF_ID		0xAA#define	WINE_MIXER_PRODUCT_ID		0x55#define	WINE_MIXER_VERSION		0x0100#define	WINE_MIXER_NAME			"WINE OSS Mixer"#define WINE_CHN_MASK(_x)		(1L << (_x))#define WINE_CHN_SUPPORTS(_c, _x)	((_c) & WINE_CHN_MASK(_x))/* Bass and Treble are no longer in the mask as Windows does not handle them */#define WINE_MIXER_MASK_SPEAKER		(WINE_CHN_MASK(SOUND_MIXER_SYNTH)  | \                                         WINE_CHN_MASK(SOUND_MIXER_PCM)    | \                                         WINE_CHN_MASK(SOUND_MIXER_LINE)   | \                                         WINE_CHN_MASK(SOUND_MIXER_MIC)    | \                                         WINE_CHN_MASK(SOUND_MIXER_CD)     )#define WINE_MIXER_MASK_RECORD		(WINE_CHN_MASK(SOUND_MIXER_SYNTH)  | \                                         WINE_CHN_MASK(SOUND_MIXER_LINE)   | \                                         WINE_CHN_MASK(SOUND_MIXER_MIC)    | \                                         WINE_CHN_MASK(SOUND_MIXER_IMIX)   )/* FIXME: the two following string arrays should be moved to a resource file in a string table *//* if it's done, better use a struct to hold labels, name, and muted channel volume cache */static const char*	MIX_Labels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS;static const char*	MIX_Names [SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;struct mixerCtrl{    DWORD		dwLineID;    MIXERCONTROLA	ctrl;};struct mixer{    const char*		name;    int			volume[SOUND_MIXER_NRDEVICES];    int			devMask;    int			stereoMask;    int			recMask;    BOOL		singleRecChannel;    struct mixerCtrl*	ctrl;    int			numCtrl;};#define LINEID_DST	0xFFFF#define LINEID_SPEAKER	0x0000#define LINEID_RECORD	0x0001static int		MIX_NumMixers;static struct mixer	MIX_Mixers[1];/************************************************************************** * 				MIX_FillLineControls		[internal] */static void MIX_FillLineControls(struct mixer* mix, int c, DWORD lineID, DWORD dwType){    struct mixerCtrl* 	mc = &mix->ctrl[c];    int			j;    mc->dwLineID = lineID;    mc->ctrl.cbStruct = sizeof(MIXERCONTROLA);    mc->ctrl.dwControlID = c + 1;    mc->ctrl.dwControlType = dwType;    switch (dwType)    {    case MIXERCONTROL_CONTROLTYPE_VOLUME:	mc->ctrl.fdwControl = 0;	mc->ctrl.cMultipleItems = 0;	lstrcpynA(mc->ctrl.szShortName, "Vol", MIXER_SHORT_NAME_CHARS);	lstrcpynA(mc->ctrl.szName, "Volume", MIXER_LONG_NAME_CHARS);	memset(&mc->ctrl.Bounds, 0, sizeof(mc->ctrl.Bounds));	/* CONTROLTYPE_VOLUME uses the MIXER_CONTROLDETAILS_UNSIGNED struct,	 * [0, 100] is the range supported by OSS	 * whatever the min and max values are they must match	 * conversions done in (Get|Set)ControlDetails to stay in [0, 100] range	 */	mc->ctrl.Bounds.s1.dwMinimum = 0;	mc->ctrl.Bounds.s1.dwMaximum = 65535;	memset(&mc->ctrl.Metrics, 0, sizeof(mc->ctrl.Metrics));	break;    case MIXERCONTROL_CONTROLTYPE_MUTE:    case MIXERCONTROL_CONTROLTYPE_ONOFF:	mc->ctrl.fdwControl = 0;	mc->ctrl.cMultipleItems = 0;	lstrcpynA(mc->ctrl.szShortName, "Mute", MIXER_SHORT_NAME_CHARS);	lstrcpynA(mc->ctrl.szName, "Mute", MIXER_LONG_NAME_CHARS);	memset(&mc->ctrl.Bounds, 0, sizeof(mc->ctrl.Bounds));	mc->ctrl.Bounds.s1.dwMinimum = 0;	mc->ctrl.Bounds.s1.dwMaximum = 1;	memset(&mc->ctrl.Metrics, 0, sizeof(mc->ctrl.Metrics));	break;    case MIXERCONTROL_CONTROLTYPE_MUX:    case MIXERCONTROL_CONTROLTYPE_MIXER:	mc->ctrl.fdwControl = MIXERCONTROL_CONTROLF_MULTIPLE;	mc->ctrl.cMultipleItems = 0;	for (j = 0; j < SOUND_MIXER_NRDEVICES; j++)	    if (WINE_CHN_SUPPORTS(mix->recMask, j))		mc->ctrl.cMultipleItems++;	lstrcpynA(mc->ctrl.szShortName, "Mixer", MIXER_SHORT_NAME_CHARS);	lstrcpynA(mc->ctrl.szName, "Mixer", MIXER_LONG_NAME_CHARS);	memset(&mc->ctrl.Bounds, 0, sizeof(mc->ctrl.Bounds));	memset(&mc->ctrl.Metrics, 0, sizeof(mc->ctrl.Metrics));	break;    default:	FIXME("Internal error: unknown type: %08lx\n", dwType);    }    TRACE("ctrl[%2d]: typ=%08lx lin=%08lx\n", c + 1, dwType, lineID);}/****************************************************************** *		MIX_GetMixer * * */static struct mixer*	MIX_Get(WORD wDevID){    if (wDevID >= MIX_NumMixers || MIX_Mixers[wDevID].name == NULL) return NULL;    return &MIX_Mixers[wDevID];}/************************************************************************** * 				MIX_Open			[internal] */static DWORD MIX_Open(WORD wDevID, LPMIXEROPENDESC lpMod, DWORD flags){    int			mixer, i, j;    unsigned 		caps;    struct mixer*	mix;    DWORD		ret = MMSYSERR_NOERROR;    TRACE("(%04X, %p, %lu);\n", wDevID, lpMod, flags);    /* as we partly init the mixer with MIX_Open, we can allow null open decs */    /* EPP     if (lpMod == NULL) return MMSYSERR_INVALPARAM; */    /* anyway, it seems that WINMM/MMSYSTEM doesn't always open the mixer device before sending     * messages to it... it seems to be linked to all the equivalent of mixer identification     * (with a reference to a wave, midi.. handle     */    if (!(mix = MIX_Get(wDevID))) return MMSYSERR_BADDEVICEID;    if ((mixer = open(mix->name, O_RDWR)) < 0)    {	if (errno == ENODEV || errno == ENXIO)	{	    /* no driver present */	    return MMSYSERR_NODRIVER;	}	return MMSYSERR_ERROR;    }    if (ioctl(mixer, SOUND_MIXER_READ_DEVMASK, &mix->devMask) == -1)    {	perror("ioctl mixer SOUND_MIXER_DEVMASK");	ret = MMSYSERR_ERROR;	goto error;    }    mix->devMask &= WINE_MIXER_MASK_SPEAKER;    if (mix->devMask == 0)    {	ret = MMSYSERR_NODRIVER;	goto error;    }    if (ioctl(mixer, SOUND_MIXER_READ_STEREODEVS, &mix->stereoMask) == -1)    {	perror("ioctl mixer SOUND_MIXER_STEREODEVS");	ret = MMSYSERR_ERROR;	goto error;    }    mix->stereoMask &= WINE_MIXER_MASK_SPEAKER;    if (ioctl(mixer, SOUND_MIXER_READ_RECMASK, &mix->recMask) == -1)    {	perror("ioctl mixer SOUND_MIXER_RECMASK");	ret = MMSYSERR_ERROR;	goto error;    }    mix->recMask &= WINE_MIXER_MASK_RECORD;    /* FIXME: we may need to support both rec lev & igain */    if (!WINE_CHN_SUPPORTS(mix->recMask, SOUND_MIXER_RECLEV))    {	WARN("The sound card doesn't support rec level\n");	if (WINE_CHN_SUPPORTS(mix->recMask, SOUND_MIXER_IGAIN))	    WARN("but it does support IGain, please report\n");    }    if (ioctl(mixer, SOUND_MIXER_READ_CAPS, &caps) == -1)    {	perror("ioctl mixer SOUND_MIXER_READ_CAPS");	ret = MMSYSERR_ERROR;	goto error;    }    mix->singleRecChannel = caps & SOUND_CAP_EXCL_INPUT;    TRACE("dev=%04x rec=%04x stereo=%04x %s\n",	  mix->devMask, mix->recMask, mix->stereoMask,	  mix->singleRecChannel ? "single" : "multiple");    for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)    {	mix->volume[i] = -1;    }    mix->numCtrl = 4; /* dst lines... vol&mute on speakers, vol&onoff on rec */    /* FIXME: do we always have RECLEV on all cards ??? */    for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)    {	if (WINE_CHN_SUPPORTS(mix->devMask, i))	    mix->numCtrl += 2; /* volume & mute */	if (WINE_CHN_SUPPORTS(mix->recMask, i))	    mix->numCtrl += 2; /* volume & onoff */    }    if (!(mix->ctrl = HeapAlloc(GetProcessHeap(), 0, sizeof(mix->ctrl[0]) * mix->numCtrl)))    {	ret = MMSYSERR_NOMEM;	goto error;    }    j = 0;    MIX_FillLineControls(mix, j++, MAKELONG(0, LINEID_DST), MIXERCONTROL_CONTROLTYPE_VOLUME);    MIX_FillLineControls(mix, j++, MAKELONG(0, LINEID_DST), MIXERCONTROL_CONTROLTYPE_MUTE);    MIX_FillLineControls(mix, j++, MAKELONG(1, LINEID_DST),			 mix->singleRecChannel ?			    MIXERCONTROL_CONTROLTYPE_MUX : MIXERCONTROL_CONTROLTYPE_MIXER);    MIX_FillLineControls(mix, j++, MAKELONG(1, LINEID_DST), MIXERCONTROL_CONTROLTYPE_MUTE/*EPP*/);    for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)    {	if (WINE_CHN_SUPPORTS(mix->devMask, i))	{	    MIX_FillLineControls(mix, j++, MAKELONG(LINEID_SPEAKER, i),				 MIXERCONTROL_CONTROLTYPE_VOLUME);	    MIX_FillLineControls(mix, j++, MAKELONG(LINEID_SPEAKER, i),				 MIXERCONTROL_CONTROLTYPE_MUTE);	}    }    for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)    {	if (WINE_CHN_SUPPORTS(mix->recMask, i))	{	    MIX_FillLineControls(mix, j++, MAKELONG(LINEID_RECORD, i),				 MIXERCONTROL_CONTROLTYPE_VOLUME);	    MIX_FillLineControls(mix, j++, MAKELONG(LINEID_RECORD, i),				 MIXERCONTROL_CONTROLTYPE_MUTE/*EPP*/);	}    }    assert(j == mix->numCtrl); error:    close(mixer);    return ret;}/************************************************************************** * 				MIX_GetVal			[internal] */static	BOOL	MIX_GetVal(struct mixer* mix, int chn, int* val){    int		mixer;    BOOL	ret = FALSE;    if ((mixer = open(mix->name, O_RDWR)) < 0)    {	/* FIXME: ENXIO => no mixer installed */	WARN("mixer device not available !\n");    }    else    {	if (ioctl(mixer, MIXER_READ(chn), val) >= 0)	{	    TRACE("Reading volume %x on %d\n", *val, chn);	    ret = TRUE;	}	close(mixer);    }    return ret;}/************************************************************************** * 				MIX_SetVal			[internal] */static	BOOL	MIX_SetVal(struct mixer* mix, int chn, int val){    int		mixer;    BOOL	ret = FALSE;    TRACE("Writing volume %x on %d\n", val, chn);    if ((mixer = open(mix->name, O_RDWR)) < 0)    {	/* FIXME: ENXIO => no mixer installed */	WARN("mixer device not available !\n");    }    else    {	if (ioctl(mixer, MIXER_WRITE(chn), &val) >= 0)	{	    ret = TRUE;	}	close(mixer);    }    return ret;}/****************************************************************** *		MIX_GetRecSrc * * */static BOOL	MIX_GetRecSrc(struct mixer* mix, unsigned* mask){    int		mixer;    BOOL	ret = FALSE;    if ((mixer = open(mix->name, O_RDWR)) >= 0)    {	if (ioctl(mixer, SOUND_MIXER_READ_RECSRC, &mask) >= 0) ret = TRUE;	close(mixer);    }    return ret;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -