Added WPF tester
This commit is contained in:
245
EonaCat.VolumeMixer.Tester.WPF/MainWindow.xaml.cs
Normal file
245
EonaCat.VolumeMixer.Tester.WPF/MainWindow.xaml.cs
Normal file
@@ -0,0 +1,245 @@
|
||||
using EonaCat.VolumeMixer.Managers;
|
||||
using EonaCat.VolumeMixer.Models;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace EonaCat.VolumeMixer.Tester.WPF
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
public ObservableCollection<AudioDeviceViewModel> Devices { get; } = new();
|
||||
public ObservableCollection<AudioSessionViewModel> Sessions { get; } = new();
|
||||
private VolumeMixerManager _manager;
|
||||
private AudioDevice _currentDevice;
|
||||
private readonly DispatcherTimer _pollTimer = new() { Interval = TimeSpan.FromMilliseconds(250) };
|
||||
|
||||
private readonly DispatcherTimer _refreshTimer = new() { Interval = TimeSpan.FromSeconds(10) };
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
DeviceSelector.ItemsSource = Devices;
|
||||
SessionList.ItemsSource = Sessions;
|
||||
_refreshTimer.Tick += (s, e) => RefreshSessions().ConfigureAwait(false);
|
||||
_pollTimer.Tick += PollTimer_Tick;
|
||||
LoadDevices();
|
||||
}
|
||||
|
||||
private async void PollTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
foreach (var sessionVm in Sessions)
|
||||
{
|
||||
await sessionVm.PollRefreshAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private async void LoadDevices()
|
||||
{
|
||||
_manager = new VolumeMixerManager();
|
||||
var devices = await _manager.GetAudioDevicesAsync(DataFlow.All);
|
||||
Devices.Clear();
|
||||
foreach (var device in devices)
|
||||
{
|
||||
Devices.Add(new AudioDeviceViewModel(device));
|
||||
}
|
||||
|
||||
var defaultDevice = await _manager.GetDefaultAudioDeviceAsync();
|
||||
DeviceSelector.SelectedItem = Devices.FirstOrDefault(d => d.Id == defaultDevice.Id);
|
||||
}
|
||||
|
||||
private async void DeviceSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (DeviceSelector.SelectedItem is not AudioDeviceViewModel selectedVm)
|
||||
{
|
||||
_refreshTimer.Stop();
|
||||
_pollTimer.Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
_currentDevice = selectedVm.Device;
|
||||
await RefreshSessions();
|
||||
_refreshTimer.Start();
|
||||
_pollTimer.Start();
|
||||
}
|
||||
|
||||
private async Task RefreshSessions()
|
||||
{
|
||||
if (_currentDevice == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var sessions = await _currentDevice.GetAudioSessionsAsync();
|
||||
Sessions.Clear();
|
||||
foreach (var session in sessions)
|
||||
{
|
||||
var vm = new AudioSessionViewModel(session);
|
||||
await vm.RefreshAsync();
|
||||
Sessions.Add(vm);
|
||||
}
|
||||
}
|
||||
|
||||
private void Slider_PreviewMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
{
|
||||
if (((FrameworkElement)sender).DataContext is AudioSessionViewModel vm)
|
||||
{
|
||||
vm.IsUserChangingVolume = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void Slider_PreviewMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
{
|
||||
if (((FrameworkElement)sender).DataContext is AudioSessionViewModel vm)
|
||||
{
|
||||
vm.IsUserChangingVolume = false;
|
||||
_ = vm.RefreshAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private void Slider_PreviewTouchDown(object sender, System.Windows.Input.TouchEventArgs e)
|
||||
{
|
||||
if (((FrameworkElement)sender).DataContext is AudioSessionViewModel vm)
|
||||
{
|
||||
vm.IsUserChangingVolume = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void Slider_PreviewTouchUp(object sender, System.Windows.Input.TouchEventArgs e)
|
||||
{
|
||||
if (((FrameworkElement)sender).DataContext is AudioSessionViewModel vm)
|
||||
{
|
||||
vm.IsUserChangingVolume = false;
|
||||
_ = vm.RefreshAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class AudioDeviceViewModel
|
||||
{
|
||||
public AudioDevice Device { get; }
|
||||
public string Display => Device.Name;
|
||||
public string Id => Device.Id;
|
||||
public BitmapImage Icon => new BitmapImage(new Uri("pack://application:,,,/Resources/" + (Device.DeviceType == DeviceType.Microphone ? "mic.png" : "speaker.png")));
|
||||
|
||||
public AudioDeviceViewModel(AudioDevice device)
|
||||
{
|
||||
Device = device;
|
||||
}
|
||||
}
|
||||
|
||||
public class AudioSessionViewModel : INotifyPropertyChanged
|
||||
{
|
||||
private readonly AudioSession _session;
|
||||
private float _volume;
|
||||
private bool _isMuted;
|
||||
|
||||
public string DisplayName => _session.DisplayName;
|
||||
|
||||
private bool _isUserChangingVolume;
|
||||
|
||||
public bool IsUserChangingVolume
|
||||
{
|
||||
get => _isUserChangingVolume;
|
||||
set
|
||||
{
|
||||
if (_isUserChangingVolume != value)
|
||||
{
|
||||
_isUserChangingVolume = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public float Volume
|
||||
{
|
||||
get => _volume;
|
||||
set
|
||||
{
|
||||
if (Math.Abs(_volume - value) > 0.01)
|
||||
{
|
||||
value = Math.Clamp(value, 0, 1);
|
||||
|
||||
if (_volume == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_volume = value;
|
||||
OnPropertyChanged();
|
||||
_ = SetVolumeSafeAsync(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SetVolumeSafeAsync(float value)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _session.SetVolumeAsync(value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool IsMuted
|
||||
{
|
||||
get => _isMuted;
|
||||
set
|
||||
{
|
||||
if (_isMuted != value)
|
||||
{
|
||||
_isMuted = value;
|
||||
_ = _session.SetMuteAsync(value);
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task PollRefreshAsync()
|
||||
{
|
||||
if (!IsUserChangingVolume)
|
||||
{
|
||||
float currentVolume = await _session.GetVolumeAsync();
|
||||
if (Math.Abs(currentVolume - _volume) > 0.01)
|
||||
{
|
||||
_volume = currentVolume;
|
||||
OnPropertyChanged(nameof(Volume));
|
||||
}
|
||||
|
||||
bool currentMute = await _session.GetMuteAsync();
|
||||
if (currentMute != _isMuted)
|
||||
{
|
||||
_isMuted = currentMute;
|
||||
OnPropertyChanged(nameof(IsMuted));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public AudioSessionViewModel(AudioSession session)
|
||||
{
|
||||
_session = session;
|
||||
}
|
||||
|
||||
public async Task RefreshAsync()
|
||||
{
|
||||
Volume = await _session.GetVolumeAsync();
|
||||
IsMuted = await _session.GetMuteAsync();
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
protected void OnPropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user