aboutsummaryrefslogtreecommitdiffstats
path: root/libtransport/src/protocols/rtc/rtc_rs_fec_only.cc
blob: 5b10823ec6b56bedb49c3bf2bc78508713d66a42 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
 * Copyright (c) 2021 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <glog/logging.h>
#include <protocols/rtc/rtc_consts.h>
#include <protocols/rtc/rtc_rs_fec_only.h>

namespace transport {

namespace protocol {

namespace rtc {

RecoveryStrategyFecOnly::RecoveryStrategyFecOnly(
    Indexer *indexer, SendRtxCallback &&callback, asio::io_service &io_service,
    interface::RtcTransportRecoveryStrategies rs_type,
    interface::StrategyCallback &&external_callback)
    : RecoveryStrategy(indexer, std::move(callback), io_service, true, false,
                       rs_type, std::move(external_callback)),
      congestion_state_(false),
      probing_state_(false),
      switch_rounds_(0) {}

RecoveryStrategyFecOnly::RecoveryStrategyFecOnly(RecoveryStrategy &&rs)
    : RecoveryStrategy(std::move(rs)) {
  setRtxFec(true, false);
  switch_rounds_ = 0;
  congestion_state_ = false;
  probing_state_ = false;
}

RecoveryStrategyFecOnly::~RecoveryStrategyFecOnly() {}

void RecoveryStrategyFecOnly::turnOnRecovery() {
  recovery_on_ = true;
  // init strategy
  uint32_t fec_to_ask = computeFecPacketsToAsk();
  if (fec_to_ask > 0) {
    // the probing phase detected a lossy link. we immedialty start the fec and
    // we disable the check to prevent to send fec packets before RTX. in fact
    // here we know that we have losses and it is not a problem of OOO packets
    setRtxFec(true, true);
    rtx_during_fec_ = 1;  // avoid to stop fec
    indexer_->setNFec(fec_to_ask);
  } else {
    // keep only RTX on
    setRtxFec(true, true);
  }
}

void RecoveryStrategyFecOnly::onNewRound(bool in_sync) {
  if (!recovery_on_) {
    indexer_->setNFec(0);
    return;
  }

  // XXX for the moment we are considering congestion events
  // if(rc_->inCongestionState()){
  //   congestion_state_ = true;
  //   probing_state_ = false;
  //   indexer_->setNFec(0);
  //   return;
  // }

  // no congestion
  if (congestion_state_) {
    // this is the first round after congestion
    // enter probing phase
    probing_state_ = true;
    congestion_state_ = false;
  }

  if (probing_state_) {
    probing();
  } else {
    uint32_t fec_to_ask = computeFecPacketsToAsk();
    // If fec_to_ask == 0 we use rtx even if in these strategy we use only fec.
    // In this way the first packet loss that triggers the usage of fec can be
    // recovered using rtx, otherwise it will always be lost
    if (fec_to_ask == 0) {
      setRtxFec(true, false);
      switch_rounds_ = 0;
    } else {
      switch_rounds_++;
      if (switch_rounds_ >= ((RTC_INTEREST_LIFETIME / ROUND_LEN) * 2) &&
          rtx_during_fec_ !=
              0) {  // go to fec only if it is needed (RTX are on)
        setRtxFec(false, true);
      } else {
        setRtxFec(true, true);  // keep both
      }
    }
    if (rtx_during_fec_ == 0)  // if we do not send any RTX the losses
                               // registered may be due to jitter
      indexer_->setNFec(0);
    else
      indexer_->setNFec(fec_to_ask);
  }
}

void RecoveryStrategyFecOnly::newPacketLoss(uint32_t seq) {
  if (rtx_on_ && recovery_on_) {
    addNewRtx(seq, false);
  } else {
    if (!state_->isPending(seq) && !indexer_->isFec(seq)) {
      addNewRtx(seq, true);
    } else {
      // if not pending add to list to recover with fec
      recover_with_fec_.insert(seq);
      state_->onPossibleLossWithNoRtx(seq);
    }
  }
}

void RecoveryStrategyFecOnly::receivedPacket(uint32_t seq) {
  removePacketState(seq);
}

void RecoveryStrategyFecOnly::probing() {
  // TODO
  // for the moment ask for all fec and exit the probing phase
  probing_state_ = false;
  uint32_t fec_to_ask = computeFecPacketsToAsk();
  indexer_->setNFec(fec_to_ask);
}

}  // end namespace rtc

}  // end namespace protocol

}  // end namespace transport