LCOV - code coverage report
Current view: top level - src/media - congestion_control.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 77 90 85.6 %
Date: 2024-12-21 08:56:24 Functions: 15 15 100.0 %

          Line data    Source code
       1             : /*
       2             :  *  Copyright (C) 2004-2024 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 <utility>
      23             : #include <cmath>
      24             : 
      25             : namespace jami {
      26             : static constexpr uint8_t packetVersion = 2;
      27             : static constexpr uint8_t packetFMT = 15;
      28             : static constexpr uint8_t packetType = 206;
      29             : static constexpr uint32_t uniqueIdentifier = 0x52454D42; // 'R' 'E' 'M' 'B'.
      30             : 
      31             : static constexpr float Q = 0.5f;
      32             : static constexpr float beta = 0.95f;
      33             : 
      34             : static constexpr float ku = 0.004f;
      35             : static constexpr float kd = 0.002f;
      36             : 
      37             : constexpr auto OVERUSE_THRESH = std::chrono::milliseconds(100);
      38             : 
      39             : // Receiver Estimated Max Bitrate (REMB) (draft-alvestrand-rmcat-remb).
      40             : //
      41             : //     0                   1                   2                   3
      42             : //     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
      43             : //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      44             : //    |V=2|P| FMT=15  |   PT=206      |             length            |
      45             : //    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
      46             : //  0 |                  SSRC of packet sender                        |
      47             : //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      48             : //  4 |                       Unused = 0                              |
      49             : //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      50             : //  8 |  Unique identifier 'R' 'E' 'M' 'B'                            |
      51             : //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      52             : // 12 |  Num SSRC     | BR Exp    |  BR Mantissa                      |
      53             : //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      54             : // 16 |   SSRC feedback                                               |
      55             : //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      56             : //    :  ...                                                          :
      57             : 
      58         315 : CongestionControl::CongestionControl() {}
      59             : 
      60         315 : CongestionControl::~CongestionControl() {}
      61             : 
      62             : static void
      63         326 : insert2Byte(std::vector<uint8_t>& v, uint16_t val)
      64             : {
      65         326 :     v.insert(v.end(), val >> 8);
      66         326 :     v.insert(v.end(), val & 0xff);
      67         326 : }
      68             : 
      69             : static void
      70         652 : insert4Byte(std::vector<uint8_t>& v, uint32_t val)
      71             : {
      72         652 :     v.insert(v.end(), val >> 24);
      73         652 :     v.insert(v.end(), (val >> 16) & 0xff);
      74         652 :     v.insert(v.end(), (val >> 8) & 0xff);
      75         652 :     v.insert(v.end(), val & 0xff);
      76         652 : }
      77             : 
      78             : uint64_t
      79         163 : CongestionControl::parseREMB(const rtcpREMBHeader& packet)
      80             : {
      81         163 :     if (packet.fmt != 15 || packet.pt != 206) {
      82           0 :         JAMI_ERR("Unable to parse REMB packet.");
      83           0 :         return 0;
      84             :     }
      85         163 :     uint64_t bitrate_bps = (packet.br_mantis << packet.br_exp);
      86         163 :     bool shift_overflow = (bitrate_bps >> packet.br_exp) != packet.br_mantis;
      87         163 :     if (shift_overflow) {
      88           0 :         JAMI_ERR("Invalid remb bitrate value : %u*2^%u", packet.br_mantis, packet.br_exp);
      89           0 :         return false;
      90             :     }
      91         163 :     return bitrate_bps;
      92             : }
      93             : 
      94             : std::vector<uint8_t>
      95         163 : CongestionControl::createREMB(uint64_t bitrate_bps)
      96             : {
      97         163 :     std::vector<uint8_t> remb;
      98         163 :     remb.reserve(24);
      99             : 
     100         163 :     remb.insert(remb.end(), packetVersion << 6 | packetFMT);
     101         163 :     remb.insert(remb.end(), packetType);
     102         163 :     insert2Byte(remb, 5);                // (sizeof(rtcpREMBHeader)/4)-1 -> not safe
     103         163 :     insert4Byte(remb, 0x12345678);       // ssrc
     104         163 :     insert4Byte(remb, 0x0);              // ssrc source
     105         163 :     insert4Byte(remb, uniqueIdentifier); // uid
     106         163 :     remb.insert(remb.end(), 1);          // n_ssrc
     107             : 
     108         163 :     const uint32_t maxMantissa = 0x3ffff; // 18 bits.
     109         163 :     uint64_t mantissa = bitrate_bps;
     110         163 :     uint8_t exponenta = 0;
     111         163 :     while (mantissa > maxMantissa) {
     112           0 :         mantissa >>= 1;
     113           0 :         ++exponenta;
     114             :     }
     115             : 
     116         163 :     remb.insert(remb.end(), (exponenta << 2) | (mantissa >> 16));
     117         163 :     insert2Byte(remb, mantissa & 0xffff);
     118         163 :     insert4Byte(remb, 0x2345678b);
     119             : 
     120         163 :     return remb;
     121           0 : }
     122             : 
     123             : float
     124        5240 : CongestionControl::kalmanFilter(uint64_t gradiant_delay)
     125             : {
     126        5240 :     float var_n = get_var_n(gradiant_delay);
     127        5240 :     float k = get_gain_k(Q, var_n);
     128        5240 :     float m = get_estimate_m(k, gradiant_delay);
     129        5240 :     last_var_p_ = get_sys_var_p(k, Q);
     130        5240 :     last_estimate_m_ = m;
     131        5240 :     last_var_n_ = var_n;
     132             : 
     133        5240 :     return m;
     134             : }
     135             : 
     136             : float
     137        5240 : CongestionControl::get_estimate_m(float k, int d_m)
     138             : {
     139             :     // JAMI_WARN("[get_estimate_m]k:%f, last_estimate_m_:%f, d_m:%f", k, last_estimate_m_, d_m);
     140             :     // JAMI_WARN("m: %f", ((1-k) * last_estimate_m_) + (k * d_m));
     141        5240 :     return ((1 - k) * last_estimate_m_) + (k * d_m);
     142             : }
     143             : 
     144             : float
     145        5240 : CongestionControl::get_gain_k(float q, float dev_n)
     146             : {
     147             :     // JAMI_WARN("k: %f", (last_var_p_ + q) / (last_var_p_ + q + dev_n));
     148        5240 :     return (last_var_p_ + q) / (last_var_p_ + q + dev_n);
     149             : }
     150             : 
     151             : float
     152        5240 : CongestionControl::get_sys_var_p(float k, float q)
     153             : {
     154             :     // JAMI_WARN("var_p: %f", ((1-k) * (last_var_p_ + q)));
     155        5240 :     return ((1 - k) * (last_var_p_ + q));
     156             : }
     157             : 
     158             : float
     159        5240 : CongestionControl::get_var_n(int d_m)
     160             : {
     161        5240 :     float z = get_residual_z(d_m);
     162             :     // JAMI_WARN("var_n: %f", (beta * last_var_n_) + ((1.0f - beta) * z * z));
     163        5240 :     return (beta * last_var_n_) + ((1.0f - beta) * z * z);
     164             : }
     165             : 
     166             : float
     167        5240 : CongestionControl::get_residual_z(float d_m)
     168             : {
     169             :     // JAMI_WARN("z: %f", d_m - last_estimate_m_);
     170        5240 :     return (d_m - last_estimate_m_);
     171             : }
     172             : 
     173             : float
     174        5240 : CongestionControl::update_thresh(float m, int deltaT)
     175             : {
     176        5240 :     float ky = 0.0f;
     177        5240 :     if (std::fabs(m) < last_thresh_y_)
     178        3742 :         ky = kd;
     179             :     else
     180        1498 :         ky = ku;
     181        5240 :     float res = last_thresh_y_ + ((deltaT * ky) * (std::fabs(m) - last_thresh_y_));
     182        5240 :     last_thresh_y_ = res;
     183        5240 :     return res;
     184             : }
     185             : 
     186             : float
     187        5240 : CongestionControl::get_thresh()
     188             : {
     189        5240 :     return last_thresh_y_;
     190             : }
     191             : 
     192             : BandwidthUsage
     193        5240 : CongestionControl::get_bw_state(float estimation, float thresh)
     194             : {
     195        5240 :     if (estimation > thresh) {
     196             :         // JAMI_WARN("Enter overuse state");
     197         210 :         if (not overuse_counter_) {
     198         210 :             t0_overuse = clock::now();
     199         210 :             overuse_counter_++;
     200         210 :             return bwNormal;
     201             :         }
     202           0 :         overuse_counter_++;
     203           0 :         time_point now = clock::now();
     204           0 :         auto overuse_timer = now - t0_overuse;
     205           0 :         if ((overuse_timer >= OVERUSE_THRESH) and (overuse_counter_ > 1)) {
     206           0 :             overuse_counter_ = 0;
     207           0 :             last_state_ = bwOverusing;
     208             :         }
     209        5030 :     } else if (estimation < -thresh) {
     210             :         // JAMI_WARN("Enter underuse state");
     211        1288 :         overuse_counter_ = 0;
     212        1288 :         last_state_ = bwUnderusing;
     213             :     } else {
     214        3742 :         overuse_counter_ = 0;
     215        3742 :         last_state_ = bwNormal;
     216             :     }
     217        5030 :     return last_state_;
     218             : }
     219             : 
     220             : } // namespace jami

Generated by: LCOV version 1.14