如何使用PowerShell静音一个应用程序

7
我刚接触PowerShell并且最近一直在学习。我的问题是,如何使用PowerShell静音特定应用程序?例如,如果我正在使用Chrome观看YouTube视频,则只需进入音量混合器并将Chrome从应用程序列表中静音即可。是否有一种方法可以使用PowerShell实现这一点?
我找到了一篇关于如何使所有内容静音但不包括特定应用程序的文章。 Change audio level from powershell?

2
不是PowerShell,但可能仍然有用:http://www.nirsoft.net/utils/nircmd.html NirCmd提供了一个命令来静音特定的应用程序。 - David Brabant
1
Simon Mourier在这里发布了一个用C#编写的应用程序。您可以查看他在GetVolumeObject函数中所做的工作,并将其适应于PowerShell。 - JamesQMurphy
1
...或者在使用Add-Type之后,直接使用PowerShell中的相同方法。 - Joey
2个回答

2
我把发布在这里的示例应用程序封装在一个小的powershell脚本中,以便可以轻松地使用静态方法从Powershell中使用。只要指定正确的应用程序名称,这就是您要寻找的内容。
例如:
[SetAppVolume.AppMuter]::Mute("Mozilla Firefox");

示例代码:

$def = @"
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;

namespace SetAppVolume
{
    public class AppMuter
    {
        public static void Mute(string app)
        {
            foreach (string name in EnumerateApplications())
            {
                Console.WriteLine("name:" + name);
                if (name == app)
                {
                    // display mute state & volume level (% of master)
                    Console.WriteLine("Mute:" + GetApplicationMute(app));
                    Console.WriteLine("Volume:" + GetApplicationVolume(app));

                    // mute the application
                    SetApplicationMute(app, true);

                    // set the volume to half of master volume (50%)
                    SetApplicationVolume(app, 50);
                }
            }
        }

        public static float? GetApplicationVolume(string name)
        {
            ISimpleAudioVolume volume = GetVolumeObject(name);
            if (volume == null)
                return null;

            float level;
            volume.GetMasterVolume(out level);
            return level * 100;
        }

        public static bool? GetApplicationMute(string name)
        {
            ISimpleAudioVolume volume = GetVolumeObject(name);
            if (volume == null)
                return null;

            bool mute;
            volume.GetMute(out mute);
            return mute;
        }

        public static void SetApplicationVolume(string name, float level)
        {
            ISimpleAudioVolume volume = GetVolumeObject(name);
            if (volume == null)
                return;

            Guid guid = Guid.Empty;
            volume.SetMasterVolume(level / 100, ref guid);
        }

        public static void SetApplicationMute(string name, bool mute)
        {
            ISimpleAudioVolume volume = GetVolumeObject(name);
            if (volume == null)
                return;

            Guid guid = Guid.Empty;
            volume.SetMute(mute, ref guid);
        }

        public static IEnumerable<string> 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(ref 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);
                string dn;
                ctl.GetDisplayName(out dn);
                yield return dn;
                Marshal.ReleaseComObject(ctl);
            }
            Marshal.ReleaseComObject(sessionEnumerator);
            Marshal.ReleaseComObject(mgr);
            Marshal.ReleaseComObject(speakers);
            Marshal.ReleaseComObject(deviceEnumerator);
        }

        private static ISimpleAudioVolume GetVolumeObject(string name)
        {
            // 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(ref 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);

            // search for an audio session with the required name
            // NOTE: we could also use the process id instead of the app name (with IAudioSessionControl2)
            ISimpleAudioVolume volumeControl = null;
            for (int i = 0; i < count; i++)
            {
                IAudioSessionControl ctl;
                sessionEnumerator.GetSession(i, out ctl);
                string dn;
                ctl.GetDisplayName(out dn);
                if (string.Compare(name, dn, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    volumeControl = ctl as ISimpleAudioVolume;
                    break;
                }
                Marshal.ReleaseComObject(ctl);
            }
            Marshal.ReleaseComObject(sessionEnumerator);
            Marshal.ReleaseComObject(mgr);
            Marshal.ReleaseComObject(speakers);
            Marshal.ReleaseComObject(deviceEnumerator);
            return volumeControl;
        }
    }

    [ComImport]
    [Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
    internal class MMDeviceEnumerator
    {
    }

    internal enum EDataFlow
    {
        eRender,
        eCapture,
        eAll,
        EDataFlow_enum_count
    }

    internal enum ERole
    {
        eConsole,
        eMultimedia,
        eCommunications,
        ERole_enum_count
    }

    [Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IMMDeviceEnumerator
    {
        int NotImpl1();

        [PreserveSig]
        int GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, out IMMDevice ppDevice);

        // the rest is not implemented
    }

    [Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IMMDevice
    {
        [PreserveSig]
        int Activate(ref Guid iid, int dwClsCtx, IntPtr pActivationParams, [MarshalAs(UnmanagedType.IUnknown)] out object ppInterface);

        // the rest is not implemented
    }

    [Guid("77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IAudioSessionManager2
    {
        int NotImpl1();
        int NotImpl2();

        [PreserveSig]
        int GetSessionEnumerator(out IAudioSessionEnumerator SessionEnum);

        // the rest is not implemented
    }

    [Guid("E2F5BB11-0570-40CA-ACDD-3AA01277DEE8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IAudioSessionEnumerator
    {
        [PreserveSig]
        int GetCount(out int SessionCount);

        [PreserveSig]
        int GetSession(int SessionCount, out IAudioSessionControl Session);
    }

    [Guid("F4B1A599-7266-4319-A8CA-E70ACB11E8CD"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IAudioSessionControl
    {
        int NotImpl1();

        [PreserveSig]
        int GetDisplayName([MarshalAs(UnmanagedType.LPWStr)] out string pRetVal);

        // the rest is not implemented
    }

    [Guid("87CE5498-68D6-44E5-9215-6DA47EF883D8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface ISimpleAudioVolume
    {
        [PreserveSig]
        int SetMasterVolume(float fLevel, ref Guid EventContext);

        [PreserveSig]
        int GetMasterVolume(out float pfLevel);

        [PreserveSig]
        int SetMute(bool bMute, ref Guid EventContext);

        [PreserveSig]
        int GetMute(out bool pbMute);
    }
}
"@;


Add-Type -TypeDefinition $def -Language CSharpVersion3
# Example usage
[SetAppVolume.AppMuter]::Mute("Mozilla Firefox");

当我想要静音除了 Firefox 之外的其他应用程序时,输出为: 名称: 名称: 名称:Mozilla Firefox 名称: 名称:@%SystemRoot%\System32\AudioSrv.Dll,-202 名称: - Motte001

2

最近我读了一篇名为“特性标志作为服务:您想要的唯一方式”的文章,它清晰地表达了我的观点(我与rollout.io团队没有任何关联)。

软件界存在一个重要的争论,即构建 vs. 购买。任何有软件开发背景的人都会告诉你,重新发明轮子的诱惑是很强烈的。当然,任何语言的标准库都有优化的列表排序功能。但是,写自己的功能将是有趣和有意义的,并且你不必依赖其他人的方法...当你以编写软件为生时,你倾向于通过编写软件来应对障碍。你做你擅长的事情。这适用于个人,也适用于整个团队。但是,克服这种倾向并做出商业决策而不是情绪化的决策非常重要。

因此,我建议使用NirCmd 的 muteappvolume 功能,并构建一个小的 PowerShell 包装器以适应您的需求。在我的情况下,我有一个长时间播放的rain.mp3音频文件作为我的专注时段的背景音乐,使用无界面的 VLC 播放器。但是,当需要进行视频会议或者做一些单调的事情时,我需要切换静音/非静音。我通过在 PowerShell 的$profile中添加这段代码,在终端中按下r键即可切换静音/非静音。再次强调,这不仅仅是静音,而是静音/非静音的切换,因此我可以通过完全相同的方式取消静音。既然有如此酷的工具nircmd,就没有必要重新发明轮子了。

function toggleRain {
    $commandLineProperty = '"C:\Program Files\VideoLAN\VLC\vlc.exe" --intf dummy c:\Users\Admin\Music\rain.mp3'
    $rainPid = (Get-Process vlc | Where-Object {$_.CommandLine -eq $commandLineProperty}).Id
    nircmd muteappvolume /$rainPid 2
}

Set-Alias r toggleRain

谢谢,这对我非常有效!Harald的解决方案对我无效。 - Mike Anthony

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接