Repo created
This commit is contained in:
parent
81b91f4139
commit
f8c34fa5ee
22732 changed files with 4815320 additions and 2 deletions
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/congestion_controller/rtp/control_handler.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "api/units/data_rate.h"
|
||||
#include "modules/pacing/pacing_controller.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
#include "rtc_base/numerics/safe_minmax.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
void CongestionControlHandler::SetTargetRate(
|
||||
TargetTransferRate new_target_rate) {
|
||||
RTC_DCHECK_RUN_ON(&sequenced_checker_);
|
||||
RTC_CHECK(new_target_rate.at_time.IsFinite());
|
||||
last_incoming_ = new_target_rate;
|
||||
}
|
||||
|
||||
void CongestionControlHandler::SetNetworkAvailability(bool network_available) {
|
||||
RTC_DCHECK_RUN_ON(&sequenced_checker_);
|
||||
network_available_ = network_available;
|
||||
}
|
||||
|
||||
void CongestionControlHandler::SetPacerQueue(TimeDelta expected_queue_time) {
|
||||
RTC_DCHECK_RUN_ON(&sequenced_checker_);
|
||||
pacer_expected_queue_ms_ = expected_queue_time.ms();
|
||||
}
|
||||
|
||||
absl::optional<TargetTransferRate> CongestionControlHandler::GetUpdate() {
|
||||
RTC_DCHECK_RUN_ON(&sequenced_checker_);
|
||||
if (!last_incoming_.has_value())
|
||||
return absl::nullopt;
|
||||
TargetTransferRate new_outgoing = *last_incoming_;
|
||||
DataRate log_target_rate = new_outgoing.target_rate;
|
||||
bool pause_encoding = false;
|
||||
if (!network_available_) {
|
||||
pause_encoding = true;
|
||||
} else if (pacer_expected_queue_ms_ >
|
||||
PacingController::kMaxExpectedQueueLength.ms()) {
|
||||
pause_encoding = true;
|
||||
}
|
||||
if (pause_encoding)
|
||||
new_outgoing.target_rate = DataRate::Zero();
|
||||
if (!last_reported_ ||
|
||||
last_reported_->target_rate != new_outgoing.target_rate ||
|
||||
(!new_outgoing.target_rate.IsZero() &&
|
||||
(last_reported_->network_estimate.loss_rate_ratio !=
|
||||
new_outgoing.network_estimate.loss_rate_ratio ||
|
||||
last_reported_->network_estimate.round_trip_time !=
|
||||
new_outgoing.network_estimate.round_trip_time))) {
|
||||
if (encoder_paused_in_last_report_ != pause_encoding)
|
||||
RTC_LOG(LS_INFO) << "Bitrate estimate state changed, BWE: "
|
||||
<< ToString(log_target_rate) << ".";
|
||||
encoder_paused_in_last_report_ = pause_encoding;
|
||||
last_reported_ = new_outgoing;
|
||||
return new_outgoing;
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_CONGESTION_CONTROLLER_RTP_CONTROL_HANDLER_H_
|
||||
#define MODULES_CONGESTION_CONTROLLER_RTP_CONTROL_HANDLER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/sequence_checker.h"
|
||||
#include "api/transport/network_types.h"
|
||||
#include "api/units/data_size.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "rtc_base/system/no_unique_address.h"
|
||||
|
||||
namespace webrtc {
|
||||
// This is used to observe the network controller state and route calls to
|
||||
// the proper handler. It also keeps cached values for safe asynchronous use.
|
||||
// This makes sure that things running on the worker queue can't access state
|
||||
// in RtpTransportControllerSend, which would risk causing data race on
|
||||
// destruction unless members are properly ordered.
|
||||
class CongestionControlHandler {
|
||||
public:
|
||||
CongestionControlHandler() = default;
|
||||
|
||||
CongestionControlHandler(const CongestionControlHandler&) = delete;
|
||||
CongestionControlHandler& operator=(const CongestionControlHandler&) = delete;
|
||||
|
||||
~CongestionControlHandler() = default;
|
||||
|
||||
void SetTargetRate(TargetTransferRate new_target_rate);
|
||||
void SetNetworkAvailability(bool network_available);
|
||||
void SetPacerQueue(TimeDelta expected_queue_time);
|
||||
absl::optional<TargetTransferRate> GetUpdate();
|
||||
|
||||
private:
|
||||
absl::optional<TargetTransferRate> last_incoming_;
|
||||
absl::optional<TargetTransferRate> last_reported_;
|
||||
bool network_available_ = true;
|
||||
bool encoder_paused_in_last_report_ = false;
|
||||
|
||||
int64_t pacer_expected_queue_ms_ = 0;
|
||||
|
||||
RTC_NO_UNIQUE_ADDRESS SequenceChecker sequenced_checker_;
|
||||
};
|
||||
} // namespace webrtc
|
||||
#endif // MODULES_CONGESTION_CONTROLLER_RTP_CONTROL_HANDLER_H_
|
||||
|
|
@ -0,0 +1,275 @@
|
|||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/congestion_controller/rtp/transport_feedback_adapter.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/algorithm/container.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
constexpr TimeDelta kSendTimeHistoryWindow = TimeDelta::Seconds(60);
|
||||
|
||||
void InFlightBytesTracker::AddInFlightPacketBytes(
|
||||
const PacketFeedback& packet) {
|
||||
RTC_DCHECK(packet.sent.send_time.IsFinite());
|
||||
auto it = in_flight_data_.find(packet.network_route);
|
||||
if (it != in_flight_data_.end()) {
|
||||
it->second += packet.sent.size;
|
||||
} else {
|
||||
in_flight_data_.insert({packet.network_route, packet.sent.size});
|
||||
}
|
||||
}
|
||||
|
||||
void InFlightBytesTracker::RemoveInFlightPacketBytes(
|
||||
const PacketFeedback& packet) {
|
||||
if (packet.sent.send_time.IsInfinite())
|
||||
return;
|
||||
auto it = in_flight_data_.find(packet.network_route);
|
||||
if (it != in_flight_data_.end()) {
|
||||
RTC_DCHECK_GE(it->second, packet.sent.size);
|
||||
it->second -= packet.sent.size;
|
||||
if (it->second.IsZero())
|
||||
in_flight_data_.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
DataSize InFlightBytesTracker::GetOutstandingData(
|
||||
const rtc::NetworkRoute& network_route) const {
|
||||
auto it = in_flight_data_.find(network_route);
|
||||
if (it != in_flight_data_.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
return DataSize::Zero();
|
||||
}
|
||||
}
|
||||
|
||||
// Comparator for consistent map with NetworkRoute as key.
|
||||
bool InFlightBytesTracker::NetworkRouteComparator::operator()(
|
||||
const rtc::NetworkRoute& a,
|
||||
const rtc::NetworkRoute& b) const {
|
||||
if (a.local.network_id() != b.local.network_id())
|
||||
return a.local.network_id() < b.local.network_id();
|
||||
if (a.remote.network_id() != b.remote.network_id())
|
||||
return a.remote.network_id() < b.remote.network_id();
|
||||
|
||||
if (a.local.adapter_id() != b.local.adapter_id())
|
||||
return a.local.adapter_id() < b.local.adapter_id();
|
||||
if (a.remote.adapter_id() != b.remote.adapter_id())
|
||||
return a.remote.adapter_id() < b.remote.adapter_id();
|
||||
|
||||
if (a.local.uses_turn() != b.local.uses_turn())
|
||||
return a.local.uses_turn() < b.local.uses_turn();
|
||||
if (a.remote.uses_turn() != b.remote.uses_turn())
|
||||
return a.remote.uses_turn() < b.remote.uses_turn();
|
||||
|
||||
return a.connected < b.connected;
|
||||
}
|
||||
|
||||
TransportFeedbackAdapter::TransportFeedbackAdapter() = default;
|
||||
|
||||
void TransportFeedbackAdapter::AddPacket(const RtpPacketSendInfo& packet_info,
|
||||
size_t overhead_bytes,
|
||||
Timestamp creation_time) {
|
||||
PacketFeedback packet;
|
||||
packet.creation_time = creation_time;
|
||||
packet.sent.sequence_number =
|
||||
seq_num_unwrapper_.Unwrap(packet_info.transport_sequence_number);
|
||||
packet.sent.size = DataSize::Bytes(packet_info.length + overhead_bytes);
|
||||
packet.sent.audio = packet_info.packet_type == RtpPacketMediaType::kAudio;
|
||||
packet.network_route = network_route_;
|
||||
packet.sent.pacing_info = packet_info.pacing_info;
|
||||
|
||||
while (!history_.empty() &&
|
||||
creation_time - history_.begin()->second.creation_time >
|
||||
kSendTimeHistoryWindow) {
|
||||
// TODO(sprang): Warn if erasing (too many) old items?
|
||||
if (history_.begin()->second.sent.sequence_number > last_ack_seq_num_)
|
||||
in_flight_.RemoveInFlightPacketBytes(history_.begin()->second);
|
||||
history_.erase(history_.begin());
|
||||
}
|
||||
history_.insert(std::make_pair(packet.sent.sequence_number, packet));
|
||||
}
|
||||
|
||||
absl::optional<SentPacket> TransportFeedbackAdapter::ProcessSentPacket(
|
||||
const rtc::SentPacket& sent_packet) {
|
||||
auto send_time = Timestamp::Millis(sent_packet.send_time_ms);
|
||||
// TODO(srte): Only use one way to indicate that packet feedback is used.
|
||||
if (sent_packet.info.included_in_feedback || sent_packet.packet_id != -1) {
|
||||
int64_t unwrapped_seq_num =
|
||||
seq_num_unwrapper_.Unwrap(sent_packet.packet_id);
|
||||
auto it = history_.find(unwrapped_seq_num);
|
||||
if (it != history_.end()) {
|
||||
bool packet_retransmit = it->second.sent.send_time.IsFinite();
|
||||
it->second.sent.send_time = send_time;
|
||||
last_send_time_ = std::max(last_send_time_, send_time);
|
||||
// TODO(srte): Don't do this on retransmit.
|
||||
if (!pending_untracked_size_.IsZero()) {
|
||||
if (send_time < last_untracked_send_time_)
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "appending acknowledged data for out of order packet. (Diff: "
|
||||
<< ToString(last_untracked_send_time_ - send_time) << " ms.)";
|
||||
it->second.sent.prior_unacked_data += pending_untracked_size_;
|
||||
pending_untracked_size_ = DataSize::Zero();
|
||||
}
|
||||
if (!packet_retransmit) {
|
||||
if (it->second.sent.sequence_number > last_ack_seq_num_)
|
||||
in_flight_.AddInFlightPacketBytes(it->second);
|
||||
it->second.sent.data_in_flight = GetOutstandingData();
|
||||
return it->second.sent;
|
||||
}
|
||||
}
|
||||
} else if (sent_packet.info.included_in_allocation) {
|
||||
if (send_time < last_send_time_) {
|
||||
RTC_LOG(LS_WARNING) << "ignoring untracked data for out of order packet.";
|
||||
}
|
||||
pending_untracked_size_ +=
|
||||
DataSize::Bytes(sent_packet.info.packet_size_bytes);
|
||||
last_untracked_send_time_ = std::max(last_untracked_send_time_, send_time);
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
absl::optional<TransportPacketsFeedback>
|
||||
TransportFeedbackAdapter::ProcessTransportFeedback(
|
||||
const rtcp::TransportFeedback& feedback,
|
||||
Timestamp feedback_receive_time) {
|
||||
if (feedback.GetPacketStatusCount() == 0) {
|
||||
RTC_LOG(LS_INFO) << "Empty transport feedback packet received.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
TransportPacketsFeedback msg;
|
||||
msg.feedback_time = feedback_receive_time;
|
||||
|
||||
msg.prior_in_flight = in_flight_.GetOutstandingData(network_route_);
|
||||
msg.packet_feedbacks =
|
||||
ProcessTransportFeedbackInner(feedback, feedback_receive_time);
|
||||
if (msg.packet_feedbacks.empty())
|
||||
return absl::nullopt;
|
||||
|
||||
auto it = history_.find(last_ack_seq_num_);
|
||||
if (it != history_.end()) {
|
||||
msg.first_unacked_send_time = it->second.sent.send_time;
|
||||
}
|
||||
msg.data_in_flight = in_flight_.GetOutstandingData(network_route_);
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
void TransportFeedbackAdapter::SetNetworkRoute(
|
||||
const rtc::NetworkRoute& network_route) {
|
||||
network_route_ = network_route;
|
||||
}
|
||||
|
||||
DataSize TransportFeedbackAdapter::GetOutstandingData() const {
|
||||
return in_flight_.GetOutstandingData(network_route_);
|
||||
}
|
||||
|
||||
std::vector<PacketResult>
|
||||
TransportFeedbackAdapter::ProcessTransportFeedbackInner(
|
||||
const rtcp::TransportFeedback& feedback,
|
||||
Timestamp feedback_receive_time) {
|
||||
// Add timestamp deltas to a local time base selected on first packet arrival.
|
||||
// This won't be the true time base, but makes it easier to manually inspect
|
||||
// time stamps.
|
||||
if (last_timestamp_.IsInfinite()) {
|
||||
current_offset_ = feedback_receive_time;
|
||||
} else {
|
||||
// TODO(srte): We shouldn't need to do rounding here.
|
||||
const TimeDelta delta = feedback.GetBaseDelta(last_timestamp_)
|
||||
.RoundDownTo(TimeDelta::Millis(1));
|
||||
// Protect against assigning current_offset_ negative value.
|
||||
if (delta < Timestamp::Zero() - current_offset_) {
|
||||
RTC_LOG(LS_WARNING) << "Unexpected feedback timestamp received.";
|
||||
current_offset_ = feedback_receive_time;
|
||||
} else {
|
||||
current_offset_ += delta;
|
||||
}
|
||||
}
|
||||
last_timestamp_ = feedback.BaseTime();
|
||||
|
||||
std::vector<PacketResult> packet_result_vector;
|
||||
packet_result_vector.reserve(feedback.GetPacketStatusCount());
|
||||
|
||||
size_t failed_lookups = 0;
|
||||
size_t ignored = 0;
|
||||
|
||||
feedback.ForAllPackets(
|
||||
[&](uint16_t sequence_number, TimeDelta delta_since_base) {
|
||||
int64_t seq_num = seq_num_unwrapper_.Unwrap(sequence_number);
|
||||
|
||||
if (seq_num > last_ack_seq_num_) {
|
||||
// Starts at history_.begin() if last_ack_seq_num_ < 0, since any
|
||||
// valid sequence number is >= 0.
|
||||
for (auto it = history_.upper_bound(last_ack_seq_num_);
|
||||
it != history_.upper_bound(seq_num); ++it) {
|
||||
in_flight_.RemoveInFlightPacketBytes(it->second);
|
||||
}
|
||||
last_ack_seq_num_ = seq_num;
|
||||
}
|
||||
|
||||
auto it = history_.find(seq_num);
|
||||
if (it == history_.end()) {
|
||||
++failed_lookups;
|
||||
return;
|
||||
}
|
||||
|
||||
if (it->second.sent.send_time.IsInfinite()) {
|
||||
// TODO(srte): Fix the tests that makes this happen and make this a
|
||||
// DCHECK.
|
||||
RTC_DLOG(LS_ERROR)
|
||||
<< "Received feedback before packet was indicated as sent";
|
||||
return;
|
||||
}
|
||||
|
||||
PacketFeedback packet_feedback = it->second;
|
||||
if (delta_since_base.IsFinite()) {
|
||||
packet_feedback.receive_time =
|
||||
current_offset_ +
|
||||
delta_since_base.RoundDownTo(TimeDelta::Millis(1));
|
||||
// Note: Lost packets are not removed from history because they might
|
||||
// be reported as received by a later feedback.
|
||||
history_.erase(it);
|
||||
}
|
||||
if (packet_feedback.network_route == network_route_) {
|
||||
PacketResult result;
|
||||
result.sent_packet = packet_feedback.sent;
|
||||
result.receive_time = packet_feedback.receive_time;
|
||||
packet_result_vector.push_back(result);
|
||||
} else {
|
||||
++ignored;
|
||||
}
|
||||
});
|
||||
|
||||
if (failed_lookups > 0) {
|
||||
RTC_LOG(LS_WARNING) << "Failed to lookup send time for " << failed_lookups
|
||||
<< " packet" << (failed_lookups > 1 ? "s" : "")
|
||||
<< ". Send time history too small?";
|
||||
}
|
||||
if (ignored > 0) {
|
||||
RTC_LOG(LS_INFO) << "Ignoring " << ignored
|
||||
<< " packets because they were sent on a different route.";
|
||||
}
|
||||
|
||||
return packet_result_vector;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_CONGESTION_CONTROLLER_RTP_TRANSPORT_FEEDBACK_ADAPTER_H_
|
||||
#define MODULES_CONGESTION_CONTROLLER_RTP_TRANSPORT_FEEDBACK_ADAPTER_H_
|
||||
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "api/sequence_checker.h"
|
||||
#include "api/transport/network_types.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||
#include "rtc_base/network/sent_packet.h"
|
||||
#include "rtc_base/network_route.h"
|
||||
#include "rtc_base/numerics/sequence_number_unwrapper.h"
|
||||
#include "rtc_base/thread_annotations.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
struct PacketFeedback {
|
||||
PacketFeedback() = default;
|
||||
// Time corresponding to when this object was created.
|
||||
Timestamp creation_time = Timestamp::MinusInfinity();
|
||||
SentPacket sent;
|
||||
// Time corresponding to when the packet was received. Timestamped with the
|
||||
// receiver's clock. For unreceived packet, Timestamp::PlusInfinity() is
|
||||
// used.
|
||||
Timestamp receive_time = Timestamp::PlusInfinity();
|
||||
|
||||
// The network route that this packet is associated with.
|
||||
rtc::NetworkRoute network_route;
|
||||
};
|
||||
|
||||
class InFlightBytesTracker {
|
||||
public:
|
||||
void AddInFlightPacketBytes(const PacketFeedback& packet);
|
||||
void RemoveInFlightPacketBytes(const PacketFeedback& packet);
|
||||
DataSize GetOutstandingData(const rtc::NetworkRoute& network_route) const;
|
||||
|
||||
private:
|
||||
struct NetworkRouteComparator {
|
||||
bool operator()(const rtc::NetworkRoute& a,
|
||||
const rtc::NetworkRoute& b) const;
|
||||
};
|
||||
std::map<rtc::NetworkRoute, DataSize, NetworkRouteComparator> in_flight_data_;
|
||||
};
|
||||
|
||||
class TransportFeedbackAdapter {
|
||||
public:
|
||||
TransportFeedbackAdapter();
|
||||
|
||||
void AddPacket(const RtpPacketSendInfo& packet_info,
|
||||
size_t overhead_bytes,
|
||||
Timestamp creation_time);
|
||||
absl::optional<SentPacket> ProcessSentPacket(
|
||||
const rtc::SentPacket& sent_packet);
|
||||
|
||||
absl::optional<TransportPacketsFeedback> ProcessTransportFeedback(
|
||||
const rtcp::TransportFeedback& feedback,
|
||||
Timestamp feedback_receive_time);
|
||||
|
||||
void SetNetworkRoute(const rtc::NetworkRoute& network_route);
|
||||
|
||||
DataSize GetOutstandingData() const;
|
||||
|
||||
private:
|
||||
enum class SendTimeHistoryStatus { kNotAdded, kOk, kDuplicate };
|
||||
|
||||
std::vector<PacketResult> ProcessTransportFeedbackInner(
|
||||
const rtcp::TransportFeedback& feedback,
|
||||
Timestamp feedback_receive_time);
|
||||
|
||||
DataSize pending_untracked_size_ = DataSize::Zero();
|
||||
Timestamp last_send_time_ = Timestamp::MinusInfinity();
|
||||
Timestamp last_untracked_send_time_ = Timestamp::MinusInfinity();
|
||||
RtpSequenceNumberUnwrapper seq_num_unwrapper_;
|
||||
std::map<int64_t, PacketFeedback> history_;
|
||||
|
||||
// Sequence numbers are never negative, using -1 as it always < a real
|
||||
// sequence number.
|
||||
int64_t last_ack_seq_num_ = -1;
|
||||
InFlightBytesTracker in_flight_;
|
||||
|
||||
Timestamp current_offset_ = Timestamp::MinusInfinity();
|
||||
Timestamp last_timestamp_ = Timestamp::MinusInfinity();
|
||||
|
||||
rtc::NetworkRoute network_route_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_CONGESTION_CONTROLLER_RTP_TRANSPORT_FEEDBACK_ADAPTER_H_
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#include "modules/congestion_controller/rtp/transport_feedback_demuxer.h"
|
||||
|
||||
#include "absl/algorithm/container.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
static const size_t kMaxPacketsInHistory = 5000;
|
||||
}
|
||||
|
||||
TransportFeedbackDemuxer::TransportFeedbackDemuxer() {
|
||||
// In case the construction thread is different from where the registration
|
||||
// and callbacks occur, detach from the construction thread.
|
||||
observer_checker_.Detach();
|
||||
}
|
||||
|
||||
void TransportFeedbackDemuxer::RegisterStreamFeedbackObserver(
|
||||
std::vector<uint32_t> ssrcs,
|
||||
StreamFeedbackObserver* observer) {
|
||||
RTC_DCHECK_RUN_ON(&observer_checker_);
|
||||
RTC_DCHECK(observer);
|
||||
RTC_DCHECK(absl::c_find_if(observers_, [=](const auto& pair) {
|
||||
return pair.second == observer;
|
||||
}) == observers_.end());
|
||||
observers_.push_back({ssrcs, observer});
|
||||
}
|
||||
|
||||
void TransportFeedbackDemuxer::DeRegisterStreamFeedbackObserver(
|
||||
StreamFeedbackObserver* observer) {
|
||||
RTC_DCHECK_RUN_ON(&observer_checker_);
|
||||
RTC_DCHECK(observer);
|
||||
const auto it = absl::c_find_if(
|
||||
observers_, [=](const auto& pair) { return pair.second == observer; });
|
||||
RTC_DCHECK(it != observers_.end());
|
||||
observers_.erase(it);
|
||||
}
|
||||
|
||||
void TransportFeedbackDemuxer::AddPacket(const RtpPacketSendInfo& packet_info) {
|
||||
RTC_DCHECK_RUN_ON(&observer_checker_);
|
||||
|
||||
StreamFeedbackObserver::StreamPacketInfo info;
|
||||
info.ssrc = packet_info.media_ssrc;
|
||||
info.rtp_sequence_number = packet_info.rtp_sequence_number;
|
||||
info.received = false;
|
||||
info.is_retransmission =
|
||||
packet_info.packet_type == RtpPacketMediaType::kRetransmission;
|
||||
history_.insert(
|
||||
{seq_num_unwrapper_.Unwrap(packet_info.transport_sequence_number), info});
|
||||
|
||||
while (history_.size() > kMaxPacketsInHistory) {
|
||||
history_.erase(history_.begin());
|
||||
}
|
||||
}
|
||||
|
||||
void TransportFeedbackDemuxer::OnTransportFeedback(
|
||||
const rtcp::TransportFeedback& feedback) {
|
||||
RTC_DCHECK_RUN_ON(&observer_checker_);
|
||||
|
||||
std::vector<StreamFeedbackObserver::StreamPacketInfo> stream_feedbacks;
|
||||
feedback.ForAllPackets(
|
||||
[&](uint16_t sequence_number, TimeDelta delta_since_base) {
|
||||
RTC_DCHECK_RUN_ON(&observer_checker_);
|
||||
auto it = history_.find(seq_num_unwrapper_.PeekUnwrap(sequence_number));
|
||||
if (it != history_.end()) {
|
||||
auto packet_info = it->second;
|
||||
packet_info.received = delta_since_base.IsFinite();
|
||||
stream_feedbacks.push_back(std::move(packet_info));
|
||||
if (delta_since_base.IsFinite())
|
||||
history_.erase(it);
|
||||
}
|
||||
});
|
||||
|
||||
for (auto& observer : observers_) {
|
||||
std::vector<StreamFeedbackObserver::StreamPacketInfo> selected_feedback;
|
||||
for (const auto& packet_info : stream_feedbacks) {
|
||||
if (absl::c_count(observer.first, packet_info.ssrc) > 0) {
|
||||
selected_feedback.push_back(packet_info);
|
||||
}
|
||||
}
|
||||
if (!selected_feedback.empty()) {
|
||||
observer.second->OnPacketFeedbackVector(std::move(selected_feedback));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#ifndef MODULES_CONGESTION_CONTROLLER_RTP_TRANSPORT_FEEDBACK_DEMUXER_H_
|
||||
#define MODULES_CONGESTION_CONTROLLER_RTP_TRANSPORT_FEEDBACK_DEMUXER_H_
|
||||
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "api/sequence_checker.h"
|
||||
#include "modules/include/module_common_types_public.h"
|
||||
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||
#include "rtc_base/numerics/sequence_number_unwrapper.h"
|
||||
#include "rtc_base/system/no_unique_address.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Implementation of StreamFeedbackProvider that provides a way for
|
||||
// implementations of StreamFeedbackObserver to register for feedback callbacks
|
||||
// for a given set of SSRCs.
|
||||
// Registration methods need to be called from the same execution context
|
||||
// (thread or task queue) and callbacks to
|
||||
// StreamFeedbackObserver::OnPacketFeedbackVector will be made in that same
|
||||
// context.
|
||||
// TODO(tommi): This appears to be the only implementation of this interface.
|
||||
// Do we need the interface?
|
||||
class TransportFeedbackDemuxer final : public StreamFeedbackProvider {
|
||||
public:
|
||||
TransportFeedbackDemuxer();
|
||||
|
||||
// Implements StreamFeedbackProvider interface
|
||||
void RegisterStreamFeedbackObserver(
|
||||
std::vector<uint32_t> ssrcs,
|
||||
StreamFeedbackObserver* observer) override;
|
||||
void DeRegisterStreamFeedbackObserver(
|
||||
StreamFeedbackObserver* observer) override;
|
||||
void AddPacket(const RtpPacketSendInfo& packet_info);
|
||||
void OnTransportFeedback(const rtcp::TransportFeedback& feedback);
|
||||
|
||||
private:
|
||||
RTC_NO_UNIQUE_ADDRESS SequenceChecker observer_checker_;
|
||||
RtpSequenceNumberUnwrapper seq_num_unwrapper_
|
||||
RTC_GUARDED_BY(&observer_checker_);
|
||||
std::map<int64_t, StreamFeedbackObserver::StreamPacketInfo> history_
|
||||
RTC_GUARDED_BY(&observer_checker_);
|
||||
|
||||
// Maps a set of ssrcs to corresponding observer. Vectors are used rather than
|
||||
// set/map to ensure that the processing order is consistent independently of
|
||||
// the randomized ssrcs.
|
||||
std::vector<std::pair<std::vector<uint32_t>, StreamFeedbackObserver*>>
|
||||
observers_ RTC_GUARDED_BY(&observer_checker_);
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_CONGESTION_CONTROLLER_RTP_TRANSPORT_FEEDBACK_DEMUXER_H_
|
||||
Loading…
Add table
Add a link
Reference in a new issue