TwccContext.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /*
  2. * Copyright (c) 2021 The ZLMediaKit project authors. All Rights Reserved.
  3. *
  4. * This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
  5. *
  6. * Use of this source code is governed by MIT-like license that can be found in the
  7. * LICENSE file in the root of the source tree. All contributing project authors
  8. * may be found in the AUTHORS file in the root of the source tree.
  9. */
  10. #include "TwccContext.h"
  11. #include "Rtcp/RtcpFCI.h"
  12. namespace mediakit {
  13. enum class ExtSeqStatus : int {
  14. normal = 0,
  15. looped,
  16. jumped,
  17. };
  18. void TwccContext::onRtp(uint32_t ssrc, uint16_t twcc_ext_seq, uint64_t stamp_ms) {
  19. switch ((ExtSeqStatus) checkSeqStatus(twcc_ext_seq)) {
  20. case ExtSeqStatus::jumped: /*seq异常,过滤掉*/ return;
  21. case ExtSeqStatus::looped: /*回环,触发发送twcc rtcp*/ onSendTwcc(ssrc); break;
  22. case ExtSeqStatus::normal: break;
  23. default: /*不可达*/assert(0); break;
  24. }
  25. auto result = _rtp_recv_status.emplace(twcc_ext_seq, stamp_ms);
  26. if (!result.second) {
  27. WarnL << "recv same twcc ext seq:" << twcc_ext_seq;
  28. return;
  29. }
  30. _max_stamp = result.first->second;
  31. if (!_min_stamp) {
  32. _min_stamp = _max_stamp;
  33. }
  34. if (needSendTwcc()) {
  35. // 其他匹配条件立即发送twcc [AUTO-TRANSLATED:959d22b6]
  36. // Send twcc immediately if other matching conditions are met
  37. onSendTwcc(ssrc);
  38. }
  39. }
  40. bool TwccContext::needSendTwcc() const {
  41. if (_rtp_recv_status.empty()) {
  42. return false;
  43. }
  44. return (_rtp_recv_status.size() >= kMaxSeqSize) || (_max_stamp - _min_stamp >= kMaxTimeDelta);
  45. }
  46. int TwccContext::checkSeqStatus(uint16_t twcc_ext_seq) const {
  47. if (_rtp_recv_status.empty()) {
  48. return (int) ExtSeqStatus::normal;
  49. }
  50. auto max = _rtp_recv_status.rbegin()->first;
  51. auto delta = (int32_t) twcc_ext_seq - (int32_t) max;
  52. if (delta > 0 && delta < 0xFFFF / 2) {
  53. // 正常增长 [AUTO-TRANSLATED:7699c37d]
  54. // Normal growth
  55. return (int) ExtSeqStatus::normal;
  56. }
  57. if (delta < -0xFF00) {
  58. // 回环 [AUTO-TRANSLATED:82956e03]
  59. // Loop
  60. TraceL << "rtp twcc ext seq looped:" << max << " -> " << twcc_ext_seq;
  61. return (int) ExtSeqStatus::looped;
  62. }
  63. if (delta > 0xFF00) {
  64. // 回环后收到前面大的乱序的包,无法处理,丢弃 [AUTO-TRANSLATED:512cc269]
  65. // Discard packets that are out of order and large after looping back, as they cannot be processed
  66. TraceL << "rtp twcc ext seq jumped after looped:" << max << " -> " << twcc_ext_seq;
  67. return (int) ExtSeqStatus::jumped;
  68. }
  69. auto min = _rtp_recv_status.begin()->first;
  70. if (min <= twcc_ext_seq || twcc_ext_seq <= max) {
  71. // 正常回退 [AUTO-TRANSLATED:c8c6803f]
  72. // Normal rollback
  73. return (int) ExtSeqStatus::normal;
  74. }
  75. // seq莫名的大幅增加或减少,无法处理,丢弃 [AUTO-TRANSLATED:44dbbd28]
  76. // Discard packets with a large increase or decrease in seq, as they cannot be processed
  77. TraceL << "rtp twcc ext seq jumped:" << max << " -> " << twcc_ext_seq;
  78. return (int) ExtSeqStatus::jumped;
  79. }
  80. void TwccContext::onSendTwcc(uint32_t ssrc) {
  81. auto max = _rtp_recv_status.rbegin()->first;
  82. auto begin = _rtp_recv_status.begin();
  83. auto min = begin->first;
  84. // 参考时间戳的最小单位是64ms [AUTO-TRANSLATED:2e701a8c]
  85. // The minimum unit of the reference timestamp is 64ms
  86. auto ref_time = begin->second >> 6;
  87. // 还原基准时间戳 [AUTO-TRANSLATED:bab53195]
  88. // Restore the baseline timestamp
  89. auto last_time = ref_time << 6;
  90. FCI_TWCC::TwccPacketStatus status;
  91. for (auto seq = min; seq <= max; ++seq) {
  92. int16_t delta = 0;
  93. SymbolStatus symbol = SymbolStatus::not_received;
  94. auto it = _rtp_recv_status.find(seq);
  95. if (it != _rtp_recv_status.end()) {
  96. // recv delta,单位为250us,1ms等于4x250us [AUTO-TRANSLATED:46a0e186]
  97. // recv delta, unit is 250us, 1ms equals 4x250us
  98. delta = (int16_t) (4 * ((int64_t) it->second - (int64_t) last_time));
  99. if (delta < 0 || delta > 0xFF) {
  100. symbol = SymbolStatus::large_delta;
  101. } else {
  102. symbol = SymbolStatus::small_delta;
  103. }
  104. last_time = it->second;
  105. }
  106. status.emplace(seq, std::make_pair(symbol, delta));
  107. }
  108. auto fci = FCI_TWCC::create(ref_time, _twcc_pkt_count++, status);
  109. if (_cb) {
  110. _cb(ssrc, std::move(fci));
  111. }
  112. clearStatus();
  113. }
  114. void TwccContext::clearStatus() {
  115. _rtp_recv_status.clear();
  116. _min_stamp = 0;
  117. }
  118. void TwccContext::setOnSendTwccCB(TwccContext::onSendTwccCB cb) {
  119. _cb = std::move(cb);
  120. }
  121. }// namespace mediakit