So I've been pondering on this problem for a while and I can't figure out what the right way to go about this is. I want to determine if Windows is outputting sound at a certain time using a Powershell
script. I can determine whether or not the audio driver has an error, but I cannot for the life of me figure out if the system is playing sound.
I looked at the .NET
class for System.Media
and the three classes inside all had to do with playing sound or manipulating the system sounds.
I'm not asking for code to be written for me, I just need to know where to start to check if the windows system is currently playing sound.
I have a sound monitor that is continuously monitoring sound on the Node.js platform and when it loses sound it sends me a text. Well, I also want it to go through all the systems its hooked up to and see where the fault lies. That's why I want to see whether or not the windows computer is playing sound.
Right click on volume icon in systray, select mixer and you can see all applications that are using sound devices, can see VU bars showing sound levels, mute each one separately to see which application is doing the sound etc.
There is no way to tell, you're supposed to be able to identify them from experience. You can easily browse the Windows system sounds from the Sound Control Panel, using the Test button in the Sounds tab. For other sounds, each application is configured differently, there is no single rule.
Your brain is able to do this by comparing tiny differences in the way that sounds affect each ear. A noise coming from the right is slightly louder in your right ear, and reaches it fractionally earlier than your left. A sound in front or behind affects each ear the same way, with intermediate effects in-between.
If the sound starts as soon as your computer logs in to Windows, or after rebooting the system, check your Startup programs list for programs that could produce background sound. You can view the Startup tab by pressing "Ctrl-Shift-Esc" and selecting the "Startup" tab.
There is no way to tell, you're supposed to be able to identify them from experience. You can easily browse the Windows system sounds from the Sound Control Panel, using the Test button in the Sounds tab. For other sounds, each application is configured differently, there is no single rule.
There is no way to tell, you're supposed to be able to identify them from experience. For other sounds, each application is configured differently, there is no single rule. Can't you identify the application from what you or the computer were doing at the time?
If these sounds are actually in Windows 10 after login then they are a part of the specific Sound Theme and that's where you need to look to find the definitions of what they mean. On the other hand, if they are sounds that occur when the Computer is booting then they aren't Windows Sounds at all, they are Beep Codes produced by the Computer BIOS.
Websites that automatically play sound are evil, pure and simple. And there is only one way to quickly get rid of the intrusive sounds. When I load several tabs, I have no audio sounds at all at first.
Here is a sample C# code that determines if Windows is rendering any audio stream. It uses Windows Core Audio API (specifically the IAudioMeterInformation interface) and is supported on Vista and higher.
public static bool IsWindowsPlayingSound()
{
var enumerator = (IMMDeviceEnumerator)(new MMDeviceEnumerator());
var speakers = enumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia);
var meter = (IAudioMeterInformation)speakers.Activate(typeof(IAudioMeterInformation).GUID, 0, IntPtr.Zero);
var value = meter.GetPeakValue();
// this is a bit tricky. 0 is the official "no sound" value
// but for example, if you open a video and plays/stops with it (w/o killing the app/window/stream),
// the value will not be zero, but something really small (around 1E-09)
// so, depending on your context, it is up to you to decide
// if you want to test for 0 or for a small value
return value > 1E-08;
}
[ComImport, Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
private class MMDeviceEnumerator
{
}
private enum EDataFlow
{
eRender,
eCapture,
eAll,
}
private enum ERole
{
eConsole,
eMultimedia,
eCommunications,
}
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("A95664D2-9614-4F35-A746-DE8DB63617E6")]
private interface IMMDeviceEnumerator
{
void NotNeeded();
IMMDevice GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role);
// the rest is not defined/needed
}
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("D666063F-1587-4E43-81F1-B948E807363F")]
private interface IMMDevice
{
[return: MarshalAs(UnmanagedType.IUnknown)]
object Activate([MarshalAs(UnmanagedType.LPStruct)] Guid iid, int dwClsCtx, IntPtr pActivationParams);
// the rest is not defined/needed
}
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("C02216F6-8C67-4B5B-9D00-D008E73E0064")]
private interface IAudioMeterInformation
{
float GetPeakValue();
// the rest is not defined/needed
}
As said in my comment, I have also created an open source c++ project, a simple friction-free zero-dependencies console application, available here: https://github.com/smourier/IsWindowsPlayingSound. I have added one x86 release binary that should support 32 and 64 bit OSes: https://github.com/smourier/IsWindowsPlayingSound/releases
You can use it in PowerShell like any external .exe program. It will return an error level that you can retrieve using standard ways, for example: https://blogs.msdn.microsoft.com/powershell/2006/09/15/errorlevel-equivalent/
Here is the equivalent C++ code:
#include "stdafx.h" // includes <Endpointvolume.h> and <Mmdeviceapi.h>
#define WIDEN2(x) L ## x
#define WIDEN(x) WIDEN2(x)
#define __WFILE__ WIDEN(__FILE__)
#define HRCHECK(__expr) {hr=(__expr);if(FAILED(hr)){wprintf(L"FAILURE 0x%08X (%i)\n\tline: %u file: '%s'\n\texpr: '" WIDEN(#__expr) L"'\n",hr, hr, __LINE__,__WFILE__);goto cleanup;}}
#define RELEASE(__p) {if(__p!=nullptr){__p->Release();__p=nullptr;}}
int main(int argc, char *argv[])
{
BOOL playing = FALSE;
BOOL loopmode = FALSE;
float epsilon = 1E-07;
float value = 0;
HRESULT hr = S_OK;
IMMDeviceEnumerator* pEnumerator = NULL;
IMMDevice *pDevice = NULL;
IAudioMeterInformation *pMeter = NULL;
// Parse optional args
// "loop" -> sets a loop mode for easy testing
// <float value> -> changes epsilon
for (int i = 1; i < argc; i++)
{
if (!strcmp(argv[i], "loop"))
{
loopmode = TRUE;
continue;
}
float eps = atof(argv[i]);
if (eps != 0.0)
{
epsilon = eps;
continue;
}
}
CoInitialize(NULL);
HRCHECK(CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator));
HRCHECK(pEnumerator->GetDefaultAudioEndpoint(EDataFlow::eRender, ERole::eMultimedia, &pDevice));
HRCHECK(pDevice->Activate(__uuidof(IAudioMeterInformation), CLSCTX_ALL, NULL, (void**)&pMeter));
do
{
HRCHECK(pMeter->GetPeakValue(&value));
playing = value > epsilon;
if (!loopmode)
break;
printf("%.10f playing:%i\n", value, playing);
Sleep(100);
} while (TRUE);
cleanup:
RELEASE(pMeter);
RELEASE(pDevice);
RELEASE(pEnumerator);
CoUninitialize();
if (FAILED(hr))
{
printf("An error occurred: 0x%08X\n", hr);
return hr;
}
if (playing)
{
printf("Windows is playing a sound.\n");
}
else
{
printf("Windows is not playing a sound.\n");
}
return playing;
}
Here's how to use the code that Simon Mourier provided.
Run the code below:
Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;
namespace Foo
{
public class Bar
{
public static bool IsWindowsPlayingSound()
{
IMMDeviceEnumerator enumerator = (IMMDeviceEnumerator)(new MMDeviceEnumerator());
IMMDevice speakers = enumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia);
IAudioMeterInformation meter = (IAudioMeterInformation)speakers.Activate(typeof(IAudioMeterInformation).GUID, 0, IntPtr.Zero);
float value = meter.GetPeakValue();
// this is a bit tricky. 0 is the official "no sound" value
// but for example, if you open a video and plays/stops with it (w/o killing the app/window/stream),
// the value will not be zero, but something really small (around 1E-09)
// so, depending on your context, it is up to you to decide
// if you want to test for 0 or for a small value
return value > 1E-08;
}
[ComImport, Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
private class MMDeviceEnumerator
{
}
private enum EDataFlow
{
eRender,
eCapture,
eAll,
}
private enum ERole
{
eConsole,
eMultimedia,
eCommunications,
}
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("A95664D2-9614-4F35-A746-DE8DB63617E6")]
private interface IMMDeviceEnumerator
{
void NotNeeded();
IMMDevice GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role);
// the rest is not defined/needed
}
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("D666063F-1587-4E43-81F1-B948E807363F")]
private interface IMMDevice
{
[return: MarshalAs(UnmanagedType.IUnknown)]
object Activate([MarshalAs(UnmanagedType.LPStruct)] Guid iid, int dwClsCtx, IntPtr pActivationParams);
// the rest is not defined/needed
}
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("C02216F6-8C67-4B5B-9D00-D008E73E0064")]
private interface IAudioMeterInformation
{
float GetPeakValue();
// the rest is not defined/needed
}
}
}
'@
I replaced all var
types as that seems to fix the issue with the code not compiling on PowerShell version 2.
Once loaded you can check the state like so:
[Foo.Bar]::IsWindowsPlayingSound()
True or False
I've tested this working with Windows 10 1703 on PowerShell 5.1
But there are caveats:
this is a bit tricky. 0 is the official "no sound" value
but for example, if you open a video and plays/stops with it (w/o killing the app/window/stream),
the value will not be zero, but something really small (around 1E-09)
so, depending on your context, it is up to you to decide
if you want to test for 0 or for a small value
So if you change return value > 1E-08
to return value > 0
you will get true when a video is paused.
You could use AudioDeviceCmdlets
module written by Chris Hunt
Write-DefaultAudioDeviceValue -StreamValue
looks like what you are looking for. Otherwise you can take a look at his source on how he pulling those values using the CoreAudioApi
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With