Skip to content

Instantly share code, notes, and snippets.

@Jaykul
Created July 19, 2016 18:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Jaykul/c3bd8580df8ea49cd3ac737008a9bcef to your computer and use it in GitHub Desktop.
Save Jaykul/c3bd8580df8ea49cd3ac737008a9bcef to your computer and use it in GitHub Desktop.
Playing With Volume...
Add-Type -Path C:\Users\JBennett\Source\Repos\SoundUtils\SoundUtils\SoundUtils.cs
$volume = [WOSI.Utilities.EndpointVolume]::new()
$volume | gm
foreach($channel in 0..($volume.GetChannelCount()-1)) {
[PSCustomObject]@{Channel = $channel; Volume = $volume.GetChannelVolume($channel) }
}
$volume.SetChannelVolume(0, 0.5)
foreach($channel in 0..($volume.GetChannelCount()-1)) {
[PSCustomObject]@{Channel = $channel; Volume = $volume.GetChannelVolume($channel) }
}
///////////////////////////////////////////////////////////////////////////////////////////////
//
// This File is Part of the CallButler Open Source PBX (http://www.codeplex.com/callbutler
//
// Copyright (c) 2005-2008, Jim Heising
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
//
// * Neither the name of Jim Heising nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////////////////////////
using System;
using System.Runtime.InteropServices;
using System.IO;
namespace WOSI.Utilities
{
/// <summary>
/// Summary description for SoundUtilities.
/// </summary>
public sealed class SoundUtils
{
public const int MMSYSERR_NOERROR = 0;
public const int MAXPNAMELEN = 32;
public const int MIXER_LONG_NAME_CHARS = 64;
public const int MIXER_SHORT_NAME_CHARS = 16;
public const int MIXER_GETLINEINFOF_COMPONENTTYPE = 0x3;
public const int MIXER_GETCONTROLDETAILSF_VALUE = 0x0;
public const int MIXER_GETLINECONTROLSF_ONEBYTYPE = 0x2;
public const int MIXER_SETCONTROLDETAILSF_VALUE = 0x0;
public const int MIXERLINE_COMPONENTTYPE_DST_FIRST = 0x0;
public const int MIXERLINE_COMPONENTTYPE_SRC_FIRST = 0x1000;
public const int MIXERLINE_COMPONENTTYPE_DST_SPEAKERS = (MIXERLINE_COMPONENTTYPE_DST_FIRST + 4);
public const int MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 3);
public const int MIXERLINE_COMPONENTTYPE_SRC_LINE = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 2);
public const int MIXERCONTROL_CT_CLASS_FADER = 0x50000000;
public const int MIXERCONTROL_CT_UNITS_UNSIGNED = 0x30000;
public const int MIXERCONTROL_CT_CLASS_SWITCH = 0x20000000;
public const int MIXERCONTROL_CT_SC_SWITCH_BOOLEAN = 0x0;
public const int MIXERCONTROL_CT_UNITS_BOOLEAN = 0x10000;
public const int MIXERCONTROL_CONTROLTYPE_FADER = (MIXERCONTROL_CT_CLASS_FADER | MIXERCONTROL_CT_UNITS_UNSIGNED);
public const int MIXERCONTROL_CONTROLTYPE_VOLUME = (MIXERCONTROL_CONTROLTYPE_FADER + 1);
public const int MIXERCONTROL_CONTROLTYPE_BOOLEAN = (MIXERCONTROL_CT_CLASS_SWITCH | MIXERCONTROL_CT_SC_SWITCH_BOOLEAN | MIXERCONTROL_CT_UNITS_BOOLEAN);
public const int MIXERCONTROL_CONTROLTYPE_MUTE = (MIXERCONTROL_CONTROLTYPE_BOOLEAN + 2);
public struct MIXERCAPS
{
public int wMid;
public int wPid;
public int vDriverVersion;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAXPNAMELEN)]
public string szPname;
public int fdwSupport;
public int cDestinations;
}
public struct MIXERCONTROL
{
public int cbStruct;
public int dwControlID;
public int dwControlType;
public int fdwControl;
public int cMultipleItems;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MIXER_SHORT_NAME_CHARS)]
public string szShortName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MIXER_LONG_NAME_CHARS)]
public string szName;
public int lMinimum;
public int lMaximum;
[MarshalAs(UnmanagedType.U4, SizeConst = 10)]
public int reserved;
}
public struct MIXERCONTROLDETAILS
{
public int cbStruct;
public int dwControlID;
public int cChannels;
public int item;
public int cbDetails;
public IntPtr paDetails;
}
public struct MIXERCONTROLDETAILS_UNSIGNED
{
public int dwValue;
}
public struct MIXERCONTROLDETAILS_BOOLEAN
{
public int dwValue;
}
public struct MIXERLINE
{
public int cbStruct;
public int dwDestination;
public int dwSource;
public int dwLineID;
public int fdwLine;
public int dwUser;
public int dwComponentType;
public int cChannels;
public int cConnections;
public int cControls;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MIXER_SHORT_NAME_CHARS)]
public string szShortName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MIXER_LONG_NAME_CHARS)]
public string szName;
public int dwType;
public int dwDeviceID;
public int wMid;
public int wPid;
public int vDriverVersion;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAXPNAMELEN)]
public string szPname;
}
public struct MIXERLINECONTROLS
{
public int cbStruct;
public int dwLineID;
public int dwControl;
public int cControls;
public int cbmxctrl;
public IntPtr pamxctrl;
}
[DllImport("winmm.dll", CharSet = CharSet.Ansi)]
public static extern int mixerClose(int hmx);
[DllImport("winmm.dll", CharSet = CharSet.Ansi)]
public static extern int mixerGetControlDetailsA(int hmxobj, ref MIXERCONTROLDETAILS pmxcd, int fdwDetails);
[DllImport("winmm.dll", CharSet = CharSet.Ansi)]
public static extern int mixerGetDevCapsA(int uMxId, MIXERCAPS pmxcaps, int cbmxcaps);
[DllImport("winmm.dll", CharSet = CharSet.Ansi)]
public static extern int mixerGetID(int hmxobj, int pumxID, int fdwId);
[DllImport("winmm.dll", CharSet = CharSet.Ansi)]
public static extern int mixerGetLineControlsA(int hmxobj, ref MIXERLINECONTROLS pmxlc, int fdwControls);
[DllImport("winmm.dll", CharSet = CharSet.Ansi)]
public static extern int mixerGetLineInfoA(int hmxobj, ref MIXERLINE pmxl, int fdwInfo);
[DllImport("winmm.dll", CharSet = CharSet.Ansi)]
public static extern int mixerGetNumDevs();
[DllImport("winmm.dll", CharSet = CharSet.Ansi)]
public static extern int mixerMessage(int hmx, int uMsg, int dwParam1, int dwParam2);
[DllImport("winmm.dll", CharSet = CharSet.Ansi)]
public static extern int mixerOpen(out int phmx, int uMxId, int dwCallback, int dwInstance, int fdwOpen);
[DllImport("winmm.dll", CharSet = CharSet.Ansi)]
public static extern int mixerSetControlDetails(int hmxobj, ref MIXERCONTROLDETAILS pmxcd, int fdwDetails);
[DllImport("winmm.dll", EntryPoint = "sndPlaySoundA")]
public static extern int sndPlaySound(string lpszSoundName, int uFlags);
public const int SND_ASYNC = 0x1;
public const int SND_LOOP = 0x8;
public SoundUtils()
{
}
public static void PlaySound(string filename, bool loop)
{
if (File.Exists(filename))
{
if (loop)
sndPlaySound(filename, SND_ASYNC | SND_LOOP);
else
sndPlaySound(filename, SND_ASYNC);
}
}
public static void StopSound()
{
sndPlaySound(null, SND_ASYNC);
}
public static void Mute(bool mute)
{
// Check if this is vista or XP
if (System.Environment.OSVersion.Version.Major >= 6)
{
EndpointVolume epVol = new EndpointVolume();
epVol.Mute = mute;
epVol.Dispose();
}
else
{
int mixerID = 0;
if (mixerOpen(out mixerID, 0, 0, 0, 0) == MMSYSERR_NOERROR)
{
MIXERLINE line = new MIXERLINE();
line.cbStruct = Marshal.SizeOf(line);
line.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
if (mixerGetLineInfoA(mixerID, ref line, MIXER_GETLINEINFOF_COMPONENTTYPE) == MMSYSERR_NOERROR)
{
int sizeofMIXERCONTROL = 152;
MIXERCONTROL mixerControl = new MIXERCONTROL();
MIXERLINECONTROLS lineControl = new MIXERLINECONTROLS();
lineControl.pamxctrl = Marshal.AllocCoTaskMem(sizeofMIXERCONTROL);
lineControl.cbStruct = Marshal.SizeOf(lineControl);
lineControl.dwLineID = line.dwLineID;
lineControl.dwControl = MIXERCONTROL_CONTROLTYPE_MUTE;
lineControl.cControls = 1;
lineControl.cbmxctrl = sizeofMIXERCONTROL;
mixerControl.cbStruct = sizeofMIXERCONTROL;
if (mixerGetLineControlsA(mixerID, ref lineControl, MIXER_GETLINECONTROLSF_ONEBYTYPE) == MMSYSERR_NOERROR)
{
mixerControl = (MIXERCONTROL)Marshal.PtrToStructure(lineControl.pamxctrl, typeof(MIXERCONTROL));
MIXERCONTROLDETAILS controlDetails = new MIXERCONTROLDETAILS();
MIXERCONTROLDETAILS_BOOLEAN muteValue = new MIXERCONTROLDETAILS_BOOLEAN();
controlDetails.item = 0;
controlDetails.dwControlID = mixerControl.dwControlID;
controlDetails.cbStruct = Marshal.SizeOf(controlDetails);
controlDetails.cbDetails = Marshal.SizeOf(muteValue);
controlDetails.cChannels = 1;
muteValue.dwValue = Convert.ToInt32(mute);
controlDetails.paDetails = Marshal.AllocCoTaskMem(Marshal.SizeOf(muteValue));
Marshal.StructureToPtr(muteValue, controlDetails.paDetails, false);
int rc = mixerSetControlDetails(mixerID, ref controlDetails, MIXER_SETCONTROLDETAILSF_VALUE);
Marshal.FreeCoTaskMem(controlDetails.paDetails);
Marshal.FreeCoTaskMem(lineControl.pamxctrl);
}
}
}
}
}
}
public class EndpointVolume
{
private readonly Guid GuidEventContext = Guid.NewGuid();
#region Interface to COM objects
const int DEVICE_STATE_ACTIVE = 0x00000001;
const int DEVICE_STATE_DISABLE = 0x00000002;
const int DEVICE_STATE_NOTPRESENT = 0x00000004;
const int DEVICE_STATE_UNPLUGGED = 0x00000008;
const int DEVICE_STATEMASK_ALL = 0x0000000f;
[DllImport("ole32.Dll")]
static public extern uint CoCreateInstance(
ref Guid clsid,
[MarshalAs(UnmanagedType.IUnknown)] object inner,
uint context,
ref Guid uuid,
[MarshalAs(UnmanagedType.IUnknown)] out object rReturnedComObject);
// C Header file : Include Mmdeviceapi.h (Windows Vista SDK)
[Guid("5CDF2C82-841E-4546-9722-0CF74078229A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAudioEndpointVolume
{
//virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE RegisterControlChangeNotify(/* [in] */__in IAudioEndpointVolumeCallback *pNotify) = 0;
//int RegisterControlChangeNotify(IntPtr pNotify);
int RegisterControlChangeNotify(DelegateMixerChange pNotify);
//virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE UnregisterControlChangeNotify(/* [in] */ __in IAudioEndpointVolumeCallback *pNotify) = 0;
//int UnregisterControlChangeNotify(IntPtr pNotify);
int UnregisterControlChangeNotify(DelegateMixerChange pNotify);
//virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetChannelCount(/* [out] */ __out UINT *pnChannelCount) = 0;
int GetChannelCount(ref uint pnChannelCount);
//virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE SetMasterVolumeLevel( /* [in] */ __in float fLevelDB,/* [unique][in] */ LPCGUID pguidEventContext) = 0;
int SetMasterVolumeLevel(float fLevelDB, Guid pguidEventContext);
//virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE SetMasterVolumeLevelScalar( /* [in] */ __in float fLevel,/* [unique][in] */ LPCGUID pguidEventContext) = 0;
int SetMasterVolumeLevelScalar(float fLevel, Guid pguidEventContext);
//virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetMasterVolumeLevel(/* [out] */ __out float *pfLevelDB) = 0;
int GetMasterVolumeLevel(ref float pfLevelDB);
//virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetMasterVolumeLevelScalar( /* [out] */ __out float *pfLevel) = 0;
int GetMasterVolumeLevelScalar(ref float pfLevel);
//virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE SetChannelVolumeLevel(/* [in] */__in UINT nChannel,float fLevelDB,/* [unique][in] */ LPCGUID pguidEventContext) = 0;
int SetChannelVolumeLevel(uint nChannel, float fLevelDB, Guid pguidEventContext);
//virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE SetChannelVolumeLevelScalar(/* [in] */ __in UINT nChannel,float fLevel,/* [unique][in] */ LPCGUID pguidEventContext) = 0;
int SetChannelVolumeLevelScalar(uint nChannel, float fLevel, Guid pguidEventContext);
//virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetChannelVolumeLevel(/* [in] */ __in UINT nChannel,/* [out] */__out float *pfLevelDB) = 0;
int GetChannelVolumeLevel(uint nChannel, ref float pfLevelDB);
//virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetChannelVolumeLevelScalar(/* [in] */__in UINT nChannel,/* [out] */__out float *pfLevel) = 0;
int GetChannelVolumeLevelScalar(uint nChannel, ref float pfLevel);
//virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE SetMute( /* [in] *__in BOOL bMute, /* [unique][in] */ LPCGUID pguidEventContext) = 0;
int SetMute(int bMute, Guid pguidEventContext);
//virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetMute( /* [out] */ __out BOOL *pbMute) = 0;
int GetMute(ref bool pbMute);
//virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetVolumeStepInfo( /* [out] */ __out UINT *pnStep,/* [out] */__out UINT *pnStepCount) = 0;
int GetVolumeStepInfo(ref uint pnStep, ref uint pnStepCount);
//virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE VolumeStepUp( /* [unique][in] */ LPCGUID pguidEventContext) = 0;
int VolumeStepUp(Guid pguidEventContext);
//virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE VolumeStepDown(/* [unique][in] */ LPCGUID pguidEventContext) = 0;
int VolumeStepDown(Guid pguidEventContext);
//virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE QueryHardwareSupport(/* [out] */ __out DWORD *pdwHardwareSupportMask) = 0;
int QueryHardwareSupport(ref uint pdwHardwareSupportMask);
//virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetVolumeRange( /* [out] */ __out float *pflVolumeMindB,/* [out] */ __out float *pflVolumeMaxdB,/* [out] */ __out float *pflVolumeIncrementdB) = 0;
int GetVolumeRange(ref float pflVolumeMindB, ref float pflVolumeMaxdB, ref float pflVolumeIncrementdB);
}
[Guid("0BD7A1BE-7A1A-44DB-8397-CC5392387B5E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IMMDeviceCollection
{
//HRESULT GetCount([out, annotation("__out")] UINT* pcDevices);
int GetCount(ref uint pcDevices);
//HRESULT Item([in, annotation("__in")]UINT nDevice, [out, annotation("__out")] IMMDevice** ppDevice);
int Item(uint nDevice, ref IntPtr ppDevice);
}
[Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IMMDevice
{
//HRESULT Activate([in, annotation("__in")] REFIID iid, [in, annotation("__in")] DWORD dwClsCtx, [in,unique, annotation("__in_opt")] PROPVARIANT* pActivationParams, [out,iid_is(iid), annotation("__out")] void** ppInterface);
int Activate(ref Guid iid, uint dwClsCtx, IntPtr pActivationParams, ref IntPtr ppInterface);
//HRESULT OpenPropertyStore([in, annotation("__in")] DWORD stgmAccess, [out, annotation("__out")] IPropertyStore** ppProperties);
int OpenPropertyStore(int stgmAccess, ref IntPtr ppProperties);
//HRESULT GetId([out,annotation("__deref_out")] LPWSTR* ppstrId);
int GetId(ref string ppstrId);
//HRESULT GetState([out, annotation("__out")] DWORD* pdwState);
int GetState(ref int pdwState);
}
[Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] //[Guid("BCDE0395-E52F-467C-8E3D-C4579291692E"),
public interface IMMDeviceEnumerator
{
//HRESULT EnumAudioEndpoints([in, annotation("__in")] EDataFlow dataFlow, [in, annotation("__in")] DWORD dwStateMask, [out, annotation("__out")] IMMDeviceCollection** ppDevices);
int EnumAudioEndpoints(EDataFlow dataFlow, int dwStateMask, ref IntPtr ppDevices);
//HRESULT GetDefaultAudioEndpoint([in, annotation("__in")] EDataFlow dataFlow, [in, annotation("__in")] ERole role, [out, annotation("__out")] IMMDevice** ppEndpoint);
int GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, ref IntPtr ppEndpoint);
//HRESULT GetDevice([, annotation("__in")]LPCWSTR pwstrId, [out, annotation("__out")] IMMDevice** ppDevice);
int GetDevice(string pwstrId, ref IntPtr ppDevice);
//HRESULT RegisterEndpointNotificationCallback([in, annotation("__in")] IMMNotificationClient* pClient);
int RegisterEndpointNotificationCallback(IntPtr pClient);
//HRESULT UnregisterEndpointNotificationCallback([in, annotation("__in")] IMMNotificationClient* pClient);
int UnregisterEndpointNotificationCallback(IntPtr pClient);
}
[Flags]
enum CLSCTX : uint
{
CLSCTX_INPROC_SERVER = 0x1,
CLSCTX_INPROC_HANDLER = 0x2,
CLSCTX_LOCAL_SERVER = 0x4,
CLSCTX_INPROC_SERVER16 = 0x8,
CLSCTX_REMOTE_SERVER = 0x10,
CLSCTX_INPROC_HANDLER16 = 0x20,
CLSCTX_RESERVED1 = 0x40,
CLSCTX_RESERVED2 = 0x80,
CLSCTX_RESERVED3 = 0x100,
CLSCTX_RESERVED4 = 0x200,
CLSCTX_NO_CODE_DOWNLOAD = 0x400,
CLSCTX_RESERVED5 = 0x800,
CLSCTX_NO_CUSTOM_MARSHAL = 0x1000,
CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000,
CLSCTX_NO_FAILURE_LOG = 0x4000,
CLSCTX_DISABLE_AAA = 0x8000,
CLSCTX_ENABLE_AAA = 0x10000,
CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000,
CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER,
CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER,
CLSCTX_ALL = CLSCTX_SERVER | CLSCTX_INPROC_HANDLER
}
public enum EDataFlow
{
eRender,
eCapture,
eAll,
EDataFlow_enum_count
}
public enum ERole
{
eConsole,
eMultimedia,
eCommunications,
ERole_enum_count
}
#endregion
// public internal var
object oEnumerator = null;
IMMDeviceEnumerator iMde = null;
object oDevice = null;
IMMDevice imd = null;
object oEndPoint = null;
IAudioEndpointVolume iAudioEndpoint = null;
// TODO
// Problem #1 : I can't handle a volume changed event by other applications
// (example while using the program SndVol.exe)
public delegate void DelegateMixerChange();
//public DelegateMixerChange delMixerChange = null;
public delegate void MixerChangedEventHandler();
//public event MixerChangedEventHandler MixerChanged;
#region Class Constructor and Dispose public methods
/// <summary>
/// Constructor
/// </summary>
public EndpointVolume()
{
const uint CLSCTX_INPROC_SERVER = 1;
Guid clsid = new Guid("BCDE0395-E52F-467C-8E3D-C4579291692E");
Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");
oEnumerator = null;
uint hResult = CoCreateInstance(ref clsid, null, CLSCTX_INPROC_SERVER, ref IID_IUnknown, out oEnumerator);
if (hResult != 0 || oEnumerator == null)
{
throw new Exception("CoCreateInstance() pInvoke failed");
}
iMde = oEnumerator as IMMDeviceEnumerator;
if (iMde == null)
{
throw new Exception("COM cast failed to IMMDeviceEnumerator");
}
IntPtr pDevice = IntPtr.Zero;
int retVal = iMde.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eConsole, ref pDevice);
if (retVal != 0)
{
throw new Exception("IMMDeviceEnumerator.GetDefaultAudioEndpoint()");
}
int dwStateMask = DEVICE_STATE_ACTIVE | DEVICE_STATE_NOTPRESENT | DEVICE_STATE_UNPLUGGED;
IntPtr pCollection = IntPtr.Zero;
retVal = iMde.EnumAudioEndpoints(EDataFlow.eRender, dwStateMask, ref pCollection);
if (retVal != 0)
{
throw new Exception("IMMDeviceEnumerator.EnumAudioEndpoints()");
}
oDevice = System.Runtime.InteropServices.Marshal.GetObjectForIUnknown(pDevice);
imd = oDevice as IMMDevice;
if (imd == null)
{
throw new Exception("COM cast failed to IMMDevice");
}
Guid iid = new Guid("5CDF2C82-841E-4546-9722-0CF74078229A");
uint dwClsCtx = (uint)CLSCTX.CLSCTX_ALL;
IntPtr pActivationParams = IntPtr.Zero;
IntPtr pEndPoint = IntPtr.Zero;
retVal = imd.Activate(ref iid, dwClsCtx, pActivationParams, ref pEndPoint);
if (retVal != 0)
{
throw new Exception("IMMDevice.Activate()");
}
oEndPoint = System.Runtime.InteropServices.Marshal.GetObjectForIUnknown(pEndPoint);
iAudioEndpoint = oEndPoint as IAudioEndpointVolume;
if (iAudioEndpoint == null)
{
throw new Exception("COM cast failed to IAudioEndpointVolume");
}
/*
delMixerChange = new DelegateMixerChange(MixerChange);
retVal = iAudioEndpoint.RegisterControlChangeNotify(delMixerChange);
if (retVal != 0)
{
throw new Exception("iAudioEndpoint.RegisterControlChangeNotify(delMixerChange)");
}
*/
}
/// <summary>
/// Call this method to release all com objetcs
/// </summary>
public virtual void Dispose()
{
/*
if (delMixerChange != null && iAudioEndpoint != null)
{
iAudioEndpoint.UnregisterControlChangeNotify(delMixerChange);
}
*/
if (iAudioEndpoint != null)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(iAudioEndpoint);
iAudioEndpoint = null;
}
if (oEndPoint != null)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(oEndPoint);
oEndPoint = null;
}
if (imd != null)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(imd);
imd = null;
}
if (oDevice != null)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(oDevice);
oDevice = null;
}
//System.Runtime.InteropServices.Marshal.ReleaseComObject(pCollection);
if (iMde != null)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(iMde);
iMde = null;
}
if (oEnumerator != null)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(oEnumerator);
oEnumerator = null;
}
}
#endregion
#region public internal functions
public void MixerChange()
{
/*
if (MixerChanged != null)
// Notify (raise) event
MixerChanged();
*/
}
#endregion
#region Public properties
/// <summary>
/// Get/set the master mute. WARNING : The set mute do NOT work!
/// </summary>
public bool Mute
{
get
{
bool mute = false;
int retVal = iAudioEndpoint.GetMute(ref mute);
if (retVal != 0)
{
throw new Exception("IAudioEndpointVolume.GetMute() failed!");
}
return mute;
}
set
{
// TODO
// Problem #2 : This function always terminate with an internal error!
int retVal = iAudioEndpoint.SetMute(Convert.ToInt32(value), GuidEventContext);
if (retVal != 0)
{
throw new Exception("IAudioEndpointVolume.SetMute() failed!");
}
}
}
/// <summary>
/// Get/set the master volume level. Valid range is from 0.00F (0%) to 1.00F (100%).
/// </summary>
public float MasterVolume
{
get
{
float level = 0.0F;
int retVal = iAudioEndpoint.GetMasterVolumeLevelScalar(ref level);
if (retVal != 0)
{
throw new Exception("IAudioEndpointVolume.GetMasterVolumeLevelScalar()");
}
return level;
}
set
{
int retVal = iAudioEndpoint.SetMasterVolumeLevelScalar(value, GuidEventContext);
if (retVal != 0)
{
throw new Exception("IAudioEndpointVolume.SetMasterVolumeLevelScalar()");
}
}
}
public uint GetChannelCount()
{
uint result = 0;
int retVal = iAudioEndpoint.GetChannelCount(ref result);
Marshal.ThrowExceptionForHR(retVal);
return result;
}
public float GetChannelVolume(uint channel)
{
float level = 0.0F;
int retVal = iAudioEndpoint.GetChannelVolumeLevelScalar(channel, ref level);
Marshal.ThrowExceptionForHR(retVal);
return level;
}
public void SetChannelVolume(uint channel, float level)
{
int retVal = iAudioEndpoint.SetChannelVolumeLevelScalar(channel, level, GuidEventContext);
Marshal.ThrowExceptionForHR(retVal);
}
#endregion
#region Public Methods
/// <summary>
/// Increase the master volume
/// </summary>
public void VolumeUp()
{
int retVal = iAudioEndpoint.VolumeStepUp(GuidEventContext);
Marshal.ThrowExceptionForHR(retVal);
}
/// <summary>
/// Decrease the master volume
/// </summary>
public void VolumeDown()
{
int retVal = iAudioEndpoint.VolumeStepDown(GuidEventContext);
Marshal.ThrowExceptionForHR(retVal);
}
#endregion
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment