(view source code of audioendpoints.cs as plain text)
using NAudio;
using NAudio.CoreAudioApi;
using NAudio.Wave;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace RobvanderWoude{internal class AudioEndPoints
{static readonly string progver = "2.04";
#region Global Variablesstatic bool bgcolors = true;
static bool fgcolors = false;
static bool helprequested = false;
static bool norecordingdevice = false;
static bool statusintitlebar = false;
static bool stereo = true;
static bool topmost = false;
static DataGridView datagrid;
static readonly Dictionary<DeviceState, Color> foregroundcolors = new Dictionary<DeviceState, Color>
{[DeviceState.Active] = Color.Green,
[DeviceState.Disabled] = Color.Orange,
[DeviceState.NotPresent] = Color.SlateGray,
[DeviceState.Unplugged] = Color.Red
};
static readonly Dictionary<DeviceState, Color> backgroundcolors = new Dictionary<DeviceState, Color>
{[DeviceState.Active] = Color.LightGreen,
[DeviceState.Disabled] = Color.Yellow,
[DeviceState.NotPresent] = Color.LightGray,
[DeviceState.Unplugged] = Color.Red
};
static Dictionary<int, AudioEndPoint> audioendpoints;
static Form form;
static int interval = 0;
static Timer timer = new Timer( );
static WaveIn recorder;
static readonly string titletext = "AudioEndPoints.exe, \u00A0 Version " + progver + " \u00A0?\u00A0 \u00A0 Copyright \u00A9 2025 Rob van der Woude";
private static readonly IntPtr HWND_TOPMOST = new IntPtr( -1 );
private const UInt32 SWP_NOSIZE = 0x0001;
private const UInt32 SWP_NOMOVE = 0x0002;
private const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;
#endregion Global Variables[STAThread]
static int Main( string[] args )
{ #region Parse Command Lineforeach ( string arg in args )
{string[] kvp = arg.Split( ":=".ToCharArray( ), 2 );
string key = kvp[0].ToUpper( );
string val = ( kvp.Length == 2 ? kvp[1] : string.Empty );
switch ( key )
{case "/?":
return ShowHelp( true );
case "/B":
bgcolors = false;
fgcolors = false;
break;
case "/F":
bgcolors = false;
fgcolors = true;
break;
case "/M":
stereo = false;
break;
case "/R":
interval = 1;
if ( string.IsNullOrWhiteSpace( val ) )
{interval = 1;
}else if ( !int.TryParse( val, out interval ) )
{interval = 1;
}if ( interval < 1 )
{interval = 1;
}timer.Interval = interval * 1000;
timer.Tick += Timer_Tick;
timer.Start( );
break;
case "/S":
statusintitlebar = true;
break;
case "/T":
topmost = true;
break;
default:
return ShowHelp( true );
} } #endregion Parse Command LineApplication.EnableVisualStyles( );
form = new Form
{BackColor = Color.White,
Font = new Font( FontFamily.GenericSansSerif, 12 ),
Size = new Size( 1380, 840 ),
StartPosition = FormStartPosition.CenterScreen,
Text = titletext,Visible = true
};
form.FormClosing += Form_FormClosing;
if ( topmost )
{SetWindowPos( form.Handle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS );
}Console.CursorVisible = false;
audioendpoints = new Dictionary<int, AudioEndPoint>( );
recorder = new WaveIn( );
recorder.RecordingStopped += Recorder_RecordingStopped;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine( "Monitoring output levels" );
Console.ResetColor( );
RestartRecorder( );
SetupDataGrid( );
PopulateDataGrid( );
while ( form.Enabled )
{Application.DoEvents( );
}Console.CursorVisible = true;
return 0;
}private static void Datagrid_KeyUp( object sender, KeyEventArgs e )
{if ( e.KeyCode == Keys.F1 )
{ShowHelp( false );
}if ( e.KeyCode == Keys.F5 )
{RefreshDataGrid( );
}if ( e.KeyCode == Keys.Escape )
{form.Close( );
}if ( e.Control && e.KeyCode == Keys.P )
{PrintDataGrid( );
}if ( e.Control && e.KeyCode == Keys.S )
{string filename = string.Format( "AudioEndPoints.{0}.{1}.txt", Environment.GetEnvironmentVariable( "COMPUTERNAME" ), DateTime.Now.ToString( "yyyy-MM-dd_HHmmss" ) );
string outfile = Path.Combine( Environment.CurrentDirectory, filename );
SaveDataGrid( outfile );
MessageBox.Show( "Saved as \"" + filename + "\" in folder \"" + Path.GetDirectoryName( outfile ) + "\"", "File Saved", MessageBoxButtons.OK, MessageBoxIcon.Information );
} }private static void Datagrid_SortCompare( object sender, DataGridViewSortCompareEventArgs e )
{if ( e.Column.Index == 0 )
{e.SortResult = int.Parse( e.CellValue1.ToString( ) ).CompareTo( int.Parse( e.CellValue2.ToString( ) ) );
e.Handled = true; // skip the default sorting
} }private static void Form_FormClosing( object sender, FormClosingEventArgs e )
{ try {timer.Stop( );
}catch { }
try {recorder.StopRecording( );
}catch { }
if ( helprequested )
{ShowHelp( true );
}form.Enabled = false;
}private static void Recorder_RecordingStopped( object sender, StoppedEventArgs e )
{RestartRecorder( );
}private static void Timer_Tick( object sender, EventArgs e )
{RefreshDataGrid( );
}private static void InventoryAudioEndPoints( )
{MMDeviceEnumerator enumerator = new MMDeviceEnumerator( );
int index = 0;
foreach ( MMDevice endpoint in enumerator.EnumerateAudioEndPoints( DataFlow.All, DeviceState.All ) )
{AudioEndPoint audioendpoint = new AudioEndPoint
{ Index = index,InOut = endpoint.DataFlow,
Name = endpoint.FriendlyName,
State = endpoint.State,
ID = endpoint.ID,
};
if ( audioendpoint.State == DeviceState.Active )
{audioendpoint.MasterVolumeLevelScalar = endpoint.AudioEndpointVolume.MasterVolumeLevelScalar;
audioendpoint.MasterPeakValue = endpoint.AudioMeterInformation.MasterPeakValue;
audioendpoint.PeakValues = endpoint.AudioMeterInformation.PeakValues;
} else {audioendpoint.MasterVolumeLevelScalar = 0f;
audioendpoint.MasterPeakValue = 0f;
audioendpoint.PeakValues = null;
}audioendpoints[index] = audioendpoint;
index++; }if ( norecordingdevice )
{RestartRecorder( );
} }private static void PopulateDataGrid( )
{InventoryAudioEndPoints( );
foreach ( AudioEndPoint endpoint in audioendpoints.Values )
{PopulateDataGridRow( endpoint );
}for ( int i = 0; i < datagrid.ColumnCount; i++ )
{if ( i == datagrid.ColumnCount - 1 )
{datagrid.Columns[i].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
} else {datagrid.Columns[i].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
} } }private static void PopulateDataGridRow( AudioEndPoint endpoint )
{string[] line;
if ( stereo )
{line = new string[] { endpoint.Index.ToString( ), ( endpoint.InOut == DataFlow.Capture ? "IN" : "OUT" ), endpoint.Name, endpoint.State.ToString( ), endpoint.ID, endpoint.GetVolume( ), endpoint.GetPeakLevel( 0 ), endpoint.GetPeakLevel( 1 ) };
} else {line = new string[] { endpoint.Index.ToString( ), ( endpoint.InOut == DataFlow.Capture ? "IN" : "OUT" ), endpoint.Name, endpoint.State.ToString( ), endpoint.ID, endpoint.GetVolume( ), endpoint.GetPeakLevel( -1 ) };
}int row;
if ( endpoint.Index < datagrid.Rows.Count - 1 )
{row = endpoint.Index;
datagrid.Rows[row].SetValues( line );
} else {row = datagrid.Rows.Count - 1;
datagrid.Rows.Add( line );
}if ( bgcolors )
{datagrid.Rows[row].DefaultCellStyle.BackColor = backgroundcolors[endpoint.State];
}if ( fgcolors )
{datagrid.Rows[row].DefaultCellStyle.ForeColor = foregroundcolors[endpoint.State];
} }private static void PrintDataGrid( )
{string printout = Path.GetTempFileName( );
SaveDataGrid( printout );
ProcessStartInfo psi = new ProcessStartInfo
{UseShellExecute = false,
Arguments = string.Format( "/p \"{0}\"", printout ),
FileName = "notepad.exe"
};
Process proc = Process.Start( psi );
proc.WaitForExit( );
File.Delete( printout );
}private static void RefreshDataGrid( )
{PopulateDataGrid( );
}private static void RestartRecorder( )
{string message;
try {recorder.StartRecording( );
norecordingdevice = false;
message = "Monitoring input levels" + new string( ' ', 30 );
Console.SetCursorPosition( 0, Console.CursorTop );
Console.ForegroundColor = ConsoleColor.Green;
Console.Write( message );
Console.ResetColor( );
}catch ( MmException )
{norecordingdevice = true;
message = "Unable to monitor input levels" + new string( ' ', 30 );
Console.SetCursorPosition( 0, Console.CursorTop );
Console.ForegroundColor = ConsoleColor.Red;
Console.Error.Write( message );
Console.ResetColor( );
}form.Text = titletext + " \u00A0?\u00A0 \u00A0 " + message.Trim( );
}private static void SaveDataGrid( string outfile )
{ // line out columsint[] cw;
if ( stereo )
{cw = new int[] { 5, 6, 0, 0, 0, 6, 6, 6 };
} else {cw = new int[] { 5, 6, 0, 0, 0, 6, 4 };
}for ( int i = 0; i < datagrid.Columns.Count; i++ )
{for ( int j = 0; j < datagrid.Rows.Count; j++ )
{if ( datagrid.Rows[j].Cells[i].Value != null && datagrid.Rows[j].Cells[i].Value.ToString( ).Length > cw[i] )
{cw[i] = datagrid.Rows[j].Cells[i].Value.ToString( ).Length;
} } } // format printoutList<string> lines = new List<string>( );
string linetemplate;
if ( stereo )
{linetemplate = "{0,-" + cw[0] + "} {1,-" + cw[1] + "} {2,-" + cw[2] + "} {3,-" + cw[3] + "} {4,-" + cw[4] + "} {5," + cw[5] + "} {6," + cw[6] + "} {7," + cw[7] + "}";
} else {linetemplate = "{0,-" + cw[0] + "} {1,-" + cw[1] + "} {2,-" + cw[2] + "} {3,-" + cw[3] + "} {4,-" + cw[4] + "} {5," + cw[5] + "} {6," + cw[6] + "}";
} // headervar cols = datagrid.Columns;
string headerline;
if ( stereo )
{headerline = string.Format( linetemplate, cols[0].HeaderText, cols[1].HeaderText.Replace( "\u00A0", "" ), cols[2].HeaderText, cols[3].HeaderText, cols[4].HeaderText, cols[5].HeaderText, cols[6].HeaderText, cols[7].HeaderText );
} else {headerline = string.Format( linetemplate, cols[0].HeaderText, cols[1].HeaderText.Replace( "\u00A0", "" ), cols[2].HeaderText, cols[3].HeaderText, cols[4].HeaderText, cols[5].HeaderText, cols[6].HeaderText );
}lines.Add( headerline );
// rowsfor ( int i = 0; i < datagrid.Rows.Count; i++ )
{var cells = datagrid.Rows[i].Cells;
string line;
if ( stereo )
{line = string.Format( linetemplate, cells[0].Value, cells[1].Value, cells[2].Value, cells[3].Value, cells[4].Value, cells[5].Value, cells[6].Value, cells[7].Value );
} else {line = string.Format( linetemplate, cells[0].Value, cells[1].Value, cells[2].Value, cells[3].Value, cells[4].Value, cells[5].Value, cells[6].Value );
}lines.Add( line );
}using ( StreamWriter print = new StreamWriter( outfile ) )
{for ( int i = 0; i < lines.Count; i++ )
{print.WriteLine( lines[i] );
} } }private static void SetupDataGrid( )
{datagrid = new DataGridView
{Location = new Point( 0, 0 ),
Size = new Size( 1200, 250 ),
AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCellsExceptHeaders,
ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single,
CellBorderStyle = DataGridViewCellBorderStyle.Single,
GridColor = Color.Black,
RowHeadersVisible = false,
SelectionMode = DataGridViewSelectionMode.FullRowSelect,
MultiSelect = false,
Dock = DockStyle.Fill
};
if ( stereo )
{datagrid.ColumnCount = 8;
} else {datagrid.ColumnCount = 7;
form.Width -= 85;
}datagrid.ColumnHeadersDefaultCellStyle.BackColor = Color.Navy;
datagrid.ColumnHeadersDefaultCellStyle.ForeColor = Color.White;
datagrid.ColumnHeadersDefaultCellStyle.Font = new Font( FontFamily.GenericSansSerif, 12, FontStyle.Bold );
datagrid.Columns[0].Name = "Index";
datagrid.Columns[1].Name = "In\u00A0/\u00A0Out";
datagrid.Columns[2].Name = "Name";
datagrid.Columns[3].Name = "Status";
datagrid.Columns[4].Name = "ID";
datagrid.Columns[5].Name = "Volume";
datagrid.Columns[5].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
if ( stereo )
{datagrid.Columns[6].Name = "Peak\u00A0L";
datagrid.Columns[6].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
datagrid.Columns[7].Name = "Peak\u00A0R";
datagrid.Columns[7].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
} else {datagrid.Columns[6].Name = "Peak";
datagrid.Columns[6].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
}datagrid.KeyUp += Datagrid_KeyUp;
datagrid.SortCompare += Datagrid_SortCompare;
form.Controls.Add( datagrid );
datagrid.Focus( );
}private static int ShowHelp( bool cli = false )
{string message = string.Format( "\nAudioEndPoints.exe, Version {0}\n", progver );
message += "List the local computer's audio endpoints\n\n";
message += "Usage:\tAudioEndPoints.exe\t[ options ]\n\n";
message += "Options:\t \t/? \tdisplay this help text and exit\n";
message += " \t \t/F \tuse status dependent\n";
message += " \t \t \tFOREGROUND colors,\n";
message += " \t \t/B \tuse BLACK and WHITE,\n";
message += " \t \t \tdefault is status dependent\n";
message += " \t \t \tBACKGROUND colors\n";
message += " \t \t/M \tpeak levels for L and R combined,\n";
message += " \t \t \tdefault is separate peak levels\n";
message += " \t \t/R[:nn]\trefresh values every nn seconds,\n";
message += " \t \t \tdefault interval is 1 second\n";
message += " \t \t/S \tStatus information in title bar too\n";
message += " \t \t \t(default: show in console only)\n";
message += " \t \t/T \tkeep window always on Top\n\n";
message += "Click on ANY column header to sort the table by that column.\n";
message += "Note that the table's sort order will be reset to its default at\n";
message += "every refresh, be it by pressing F5 or by specifying a refresh\n";
message += "interval with the /R command line switch.\n";
message += "You can edit all cells, if you like.\n\n";
message += "Keys: \tCtrl+C will copy the SELECTED LINE to the clipboard,\n";
message += " \tCtrl+P will print the list,\n";
message += " \tCtrl+S will save it in a text file,\n";
message += " \tF1 will show this help text,\n";
message += " \tF5 will refresh volume and peak level values,\n";
message += " \tEscape will abort the program.\n\n";
message += "Credits:\tTo access audio endpoints, this program uses\n";
message += " \tNAudio created by Mark Heath:\n";
message += " \thttps://github.com/naudio/NAudio\n";
message += " \tVolume reading based on code by Mike de Klerk:\n";
message += " \thttps://stackoverflow.com/a/12534584\n\n";
message += "Written by Rob van der Woude\n";
message += "https://www.robvanderwoude.com\n";
if ( cli )
{Console.Error.WriteLine( message );
} else {helprequested = true;
MessageBox.Show( message, "AudioEndPoints.exe, \u00A0 Version " + progver );
}return -1;
} // Tip to keep window on top by clamum on StackOverflow.com // https://stackoverflow.com/a/34703664[DllImport( "user32.dll" )]
[return: MarshalAs( UnmanagedType.Bool )]
public static extern bool SetWindowPos( IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags );
}public class AudioEndPoint
{public int Index
{get; set;
} public DataFlow InOut {get; set;
}public string Name
{get; set;
} public DeviceState State {get; set;
}public string ID
{get; set;
}public float MasterVolumeLevelScalar
{get; set;
}public float MasterPeakValue
{get; set;
} public AudioMeterInformationChannels PeakValues {get; set;
}public string GetVolume( )
{if ( State == DeviceState.Active )
{return string.Format( "{0} %", (int) ( MasterVolumeLevelScalar * 100 ) );
} else {return string.Empty;
} }public string GetPeakLevel( int channel = -1 )
{if ( State == DeviceState.Active )
{switch ( channel )
{case 0:
if ( PeakValues.Count > 0 )
{return string.Format( "{0} %", (int) ( 100 * float.Parse( PeakValues[0].ToString( ) ) ) );
} else {return string.Empty;
}case 1:
if ( PeakValues.Count > 1 )
{return string.Format( "{0} %", (int) ( 100 * float.Parse( PeakValues[1].ToString( ) ) ) );
} else {return string.Empty;
}default:
return string.Format( "{0} %", (int) ( 100 * MasterPeakValue ) );
} } else {return string.Empty;
} } }}page last modified: 2025-10-11; loaded in 0.0116 seconds