Add settings for fallback behavior

update action icon with padding
This commit is contained in:
2023-08-20 20:52:48 -06:00
parent 1dc8ab8a2d
commit 90c014e932
24 changed files with 760 additions and 786 deletions

View File

@ -1,135 +1,118 @@
using CoreAudio;
using FocusVolumeControl;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Management;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace SoundBrowser
namespace SoundBrowser;
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
AudioHelper _audioHelper;
Native.WinEventDelegate _delegate;
public MainWindow()
{
InitializeComponent();
_audioHelper = new AudioHelper();
AudioHelper _audioHelper;
Native.WinEventDelegate _delegate;
public MainWindow()
{
InitializeComponent();
_audioHelper = new AudioHelper();
//normally you can just pass a lambda, but for some reason, that seems to get garbage collected
_delegate = new Native.WinEventDelegate(WinEventProc);
Native.RegisterForForegroundWindowChangedEvent(_delegate);
}
public void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
SetupCurrentAppFields();
SetupAllSessionFields();
}
private void SetupCurrentAppFields()
{
var handle = Native.GetForegroundWindow();
var sb = new StringBuilder();
if (handle != IntPtr.Zero)
{
//use this in debug to help there be less events
/*
Native.GetWindowThreadProcessId(handle, out var fpid);
var fp = Process.GetProcessById(fpid);
if(!fp.ProcessName.Contains("FSD"))
{
return;
}
*/
var processes = _audioHelper.GetPossibleProcesses();
var session = _audioHelper.FindSession(processes);
foreach (var p in processes)
{
sb.AppendLine($"pid: {p.Id}");
sb.AppendLine($"\tprocessName: {p.ProcessName}");
try
{
sb.AppendLine($"\tFileDescription: {p!.MainModule!.FileVersionInfo.FileDescription}");
}
catch
{
sb.AppendLine("\tFileDescription: ##ERROR##");
}
}
sb.AppendLine();
if (session != null)
{
sb.AppendLine("picked the following best match");
sb.AppendLine($"\tsession: {session.DisplayName}");
sb.AppendLine($"\tvolume: {session.GetVolumeLevel()}");
sb.AppendLine($"\tcount: {session.Count}");
}
else
{
sb.AppendLine("No Match");
}
}
_tf.Text = sb.ToString();
}
private void SetupAllSessionFields()
{
_tf2.Text = "";
var sb = new StringBuilder();
sb.AppendLine("-------------------------------------------------------------------------------");
var deviceEnumerator = new MMDeviceEnumerator(Guid.NewGuid());
using var device = deviceEnumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
using var manager = device.AudioSessionManager2;
var sessions = manager!.Sessions;
foreach (var session in sessions!)
{
var audioProcess = Process.GetProcessById((int)session.ProcessID);
var displayName = audioProcess!.MainModule!.FileVersionInfo.FileDescription;
sb.AppendLine($"pid: {audioProcess.Id}");
sb.AppendLine($"\tprocessName: {audioProcess.ProcessName}");
sb.AppendLine($"\tsession: {displayName}");
}
_tf2.Text = sb.ToString();
}
//normally you can just pass a lambda, but for some reason, that seems to get garbage collected
_delegate = new Native.WinEventDelegate(WinEventProc);
Native.RegisterForForegroundWindowChangedEvent(_delegate);
}
public void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
SetupCurrentAppFields();
SetupAllSessionFields();
}
private void SetupCurrentAppFields()
{
var handle = Native.GetForegroundWindow();
var sb = new StringBuilder();
if (handle != IntPtr.Zero)
{
//use this in debug to help there be less events
/*
Native.GetWindowThreadProcessId(handle, out var fpid);
var fp = Process.GetProcessById(fpid);
if(!fp.ProcessName.Contains("FSD"))
{
return;
}
*/
var processes = _audioHelper.GetPossibleProcesses();
var session = _audioHelper.FindSession(processes);
foreach (var p in processes)
{
sb.AppendLine($"pid: {p.Id}");
sb.AppendLine($"\tprocessName: {p.ProcessName}");
try
{
sb.AppendLine($"\tFileDescription: {p!.MainModule!.FileVersionInfo.FileDescription}");
}
catch
{
sb.AppendLine("\tFileDescription: ##ERROR##");
}
}
sb.AppendLine();
if (session != null)
{
sb.AppendLine("picked the following best match");
sb.AppendLine($"\tsession: {session.DisplayName}");
sb.AppendLine($"\tvolume: {session.GetVolumeLevel()}");
}
else
{
sb.AppendLine("No Match");
}
}
_tf.Text = sb.ToString();
}
private void SetupAllSessionFields()
{
_tf2.Text = "";
var sb = new StringBuilder();
sb.AppendLine("-------------------------------------------------------------------------------");
var deviceEnumerator = new MMDeviceEnumerator(Guid.NewGuid());
using var device = deviceEnumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
using var manager = device.AudioSessionManager2;
var sessions = manager!.Sessions;
foreach (var session in sessions!)
{
var audioProcess = Process.GetProcessById((int)session.ProcessID);
var displayName = audioProcess!.MainModule!.FileVersionInfo.FileDescription;
sb.AppendLine($"pid: {audioProcess.Id}");
sb.AppendLine($"\tprocessName: {audioProcess.ProcessName}");
sb.AppendLine($"\tsession: {displayName}");
}
_tf2.Text = sb.ToString();
}
}

View File

@ -1,65 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace SoundBrowser
{
/// <summary>
/// A utility class to determine a process parent.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct ParentProcessUtilities
{
// These members must match PROCESS_BASIC_INFORMATION
internal IntPtr Reserved1;
internal IntPtr PebBaseAddress;
internal IntPtr Reserved2_0;
internal IntPtr Reserved2_1;
internal IntPtr UniqueProcessId;
internal IntPtr InheritedFromUniqueProcessId;
[DllImport("ntdll.dll")]
private static extern int NtQueryInformationProcess(IntPtr processHandle, int processInformationClass, ref ParentProcessUtilities processInformation, int processInformationLength, out int returnLength);
/// <summary>
/// Gets the parent process of specified process.
/// </summary>
/// <param name="id">The process id.</param>
/// <returns>An instance of the Process class.</returns>
public static Process? GetParentProcess(int id)
{
Process process = Process.GetProcessById(id);
return GetParentProcess(process.Handle);
}
/// <summary>
/// Gets the parent process of a specified process.
/// </summary>
/// <param name="handle">The process handle.</param>
/// <returns>An instance of the Process class.</returns>
public static Process? GetParentProcess(IntPtr handle)
{
ParentProcessUtilities pbi = new ParentProcessUtilities();
int returnLength;
int status = NtQueryInformationProcess(handle, 0, ref pbi, Marshal.SizeOf(pbi), out returnLength);
if (status != 0)
throw new Win32Exception(status);
try
{
return Process.GetProcessById(pbi.InheritedFromUniqueProcessId.ToInt32());
}
catch (ArgumentException)
{
// not found
return null;
}
}
}
}