diff --git a/docs/sphinx/internals/timestamps.rst b/docs/sphinx/internals/timestamps.rst index 16f781ae6..a999da911 100644 --- a/docs/sphinx/internals/timestamps.rst +++ b/docs/sphinx/internals/timestamps.rst @@ -8,11 +8,12 @@ Timestamps Types of timestamps =================== -:doc:`Packets and frames ` have three major types of timestamps: +:doc:`Packets and frames ` have four major types of timestamps: * STS - stream timestamp * CTS - capture timestamp * RTS - receive timestamp +* QTS - queue timestamp **Stream timestamp** (STS) describes position of the first sample in packet or frame using abstract stream clock. @@ -37,6 +38,10 @@ The clock for RTS is the same as for CTS: local Unix-time UTC clock, counting na This timestamp is used only on receiver and only for packets. +**Queue timestamp** (QTS) is the time when the packet was transferred to a local queue of a sink-thread. The main difference with RTS is thread-switch time. + +This timestamp is used only on receiver and only for packets. + Use of timestamps ================= diff --git a/src/internal_modules/roc_packet/router.cpp b/src/internal_modules/roc_packet/router.cpp index 0693a11b0..901de0288 100644 --- a/src/internal_modules/roc_packet/router.cpp +++ b/src/internal_modules/roc_packet/router.cpp @@ -55,6 +55,10 @@ status::StatusCode Router::write(const PacketPtr& packet) { if (Route* route = find_route_(packet->flags())) { if (allow_route_(*route, *packet)) { + if (packet->udp()) { + packet->udp()->queue_ts = core::timestamp(core::ClockUnix); + } + return route->writer->write(packet); } } diff --git a/src/internal_modules/roc_packet/target_libuv/roc_packet/udp.cpp b/src/internal_modules/roc_packet/target_libuv/roc_packet/udp.cpp index de7fb976f..f192b1c10 100644 --- a/src/internal_modules/roc_packet/target_libuv/roc_packet/udp.cpp +++ b/src/internal_modules/roc_packet/target_libuv/roc_packet/udp.cpp @@ -13,7 +13,8 @@ namespace roc { namespace packet { UDP::UDP() - : receive_timestamp(0) { + : receive_timestamp(0) + , queue_ts(0) { memset(&request, 0, sizeof(request)); } diff --git a/src/internal_modules/roc_packet/target_libuv/roc_packet/udp.h b/src/internal_modules/roc_packet/target_libuv/roc_packet/udp.h index 1c16d6bd0..caf96961e 100644 --- a/src/internal_modules/roc_packet/target_libuv/roc_packet/udp.h +++ b/src/internal_modules/roc_packet/target_libuv/roc_packet/udp.h @@ -33,6 +33,13 @@ struct UDP { //! Packet receive timestamp (RTS), nanoseconds since Unix epoch. core::nanoseconds_t receive_timestamp; + //! Timestamp in ns since unix-epoch. It points to a moment when + //! the packet was transferred to a sink-thread, that "consumes" + //! this packet. The reason to have it separate is that this + //! allows us to account additional jitter introduced by + //! thread-switch time. + core::nanoseconds_t queue_ts; + //! Sender request state. uv_udp_send_t request; diff --git a/src/tests/roc_rtp/test_link_meter.cpp b/src/tests/roc_rtp/test_link_meter.cpp index bdb59f705..adedaaf02 100644 --- a/src/tests/roc_rtp/test_link_meter.cpp +++ b/src/tests/roc_rtp/test_link_meter.cpp @@ -29,9 +29,10 @@ packet::PacketPtr new_packet(packet::seqnum_t sn) { packet::PacketPtr packet = packet_factory.new_packet(); CHECK(packet); - packet->add_flags(packet::Packet::FlagRTP); + packet->add_flags(packet::Packet::FlagRTP | packet::Packet::FlagUDP); packet->rtp()->payload_type = PayloadType_L16_Stereo; packet->rtp()->seqnum = sn; + packet->udp()->queue_ts = 666; return packet; }