I’ve previously written about making adjustments to the Windows Master Volume control programmatically. I alluded to the addition of possible other features such as being able to view the volume levels of other applications. I’ve gone ahead and made those changes.
The first thing to reiterate is that this makes use of a low-level .NET Wrapper for the Windows Core Audio API. This can be found here.
The first thing I decided to define was an object to represent a single Applications Volume Session info/properties. In addition, it will be provided a reference to the IAudioSessionControl interface representing that application’s Audio session, so it can be directly manipulated by adjusting the properties of the class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
public class ApplicationVolumeInformation { private IAudioSessionControl AudioSession { get; set; } public uint ProcessID { get; set; } private float _Volume = 0; public float Volume { get { return _Volume; } set { _Volume = value; if(AudioSession !=null) { ISimpleAudioVolume vol = AudioSession as ISimpleAudioVolume; vol?.SetMasterVolume(_Volume, Guid.Empty); } } } public String Name { get; private set; } public String IconPath { get; private set; } public ApplicationVolumeInformation(IAudioSessionControl Session,uint pProcessID,float pVolume,String pName,String pIconPath) { AudioSession = Session; ProcessID = pProcessID; _Volume = pVolume; Name = pName; IconPath = pIconPath; } } |
Next, we need to declare a COM import, the Multimedia Device enumerator. Specifically, we need to import the class, as the Vannatech Library only provides interfaces, which we cannot instantiate:
1 2 3 4 5 |
[ComImport] [Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")] private class MMDeviceEnumerator { } |
Now that we have a starting point, we can create an enumerator method that retrieves all active audio sessions as “ApplicationVolumeInformation” instances:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
public static IEnumerable<ApplicationVolumeInformation> EnumerateApplications() { // get the speakers (1st render + multimedia) device IMMDeviceEnumerator deviceEnumerator = (IMMDeviceEnumerator)(new MMDeviceEnumerator()); IMMDevice speakers; deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia, out speakers); // activate the session manager. we need the enumerator Guid IID_IAudioSessionManager2 = typeof(IAudioSessionManager2).GUID; object o; speakers.Activate(IID_IAudioSessionManager2, 0, IntPtr.Zero, out o); IAudioSessionManager2 mgr = (IAudioSessionManager2)o; // enumerate sessions for on this device IAudioSessionEnumerator sessionEnumerator; mgr.GetSessionEnumerator(out sessionEnumerator); int count; sessionEnumerator.GetCount(out count); for (int i = 0; i < count; i++) { IAudioSessionControl ctl; sessionEnumerator.GetSession(i, out ctl); uint GetProcessID=0; String GetName = ""; float GetVolume = 0; String GetIconPath = ""; IAudioSessionControl getsession = null; getsession = ctl; if (ctl is IAudioSessionControl2) { IAudioSessionControl2 ctl2 = ((IAudioSessionControl2)ctl); ctl2.GetProcessId(out GetProcessID); ctl2.GetDisplayName(out GetName); String sIconPath; ctl2.GetIconPath(out sIconPath); ISimpleAudioVolume volcast = (ctl2 as ISimpleAudioVolume); float grabvolume; volcast.GetMasterVolume(out grabvolume); GetVolume = grabvolume; Process grabProcess = Process.GetProcessById((int)GetProcessID); if(String.IsNullOrEmpty(GetName)) { GetName = grabProcess.ProcessName; } } ApplicationVolumeInformation avi = new ApplicationVolumeInformation(getsession,GetProcessID,GetVolume,GetName,GetIconPath); yield return avi; Marshal.ReleaseComObject(ctl); } Marshal.ReleaseComObject(sessionEnumerator); Marshal.ReleaseComObject(mgr); Marshal.ReleaseComObject(speakers); Marshal.ReleaseComObject(deviceEnumerator); } |
A github repository with a more… complete… implementation of a working Console program can be found here.
Have something to say about this post? Comment!