LCOV - code coverage report
Current view: top level - src/media - congestion_control.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 81 90 90.0 %
Date: 2024-04-26 09:41:19 Functions: 15 15 100.0 %

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

Generated by: LCOV version 1.14