v0.6: DHCP tunnel transport with NOP heartbeat protocol

This commit is contained in:
2026-08-12 00:29:54 +00:00
parent 4a58b94f35
commit e1739059d9
12 changed files with 743 additions and 528 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ public sealed class AppConfig
public int LengthScale { get; set; } = 100;
public int NoiseWScale { get; set; } = 800;
public bool MinimizeToTray { get; set; } = true;
public string ServerEndpoint { get; set; } = "127.0.0.1:5210";
public string InterfaceIp { get; set; } = string.Empty;
public static string AppDataDir => Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
+9 -17
View File
@@ -17,8 +17,7 @@ partial class MainForm
private Button btnBrowseFile = null!;
private Label lblFileName = null!;
private Label lblServer = null!;
private TextBox txtServer = null!;
private Button btnConnect = null!;
private ComboBox cmbInterface = null!;
private Label lblLineStatus = null!;
private RichTextBox txtLog = null!;
private CheckBox chkMinimizeToTray = null!;
@@ -58,8 +57,7 @@ partial class MainForm
btnBrowseFile = new Button();
lblFileName = new Label();
lblServer = new Label();
txtServer = new TextBox();
btnConnect = new Button();
cmbInterface = new ComboBox();
lblLineStatus = new Label();
txtLog = new RichTextBox();
chkMinimizeToTray = new CheckBox();
@@ -145,20 +143,15 @@ partial class MainForm
lblFileName.ForeColor = Color.Gray;
// lblServer
lblServer.Text = "Server:";
lblServer.Text = "Interface:";
lblServer.Location = new Point(440, 48);
lblServer.Size = new Size(45, 23);
lblServer.Size = new Size(55, 23);
lblServer.TextAlign = ContentAlignment.MiddleLeft;
// txtServer
txtServer.Location = new Point(488, 45);
txtServer.Size = new Size(110, 23);
// btnConnect
btnConnect.Text = "Connect";
btnConnect.Location = new Point(603, 44);
btnConnect.Size = new Size(60, 25);
btnConnect.UseVisualStyleBackColor = true;
// cmbInterface
cmbInterface.Location = new Point(498, 45);
cmbInterface.Size = new Size(165, 23);
cmbInterface.DropDownStyle = ComboBoxStyle.DropDownList;
// lblLineStatus
lblLineStatus.Text = "";
@@ -277,8 +270,7 @@ partial class MainForm
Controls.Add(btnBrowseFile);
Controls.Add(lblFileName);
Controls.Add(lblServer);
Controls.Add(txtServer);
Controls.Add(btnConnect);
Controls.Add(cmbInterface);
Controls.Add(lblLineStatus);
Controls.Add(lblNoise);
Controls.Add(trkNoise);
+48 -29
View File
@@ -2,7 +2,7 @@ using NAudio.Wave;
using Robovoice.App;
using Robovoice.Core;
using Robovoice.Core.Voices;
using Robovoice.Stt.Tcp;
using Robovoice.Stt.Dhcp;
using Robovoice.Tts.LibPiper;
using System.Diagnostics;
@@ -16,7 +16,7 @@ internal sealed partial class MainForm : Form
private LibPiperTtsEngine? _tts;
private AudioOutput? _audioOutput;
private TcpSttSource? _sttSource;
private DhcpSttSource? _sttSource;
private Orchestrator? _orchestrator;
private PttHotkey? _pttHotkey;
private NotifyIcon? _trayIcon;
@@ -61,7 +61,7 @@ internal sealed partial class MainForm : Form
OnSliderScroll(null, EventArgs.Empty);
chkMinimizeToTray.Checked = _config.MinimizeToTray;
txtServer.Text = _config.ServerEndpoint;
PopulateInterfaces();
btnBrowseFile.Click += OnBrowseFile;
btnTestVoice.Click += OnTestVoice;
@@ -71,8 +71,7 @@ internal sealed partial class MainForm : Form
txtPttKey.KeyDown += OnPttKeyDown;
cmbOutput.SelectedIndexChanged += OnOutputChanged;
cmbVoice.SelectedIndexChanged += OnVoiceChanged;
txtServer.Leave += OnServerChanged;
btnConnect.Click += OnConnect;
cmbInterface.SelectedIndexChanged += OnInterfaceChanged;
trkNoise.Scroll += OnSliderScroll;
trkSpeed.Scroll += OnSliderScroll;
@@ -245,8 +244,9 @@ internal sealed partial class MainForm : Form
if (_sttSource is null)
{
_sttSource = new TcpSttSource { ServerEndpoint = txtServer.Text, Log = Log };
Log($"STT endpoint: {_sttSource.ServerEndpoint} (press Connect)");
string ifaceIp = cmbInterface.SelectedItem as string ?? "";
_sttSource = new DhcpSttSource { InterfaceIp = ifaceIp, Log = Log };
await _sttSource.StartAsync();
}
_orchestrator?.DisposeAsync().AsTask().Wait();
@@ -425,40 +425,59 @@ internal sealed partial class MainForm : Form
SaveConfig();
}
private void OnServerChanged(object? sender, EventArgs e)
private void PopulateInterfaces()
{
if (_sttSource is not null)
cmbInterface.Items.Clear();
foreach (var (ip, name) in DhcpSttSource.GetAvailableInterfaces())
{
_sttSource.ServerEndpoint = txtServer.Text;
Log($"Server endpoint: {txtServer.Text}");
cmbInterface.Items.Add(name);
cmbInterface.Items[^1] = name;
cmbInterface.Items[cmbInterface.Items.Count - 1] = name;
}
SaveConfig();
if (!string.IsNullOrEmpty(_config.InterfaceIp))
{
for (int i = 0; i < cmbInterface.Items.Count; i++)
{
if (cmbInterface.Items[i] is string s && s.Contains(_config.InterfaceIp))
{
cmbInterface.SelectedIndex = i;
return;
}
}
}
if (cmbInterface.Items.Count > 0)
cmbInterface.SelectedIndex = 0;
}
private async void OnConnect(object? sender, EventArgs e)
private void OnInterfaceChanged(object? sender, EventArgs e)
{
if (_sttSource is null)
{
Log("STT source not initialized.");
if (cmbInterface.SelectedItem is not string selected)
return;
}
_sttSource.ServerEndpoint = txtServer.Text;
string? ip = ExtractIpFromDisplay(selected);
if (ip is null) return;
_config.InterfaceIp = ip;
SaveConfig();
btnConnect.Enabled = false;
try
if (_sttSource is not null)
{
if (_sttSource.IsRunning)
await _sttSource.ReconnectAsync();
else
await _sttSource.StartAsync();
}
finally
{
btnConnect.Enabled = true;
_sttSource.DisposeAsync().AsTask().Wait(2000);
_sttSource = null;
_ = InitializeEngineAsync();
}
}
private static string? ExtractIpFromDisplay(string display)
{
int start = display.IndexOf('(');
int end = display.IndexOf(')');
if (start < 0 || end <= start) return null;
return display[(start + 1)..end];
}
private void SetupTray()
{
if (_trayInit) return;
@@ -524,7 +543,7 @@ internal sealed partial class MainForm : Form
_config.LengthScale = trkSpeed.Value;
_config.NoiseWScale = trkNoiseW.Value;
_config.MinimizeToTray = chkMinimizeToTray.Checked;
_config.ServerEndpoint = txtServer.Text;
_config.InterfaceIp = ExtractIpFromDisplay(cmbInterface.SelectedItem as string ?? "") ?? "";
_config.Save();
}
+1 -1
View File
@@ -3,7 +3,7 @@
<ItemGroup>
<ProjectReference Include="..\Robovoice.Core\Robovoice.Core.csproj" />
<ProjectReference Include="..\Robovoice.Tts.LibPiper\Robovoice.Tts.LibPiper.csproj" />
<ProjectReference Include="..\Robovoice.Stt.Tcp\Robovoice.Stt.Tcp.csproj" />
<ProjectReference Include="..\Robovoice.Stt.Dhcp\Robovoice.Stt.Dhcp.csproj" />
</ItemGroup>
<ItemGroup>