2

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.

SagiZiv
  • 932
  • 1
  • 16
  • 38
  • 1
    Those people in the meeting will be upset when they find they've been recorded without their knowledge – David Heffernan Dec 13 '21 at 02:45
  • Obviously, that's why I keep it to myself. All the recordings are for myself, so I can go over them later on. – SagiZiv Dec 13 '21 at 02:58
  • SO, I _think_, is generally not the place to judge a question's motive, but in this case - and given your recent comment - I would strongly advice not to do this. You will certainly violate some data protection / privace act, regulation, standards or similar (corporate, governmental or just "implied" between two private persons). That could have dire consequences for you. Just saying... YMMV – Christian.K Dec 13 '21 at 07:49
  • 1
    If it's just for you then you could use OBS. So it doesn't make much sense to me. And yes it is ethically unacceptable to do this. – David Heffernan Dec 13 '21 at 08:05
  • A combination of [EarTrumpet](https://eartrumpet.app/) and [OBS](https://obsproject.com/) does what you're asking for. No heavy-handed custom code required. – IInspectable Dec 13 '21 at 08:58
  • waveOutSetVolume 1st parameter has nothing to do with a process handle. – Simon Mourier Dec 13 '21 at 09:03
  • "mute other application"——You could try to use [WASAPI](https://learn.microsoft.com/en-us/windows/win32/coreaudio/wasapi) and an [exclusive mode stream](https://learn.microsoft.com/en-us/windows/win32/coreaudio/exclusive-mode-streams?redirectedfrom=MSDN). – Jeaninez - MSFT Dec 14 '21 at 03:01
  • Maybe https://stackoverflow.com/questions/14306048/controlling-volume-mixer or https://stackoverflow.com/questions/21200825/ ? – Make that 4 Dec 15 '21 at 11:43
  • @make-that-4 thank you for the help ‍ – SagiZiv Dec 15 '21 at 20:57

1 Answers1

3

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;
        }
    }
}
SagiZiv
  • 932
  • 1
  • 16
  • 38