diff --git a/contrib/src/ffmpeg/rtp_ext_abs_send_time.patch b/contrib/src/ffmpeg/rtp_ext_abs_send_time.patch new file mode 100644 index 0000000000000000000000000000000000000000..cf52cf972ae6ba49ac97f80455d5cba8515f23d0 --- /dev/null +++ b/contrib/src/ffmpeg/rtp_ext_abs_send_time.patch @@ -0,0 +1,71 @@ +diff --git a/libavformat/rtpenc.c b/libavformat/rtpenc.c +index 63047beccc..d59ec3dc8c 100644 +--- a/libavformat/rtpenc.c ++++ b/libavformat/rtpenc.c +@@ -28,6 +28,8 @@ + + #include "rtpenc.h" + ++#define EXT_ABS_SEND_TIME ++ + static const AVOption options[] = { + FF_RTP_FLAG_OPTS(RTPMuxContext, flags), + { "payload_type", "Specify RTP payload type", offsetof(RTPMuxContext, payload_type), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 127, AV_OPT_FLAG_ENCODING_PARAM }, +@@ -146,7 +148,11 @@ static int rtp_write_header(AVFormatContext *s1) + s1->pb->max_packet_size); + } else + s1->packet_size = s1->pb->max_packet_size; ++#ifdef EXT_ABS_SEND_TIME ++ if (s1->packet_size <= 20) { ++#else + if (s1->packet_size <= 12) { ++#endif + av_log(s1, AV_LOG_ERROR, "Max packet size %u too low\n", s1->packet_size); + return AVERROR(EIO); + } +@@ -154,7 +160,11 @@ static int rtp_write_header(AVFormatContext *s1) + if (!s->buf) { + return AVERROR(ENOMEM); + } ++#ifdef EXT_ABS_SEND_TIME ++ s->max_payload_size = s1->packet_size - 20; ++#else + s->max_payload_size = s1->packet_size - 12; ++#endif + + if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { + avpriv_set_pts_info(st, 32, 1, st->codecpar->sample_rate); +@@ -332,16 +342,34 @@ static void rtcp_send_sr(AVFormatContext *s1, int64_t ntp_time, int bye) + void ff_rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m) + { + RTPMuxContext *s = s1->priv_data; ++ uint64_t ntp64_time; ++ uint32_t absoluteSendTime; + + av_log(s1, AV_LOG_TRACE, "rtp_send_data size=%d\n", len); + + /* build the RTP header */ ++#ifdef EXT_ABS_SEND_TIME ++ avio_w8(s1->pb, RTP_VERSION << 6 | 0x10); // extention bit ++#else + avio_w8(s1->pb, RTP_VERSION << 6); ++#endif + avio_w8(s1->pb, (s->payload_type & 0x7f) | ((m & 0x01) << 7)); + avio_wb16(s1->pb, s->seq); + avio_wb32(s1->pb, s->timestamp); + avio_wb32(s1->pb, s->ssrc); + ++#ifdef EXT_ABS_SEND_TIME ++ avio_wb16(s1->pb, 0xBEDE); // magic word ++ avio_wb16(s1->pb, 0x0001); // length=1 ++ avio_w8(s1->pb, 0x32); // ID=3 and lenght=2 ++ ntp64_time = ff_get_formatted_ntp_time(ff_ntp_time()); ++ absoluteSendTime = (uint32_t)((ntp64_time>> 14) & 0x00ffffff); ++ av_log(s1, AV_LOG_TRACE, "ntp64:%lu, abs_time:%u\n", ntp64_time, absoluteSendTime); ++ avio_w8(s1->pb, (uint8_t)(absoluteSendTime >> 16)); ++ avio_w8(s1->pb, (uint8_t)(absoluteSendTime >> 8 & 0xff)); ++ avio_w8(s1->pb, (uint8_t)(absoluteSendTime & 0xff)); ++#endif ++ + avio_write(s1->pb, buf1, len); + avio_flush(s1->pb); diff --git a/contrib/src/ffmpeg/rules.mak b/contrib/src/ffmpeg/rules.mak index a8cd10aab269a185eb14a1af305998eb2cd7c771..32e32b1b63f021b914324922a0738d7294ff49c6 100644 --- a/contrib/src/ffmpeg/rules.mak +++ b/contrib/src/ffmpeg/rules.mak @@ -325,6 +325,7 @@ ffmpeg: ffmpeg-$(FFMPEG_HASH).tar.gz (cd $@-$(FFMPEG_HASH) && tar x $(if ${BATCH_MODE},,-v) --strip-components=1 -f ../$<) $(APPLY) $(SRC)/ffmpeg/remove-mjpeg-log.patch $(APPLY) $(SRC)/ffmpeg/change-RTCP-ratio.patch + $(APPLY) $(SRC)/ffmpeg/rtp_ext_abs_send_time.patch $(UPDATE_AUTOCONFIG) $(MOVE) diff --git a/src/media/socket_pair.cpp b/src/media/socket_pair.cpp index b0773132d7fcf950c7e0208e2065462027b905cc..5cebf77e9c88d4415e10b5fab6d7ddf7631c6bf8 100644 --- a/src/media/socket_pair.cpp +++ b/src/media/socket_pair.cpp @@ -493,14 +493,21 @@ SocketPair::readCallback(uint8_t* buf, int buf_size) // SRTP decrypt if (not fromRTCP and srtpContext_ and srtpContext_->srtp_in.aes) { - uint32_t curentSendTS = buf[4] << 24 | buf[5] << 16 | buf[6] << 8 | buf[7]; - int32_t delay = 0; + int32_t gradient = 0; + int32_t deltaT = 0; float abs = 0.0f; + bool res_parse = false; + bool res_delay = false; + + res_parse = parse_RTP_ext(buf, &abs); bool marker = (buf[1] & 0x80) >> 7; - bool res = getOneWayDelayGradient2(abs, marker, &delay); - if (res) - rtpDelayCallback_(delay); + if(res_parse) + res_delay = getOneWayDelayGradient2(abs, marker, &gradient, &deltaT); + + // rtpDelayCallback_ is not set for audio + if (rtpDelayCallback_ && res_delay) + rtpDelayCallback_(gradient); auto err = ff_srtp_decrypt(&srtpContext_->srtp_in, buf, &len); if(packetLossCallback_ and (buf[2] << 8 | buf[3]) != lastSeqNum_+1) { @@ -667,7 +674,7 @@ SocketPair::getOneWayDelayGradient(uint32_t sendTS) } bool -SocketPair::getOneWayDelayGradient2(float sendTS, bool marker, int32_t* gradient) +SocketPair::getOneWayDelayGradient2(float sendTS, bool marker, int32_t* gradient, int32_t* deltaT) { // Keep only last packet of each frame if (not marker) { @@ -681,7 +688,7 @@ SocketPair::getOneWayDelayGradient2(float sendTS, bool marker, int32_t* gradient return 0; } - uint32_t deltaS = (sendTS - lastSendTS_) * 1000; // milliseconds + int32_t deltaS = (sendTS - lastSendTS_) * 1000; // milliseconds if(deltaS < 0) deltaS += 64000; lastSendTS_ = sendTS; @@ -691,6 +698,7 @@ SocketPair::getOneWayDelayGradient2(float sendTS, bool marker, int32_t* gradient lastReceiveTS_ = arrival_TS; *gradient = deltaR - deltaS; + *deltaT = deltaR; return true; } @@ -739,4 +747,22 @@ SocketPair::getOneWayDelayGradient3(uint32_t sendTS, int32_t* gradient) return true; } +bool +SocketPair::parse_RTP_ext(uint8_t* buf, float* abs) +{ + if(not(buf[0] & 0x10)) + return false; + + uint16_t magic_word = (buf[12] << 8) + buf[13]; + if(magic_word != 0xBEDE) + return false; + + uint8_t sec = buf[17] >> 2; + uint32_t fract = ((buf[17] & 0x3) << 16 | (buf[18] << 8) | buf[19]) << 14; + float milli = fract / pow(2,32); + + *abs = sec + (milli); + return true; +} + } // namespace jami diff --git a/src/media/socket_pair.h b/src/media/socket_pair.h index 6024aa9d139bb1bfac6839d73eae2cba4ef93666..0a4d6104bcab1b3e03568f70d0722fdd9c8497ac 100644 --- a/src/media/socket_pair.h +++ b/src/media/socket_pair.h @@ -203,8 +203,9 @@ class SocketPair { std::function<void(void)> packetLossCallback_; std::function<void(int)> rtpDelayCallback_; int32_t getOneWayDelayGradient(uint32_t sendTS); - bool getOneWayDelayGradient2(float sendTS, bool marker, int32_t* gradient); + bool getOneWayDelayGradient2(float sendTS, bool marker, int32_t* gradient, int32_t* deltaR); bool getOneWayDelayGradient3(uint32_t sendTS, int32_t* gradient); + bool parse_RTP_ext(uint8_t* buf, float* abs); std::list<rtcpRRHeader> listRtcpRRHeader_; std::list<rtcpREMBHeader> listRtcpREMBHeader_; @@ -220,8 +221,7 @@ class SocketPair { std::chrono::steady_clock::time_point lastRR_time; uint16_t lastSeqNum_ {0}; - uint32_t lastSendTS_ {0}; - bool lastMarker_ {false}; + float lastSendTS_ {0.0f}; std::chrono::steady_clock::time_point lastReceiveTS_ {}; std::chrono::steady_clock::time_point arrival_TS {}; diff --git a/src/media/video/video_rtp_session.cpp b/src/media/video/video_rtp_session.cpp index 88a1cc6674a2eff6b4f43f3d8af694c740db4959..17440c0478860d82e6ab9a73a0b4e8d3cad038e7 100644 --- a/src/media/video/video_rtp_session.cpp +++ b/src/media/video/video_rtp_session.cpp @@ -151,10 +151,6 @@ void VideoRtpSession::startSender() rtcpCheckerThread_.start(); else if (not autoQuality and rtcpCheckerThread_.isRunning()) rtcpCheckerThread_.join(); - - socketPair_->setRtpDelayCallback([&](int delay) { - this->delayMonitor(delay); - }); } } @@ -207,6 +203,8 @@ void VideoRtpSession::start(std::unique_ptr<IceSocket> rtp_sock, else socketPair_.reset(new SocketPair(getRemoteRtpUri().c_str(), receive_.addr.getPort())); + socketPair_->setRtpDelayCallback([&](int delay) {delayMonitor(delay);}); + if (send_.crypto and receive_.crypto) { socketPair_->createSRTP(receive_.crypto.getCryptoSuite().c_str(), receive_.crypto.getSrtpKeyInfo().c_str(),