尝试编写一个 PowerShell cmdlet,它将在开始时静音,除非已经静音,并在最后取消静音(只有在开始时没有静音)。找不到我可以使用的任何 PoweShell 或 WMI 对象。我正在玩弄使用auxGetVolume或auxSetVolume 之类的 Win32 函数,但不能完全让它工作(如何从 IntPtr 读取值?)。
我正在使用 V2 CTP2。有什么想法吗?
谢谢!
尝试编写一个 PowerShell cmdlet,它将在开始时静音,除非已经静音,并在最后取消静音(只有在开始时没有静音)。找不到我可以使用的任何 PoweShell 或 WMI 对象。我正在玩弄使用auxGetVolume或auxSetVolume 之类的 Win32 函数,但不能完全让它工作(如何从 IntPtr 读取值?)。
我正在使用 V2 CTP2。有什么想法吗?
谢谢!
从 Vista 开始,您必须使用Core Audio API来控制系统音量。它是一个不支持自动化的 COM API,因此需要从 .NET 和 PowerShell 使用大量样板文件。
无论如何,下面的代码让您可以从 PowerShell 访问[Audio]::Volume
和[Audio]::Mute
属性。这也适用于可能有用的远程计算机。只需将代码复制粘贴到您的 PowerShell 窗口中即可。
Add-Type -TypeDefinition @'
using System.Runtime.InteropServices;
[Guid("5CDF2C82-841E-4546-9722-0CF74078229A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IAudioEndpointVolume {
// f(), g(), ... are unused COM method slots. Define these if you care
int f(); int g(); int h(); int i();
int SetMasterVolumeLevelScalar(float fLevel, System.Guid pguidEventContext);
int j();
int GetMasterVolumeLevelScalar(out float pfLevel);
int k(); int l(); int m(); int n();
int SetMute([MarshalAs(UnmanagedType.Bool)] bool bMute, System.Guid pguidEventContext);
int GetMute(out bool pbMute);
}
[Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IMMDevice {
int Activate(ref System.Guid id, int clsCtx, int activationParams, out IAudioEndpointVolume aev);
}
[Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IMMDeviceEnumerator {
int f(); // Unused
int GetDefaultAudioEndpoint(int dataFlow, int role, out IMMDevice endpoint);
}
[ComImport, Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")] class MMDeviceEnumeratorComObject { }
public class Audio {
static IAudioEndpointVolume Vol() {
var enumerator = new MMDeviceEnumeratorComObject() as IMMDeviceEnumerator;
IMMDevice dev = null;
Marshal.ThrowExceptionForHR(enumerator.GetDefaultAudioEndpoint(/*eRender*/ 0, /*eMultimedia*/ 1, out dev));
IAudioEndpointVolume epv = null;
var epvid = typeof(IAudioEndpointVolume).GUID;
Marshal.ThrowExceptionForHR(dev.Activate(ref epvid, /*CLSCTX_ALL*/ 23, 0, out epv));
return epv;
}
public static float Volume {
get {float v = -1; Marshal.ThrowExceptionForHR(Vol().GetMasterVolumeLevelScalar(out v)); return v;}
set {Marshal.ThrowExceptionForHR(Vol().SetMasterVolumeLevelScalar(value, System.Guid.Empty));}
}
public static bool Mute {
get { bool mute; Marshal.ThrowExceptionForHR(Vol().GetMute(out mute)); return mute; }
set { Marshal.ThrowExceptionForHR(Vol().SetMute(value, System.Guid.Empty)); }
}
}
'@
使用示例:
PS C:\> [Audio]::Volume # Check current volume (now about 10%)
0,09999999
PS C:\> [Audio]::Mute # See if speaker is muted
False
PS C:\> [Audio]::Mute = $true # Mute speaker
PS C:\> [Audio]::Volume = 0.75 # Set volume to 75%
PS C:\> [Audio]::Volume # Check that the changes are applied
0,75
PS C:\> [Audio]::Mute
True
PS C:\>
如果您需要,还有更全面的 Core Audio API 的 .NET 包装器,但我不知道有一组 PowerShell 友好的 cmdlet。
PS Diogo 的答案似乎很聪明,但对我不起作用。
在 ps1 powershell 脚本上使用以下命令:
$obj = new-object -com wscript.shell
$obj.SendKeys([char]173)
Alexandre 的回答适合我的情况,但由于有关“var”名称空间的编译错误,他的示例不起作用。似乎较新/不同版本的 .net 可能会导致该示例不起作用。如果您发现收到了编译错误,这是针对这些情况的替代版本:
Add-Type -Language CsharpVersion3 -TypeDefinition @'
using System.Runtime.InteropServices;
[Guid("5CDF2C82-841E-4546-9722-0CF74078229A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IAudioEndpointVolume {
// f(), g(), ... are unused COM method slots. Define these if you care
int f(); int g(); int h(); int i();
int SetMasterVolumeLevelScalar(float fLevel, System.Guid pguidEventContext);
int j();
int GetMasterVolumeLevelScalar(out float pfLevel);
int k(); int l(); int m(); int n();
int SetMute([MarshalAs(UnmanagedType.Bool)] bool bMute, System.Guid pguidEventContext);
int GetMute(out bool pbMute);
}
[Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IMMDevice {
int Activate(ref System.Guid id, int clsCtx, int activationParams, out IAudioEndpointVolume aev);
}
[Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IMMDeviceEnumerator {
int f(); // Unused
int GetDefaultAudioEndpoint(int dataFlow, int role, out IMMDevice endpoint);
}
[ComImport, Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")] class MMDeviceEnumeratorComObject { }
public class Audio {
static IAudioEndpointVolume Vol() {
var enumerator = new MMDeviceEnumeratorComObject() as IMMDeviceEnumerator;
IMMDevice dev = null;
Marshal.ThrowExceptionForHR(enumerator.GetDefaultAudioEndpoint(/*eRender*/ 0, /*eMultimedia*/ 1, out dev));
IAudioEndpointVolume epv = null;
var epvid = typeof(IAudioEndpointVolume).GUID;
Marshal.ThrowExceptionForHR(dev.Activate(ref epvid, /*CLSCTX_ALL*/ 23, 0, out epv));
return epv;
}
public static float Volume {
get {float v = -1; Marshal.ThrowExceptionForHR(Vol().GetMasterVolumeLevelScalar(out v)); return v;}
set {Marshal.ThrowExceptionForHR(Vol().SetMasterVolumeLevelScalar(value, System.Guid.Empty));}
}
public static bool Mute {
get { bool mute; Marshal.ThrowExceptionForHR(Vol().GetMute(out mute)); return mute; }
set { Marshal.ThrowExceptionForHR(Vol().SetMute(value, System.Guid.Empty)); }
}
}
'@
用法是一样的:
PS C:\> [Audio]::Volume # Check current volume (now about 10%)
0,09999999
PS C:\> [Audio]::Mute # See if speaker is muted
False
PS C:\> [Audio]::Mute = $true # Mute speaker
PS C:\> [Audio]::Volume = 0.75 # Set volume to 75%
PS C:\> [Audio]::Volume # Check that the changes are applied
0,75
PS C:\> [Audio]::Mute
True
PS C:\>
您可以通过简单地管理 Windows 音频服务以另一种方式给猫剥皮。停止静音,启动取消静音。
似乎没有一种快速简便的方法来调整音量。如果您有 c++ 经验,您可以使用这篇博文做一些事情,Larry Osterman 描述了如何从平台 api 调用 IAudioEndpointVolume 接口(对于 Vista,从我在几次搜索中发现的内容来看,XP 可能更难)。
V2 确实允许您编译内联代码(通过 Add-Type),因此这可能是一种选择。
我知道这不是 PowerShell,但结合 Michael 和 Diogo 的答案给出了一个单行 VBScript 解决方案:
CreateObject("WScript.Shell").SendKeys(chr(173))
把它拍进去mute.vbs
,你可以双击来切换静音
Set-ExecutionPolicy
像使用 PowerShell 那样我没有找到如何在 PowerShell 中执行此操作,但是有一个名为 NirCmd 的命令行实用程序可以通过运行以下命令来解决问题:
C:\utils\nircmd.exe mutesysvolume 2
NirCmd 可在此处免费获得:http: //www.nirsoft.net/utils/nircmd.html
vbscript中的解决方案:
Set WshShell = CreateObject("WScript.Shell")
For i = 0 To 50
WshShell.SendKeys(chr(174))
WScript.Sleep 100
Next
按键每次将音量降低 2。
Set-DefaultAudioDeviceMute
在得到对我的回答的一些反馈后,让我再试一次
这是基于@frgnca 的 AudioDeviceCmdlets,可在此处找到:https ://github.com/frgnca/AudioDeviceCmdlets
这是将使每个录音设备静音的代码。
Import-Module .\AudioDeviceCmdlets
$audio_device_list = Get-AudioDevice -list
$recording_devices = $audio_device_list | ? {$_.Type -eq "Recording"}
$recording_devices
$recording_device_index = $recording_devices.Index | Out-String -stream
foreach ($i in $recording_device_index) {
$inti = [int]$i
Set-AudioDevice $inti | out-null -erroraction SilentlyContinue
Set-AudioDevice -RecordingMute 1 -erroraction SilentlyContinue
}
您导入 AudioDeviceCmdlets dll,然后保存所有音频设备的列表,过滤到录音设备中。您获取所有录音设备的索引,然后遍历每个设备,首先将设备设置为主音频设备,然后将该设备设置为静音(这 2 步过程是 dll 施加的限制)。
要取消静音,请将-RecordingMute 1更改为RecordingMute 0
同样,要使播放设备静音,您可以使用以下代码:
Import-Module .\AudioDeviceCmdlets
$audio_device_list = Get-AudioDevice -list
$playback_devices = $audio_device_list | ? {$_.Type -eq "Playback"}
$playback_devices
$playback_device_index = $playback_devices.Index | Out-String -stream
foreach ($i in $playback_device_index) {
$inti = [int]$i
Set-AudioDevice $inti | out-null -erroraction SilentlyContinue
Set-AudioDevice -PlaybackMute 1 -erroraction SilentlyContinue
}
要取消静音,请将-PlaybackMute 1更改为PlaybackMute 0
此代码来自我拥有的一个更大项目的一部分,该项目通过 Arduino 连接到物理按钮/LED 静音状态显示,以启用单按钮按下静音/取消静音所有系统麦克风(以帮助 Zoom、Meet、Teams、Discord 等.) 并帮助人们避免令人尴尬的热点麦克风事件。
https://github.com/dakota-mewt/mewt
PS 我真的很喜欢一些单线解决方案,例如从 powershell 更改音频级别?
但是,请注意,单线静音通常仅适用于当前设置为 Windows 默认值的单个设备。因此,如果您拥有能够处理不同音频设备(如 Zoom 和 Meet)的软件,而它们恰好使用的是非默认设备,则它可能无法按预期工作。
在上面的第二个脚本中,要在 PowerShell 7 或 PowerShell Core 中的第一行更改:
-Language CsharpVersion3
到...
-Language Csharp
在 W10 上工作