更改主音量级别
我怎样才能改变主音量? 使用这个代码
[DllImport ("winmm.dll")] public static extern int waveOutSetVolume (IntPtr hwo, uint dwVolume); waveOutSetVolume (IntPtr.Zero, (((uint)uint.MaxValue & 0x0000ffff) | ((uint)uint.MaxValue << 16)));
我可以设置波形音量,但如果主音量太低,这将不会有任何影响。
感谢您的帮助。
好的,这里是:
const int MAXPNAMELEN = 32; const int MIXER_SHORT_NAME_CHARS = 16; const int MIXER_LONG_NAME_CHARS = 64; [Flags] enum MIXERLINE_LINEF : uint{ ACTIVE = 0x00000001, DISCONNECTED = 0x00008000, SOURCE = 0x80000000 } [Flags] enum MIXER : uint{ GETLINEINFOF_DESTINATION = 0x00000000, GETLINEINFOF_SOURCE = 0x00000001, GETLINEINFOF_LINEID = 0x00000002, GETLINEINFOF_COMPONENTTYPE = 0x00000003, GETLINEINFOF_TARGETTYPE = 0x00000004, GETLINEINFOF_QUERYMASK = 0x0000000F, GETLINECONTROLSF_ALL = 0x00000000, GETLINECONTROLSF_ONEBYID = 0x00000001, GETLINECONTROLSF_ONEBYTYPE = 0x00000002, GETLINECONTROLSF_QUERYMASK = 0x0000000F, GETCONTROLDETAILSF_VALUE = 0x00000000, GETCONTROLDETAILSF_LISTTEXT = 0x00000001, GETCONTROLDETAILSF_QUERYMASK = 0x0000000F, OBJECTF_MIXER = 0x00000000, OBJECTF_WAVEOUT = 0x10000000, OBJECTF_WAVEIN = 0x20000000, OBJECTF_MIDIOUT = 0x30000000, OBJECTF_MIDIIN = 0x40000000, OBJECTF_AUX = 0x50000000, OBJECTF_HANDLE = 0x80000000, OBJECTF_HMIXER = OBJECTF_HANDLE | OBJECTF_MIXER, OBJECTF_HWAVEOUT = OBJECTF_HANDLE | OBJECTF_WAVEOUT, OBJECTF_HWAVEIN = OBJECTF_HANDLE | OBJECTF_WAVEIN, OBJECTF_HMIDIOUT = OBJECTF_HANDLE | OBJECTF_MIDIOUT, OBJECTF_HMIDIIN = OBJECTF_HANDLE | OBJECTF_MIDIIN } [Flags] enum MIXERCONTROL_CT : uint{ CLASS_MASK = 0xF0000000, CLASS_CUSTOM = 0x00000000, CLASS_METER = 0x10000000, CLASS_SWITCH = 0x20000000, CLASS_NUMBER = 0x30000000, CLASS_SLIDER = 0x40000000, CLASS_FADER = 0x50000000, CLASS_TIME = 0x60000000, CLASS_LIST = 0x70000000, SUBCLASS_MASK = 0x0F000000, SC_SWITCH_BOOLEAN = 0x00000000, SC_SWITCH_BUTTON = 0x01000000, SC_METER_POLLED = 0x00000000, SC_TIME_MICROSECS = 0x00000000, SC_TIME_MILLISECS = 0x01000000, SC_LIST_SINGLE = 0x00000000, SC_LIST_MULTIPLE = 0x01000000, UNITS_MASK = 0x00FF0000, UNITS_CUSTOM = 0x00000000, UNITS_BOOLEAN = 0x00010000, UNITS_SIGNED = 0x00020000, UNITS_UNSIGNED = 0x00030000, UNITS_DECIBELS = 0x00040000, /* in 10ths */ UNITS_PERCENT = 0x00050000, /* in 10ths */ } [Flags] enum MIXERCONTROL_CONTROLTYPE : uint{ CUSTOM = MIXERCONTROL_CT.CLASS_CUSTOM | MIXERCONTROL_CT.UNITS_CUSTOM, BOOLEANMETER = MIXERCONTROL_CT.CLASS_METER | MIXERCONTROL_CT.SC_METER_POLLED | MIXERCONTROL_CT.UNITS_BOOLEAN, SIGNEDMETER = MIXERCONTROL_CT.CLASS_METER | MIXERCONTROL_CT.SC_METER_POLLED | MIXERCONTROL_CT.UNITS_SIGNED, PEAKMETER = SIGNEDMETER + 1, UNSIGNEDMETER = MIXERCONTROL_CT.CLASS_METER | MIXERCONTROL_CT.SC_METER_POLLED | MIXERCONTROL_CT.UNITS_UNSIGNED, BOOLEAN = MIXERCONTROL_CT.CLASS_SWITCH | MIXERCONTROL_CT.SC_SWITCH_BOOLEAN | MIXERCONTROL_CT.UNITS_BOOLEAN, ONOFF = BOOLEAN + 1, MUTE = BOOLEAN + 2, MONO = BOOLEAN + 3, LOUDNESS = BOOLEAN + 4, STEREOENH = BOOLEAN + 5, BASS_BOOST = BOOLEAN + 0x00002277, BUTTON = MIXERCONTROL_CT.CLASS_SWITCH | MIXERCONTROL_CT.SC_SWITCH_BUTTON | MIXERCONTROL_CT.UNITS_BOOLEAN, DECIBELS = MIXERCONTROL_CT.CLASS_NUMBER | MIXERCONTROL_CT.UNITS_DECIBELS, SIGNED = MIXERCONTROL_CT.CLASS_NUMBER | MIXERCONTROL_CT.UNITS_SIGNED, UNSIGNED = MIXERCONTROL_CT.CLASS_NUMBER | MIXERCONTROL_CT.UNITS_UNSIGNED, PERCENT = MIXERCONTROL_CT.CLASS_NUMBER | MIXERCONTROL_CT.UNITS_PERCENT, SLIDER = MIXERCONTROL_CT.CLASS_SLIDER | MIXERCONTROL_CT.UNITS_SIGNED, PAN = SLIDER + 1, QSOUNDPAN = SLIDER + 2, FADER = MIXERCONTROL_CT.CLASS_FADER | MIXERCONTROL_CT.UNITS_UNSIGNED, VOLUME = FADER + 1, BASS = FADER + 2, TREBLE = FADER + 3, EQUALIZER = FADER + 4, SINGLESELECT = MIXERCONTROL_CT.CLASS_LIST | MIXERCONTROL_CT.SC_LIST_SINGLE | MIXERCONTROL_CT.UNITS_BOOLEAN, MUX = SINGLESELECT + 1, MULTIPLESELECT = MIXERCONTROL_CT.CLASS_LIST | MIXERCONTROL_CT.SC_LIST_MULTIPLE | MIXERCONTROL_CT.UNITS_BOOLEAN, MIXER = MULTIPLESELECT + 1, MICROTIME = MIXERCONTROL_CT.CLASS_TIME | MIXERCONTROL_CT.SC_TIME_MICROSECS | MIXERCONTROL_CT.UNITS_UNSIGNED, MILLITIME = MIXERCONTROL_CT.CLASS_TIME | MIXERCONTROL_CT.SC_TIME_MILLISECS | MIXERCONTROL_CT.UNITS_UNSIGNED } [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)] struct MIXERLINE{ [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)] public struct TargetInfo{ public uint dwType; public uint dwDeviceID; public ushort wMid; public ushort wPid; public uint vDriverVersion; [MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAXPNAMELEN)] public string szPname; } public uint cbStruct; public uint dwDestination; public uint dwSource; public uint dwLineID; public MIXERLINE_LINEF fdwLine; public uint dwUser; public uint dwComponentType; public uint cChannels; public uint cConnection; public uint cControls; [MarshalAs(UnmanagedType.ByValTStr, SizeConst=MIXER_SHORT_NAME_CHARS)] public string szShortName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst=MIXER_LONG_NAME_CHARS)] public string szName; public TargetInfo Target; } [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)] struct MIXERCONTROL{ [StructLayout(LayoutKind.Explicit)] public struct BoundsInfo{ [FieldOffset(0)] public int lMinimum; [FieldOffset(4)] public int lMaximum; [FieldOffset(0)] public uint dwMinimum; [FieldOffset(4)] public uint dwMaximum; [FieldOffset(8), MarshalAs(UnmanagedType.ByValArray, SizeConst=4)] public uint[] dwReserved; } [StructLayout(LayoutKind.Explicit)] public struct MetricsInfo{ [FieldOffset(0)] public uint cSteps; [FieldOffset(0)] public uint cbCustomData; [FieldOffset(4), MarshalAs(UnmanagedType.ByValArray, SizeConst=5)] public uint[] dwReserved; } public uint cbStruct; public uint dwControlID; public MIXERCONTROL_CONTROLTYPE dwControlType; public uint fdwControl; public uint cMultipleItems; [MarshalAs(UnmanagedType.ByValTStr, SizeConst=MIXER_SHORT_NAME_CHARS)] public string szShortName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst=MIXER_LONG_NAME_CHARS)] public string szName; public BoundsInfo Bounds; public MetricsInfo Metrics; } [StructLayout(LayoutKind.Explicit)] struct MIXERLINECONTROLS{ [FieldOffset(0)] public uint cbStruct; [FieldOffset(4)] public uint dwLineID; [FieldOffset(8)] public uint dwControlID; [FieldOffset(8)] // not a typo! overlaps previous field public uint dwControlType; [FieldOffset(12)] public uint cControls; [FieldOffset(16)] public uint cbmxctrl; [FieldOffset(20)] public IntPtr pamxctrl; } [StructLayout(LayoutKind.Explicit)] struct MIXERCONTROLDETAILS{ [FieldOffset(0)] public uint cbStruct; [FieldOffset(4)] public uint dwControlID; [FieldOffset(8)] public uint cChannels; [FieldOffset(12)] public IntPtr hwndOwner; [FieldOffset(12)] // not a typo! public uint cMultipleItems; [FieldOffset(16)] public uint cbDetails; [FieldOffset(20)] public IntPtr paDetails; } [StructLayout(LayoutKind.Sequential)] struct VOLUME{ public int left; public int right; } struct MixerInfo{ public uint volumeCtl; public uint muteCtl; public int minVolume; public int maxVolume; } [DllImport("WinMM.dll", CharSet=CharSet.Auto)] static extern uint mixerGetLineInfo (IntPtr hmxobj, ref MIXERLINE pmxl, MIXER flags); [DllImport("WinMM.dll", CharSet=CharSet.Auto)] static extern uint mixerGetLineControls (IntPtr hmxobj, ref MIXERLINECONTROLS pmxlc, MIXER flags); [DllImport("WinMM.dll", CharSet=CharSet.Auto)] static extern uint mixerGetControlDetails(IntPtr hmxobj, ref MIXERCONTROLDETAILS pmxcd, MIXER flags); [DllImport("WinMM.dll", CharSet=CharSet.Auto)] static extern uint mixerSetControlDetails(IntPtr hmxobj, ref MIXERCONTROLDETAILS pmxcd, MIXER flags); static MixerInfo GetMixerControls(){ MIXERLINE mxl = new MIXERLINE(); MIXERLINECONTROLS mlc = new MIXERLINECONTROLS(); mxl.cbStruct = (uint)Marshal.SizeOf(typeof(MIXERLINE)); mlc.cbStruct = (uint)Marshal.SizeOf(typeof(MIXERLINECONTROLS)); mixerGetLineInfo(IntPtr.Zero, ref mxl, MIXER.OBJECTF_MIXER | MIXER.GETLINEINFOF_DESTINATION); mlc.dwLineID = mxl.dwLineID; mlc.cControls = mxl.cControls; mlc.cbmxctrl = (uint)Marshal.SizeOf(typeof(MIXERCONTROL)); mlc.pamxctrl = Marshal.AllocHGlobal((int)(mlc.cbmxctrl * mlc.cControls)); mixerGetLineControls(IntPtr.Zero, ref mlc, MIXER.OBJECTF_MIXER | MIXER.GETLINECONTROLSF_ALL); MixerInfo rtn = new MixerInfo(); for(int i = 0; i < mlc.cControls; i++){ MIXERCONTROL mxc = (MIXERCONTROL)Marshal.PtrToStructure((IntPtr)((int)mlc.pamxctrl + (int)mlc.cbmxctrl * i), typeof(MIXERCONTROL)); switch(mxc.dwControlType){ case MIXERCONTROL_CONTROLTYPE.VOLUME: rtn.volumeCtl = mxc.dwControlID; rtn.minVolume = mxc.Bounds.lMinimum; rtn.maxVolume = mxc.Bounds.lMaximum; break; case MIXERCONTROL_CONTROLTYPE.MUTE: rtn.muteCtl = mxc.dwControlID; break; } } Marshal.FreeHGlobal(mlc.pamxctrl); return rtn; } static VOLUME GetVolume(MixerInfo mi){ MIXERCONTROLDETAILS mcd = new MIXERCONTROLDETAILS(); mcd.cbStruct = (uint)Marshal.SizeOf(typeof(MIXERCONTROLDETAILS)); mcd.dwControlID = mi.volumeCtl; mcd.cMultipleItems = 0; mcd.cChannels = 2; mcd.cbDetails = (uint)Marshal.SizeOf(typeof(int)); mcd.paDetails = Marshal.AllocHGlobal((int)mcd.cbDetails); mixerGetControlDetails(IntPtr.Zero, ref mcd, MIXER.GETCONTROLDETAILSF_VALUE | MIXER.OBJECTF_MIXER); VOLUME rtn = (VOLUME)Marshal.PtrToStructure(mcd.paDetails, typeof(VOLUME)); Marshal.FreeHGlobal(mcd.paDetails); return rtn; } static bool IsMuted(MixerInfo mi){ MIXERCONTROLDETAILS mcd = new MIXERCONTROLDETAILS(); mcd.cbStruct = (uint)Marshal.SizeOf(typeof(MIXERCONTROLDETAILS)); mcd.dwControlID = mi.muteCtl; mcd.cMultipleItems = 0; mcd.cChannels = 1; mcd.cbDetails = 4; mcd.paDetails = Marshal.AllocHGlobal((int)mcd.cbDetails); mixerGetControlDetails(IntPtr.Zero, ref mcd, MIXER.GETCONTROLDETAILSF_VALUE | MIXER.OBJECTF_MIXER); int rtn = Marshal.ReadInt32(mcd.paDetails); Marshal.FreeHGlobal(mcd.paDetails); return rtn != 0; } static void AdjustVolume(MixerInfo mi, int delta){ VOLUME volume = GetVolume(mi); if(delta > 0){ volume.left = Math.Min(mi.maxVolume, volume.left + delta); volume.right = Math.Min(mi.maxVolume, volume.right + delta); }else{ volume.left = Math.Max(mi.minVolume, volume.left + delta); volume.right = Math.Max(mi.minVolume, volume.right + delta); } SetVolume(mi, volume); } static void SetVolume(MixerInfo mi, VOLUME volume){ MIXERCONTROLDETAILS mcd = new MIXERCONTROLDETAILS(); mcd.cbStruct = (uint)Marshal.SizeOf(typeof(MIXERCONTROLDETAILS)); mcd.dwControlID = mi.volumeCtl; mcd.cMultipleItems = 0; mcd.cChannels = 2; mcd.cbDetails = (uint)Marshal.SizeOf(typeof(int)); mcd.paDetails = Marshal.AllocHGlobal((int)mcd.cbDetails); Marshal.StructureToPtr(volume, mcd.paDetails, false); mixerSetControlDetails(IntPtr.Zero, ref mcd, MIXER.GETCONTROLDETAILSF_VALUE | MIXER.OBJECTF_MIXER); Marshal.FreeHGlobal(mcd.paDetails); } static void SetMute(MixerInfo mi, bool mute){ MIXERCONTROLDETAILS mcd = new MIXERCONTROLDETAILS(); mcd.cbStruct = (uint)Marshal.SizeOf(typeof(MIXERCONTROLDETAILS)); mcd.dwControlID = mi.muteCtl; mcd.cMultipleItems = 0; mcd.cChannels = 1; mcd.cbDetails = 4; mcd.paDetails = Marshal.AllocHGlobal((int)mcd.cbDetails); Marshal.WriteInt32(mcd.paDetails, mute ? 1 : 0); mixerSetControlDetails(IntPtr.Zero, ref mcd, MIXER.GETCONTROLDETAILSF_VALUE | MIXER.OBJECTF_MIXER); Marshal.FreeHGlobal(mcd.paDetails); }
这个代码是巨大而丑陋的。 这是一些C ++代码的翻译,并且必须定义所有的P / Invoke内容,这是更多的代码。 但是我已经testing过了,而且工作。 要使用它,你只需要像这样的东西:
MixerInfo mi = GetMixerControls(); AdjustVolume(mi, 100); // add 100 to the current volume
要么
MixerInfo mi = GetMixerControls(); AdjustVolume(mi, (mi.maxVolume - mi.minVolume) / 10); // increase the volume by 10% of total range
要么
MixerInfo mi = GetMixerControls(); SetVolume(mi, mi.maxVolume); // let's get this party crunk'd!
要么
MixerInfo mi = GetMixerControls(); SetMute(mi, true); // shhhh!!!!!!
警告
由于使用了固定大小的字段和字段偏移量,在64位Windows上可能会失败。 我不知道,我没有testing过,没有足够的注意,知道这些字段大小是否扩展到64位。 注意编码
编辑
为了简单起见(相对而言),我没有任何error handling。 你应该真的检查所有mixerXXX函数的返回代码,但是我将把它作为读者的练习(读作:我懒得做这个)。
对于主卷(对于Vista和以上版本),这将是:
ISimpleAudioVolume :: SetMasterVolume
正如这里所解释的,你可以参考下面的部分:
核心audioAPI在Windows Vista的更多。
此调用不是Media Foundation调用,而是WASAPI(Windowsaudio会话API)调用:ISimpleAudioVolume :: SetMasterVolume(SetMasterVolume方法设置audio会话的主音量级别。)
这可能是困难的,但是使媒体中心的用户界面反映了由该调用设置的新的声音级别,正如该线程所示 。
对于Windows XP,你可以学习这个脚本 ,也许这个其他的脚本 。
audio库也可能是有趣的。
还有这个老audio项目有一个主音量部分:
BOOL CVolumeDlg::amdInitialize() { ASSERT(m_hMixer == NULL); // get the number of mixer devices present in the system m_nNumMixers = ::mixerGetNumDevs(); m_hMixer = NULL; ::ZeroMemory(&m_mxcaps, sizeof(MIXERCAPS)); m_strDstLineName.Empty(); m_strVolumeControlName.Empty(); m_dwMinimum = 0; m_dwMaximum = 0; m_dwVolumeControlID = 0; // open the first mixer // A "mapper" for audio mixer devices does not currently exist. if (m_nNumMixers != 0) { if (::mixerOpen(&m_hMixer, 0, reinterpret_cast<DWORD>(this->GetSafeHwnd()), NULL, MIXER_OBJECTF_MIXER | CALLBACK_WINDOW) != MMSYSERR_NOERROR) { return FALSE; } if (::mixerGetDevCaps(reinterpret_cast<UINT>(m_hMixer), &m_mxcaps, sizeof(MIXERCAPS)) != MMSYSERR_NOERROR) { return FALSE; } } return TRUE; } BOOL CVolumeDlg::amdUninitialize() { BOOL bSucc = TRUE; if (m_hMixer != NULL) { bSucc = (::mixerClose(m_hMixer) == MMSYSERR_NOERROR); m_hMixer = NULL; } return bSucc; } BOOL CVolumeDlg::amdGetMasterVolumeControl() { if (m_hMixer == NULL) { return FALSE; } // get dwLineID MIXERLINE mxl; mxl.cbStruct = sizeof(MIXERLINE); mxl.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS; if (::mixerGetLineInfo(reinterpret_cast<HMIXEROBJ>(m_hMixer), &mxl, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE) != MMSYSERR_NOERROR) { return FALSE; } // get dwControlID MIXERCONTROL mxc; MIXERLINECONTROLS mxlc; mxlc.cbStruct = sizeof(MIXERLINECONTROLS); mxlc.dwLineID = mxl.dwLineID; mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; mxlc.cControls = 1; mxlc.cbmxctrl = sizeof(MIXERCONTROL); mxlc.pamxctrl = &mxc; if (::mixerGetLineControls(reinterpret_cast<HMIXEROBJ>(m_hMixer), &mxlc, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE) != MMSYSERR_NOERROR) { return FALSE; } // store dwControlID m_strDstLineName = mxl.szName; m_strVolumeControlName = mxc.szName; m_dwMinimum = mxc.Bounds.dwMinimum; m_dwMaximum = mxc.Bounds.dwMaximum; m_dwVolumeControlID = mxc.dwControlID; return TRUE; } BOOL CVolumeDlg::amdGetMasterVolumeValue(DWORD &dwVal) const { if (m_hMixer == NULL) { return FALSE; } MIXERCONTROLDETAILS_UNSIGNED mxcdVolume; MIXERCONTROLDETAILS mxcd; mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS); mxcd.dwControlID = m_dwVolumeControlID; mxcd.cChannels = 1; mxcd.cMultipleItems = 0; mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); mxcd.paDetails = &mxcdVolume; if (::mixerGetControlDetails(reinterpret_cast<HMIXEROBJ>(m_hMixer), &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR) { return FALSE; } dwVal = mxcdVolume.dwValue; return TRUE; } BOOL CVolumeDlg::amdSetMasterVolumeValue(DWORD dwVal) const { if (m_hMixer == NULL) { return FALSE; } MIXERCONTROLDETAILS_UNSIGNED mxcdVolume = { dwVal }; MIXERCONTROLDETAILS mxcd; mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS); mxcd.dwControlID = m_dwVolumeControlID; mxcd.cChannels = 1; mxcd.cMultipleItems = 0; mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); mxcd.paDetails = &mxcdVolume; if (::mixerSetControlDetails(reinterpret_cast<HMIXEROBJ>(m_hMixer), &mxcd, MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR) { return FALSE; } return TRUE; }
使用这个免费的图书馆,这很简单,做这项工作。 InputSimulator
它模拟一个按键。 你只需要添加这个引用,并调用任何你想要的静态方法,如:
InputSimulator.SimulateKeyPress(VirtualKeyCode.VOLUME_UP); InputSimulator.SimulateKeyPress(VirtualKeyCode.VOLUME_DOWN); InputSimulator.SimulateKeyPress(VirtualKeyCode.VOLUME_MUTE);
那么,如果你想获得主vokume水平做:
// volume update MMDevice defaultDevice = new MMDeviceEnumerator() .GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia); // veloce attesa per l'aggiornamento del volume Thread.Sleep(100); float level = defaultDevice.AudioEndpointVolume.MasterVolumeLevelScalar;
做到这一点,你将在目前的水平在0-1格式(例如52%是0.52)如果你想在0-100格式只是水平* 100