Search code examples
c#winapiwinmm

C# mute other application


I am building an app that starts a screen recorder application (like OBS) automatically (to record a zoom meeting).

I don't want any other application's audio to play during the recording, but I can't find a working code.

I used the example in this site with some code from here just to check the API

public enum MMRESULT : uint
{
    // Source: https://www.pinvoke.net/default.aspx/winmm/MMRESULT.html?diff=y
    MMSYSERR_NOERROR    = 0,
    MMSYSERR_ERROR      = 1,
    MMSYSERR_BADDEVICEID    = 2,
    MMSYSERR_NOTENABLED     = 3,
    MMSYSERR_ALLOCATED      = 4,
    MMSYSERR_INVALHANDLE    = 5,
    MMSYSERR_NODRIVER       = 6,
    MMSYSERR_NOMEM      = 7,
    MMSYSERR_NOTSUPPORTED   = 8,
    MMSYSERR_BADERRNUM      = 9,
    MMSYSERR_INVALFLAG      = 10,
    MMSYSERR_INVALPARAM     = 11,
    MMSYSERR_HANDLEBUSY     = 12,
    MMSYSERR_INVALIDALIAS   = 13,
    MMSYSERR_BADDB      = 14,
    MMSYSERR_KEYNOTFOUND    = 15,
    MMSYSERR_READERROR      = 16,
    MMSYSERR_WRITEERROR     = 17,
    MMSYSERR_DELETEERROR    = 18,
    MMSYSERR_VALNOTFOUND    = 19,
    MMSYSERR_NODRIVERCB     = 20,
    WAVERR_BADFORMAT    = 32,
    WAVERR_STILLPLAYING     = 33,
    WAVERR_UNPREPARED       = 34
}

[DllImport("winmm.dll")]
public static extern MMRESULT waveOutGetVolume(IntPtr hwo, out uint dwVolume);
[DllImport("winmm.dll")]
public static extern MMRESULT waveOutSetVolume(IntPtr hwo, uint dwVolume);
public static void Main(string[] args)
{
    foreach (Process process in Process.GetProcesses())
    {
        if (process.MainWindowHandle != IntPtr.Zero)
        {
            // Source: https://sites.google.com/site/lalitpundir/s-1
            try
            {
                uint CurrVol = 0;
                // At this point, CurrVol gets assigned the volume
                MMRESULT res = waveOutGetVolume(process.Handle, out CurrVol);
                // Calculate the volume
                ushort CalcVol = (ushort)(CurrVol & 0x0000ffff);
                // Get the volume on a scale of 1 to 10 (to fit the trackbar)
                Console.WriteLine($"The volume of {process.ProcessName} is {CalcVol / (ushort.MaxValue / 10)}");
                // Try muting chrome
                if (process.ProcessName.Equals("chrome"))
                {
                    Console.WriteLine("Muting chrome");
                    int NewVolume = 0;
                    uint NewVolumeAllChannels = (((uint)NewVolume & 0x0000ffff) | ((uint)NewVolume << 16));
                    res = waveOutSetVolume(process.Handle, NewVolumeAllChannels);
                    Console.WriteLine(res);
                    Thread.Sleep(5000);
                }
            }
            catch (Win32Exception e)
            {
                Console.WriteLine($"Error with {process.ProcessName}");
            }
        }
    }

}

The above code, always returns MMSYSERR_BADDEVICEID for the waveOutGetVolume and waveOutSetVolume methods.


Solution

  • Thanks you Make that 4 for the help.

    The links you provided helped me find this answer,, which I modified a bit to fit my needs.

    First of all, this answer requires the NuGet package CSCore.

    This is an example code that I used (I am still learning the package):

    public class MixerTest
    {
        static void Main(string[] args)
        {
            foreach (AudioSessionManager2 sessionManager in GetDefaultAudioSessionManager2(DataFlow.Render))
            {
                using (sessionManager)
                {
                    using (var sessionEnumerator = sessionManager.GetSessionEnumerator())
                    {
                        foreach (var session in sessionEnumerator)
                        {
                            using var simpleVolume = session.QueryInterface<SimpleAudioVolume>();
                            using var sessionControl = session.QueryInterface<AudioSessionControl2>();
                            Console.WriteLine((sessionControl.Process.ProcessName, sessionControl.SessionIdentifier));
                            if (Process.GetProcessById(sessionControl.ProcessID).ProcessName.Equals("chrome"))
                            {
                                simpleVolume.IsMuted = true;
                            }
                        }
                    }
                }
            }
    
            Console.ReadKey();
        }
        private static IEnumerable<AudioSessionManager2> GetDefaultAudioSessionManager2(DataFlow dataFlow)
        {
            using var enumerator = new MMDeviceEnumerator();
            using var devices = enumerator.EnumAudioEndpoints(dataFlow, DeviceState.Active);
            foreach (var device in devices)
            {
                Console.WriteLine("Device: " + device.FriendlyName);
                var sessionManager = AudioSessionManager2.FromMMDevice(device);
                yield return sessionManager;
            }
        }
    }