0

I have an application that needs to send an audio packet over UDP. To avoid jitter I want to schedule a thread or task to perform this task every 20 milliseconds. The pseudo code looks like this:

while(true) 
{
    byte[] packet = GetNextPacket();
    socket.Send(packet);
    var waitUntill = DateTime.Now.AddMilliseconds(20);
    while(DateTime.Now < waitUntill) { }
}

This works fine, but it uses 100% of a CPU core. Which is of course undesirable. I've tried playing with Thread.Sleep and Thread.Yield and their task equivalents but in all cases I either end up with 100% load or an extremely jittery experience (which is to be expected).

Is there no way in C# to schedule a task at such a fine grained level? I don't need a 100% guarantee (Windows is not a real-time OS) but something that will work most of the time. Note that I'm not worried about the GC :).

I'm fine with calling any COM code to achieve this, though my ideal solution would be multi-platform. I'm currently using dotnet core 3.0.

If it is not possible in C#, how is it achieved in languages like C++ which do perform these kinds of tasks.

Roy T.
  • 9,429
  • 2
  • 48
  • 70
  • in async method `await Task.Delay(20);` – Selvin Dec 03 '19 at 15:05
  • The problem of jitter is mainly from congestion on the network. You would do better to try to buffer it a little on the receiving end. Also, understand that UDP will lose datagrams, and you need to account for lost data. – Ron Maupin Dec 03 '19 at 15:12
  • Using asynchronous callback would greatly benefit you here. It allows you to run this packet information parallel to any other logic executed by your computer. – Frontear Dec 03 '19 at 15:13
  • Look into using a multimedia timer: https://stackoverflow.com/questions/24839105/high-resolution-timer-in-c-sharp – Slothario Dec 03 '19 at 15:26
  • @Selvin that has the same jitter problems. it will wait at least 20 ms, but it usually takes between 20 and 50ms before execution returns to the task. – Roy T. Dec 03 '19 at 16:00
  • @RonMaupin unfortunately the jitter is due to the threading. Sleeping a thread in Windows for 20ms means that Windows will return to executing your thread not earlier than in 20ms, but in realism this can mean that it sometimes takes more than 40ms to return to it. Unfortunately I can't send larger packets, and I don't have control over the receiving side (this is real-time voice via an RTP server). – Roy T. Dec 03 '19 at 16:02
  • 1
    @Slothario that sounds like the way to go! :D – Roy T. Dec 03 '19 at 16:03
  • 1
    @Slothario can you convert your comment to an answer? Because it works like a charm using multimedia timers. Unfortunately not cross-platform, but I'll hope to tackle that problem later. – Roy T. Dec 11 '19 at 21:15
  • @RoyT. I've posted it as an answer. – Slothario Dec 12 '19 at 15:28

2 Answers2

1

The System.Threading.Timer object is designed for this sort of thing, though I've never used it with such a low time interval.

var timer = new Timer(_ => socket.Send(GetNextPacket()), null, 0, 20);
Victor Wilson
  • 1,720
  • 1
  • 11
  • 22
  • Thanks for your answer. I'm not sure if this has the same jitter issues as a normal thread.sleep. Will definitely try this out tomorrow :D. – Roy T. Dec 03 '19 at 16:05
  • 2
    Unfortunately System.Threading.Timer has the same precision as all the other Sleep and Delay methods. For more information see this question/answer: https://stackoverflow.com/questions/3744032/why-are-net-timers-limited-to-15-ms-resolution – Roy T. Dec 04 '19 at 08:17
  • 1
    Have you tried the multimedia timer that Slothario mentioned in a comment to your question? – Victor Wilson Dec 04 '19 at 16:43
1

Look into using a multimedia timer:

High resolution timer in C#

They're specifically designed for these kind of high-resolution applications.

Slothario
  • 2,830
  • 3
  • 31
  • 47