Add adaptive packet loss handling
This commit is contained in:
@@ -10,6 +10,34 @@ namespace VoiceCat.Tests;
|
||||
|
||||
public sealed class MediaRelayTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task AutomaticModeReportsAuthenticatedSenderUplinkLossWithCap()
|
||||
{
|
||||
var clock = new ManualClock();
|
||||
await using var fixture = new ServerFixture(timeProvider: clock);
|
||||
Client admin = await ChannelManagementTests.AdminAsync(fixture);
|
||||
using (var store = new VoiceCat.Server.Data.AccountStore(Path.Combine(fixture.Directory, "voicecat.db")))
|
||||
{
|
||||
Channel lobby = store.LoadChannels().Single(channel => channel.Id == 1);
|
||||
lobby.Audio.PacketLossMode = PacketLossMode.PacketLossAutoFast;
|
||||
Assert.True(await ChannelManagementTests.ResultAsync(admin, new() { EditChannel = new() { Channel = lobby } }));
|
||||
}
|
||||
await using var alice = await VoicePeer.AttachAsync(fixture, admin);
|
||||
await using var bob = await VoicePeer.ConnectAsync(fixture, "Bob");
|
||||
StreamAnnounceResult stream = await alice.AnnounceAsync(StreamKind.StreamMic);
|
||||
|
||||
await alice.SendAsync(alice.Seal(stream.Ssrc, [1]));
|
||||
await bob.ReceiveVoiceAsync();
|
||||
for (int i = 0; i < 99; i++) alice.Seal(stream.Ssrc, [2]);
|
||||
clock.Advance(TimeSpan.FromSeconds(3));
|
||||
await alice.SendAsync(alice.Seal(stream.Ssrc, [3]));
|
||||
|
||||
PacketLossUpdate update = (await admin.ReadUntilAsync(envelope => envelope.PacketLossUpdate is not null)).PacketLossUpdate;
|
||||
Assert.Equal(1U, update.ChannelId);
|
||||
Assert.Equal(99U, update.MeasuredPercent);
|
||||
Assert.Equal(30U, update.AppliedPercent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DisconnectInvalidatesBothBindingAndActiveStreams()
|
||||
{
|
||||
@@ -162,6 +190,10 @@ public sealed class MediaRelayTests
|
||||
{
|
||||
Client client = await fixture.ConnectAsync();
|
||||
await client.LoginAsync(nickname);
|
||||
return await AttachAsync(fixture, client);
|
||||
}
|
||||
internal static async Task<VoicePeer> AttachAsync(ServerFixture fixture, Client client)
|
||||
{
|
||||
var peer = new VoicePeer(client, fixture.Server.MediaEndPoint, await client.TakeMediaCryptoAsync());
|
||||
client.Send(new() { UdpBinding = new() { UdpToken = client.Authentication!.UdpToken } });
|
||||
Assert.True((await client.ReadUntilAsync(e => e.UdpBinding is not null)).UdpBinding.Ack);
|
||||
@@ -217,4 +249,12 @@ public sealed class MediaRelayTests
|
||||
}
|
||||
public async ValueTask DisposeAsync() { udp.Dispose(); crypto.Dispose(); await Client.DisposeAsync(); }
|
||||
}
|
||||
|
||||
private sealed class ManualClock : TimeProvider
|
||||
{
|
||||
private long timestamp;
|
||||
public override long TimestampFrequency => 1_000;
|
||||
public override long GetTimestamp() => Volatile.Read(ref timestamp);
|
||||
internal void Advance(TimeSpan duration) => Interlocked.Add(ref timestamp, (long)duration.TotalMilliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user