c# winapi volume

c# - Cambiar el nivel de volumen principal



winapi (3)

De acuerdo, aquí va:

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); }

Este código es enorme y feo. Es una traducción de algunos códigos C ++, y al tener que definir todas las cosas de P / Invoke, es mucho más código. Pero lo probé y funciona. Para usarlo, simplemente necesitas algo como:

MixerInfo mi = GetMixerControls(); AdjustVolume(mi, 100); // add 100 to the current volume

o

MixerInfo mi = GetMixerControls(); AdjustVolume(mi, (mi.maxVolume - mi.minVolume) / 10); // increase the volume by 10% of total range

o

MixerInfo mi = GetMixerControls(); SetVolume(mi, mi.maxVolume); // let''s get this party crunk''d!

o

MixerInfo mi = GetMixerControls(); SetMute(mi, true); // shhhh!!!!!!

ADVERTENCIA

Debido al uso de ints de tamaño fijo y offsets de campo, esto puede fallar fantásticamente en Windows de 64 bits. No sé, no lo he probado y no he prestado suficiente atención para saber si estos tamaños de campo se amplían a 64 bits. código de advertencia

EDITAR

En aras de la simplicidad (en términos relativos), he omitido el manejo de errores. Deberías verificar los códigos de retorno de todas las funciones de mixerXXX, pero lo dejaré como un ejercicio para el lector (léase como: yo era demasiado vago para hacer esto).

¿Cómo puedo cambiar el nivel de volumen maestro? Usando este código

[DllImport ("winmm.dll")] public static extern int waveOutSetVolume (IntPtr hwo, uint dwVolume); waveOutSetVolume (IntPtr.Zero, (((uint)uint.MaxValue & 0x0000ffff) | ((uint)uint.MaxValue << 16)));

Puedo configurar el volumen de la onda, pero si el volumen maestro es demasiado bajo, esto no tendrá ningún efecto.

Gracias por cualquier ayuda.


Para el volumen maestro (para Vista y superior), eso sería:

ISimpleAudioVolume :: SetMasterVolume

Como se explica aquí , puede consultar la sección:

Core Audio APIs en Windows Vista para más.

Esta llamada no es una llamada de Media Foundation sino una llamada WASAPI (API de sesión de audio de Windows): ISimpleAudioVolume :: SetMasterVolume (El método SetMasterVolume establece el nivel de volumen maestro para la sesión de audio).

Sin embargo, puede ser difícil hacer que la IU del Media Center refleje el nuevo nivel de sonido establecido por esa llamada, como lo ilustra este hilo .

Para Windows Xp, puedes estudiar este script y tal vez este otro script .
La biblioteca de audio también podría ser de interés.

También está este viejo proyecto de audio que tiene una parte de volumen principal:

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; }


Usa esta biblioteca gratuita, es simple y haz el trabajo. InputSimulator

Simula una pulsación de tecla. Solo tiene que agregar esta referencia y llamar donde desee métodos estáticos como estos:

InputSimulator.SimulateKeyPress(VirtualKeyCode.VOLUME_UP); InputSimulator.SimulateKeyPress(VirtualKeyCode.VOLUME_DOWN); InputSimulator.SimulateKeyPress(VirtualKeyCode.VOLUME_MUTE);

Entonces, si quieres obtener el nivel de maestro vokume hazlo:

// 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;

Al hacer esto, tendrá en nivel el volumen actual en formato 0-1 (por ejemplo, 52% es 0.52) Si desea tenerlo en formato 0-100 simplemente haga el nivel * 100