Add per channel output devices

pull/1/head
firealarmss 11 months ago
parent f9a23c6601
commit f3185d5e05

@ -26,25 +26,16 @@ namespace WhackerLinkConsoleV2
{
public class AudioManager
{
private WaveOutEvent _waveOut;
private MixingSampleProvider _mixer;
private Dictionary<string, (BufferedWaveProvider buffer, GainSampleProvider gainProvider)> _talkgroupProviders;
private Dictionary<string, (WaveOutEvent waveOut, MixingSampleProvider mixer, BufferedWaveProvider buffer, GainSampleProvider gainProvider)> _talkgroupProviders;
private SettingsManager _settingsManager;
/// <summary>
/// Creates an instance of <see cref="AudioManager"/>
/// </summary>
public AudioManager()
public AudioManager(SettingsManager settingsManager)
{
_waveOut = new WaveOutEvent();
_talkgroupProviders = new Dictionary<string, (BufferedWaveProvider, GainSampleProvider)>();
_mixer = new MixingSampleProvider(WaveFormat.CreateIeeeFloatWaveFormat(8000, 1))
{
ReadFully = true
};
_waveOut.Init(_mixer);
_waveOut.Play();
_settingsManager = settingsManager;
_talkgroupProviders = new Dictionary<string, (WaveOutEvent, MixingSampleProvider, BufferedWaveProvider, GainSampleProvider)>();
}
/// <summary>
@ -66,6 +57,13 @@ namespace WhackerLinkConsoleV2
/// <param name="talkgroupId"></param>
private void AddTalkgroupStream(string talkgroupId)
{
int deviceIndex = _settingsManager.ChannelOutputDevices.ContainsKey(talkgroupId) ? _settingsManager.ChannelOutputDevices[talkgroupId] : 0;
var waveOut = new WaveOutEvent
{
DeviceNumber = deviceIndex
};
var bufferProvider = new BufferedWaveProvider(new WaveFormat(8000, 16, 1))
{
DiscardOnBufferOverflow = true
@ -76,8 +74,17 @@ namespace WhackerLinkConsoleV2
Gain = 1.0f
};
_talkgroupProviders[talkgroupId] = (bufferProvider, gainProvider);
_mixer.AddMixerInput(gainProvider);
var mixer = new MixingSampleProvider(WaveFormat.CreateIeeeFloatWaveFormat(8000, 1))
{
ReadFully = true
};
mixer.AddMixerInput(gainProvider);
waveOut.Init(mixer);
waveOut.Play();
_talkgroupProviders[talkgroupId] = (waveOut, mixer, bufferProvider, gainProvider);
}
/// <summary>
@ -96,12 +103,30 @@ namespace WhackerLinkConsoleV2
}
}
/// <summary>
/// Set stream output device
/// </summary>
/// <param name="talkgroupId"></param>
/// <param name="deviceIndex"></param>
public void SetTalkgroupOutputDevice(string talkgroupId, int deviceIndex)
{
if (_talkgroupProviders.ContainsKey(talkgroupId))
{
_talkgroupProviders[talkgroupId].waveOut.Stop();
_talkgroupProviders.Remove(talkgroupId);
}
_settingsManager.UpdateChannelOutputDevice(talkgroupId, deviceIndex);
AddTalkgroupStream(talkgroupId);
}
/// <summary>
/// Lop off the wave out
/// </summary>
public void Stop()
{
_waveOut.Stop();
foreach (var provider in _talkgroupProviders.Values)
provider.waveOut.Stop();
}
}
}

@ -1,22 +1,25 @@
<Window x:Class="WhackerLinkConsoleV2.AudioSettingsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Audio Settings" Height="250" Width="400"
Title="Audio Settings" Height="400" Width="450"
WindowStartupLocation="CenterScreen">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="Audio Input Device" FontWeight="Bold" Margin="0,0,0,5"/>
<ComboBox x:Name="InputDeviceComboBox" Width="300" Margin="70,15,10,5"/>
<TextBlock Text="Global Audio Input Device" FontWeight="Bold" Margin="0,0,0,5"/>
<ComboBox x:Name="InputDeviceComboBox" Width="350" Margin="0,5,0,15" Grid.Row="1"/>
<TextBlock Text="Audio Output Device" FontWeight="Bold" Grid.Row="1" Margin="0,0,0,5"/>
<ComboBox x:Name="OutputDeviceComboBox" Width="300" Grid.Row="1" Margin="70,18,10,2"/>
<TextBlock Text="Per-Channel Output Devices" FontWeight="Bold" Grid.Row="2" Margin="0,0,0,5"/>
<ScrollViewer Grid.Row="2" Height="200">
<StackPanel x:Name="ChannelOutputStackPanel"/>
</ScrollViewer>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row="2" Margin="0,20,0,0">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row="3" Margin="0,20,0,0">
<Button x:Name="SaveButton" Content="Save" Width="100" Margin="0,0,10,0" Click="SaveButton_Click"/>
<Button x:Name="CancelButton" Content="Cancel" Width="100" Click="CancelButton_Click"/>
</StackPanel>

@ -14,31 +14,79 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright (C) 2024 Caleb, K4PHP
* Copyright (C) 2024-2025 Caleb, K4PHP
*
*/
using System.Windows;
using System.Collections.Generic;
using System.Linq;
using NAudio.Wave;
using System.Windows.Controls;
using WhackerLinkLib.Models.Radio;
namespace WhackerLinkConsoleV2
{
public partial class AudioSettingsWindow : Window
{
public int? SelectedInputDeviceIndex { get; private set; }
public int? SelectedOutputDeviceIndex { get; private set; }
private readonly SettingsManager _settingsManager;
private readonly AudioManager _audioManager;
private readonly List<Codeplug.Channel> _channels;
private readonly Dictionary<string, int> _selectedOutputDevices = new Dictionary<string, int>();
public AudioSettingsWindow()
public AudioSettingsWindow(SettingsManager settingsManager, AudioManager audioManager, List<Codeplug.Channel> channels)
{
InitializeComponent();
_settingsManager = settingsManager;
_audioManager = audioManager;
_channels = channels;
LoadAudioDevices();
LoadChannelOutputSettings();
}
private void LoadAudioDevices()
{
InputDeviceComboBox.ItemsSource = GetAudioInputDevices();
OutputDeviceComboBox.ItemsSource = GetAudioOutputDevices();
List<string> inputDevices = GetAudioInputDevices();
List<string> outputDevices = GetAudioOutputDevices();
InputDeviceComboBox.ItemsSource = inputDevices;
InputDeviceComboBox.SelectedIndex = _settingsManager.ChannelOutputDevices.ContainsKey("GLOBAL_INPUT")
? _settingsManager.ChannelOutputDevices["GLOBAL_INPUT"]
: 0;
}
private void LoadChannelOutputSettings()
{
List<string> outputDevices = GetAudioOutputDevices();
foreach (var channel in _channels)
{
TextBlock channelLabel = new TextBlock
{
Text = channel.Name,
FontWeight = FontWeights.Bold,
Margin = new Thickness(0, 5, 0, 0)
};
ComboBox outputDeviceComboBox = new ComboBox
{
Width = 350,
ItemsSource = outputDevices,
SelectedIndex = _settingsManager.ChannelOutputDevices.ContainsKey(channel.Tgid)
? _settingsManager.ChannelOutputDevices[channel.Tgid]
: 0
};
outputDeviceComboBox.SelectionChanged += (s, e) =>
{
int selectedIndex = outputDeviceComboBox.SelectedIndex;
_selectedOutputDevices[channel.Tgid] = selectedIndex;
};
ChannelOutputStackPanel.Children.Add(channelLabel);
ChannelOutputStackPanel.Children.Add(outputDeviceComboBox);
}
}
private List<string> GetAudioInputDevices()
@ -69,8 +117,14 @@ namespace WhackerLinkConsoleV2
private void SaveButton_Click(object sender, RoutedEventArgs e)
{
SelectedInputDeviceIndex = InputDeviceComboBox.SelectedIndex;
SelectedOutputDeviceIndex = OutputDeviceComboBox.SelectedIndex;
int selectedInputIndex = InputDeviceComboBox.SelectedIndex;
_settingsManager.UpdateChannelOutputDevice("GLOBAL_INPUT", selectedInputIndex);
foreach (var entry in _selectedOutputDevices)
{
_settingsManager.UpdateChannelOutputDevice(entry.Key, entry.Value);
_audioManager.SetTalkgroupOutputDevice(entry.Key, entry.Value);
}
DialogResult = true;
Close();

@ -83,7 +83,7 @@ namespace WhackerLinkConsoleV2
_waveIn.StartRecording();
_audioManager = new AudioManager();
_audioManager = new AudioManager(_settingsManager);
_selectedChannelsManager.SelectedChannelsChanged += SelectedChannelsChanged;
Loaded += MainWindow_Loaded;
@ -370,42 +370,10 @@ namespace WhackerLinkConsoleV2
private void AudioSettings_Click(object sender, RoutedEventArgs e)
{
AudioSettingsWindow audioSettingsWindow = new AudioSettingsWindow();
List<Codeplug.Channel> channels = Codeplug?.Zones.SelectMany(z => z.Channels).ToList() ?? new List<Codeplug.Channel>();
if (audioSettingsWindow.ShowDialog() == true)
{
int? inputDeviceIndex = audioSettingsWindow.SelectedInputDeviceIndex;
int? outputDeviceIndex = audioSettingsWindow.SelectedOutputDeviceIndex;
if (inputDeviceIndex.HasValue && outputDeviceIndex.HasValue)
{
MessageBox.Show($"Selected Input Device Index: {inputDeviceIndex}\n" +
$"Selected Output Device Index: {outputDeviceIndex}",
"Selected Devices");
try
{
_waveIn.StopRecording();
_waveIn.DeviceNumber = inputDeviceIndex.Value;
_waveIn.StartRecording();
//_waveOut.Stop();
//_waveOut.DeviceNumber = outputDeviceIndex.Value;
//_waveOut.Init(_waveProvider);
//_waveOut.Play();
MessageBox.Show("Audio devices updated successfully.", "Success");
}
catch (Exception ex)
{
MessageBox.Show($"Failed to update audio devices: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
else
{
MessageBox.Show("No device selected.", "Warning");
}
}
AudioSettingsWindow audioSettingsWindow = new AudioSettingsWindow(_settingsManager, _audioManager, channels);
audioSettingsWindow.ShowDialog();
}
private void P25Page_Click(object sender, RoutedEventArgs e)

@ -37,6 +37,7 @@ namespace WhackerLinkConsoleV2
public Dictionary<string, ChannelPosition> SystemStatusPositions { get; set; } = new Dictionary<string, ChannelPosition>();
public List<string> AlertToneFilePaths { get; set; } = new List<string>();
public Dictionary<string, ChannelPosition> AlertTonePositions { get; set; } = new Dictionary<string, ChannelPosition>();
public Dictionary<string, int> ChannelOutputDevices { get; set; } = new Dictionary<string, int>();
public void LoadSettings()
{
@ -57,6 +58,7 @@ namespace WhackerLinkConsoleV2
SystemStatusPositions = loadedSettings.SystemStatusPositions ?? new Dictionary<string, ChannelPosition>();
AlertToneFilePaths = loadedSettings.AlertToneFilePaths ?? new List<string>();
AlertTonePositions = loadedSettings.AlertTonePositions ?? new Dictionary<string, ChannelPosition>();
ChannelOutputDevices = loadedSettings.ChannelOutputDevices ?? new Dictionary<string, int>();
}
}
catch (Exception ex)
@ -92,6 +94,12 @@ namespace WhackerLinkConsoleV2
SaveSettings();
}
public void UpdateChannelOutputDevice(string channelName, int deviceIndex)
{
ChannelOutputDevices[channelName] = deviceIndex;
SaveSettings();
}
public void SaveSettings()
{
try

Loading…
Cancel
Save

Powered by TurnKey Linux.