opusrtp: Fix transmit timing

Because it would sleep for the entire packet duration after sending
each packet, the packets would end up too far apart and cause underruns.

Do not depend on usleep() if its POSIX replacements are available.
usleep() was obsoleted in POSIX.1-2001 and removed in POSIX.1-2008.
parent 8ecc4177
...@@ -333,6 +333,8 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], ...@@ -333,6 +333,8 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
]) ])
AC_FUNC_FSEEKO AC_FUNC_FSEEKO
AC_CHECK_FUNCS([clock_gettime mach_absolute_time])
AC_CHECK_FUNCS([usleep nanosleep clock_nanosleep])
saved_LIBS="$LIBS" saved_LIBS="$LIBS"
LIBS="$LIBS $LIBM" LIBS="$LIBS $LIBM"
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#include <getopt.h> #include <getopt.h>
...@@ -48,6 +49,13 @@ ...@@ -48,6 +49,13 @@
# include <netinet/in.h> # include <netinet/in.h>
# include <arpa/inet.h> # include <arpa/inet.h>
# include <errno.h> # include <errno.h>
# if defined HAVE_MACH_ABSOLUTE_TIME
# include <mach/mach_time.h>
# elif !(defined HAVE_CLOCK_GETTIME && defined CLOCK_REALTIME && \
defined HAVE_NANOSLEEP)
# include <sys/time.h>
# endif
#endif #endif
#ifdef HAVE_PCAP #ifdef HAVE_PCAP
...@@ -500,6 +508,116 @@ int update_rtp_header(rtp_header *rtp) ...@@ -500,6 +508,116 @@ int update_rtp_header(rtp_header *rtp)
} }
#ifndef _WIN32 #ifndef _WIN32
/*
* Wait for the next time slot, which begins delta nanoseconds after the
* start of the previous time slot, or in the case of the first call at
* the time of the call. delta must be in the range 0..999999999.
*/
void wait_for_time_slot(int delta)
{
# if defined HAVE_MACH_ABSOLUTE_TIME
/* Apple */
static mach_timebase_info_data_t tbinfo;
static uint64_t target;
if (tbinfo.numer == 0) {
mach_timebase_info(&tbinfo);
target = mach_absolute_time();
} else {
target += tbinfo.numer == tbinfo.denom
? (uint64_t)delta : (uint64_t)delta * tbinfo.denom / tbinfo.numer;
mach_wait_until(target);
}
# elif defined HAVE_CLOCK_GETTIME && defined CLOCK_REALTIME && \
defined HAVE_NANOSLEEP
/* try to use POSIX monotonic clock */
static int initialized = 0;
static clockid_t clock_id;
static struct timespec target;
if (!initialized) {
# if defined CLOCK_MONOTONIC && \
defined _POSIX_MONOTONIC_CLOCK && _POSIX_MONOTONIC_CLOCK >= 0
if (
# if _POSIX_MONOTONIC_CLOCK == 0
sysconf(_SC_MONOTONIC_CLOCK) > 0 &&
# endif
clock_gettime(CLOCK_MONOTONIC, &target) == 0) {
clock_id = CLOCK_MONOTONIC;
initialized = 1;
} else
# endif
if (clock_gettime(CLOCK_REALTIME, &target) == 0) {
clock_id = CLOCK_REALTIME;
initialized = 1;
}
} else {
target.tv_nsec += delta;
if (target.tv_nsec >= 1000000000) {
++target.tv_sec;
target.tv_nsec -= 1000000000;
}
# if defined HAVE_CLOCK_NANOSLEEP && \
defined _POSIX_CLOCK_SELECTION && _POSIX_CLOCK_SELECTION > 0
clock_nanosleep(clock_id, TIMER_ABSTIME, &target, NULL);
# else
{
/* convert to relative time */
struct timespec rel;
if (clock_gettime(clock_id, &rel) == 0) {
rel.tv_sec = target.tv_sec - rel.tv_sec;
rel.tv_nsec = target.tv_nsec - rel.tv_nsec;
if (rel.tv_nsec < 0) {
rel.tv_nsec += 1000000000;
--rel.tv_sec;
}
if (rel.tv_sec >= 0 && (rel.tv_sec > 0 || rel.tv_nsec > 0)) {
nanosleep(&rel, NULL);
}
}
}
# endif
}
# else
/* fall back to the old non-monotonic gettimeofday() */
static int initialized = 0;
static struct timeval target;
struct timeval now;
int nap;
if (!initialized) {
gettimeofday(&target, NULL);
initialized = 1;
} else {
delta /= 1000;
target.tv_usec += delta;
if (target.tv_usec >= 1000000) {
++target.tv_sec;
target.tv_usec -= 1000000;
}
gettimeofday(&now, NULL);
nap = target.tv_usec - now.tv_usec;
if (now.tv_sec != target.tv_sec) {
if (now.tv_sec > target.tv_sec) nap = 0;
else if (target.tv_sec - now.tv_sec == 1) nap += 1000000;
else nap = 1000000;
}
if (nap > delta) nap = delta;
if (nap > 0) {
# if defined HAVE_USLEEP
usleep(nap);
# else
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = nap;
select(0, NULL, NULL, NULL, &timeout);
# endif
}
}
# endif
}
int send_rtp_packet(int fd, struct sockaddr *sin, int send_rtp_packet(int fd, struct sockaddr *sin,
rtp_header *rtp, const unsigned char *opus) rtp_header *rtp, const unsigned char *opus)
{ {
...@@ -645,7 +763,8 @@ int rtp_send_file(const char *filename, const char *dest, int port) ...@@ -645,7 +763,8 @@ int rtp_send_file(const char *filename, const char *dest, int port)
fprintf(stderr, "rtp %d %d %d %3d ms %5d bytes\n", fprintf(stderr, "rtp %d %d %d %3d ms %5d bytes\n",
rtp.type, rtp.seq, rtp.time, samples/48, rtp.payload_size); rtp.type, rtp.seq, rtp.time, samples/48, rtp.payload_size);
send_rtp_packet(fd, (struct sockaddr *)&sin, &rtp, op.packet); send_rtp_packet(fd, (struct sockaddr *)&sin, &rtp, op.packet);
usleep(samples*1000/48); /* convert number of 48 kHz samples to nanoseconds without overflow */
wait_for_time_slot(samples*62500/3);
} }
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment