Re: sending UDP frames at a fixed rate
On Oct 2, 12:50 pm, nat...@visi.com (Nathan Mates) wrote:
In article <1191346358.831298.68...@g4g2000hsf.googlegroups.com>,
PaulH <paul.h...@gmail.com> wrote:
I have an application where I would like to send UDP frames at a fixed
rate. (for example, 200 byte frames at 50 frames per second.)
But, using the example above, I may only get 320 frames sent in 10
seconds instead of the 500 I would expect.
First, please learn that Windows is *NOT* a realtime operating
system. You canNOT guarantee any sort of accuracy in timing -- Windows
may decide that "now is a good time to hammer on the HD/CD/DVD for a
while" and not call your app for a while. It'd be much better to
design your app to be able to send at variable rates. Your receiving
is going to be at variable rates anyhow due to lag and packet drops.
Next, GetTickCount() doesn't always have the best accuracy. Use
QueryPerformanceCounter() for greater accuracy.
Finally, waiting for timers is not going to give the best accuracy.
Sitting in a busyloop (and using Sleep() judiciously) is going to give
more accuracy, at the cost of pegging the CPU and being unfriendly to
other apps. If your app is in the foreground (e.g. games), this works
decently well. But, when your in the background, you need to handle
variability much better.
Nathan Mates
--
<*> Nathan Mates - personal webpagehttp://www.visi.com/~nathan/
# Programmer at Pandemic Studios --http://www.pandemicstudios.com/
# NOT speaking for Pandemic Studios. "Care not what the neighbors
# think. What are the facts, and to how many decimal places?" -R.A. Heinlein
Okay, if 200bytes @50 FPS is too real-time for windows, I'll back that
down to 10FPS and use QueryPerformanceCounter(). Using those
parameters, I only send 93 frames in 10 seconds.
HANDLE hTimer = ::CreateWaitableTimer( NULL, TRUE,
NULL );
LARGE_INTEGER transmitTime = { 0 };
transmitTime.QuadPart = static_cast< LONGLONG >(
-( 10000000.0f / static_cast< float
( frames_per_second ) ) );
const int period = 1000 / frames_per_second;
LARGE_INTEGER perf = { 0 },
check = { 0 },
freq = { 0 },
wait = { 0 };
QueryPerformanceFrequency( &freq );
QueryPerformanceCounter( &perf );
//
// transmit the test frames
//
while( ( err = sendto( dutSocket,
pBuf,
bufSize,
0,
reinterpret_cast< SOCKADDR* >( DUTAddr-
ai_addr ),
DUTAddr->ai_addrlen ) ) != SOCKET_ERROR &&
( GetTickCount() - dwStartTick ) < static_cast< UINT
( runtime ) )
{
sentFrames++;
QueryPerformanceCounter( &check );
wait.QuadPart = transmitTime.QuadPart + (
( check.QuadPart - perf.QuadPart ) * 10000000 /
freq.QuadPart );
::SetWaitableTimer( hTimer, &wait, 0, NULL, NULL, 0 );
::WaitForSingleObject( hTimer, period );
QueryPerformanceCounter( &perf );
}
Using Sleep() yields much worse performance. For the same example
above, I may only send 7 frames. This app is in the foreground. I
started this thread with THREAD_PRIORITY_HIGHEST.
const int period = 1000 / frames_per_second;
while( ( err = sendto( dutSocket,
pBuf,
bufSize,
0,
reinterpret_cast< SOCKADDR* >( DUTAddr-
ai_addr ),
DUTAddr->ai_addrlen ) ) != SOCKET_ERROR &&
( GetTickCount() - dwStartTick ) < static_cast< UINT
( runtime ) )
{
sentFrames++;
for( int i = 0; i < period; ++i )
Sleep( 1 );
}
Thanks,
PaulH