Fix iOS voice capture and screen sharing
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-21 14:14:15 +02:00
parent 35617e9708
commit 0372baf589
13 changed files with 389 additions and 66 deletions
+10 -9
View File
@@ -16,7 +16,7 @@ internal sealed class ClientMediaTransport : IAsyncDisposable
private readonly byte[] binding = new byte[VoiceFrameHeader.Size + 16];
private readonly byte[] keepalive = new byte[VoiceFrameHeader.Size];
private readonly PacketQueue packets = new();
private readonly Task sending;
private readonly Thread sending;
private readonly Task receiving;
private readonly TaskCompletionSource bound = new(TaskCreationOptions.RunContinuationsAsynchronously);
internal event EncodedVoiceHandler? Received;
@@ -34,12 +34,13 @@ internal sealed class ClientMediaTransport : IAsyncDisposable
token.CopyTo(binding.AsSpan(VoiceFrameHeader.Size));
new VoiceFrameHeader(MediaFrameType.Keepalive, 0, 0, 0, 0, 0).Write(keepalive);
receiving = ReceiveAsync();
sending = SendAsync();
sending = new Thread(Send) { IsBackground = true, Name = "VoiceCat UDP sender", Priority = ThreadPriority.AboveNormal };
sending.Start();
}
internal bool TrySend(VoiceFrameHeader header, ReadOnlySpan<byte> payload) => packets.TryWrite(header, payload);
private async Task SendAsync()
private void Send()
{
byte[] plain = new byte[1275], packet = new byte[1275 + VoiceFrameHeader.Size + MediaEncryptor.TagSize];
long nextKeepalive = 0;
@@ -49,19 +50,19 @@ internal sealed class ClientMediaTransport : IAsyncDisposable
{
if (Environment.TickCount64 >= nextKeepalive)
{
if (!bound.Task.IsCompleted) await socket.SendAsync(binding, SocketFlags.None, stop.Token).ConfigureAwait(false);
await socket.SendAsync(keepalive, SocketFlags.None, stop.Token).ConfigureAwait(false);
if (!bound.Task.IsCompleted) socket.Send(binding, SocketFlags.None);
socket.Send(keepalive, SocketFlags.None);
nextKeepalive = Environment.TickCount64 + (bound.Task.IsCompleted ? 5000 : 250);
}
while (packets.TryRead(plain, out VoiceFrameHeader header, out int length))
{
int size = crypto.Encryptor.Encrypt(header, plain.AsSpan(0, length), packet);
await socket.SendAsync(packet.AsMemory(0, size), SocketFlags.None, stop.Token).ConfigureAwait(false);
socket.Send(packet.AsSpan(0, size), SocketFlags.None);
}
await Task.Delay(5, stop.Token).ConfigureAwait(false);
Thread.Sleep(1);
}
}
catch (Exception exception) when (exception is OperationCanceledException or SocketException or ObjectDisposedException)
catch (Exception exception) when (exception is SocketException or ObjectDisposedException)
{ if (!stop.IsCancellationRequested) bound.TrySetException(exception); }
finally { stop.Cancel(); }
}
@@ -91,7 +92,7 @@ internal sealed class ClientMediaTransport : IAsyncDisposable
public async ValueTask DisposeAsync()
{
stop.Cancel(); socket.Dispose();
try { await Task.WhenAll(sending, receiving).ConfigureAwait(false); }
try { sending.Join(); await receiving.ConfigureAwait(false); }
finally { System.Security.Cryptography.CryptographicOperations.ZeroMemory(binding); stop.Dispose(); }
}