LCOV - code coverage report
Current view: top level - src/media - congestion_control.cpp (source / functions) Coverage Total Hit
Test: jami-coverage-filtered.info Lines: 90.0 % 90 81
Test Date: 2026-06-13 09:18:46 Functions: 78.9 % 19 15

            Line data    Source code
       1              : /*
       2              :  *  Copyright (C) 2004-2026 Savoir-faire Linux Inc.
       3              :  *
       4              :  *  This program is free software: you can redistribute it and/or modify
       5              :  *  it under the terms of the GNU General Public License as published by
       6              :  *  the Free Software Foundation, either version 3 of the License, or
       7              :  *  (at your option) any later version.
       8              :  *
       9              :  *  This program is distributed in the hope that it will be useful,
      10              :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      11              :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      12              :  *  GNU General Public License for more details.
      13              :  *
      14              :  *  You should have received a copy of the GNU General Public License
      15              :  *  along with this program. If not, see <https://www.gnu.org/licenses/>.
      16              :  */
      17              : 
      18              : #include "logger.h"
      19              : #include "media/congestion_control.h"
      20              : 
      21              : #include <cstdint>
      22              : #include <cmath>
      23              : 
      24              : namespace jami {
      25              : static constexpr uint8_t packetVersion = 2;
      26              : static constexpr uint8_t packetFMT = 15;
      27              : static constexpr uint8_t packetType = 206;
      28              : static constexpr uint32_t uniqueIdentifier = 0x52454D42; // 'R' 'E' 'M' 'B'.
      29              : 
      30              : static constexpr float Q = 0.5f;
      31              : static constexpr float beta = 0.95f;
      32              : 
      33              : static constexpr float ku = 0.004f;
      34              : static constexpr float kd = 0.002f;
      35              : 
      36              : constexpr auto OVERUSE_THRESH = std::chrono::milliseconds(100);
      37              : 
      38              : // Receiver Estimated Max Bitrate (REMB) (draft-alvestrand-rmcat-remb).
      39              : //
      40              : //     0                   1                   2                   3
      41              : //     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      42              : //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      43              : //    |V=2|P| FMT=15  |   PT=206      |             length            |
      44              : //    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
      45              : //  0 |                  SSRC of packet sender                        |
      46              : //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      47              : //  4 |                       Unused = 0                              |
      48              : //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      49              : //  8 |  Unique identifier 'R' 'E' 'M' 'B'                            |
      50              : //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      51              : // 12 |  Num SSRC     | BR Exp    |  BR Mantissa                      |
      52              : //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      53              : // 16 |   SSRC feedback                                               |
      54              : //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      55              : //    :  ...                                                          :
      56              : 
      57          301 : CongestionControl::CongestionControl() {}
      58              : 
      59          301 : CongestionControl::~CongestionControl() {}
      60              : 
      61              : static void
      62          352 : insert2Byte(std::vector<uint8_t>& v, uint16_t val)
      63              : {
      64          352 :     v.insert(v.end(), val >> 8);
      65          352 :     v.insert(v.end(), val & 0xff);
      66          352 : }
      67              : 
      68              : static void
      69          704 : insert4Byte(std::vector<uint8_t>& v, uint32_t val)
      70              : {
      71          704 :     v.insert(v.end(), val >> 24);
      72          704 :     v.insert(v.end(), (val >> 16) & 0xff);
      73          704 :     v.insert(v.end(), (val >> 8) & 0xff);
      74          704 :     v.insert(v.end(), val & 0xff);
      75          704 : }
      76              : 
      77              : uint64_t
      78          176 : CongestionControl::parseREMB(const rtcpREMBHeader& packet)
      79              : {
      80          176 :     if (packet.fmt != 15 || packet.pt != 206) {
      81            0 :         JAMI_ERROR("Unable to parse REMB packet.");
      82            0 :         return 0;
      83              :     }
      84          176 :     uint64_t bitrate_bps = (packet.br_mantis << packet.br_exp);
      85          176 :     bool shift_overflow = (bitrate_bps >> packet.br_exp) != packet.br_mantis;
      86          176 :     if (shift_overflow) {
      87            0 :         JAMI_ERROR("Invalid remb bitrate value : {}*2^{}", packet.br_mantis, packet.br_exp);
      88            0 :         return 0;
      89              :     }
      90          176 :     return bitrate_bps;
      91              : }
      92              : 
      93              : std::vector<uint8_t>
      94          176 : CongestionControl::createREMB(uint64_t bitrate_bps)
      95              : {
      96          176 :     std::vector<uint8_t> remb;
      97          176 :     remb.reserve(24);
      98              : 
      99          176 :     remb.insert(remb.end(), packetVersion << 6 | packetFMT);
     100          176 :     remb.insert(remb.end(), packetType);
     101          176 :     insert2Byte(remb, 5);                // (sizeof(rtcpREMBHeader)/4)-1 -> not safe
     102          176 :     insert4Byte(remb, 0x12345678);       // ssrc
     103          176 :     insert4Byte(remb, 0x0);              // ssrc source
     104          176 :     insert4Byte(remb, uniqueIdentifier); // uid
     105          176 :     remb.insert(remb.end(), 1);          // n_ssrc
     106              : 
     107          176 :     const uint32_t maxMantissa = 0x3ffff; // 18 bits.
     108          176 :     uint64_t mantissa = bitrate_bps;
     109          176 :     uint8_t exponenta = 0;
     110          176 :     while (mantissa > maxMantissa) {
     111            0 :         mantissa >>= 1;
     112            0 :         ++exponenta;
     113              :     }
     114              : 
     115          176 :     remb.insert(remb.end(), (exponenta << 2) | (mantissa >> 16));
     116          176 :     insert2Byte(remb, mantissa & 0xffff);
     117          176 :     insert4Byte(remb, 0x2345678b);
     118              : 
     119          176 :     return remb;
     120            0 : }
     121              : 
     122              : float
     123         5579 : CongestionControl::kalmanFilter(int gradiant_delay)
     124              : {
     125         5579 :     float var_n = get_var_n(gradiant_delay);
     126         5579 :     float k = get_gain_k(Q, var_n);
     127         5579 :     float m = get_estimate_m(k, gradiant_delay);
     128         5579 :     last_var_p_ = get_sys_var_p(k, Q);
     129         5579 :     last_estimate_m_ = m;
     130         5579 :     last_var_n_ = var_n;
     131              : 
     132         5579 :     return m;
     133              : }
     134              : 
     135              : float
     136         5579 : CongestionControl::get_estimate_m(float k, int d_m)
     137              : {
     138              :     // JAMI_WARN("[get_estimate_m]k:%f, last_estimate_m_:%f, d_m:%f", k, last_estimate_m_, d_m);
     139              :     // JAMI_WARN("m: %f", ((1-k) * last_estimate_m_) + (k * d_m));
     140         5579 :     return ((1 - k) * last_estimate_m_) + (k * static_cast<float>(d_m));
     141              : }
     142              : 
     143              : float
     144         5579 : CongestionControl::get_gain_k(float q, float dev_n)
     145              : {
     146              :     // JAMI_WARN("k: %f", (last_var_p_ + q) / (last_var_p_ + q + dev_n));
     147         5579 :     return (last_var_p_ + q) / (last_var_p_ + q + dev_n);
     148              : }
     149              : 
     150              : float
     151         5579 : CongestionControl::get_sys_var_p(float k, float q)
     152              : {
     153              :     // JAMI_WARN("var_p: %f", ((1-k) * (last_var_p_ + q)));
     154         5579 :     return ((1 - k) * (last_var_p_ + q));
     155              : }
     156              : 
     157              : float
     158         5579 : CongestionControl::get_var_n(int d_m)
     159              : {
     160         5579 :     float z = get_residual_z(d_m);
     161              :     // JAMI_WARN("var_n: %f", (beta * last_var_n_) + ((1.0f - beta) * z * z));
     162         5579 :     return (beta * last_var_n_) + ((1.0f - beta) * z * z);
     163              : }
     164              : 
     165              : float
     166         5579 : CongestionControl::get_residual_z(int d_m)
     167              : {
     168              :     // JAMI_WARN("z: %f", d_m - last_estimate_m_);
     169         5579 :     return (static_cast<float>(d_m) - last_estimate_m_);
     170              : }
     171              : 
     172              : float
     173         5579 : CongestionControl::update_thresh(float m, int deltaT)
     174              : {
     175         5579 :     float ky = 0.0f;
     176         5579 :     if (std::fabs(m) < last_thresh_y_)
     177         4006 :         ky = kd;
     178              :     else
     179         1573 :         ky = ku;
     180         5579 :     float res = last_thresh_y_ + ((static_cast<float>(deltaT) * ky) * (std::fabs(m) - last_thresh_y_));
     181         5579 :     last_thresh_y_ = res;
     182         5579 :     return res;
     183              : }
     184              : 
     185              : float
     186         5579 : CongestionControl::get_thresh()
     187              : {
     188         5579 :     return last_thresh_y_;
     189              : }
     190              : 
     191              : BandwidthUsage
     192         5579 : CongestionControl::get_bw_state(float estimation, float thresh)
     193              : {
     194         5579 :     if (estimation > thresh) {
     195              :         // JAMI_WARN("Enter overuse state");
     196          309 :         if (not overuse_counter_) {
     197          307 :             t0_overuse = clock::now();
     198          307 :             overuse_counter_++;
     199          307 :             return bwNormal;
     200              :         }
     201            2 :         overuse_counter_++;
     202            2 :         time_point now = clock::now();
     203            2 :         auto overuse_timer = now - t0_overuse;
     204            2 :         if ((overuse_timer >= OVERUSE_THRESH) and (overuse_counter_ > 1)) {
     205            0 :             overuse_counter_ = 0;
     206            0 :             last_state_ = bwOverusing;
     207              :         }
     208         5270 :     } else if (estimation < -thresh) {
     209              :         // JAMI_WARN("Enter underuse state");
     210         1264 :         overuse_counter_ = 0;
     211         1264 :         last_state_ = bwUnderusing;
     212              :     } else {
     213         4006 :         overuse_counter_ = 0;
     214         4006 :         last_state_ = bwNormal;
     215              :     }
     216         5272 :     return last_state_;
     217              : }
     218              : 
     219              : } // namespace jami
        

Generated by: LCOV version 2.0-1