Add adaptive packet loss handling
Build and test / test (macos-latest) (push) Canceled after 0s
Build and test / test (ubuntu-24.04) (push) Canceled after 0s
Build and test / test (windows-latest) (push) Canceled after 0s
Build and test / apple-client (push) Canceled after 0s

This commit is contained in:
2026-09-22 16:54:49 +02:00
parent 7c4708c3de
commit 7b0c003ad4
35 changed files with 518 additions and 60 deletions
@@ -26,6 +26,8 @@ public sealed class ChannelEditDialog : Form
private NumericUpDown _numFrameMs = null!;
private ComboBox _cboApplication = null!;
private CheckBox _chkFec = null!;
private CheckBox _chkAutomaticLoss = null!;
private ComboBox _cboLossSpeed = null!;
private NumericUpDown _numExpectedLoss = null!;
private CheckBox _chkDtx = null!;
private CheckBox _chkDred = null!;
@@ -33,11 +35,14 @@ public sealed class ChannelEditDialog : Form
public ChannelEditInfo? Result { get; private set; }
public ChannelEditDialog(IEnumerable<ChannelInfo> channels, ChannelEditInfo? existing = null)
private readonly bool _supportsAdaptivePacketLoss;
public ChannelEditDialog(IEnumerable<ChannelInfo> channels, ChannelEditInfo? existing = null, bool supportsAdaptivePacketLoss = true)
{
_isCreate = existing is null;
_editingId = existing?.Id ?? 0;
_channels = channels.Where(c => c.Id != _editingId).ToList();
_supportsAdaptivePacketLoss = supportsAdaptivePacketLoss;
Text = _isCreate ? "Create channel" : "Edit channel";
FormBorderStyle = FormBorderStyle.FixedDialog;
@@ -269,6 +274,31 @@ public sealed class ChannelEditDialog : Form
page.Controls.Add(_cboApplication);
y += 34;
_chkAutomaticLoss = new CheckBox
{
Text = "&Automatic packet loss",
Location = new Point(inputX, y),
AutoSize = true,
Checked = audio.PacketLossMode != VcPacketLossMode.Manual,
Enabled = _supportsAdaptivePacketLoss,
TabIndex = 15,
};
page.Controls.Add(_chkAutomaticLoss);
y += 30;
AddLabel(page, "Adaptation &speed:", 12, y, labelWidth);
_cboLossSpeed = new ComboBox
{
Location = new Point(inputX, y - 2),
Size = new Size(160, 23),
DropDownStyle = ComboBoxStyle.DropDownList,
TabIndex = 16,
};
_cboLossSpeed.Items.AddRange(["Fast", "Balanced", "Stable"]);
_cboLossSpeed.SelectedIndex = audio.PacketLossMode == VcPacketLossMode.Manual ? 1 : (int)audio.PacketLossMode - 1;
page.Controls.Add(_cboLossSpeed);
y += 34;
AddLabel(page, "Expected packet loss (%):", 12, y, labelWidth);
_numExpectedLoss = new NumericUpDown
{
@@ -277,9 +307,16 @@ public sealed class ChannelEditDialog : Form
Minimum = 0,
Maximum = 100,
Value = audio.ExpectedPacketLoss,
TabIndex = 15,
TabIndex = 17,
};
page.Controls.Add(_numExpectedLoss);
void UpdateLossControls()
{
_numExpectedLoss.Enabled = !_chkAutomaticLoss.Checked;
_cboLossSpeed.Enabled = _supportsAdaptivePacketLoss && _chkAutomaticLoss.Checked;
}
_chkAutomaticLoss.CheckedChanged += (_, _) => UpdateLossControls();
UpdateLossControls();
y += 34;
AddLabel(page, "Com&plexity (010):", 12, y, labelWidth);
@@ -290,7 +327,7 @@ public sealed class ChannelEditDialog : Form
Minimum = 0,
Maximum = 10,
Value = audio.Complexity,
TabIndex = 16,
TabIndex = 18,
};
page.Controls.Add(_numComplexity);
y += 34;
@@ -301,7 +338,7 @@ public sealed class ChannelEditDialog : Form
Location = new Point(inputX, y),
AutoSize = true,
Checked = audio.Fec,
TabIndex = 17,
TabIndex = 19,
};
page.Controls.Add(_chkFec);
y += 28;
@@ -312,7 +349,7 @@ public sealed class ChannelEditDialog : Form
Location = new Point(inputX, y),
AutoSize = true,
Checked = audio.Dtx,
TabIndex = 18,
TabIndex = 20,
};
page.Controls.Add(_chkDtx);
y += 28;
@@ -323,7 +360,7 @@ public sealed class ChannelEditDialog : Form
Location = new Point(inputX, y),
AutoSize = true,
Checked = audio.Dred,
TabIndex = 19,
TabIndex = 21,
};
page.Controls.Add(_chkDred);
}
@@ -375,7 +412,8 @@ public sealed class ChannelEditDialog : Form
ExpectedPacketLoss: (uint)_numExpectedLoss.Value,
Dtx: _chkDtx.Checked,
Complexity: (uint)_numComplexity.Value,
Dred: _chkDred.Checked);
Dred: _chkDred.Checked,
PacketLossMode: _chkAutomaticLoss.Checked ? (VcPacketLossMode)(_cboLossSpeed.SelectedIndex + 1) : VcPacketLossMode.Manual);
Result = new ChannelEditInfo(
Id: _editingId,
@@ -1132,7 +1132,7 @@ public partial class MainForm : Form
private void CreateChannel()
{
using var dlg = new ChannelEditDialog(_channels);
using var dlg = new ChannelEditDialog(_channels, supportsAdaptivePacketLoss: _client.SupportsAdaptivePacketLoss);
if (dlg.ShowDialog(this) != DialogResult.OK || dlg.Result is null) return;
_client.CreateChannel(dlg.Result);
}
@@ -1148,7 +1148,7 @@ public partial class MainForm : Form
channel.PasswordProtected, null, channel.MaxUsers, channel.SortOrder,
channel.Audio);
using var dlg = new ChannelEditDialog(_channels, editInfo);
using var dlg = new ChannelEditDialog(_channels, editInfo, _client.SupportsAdaptivePacketLoss);
if (dlg.ShowDialog(this) != DialogResult.OK || dlg.Result is null) return;
_client.EditChannel(dlg.Result);
}
@@ -27,6 +27,7 @@ public sealed partial class VoiceCatClient
Id = info.Id, ParentId = info.ParentId, Name = info.Name, Topic = info.Topic, MaxUsers = info.MaxUsers, Order = info.SortOrder,
Audio = new() { Codec = info.Audio.Codec, Mode = info.Audio.Stereo ? ChannelMode.ModeStereo : ChannelMode.ModeMono, SampleRate = info.Audio.SampleRate,
BitrateBps = info.Audio.BitrateBps, FrameMs = info.Audio.FrameMs, Application = (OpusApplication)info.Audio.Application, Complexity = info.Audio.Complexity,
Fec = info.Audio.Fec, ExpectedPacketLoss = info.Audio.ExpectedPacketLoss, Dtx = info.Audio.Dtx, Dred = info.Audio.Dred }
Fec = info.Audio.Fec, ExpectedPacketLoss = info.Audio.ExpectedPacketLoss, Dtx = info.Audio.Dtx, Dred = info.Audio.Dred,
PacketLossMode = (PacketLossMode)info.Audio.PacketLossMode }
};
}
@@ -1,6 +1,8 @@
// Windows-facing state and command values used by the WinForms application.
namespace VoiceCat.Windows;
public enum VcPacketLossMode { Manual, AutoFast, AutoBalanced, AutoStable }
public enum VcResult
{
Ok = 0,
+2 -1
View File
@@ -73,4 +73,5 @@ public sealed record AudioConfigInfo(
uint ExpectedPacketLoss,
bool Dtx,
uint Complexity,
bool Dred);
bool Dred,
VcPacketLossMode PacketLossMode = VcPacketLossMode.Manual);
@@ -87,6 +87,7 @@ public sealed partial class VoiceCatClient : IDisposable
StopDevices(); core.DisconnectAsync().GetAwaiter().GetResult(); return VcResult.Ok;
}
public string GetServerIdentityDisplay() => core.ServerHello is { } hello ? Convert.ToHexString(hello.ServerIdentityFingerprint.Span) : "";
public bool SupportsAdaptivePacketLoss => core.SupportsAdaptivePacketLoss;
public void PumpEvents()
{
@@ -182,7 +183,7 @@ public sealed partial class VoiceCatClient : IDisposable
public List<DeviceInfo> ListDevices(VcDeviceKind kind) => backend?.Enumerate(kind == VcDeviceKind.Input).Select(d => new DeviceInfo(d.Id, d.Name, d.IsDefault)).ToList() ?? [];
public static string VersionString => "VoiceCat managed core 0.1.0 (protocol v2)";
public static string ResultString(VcResult result) => result.ToString();
private static AudioConfigInfo Audio(AudioConfig a) => new(a.Codec, a.Mode == ChannelMode.ModeStereo, a.SampleRate, a.BitrateBps, a.FrameMs, (uint)a.Application, a.Fec, a.ExpectedPacketLoss, a.Dtx, a.Complexity, a.Dred);
private static AudioConfigInfo Audio(AudioConfig a) => new(a.Codec, a.Mode == ChannelMode.ModeStereo, a.SampleRate, a.BitrateBps, a.FrameMs, (uint)a.Application, a.Fec, a.ExpectedPacketLoss, a.Dtx, a.Complexity, a.Dred, (VcPacketLossMode)a.PacketLossMode);
private void StopDevices()
{