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 public class AudioManager
{ {
private WaveOutEvent _waveOut; private Dictionary<string, (WaveOutEvent waveOut, MixingSampleProvider mixer, BufferedWaveProvider buffer, GainSampleProvider gainProvider)> _talkgroupProviders;
private MixingSampleProvider _mixer; private SettingsManager _settingsManager;
private Dictionary<string, (BufferedWaveProvider buffer, GainSampleProvider gainProvider)> _talkgroupProviders;
/// <summary> /// <summary>
/// Creates an instance of <see cref="AudioManager"/> /// Creates an instance of <see cref="AudioManager"/>
/// </summary> /// </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 _settingsManager = settingsManager;
}; _talkgroupProviders = new Dictionary<string, (WaveOutEvent, MixingSampleProvider, BufferedWaveProvider, GainSampleProvider)>();
_waveOut.Init(_mixer);
_waveOut.Play();
} }
/// <summary> /// <summary>
@ -66,6 +57,13 @@ namespace WhackerLinkConsoleV2
/// <param name="talkgroupId"></param> /// <param name="talkgroupId"></param>
private void AddTalkgroupStream(string talkgroupId) 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)) var bufferProvider = new BufferedWaveProvider(new WaveFormat(8000, 16, 1))
{ {
DiscardOnBufferOverflow = true DiscardOnBufferOverflow = true
@ -76,8 +74,17 @@ namespace WhackerLinkConsoleV2
Gain = 1.0f Gain = 1.0f
}; };
_talkgroupProviders[talkgroupId] = (bufferProvider, gainProvider); var mixer = new MixingSampleProvider(WaveFormat.CreateIeeeFloatWaveFormat(8000, 1))
_mixer.AddMixerInput(gainProvider); {
ReadFully = true
};
mixer.AddMixerInput(gainProvider);
waveOut.Init(mixer);
waveOut.Play();
_talkgroupProviders[talkgroupId] = (waveOut, mixer, bufferProvider, gainProvider);
} }
/// <summary> /// <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> /// <summary>
/// Lop off the wave out /// Lop off the wave out
/// </summary> /// </summary>
public void Stop() public void Stop()
{ {
_waveOut.Stop(); foreach (var provider in _talkgroupProviders.Values)
provider.waveOut.Stop();
} }
} }
} }

@ -1,22 +1,25 @@
<Window x:Class="WhackerLinkConsoleV2.AudioSettingsWindow" <Window x:Class="WhackerLinkConsoleV2.AudioSettingsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 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"> WindowStartupLocation="CenterScreen">
<Grid Margin="10"> <Grid Margin="10">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
<RowDefinition Height="*"/> <RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBlock Text="Audio Input Device" FontWeight="Bold" Margin="0,0,0,5"/> <TextBlock Text="Global Audio Input Device" FontWeight="Bold" Margin="0,0,0,5"/>
<ComboBox x:Name="InputDeviceComboBox" Width="300" Margin="70,15,10,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"/> <TextBlock Text="Per-Channel Output Devices" FontWeight="Bold" Grid.Row="2" Margin="0,0,0,5"/>
<ComboBox x:Name="OutputDeviceComboBox" Width="300" Grid.Row="1" Margin="70,18,10,2"/> <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="SaveButton" Content="Save" Width="100" Margin="0,0,10,0" Click="SaveButton_Click"/>
<Button x:Name="CancelButton" Content="Cancel" Width="100" Click="CancelButton_Click"/> <Button x:Name="CancelButton" Content="Cancel" Width="100" Click="CancelButton_Click"/>
</StackPanel> </StackPanel>

@ -14,31 +14,79 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * 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.Windows;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using NAudio.Wave; using NAudio.Wave;
using System.Windows.Controls;
using WhackerLinkLib.Models.Radio;
namespace WhackerLinkConsoleV2 namespace WhackerLinkConsoleV2
{ {
public partial class AudioSettingsWindow : Window public partial class AudioSettingsWindow : Window
{ {
public int? SelectedInputDeviceIndex { get; private set; } private readonly SettingsManager _settingsManager;
public int? SelectedOutputDeviceIndex { get; private set; } 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(); InitializeComponent();
_settingsManager = settingsManager;
_audioManager = audioManager;
_channels = channels;
LoadAudioDevices(); LoadAudioDevices();
LoadChannelOutputSettings();
} }
private void LoadAudioDevices() private void LoadAudioDevices()
{ {
InputDeviceComboBox.ItemsSource = GetAudioInputDevices(); List<string> inputDevices = GetAudioInputDevices();
OutputDeviceComboBox.ItemsSource = GetAudioOutputDevices(); 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() private List<string> GetAudioInputDevices()
@ -69,8 +117,14 @@ namespace WhackerLinkConsoleV2
private void SaveButton_Click(object sender, RoutedEventArgs e) private void SaveButton_Click(object sender, RoutedEventArgs e)
{ {
SelectedInputDeviceIndex = InputDeviceComboBox.SelectedIndex; int selectedInputIndex = InputDeviceComboBox.SelectedIndex;
SelectedOutputDeviceIndex = OutputDeviceComboBox.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; DialogResult = true;
Close(); Close();

@ -83,7 +83,7 @@ namespace WhackerLinkConsoleV2
_waveIn.StartRecording(); _waveIn.StartRecording();
_audioManager = new AudioManager(); _audioManager = new AudioManager(_settingsManager);
_selectedChannelsManager.SelectedChannelsChanged += SelectedChannelsChanged; _selectedChannelsManager.SelectedChannelsChanged += SelectedChannelsChanged;
Loaded += MainWindow_Loaded; Loaded += MainWindow_Loaded;
@ -370,42 +370,10 @@ namespace WhackerLinkConsoleV2
private void AudioSettings_Click(object sender, RoutedEventArgs e) 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) AudioSettingsWindow audioSettingsWindow = new AudioSettingsWindow(_settingsManager, _audioManager, channels);
{ audioSettingsWindow.ShowDialog();
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");
}
}
} }
private void P25Page_Click(object sender, RoutedEventArgs e) 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 Dictionary<string, ChannelPosition> SystemStatusPositions { get; set; } = new Dictionary<string, ChannelPosition>();
public List<string> AlertToneFilePaths { get; set; } = new List<string>(); public List<string> AlertToneFilePaths { get; set; } = new List<string>();
public Dictionary<string, ChannelPosition> AlertTonePositions { get; set; } = new Dictionary<string, ChannelPosition>(); 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() public void LoadSettings()
{ {
@ -57,6 +58,7 @@ namespace WhackerLinkConsoleV2
SystemStatusPositions = loadedSettings.SystemStatusPositions ?? new Dictionary<string, ChannelPosition>(); SystemStatusPositions = loadedSettings.SystemStatusPositions ?? new Dictionary<string, ChannelPosition>();
AlertToneFilePaths = loadedSettings.AlertToneFilePaths ?? new List<string>(); AlertToneFilePaths = loadedSettings.AlertToneFilePaths ?? new List<string>();
AlertTonePositions = loadedSettings.AlertTonePositions ?? new Dictionary<string, ChannelPosition>(); AlertTonePositions = loadedSettings.AlertTonePositions ?? new Dictionary<string, ChannelPosition>();
ChannelOutputDevices = loadedSettings.ChannelOutputDevices ?? new Dictionary<string, int>();
} }
} }
catch (Exception ex) catch (Exception ex)
@ -92,6 +94,12 @@ namespace WhackerLinkConsoleV2
SaveSettings(); SaveSettings();
} }
public void UpdateChannelOutputDevice(string channelName, int deviceIndex)
{
ChannelOutputDevices[channelName] = deviceIndex;
SaveSettings();
}
public void SaveSettings() public void SaveSettings()
{ {
try try

Loading…
Cancel
Save

Powered by TurnKey Linux.