[feat] introduce fraction lost into congestion control module

This commit is contained in:
dijunkun
2025-03-04 17:39:54 +08:00
parent ebfeaf4754
commit cf374a0ff3
28 changed files with 187 additions and 107 deletions

View File

@@ -0,0 +1,61 @@
#include "audio_channel_receive.h"
#include "log.h"
AudioChannelReceive::AudioChannelReceive() {}
AudioChannelReceive::AudioChannelReceive(
std::shared_ptr<IceAgent> ice_agent,
std::shared_ptr<IOStatistics> ice_io_statistics,
std::function<void(const char *, size_t)> on_receive_audio)
: ice_agent_(ice_agent),
ice_io_statistics_(ice_io_statistics),
on_receive_audio_(on_receive_audio) {}
AudioChannelReceive::~AudioChannelReceive() {}
void AudioChannelReceive::Initialize(rtp::PAYLOAD_TYPE payload_type) {
rtp_audio_receiver_ = std::make_unique<RtpAudioReceiver>(ice_io_statistics_);
rtp_audio_receiver_->SetOnReceiveData(
[this](const char *data, size_t size) -> void {
if (on_receive_audio_) {
on_receive_audio_(data, size);
}
});
rtp_audio_receiver_->SetSendDataFunc(
[this](const char *data, size_t size) -> int {
if (!ice_agent_) {
LOG_ERROR("ice_agent_ is nullptr");
return -1;
}
auto ice_state = ice_agent_->GetIceState();
if (ice_state != NICE_COMPONENT_STATE_CONNECTED &&
ice_state != NICE_COMPONENT_STATE_READY) {
LOG_ERROR("Ice is not connected, state = [{}]",
nice_component_state_to_string(ice_state));
return -2;
}
ice_io_statistics_->UpdateAudioOutboundBytes((uint32_t)size);
return ice_agent_->Send(data, size);
});
}
void AudioChannelReceive::Destroy() {}
int AudioChannelReceive::OnReceiveRtpPacket(const char *data, size_t size) {
if (ice_io_statistics_) {
ice_io_statistics_->UpdateAudioInboundBytes((uint32_t)size);
}
if (rtp_audio_receiver_) {
RtpPacket rtp_packet;
rtp_packet.Build((uint8_t *)data, (uint32_t)size);
rtp_audio_receiver_->InsertRtpPacket(rtp_packet);
}
return 0;
}

View File

@@ -0,0 +1,55 @@
/*
* @Author: DI JUNKUN
* @Date: 2025-01-03
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _AUDIO_CHANNEL_RECEIVE_H_
#define _AUDIO_CHANNEL_RECEIVE_H_
#include "ice_agent.h"
#include "rtp_audio_receiver.h"
class AudioChannelReceive {
public:
AudioChannelReceive();
AudioChannelReceive(
std::shared_ptr<IceAgent> ice_agent,
std::shared_ptr<IOStatistics> ice_io_statistics,
std::function<void(const char *, size_t)> on_receive_audio);
~AudioChannelReceive();
public:
void Initialize(rtp::PAYLOAD_TYPE payload_type);
void Destroy();
uint32_t GetSsrc() {
if (rtp_audio_receiver_) {
return rtp_audio_receiver_->GetSsrc();
}
return 0;
}
uint32_t GetRemoteSsrc() {
if (rtp_audio_receiver_) {
return rtp_audio_receiver_->GetRemoteSsrc();
}
return 0;
}
int OnReceiveRtpPacket(const char *data, size_t size);
void OnSenderReport(const SenderReport &sender_report) {
if (rtp_audio_receiver_) {
rtp_audio_receiver_->OnSenderReport(sender_report);
}
}
private:
std::shared_ptr<IceAgent> ice_agent_ = nullptr;
std::shared_ptr<IOStatistics> ice_io_statistics_ = nullptr;
std::unique_ptr<RtpAudioReceiver> rtp_audio_receiver_ = nullptr;
std::function<void(const char *, size_t)> on_receive_audio_ = nullptr;
};
#endif

View File

@@ -0,0 +1,56 @@
#include "audio_channel_send.h"
#include "log.h"
AudioChannelSend::AudioChannelSend() {}
AudioChannelSend::~AudioChannelSend() {}
AudioChannelSend::AudioChannelSend(
std::shared_ptr<IceAgent> ice_agent,
std::shared_ptr<IOStatistics> ice_io_statistics)
: ice_agent_(ice_agent), ice_io_statistics_(ice_io_statistics) {}
void AudioChannelSend::Initialize(rtp::PAYLOAD_TYPE payload_type) {
rtp_audio_sender_ = std::make_unique<RtpAudioSender>(ice_io_statistics_);
rtp_packetizer_ =
RtpPacketizer::Create(payload_type, rtp_audio_sender_->GetSsrc());
rtp_audio_sender_->SetSendDataFunc(
[this](const char *data, size_t size) -> int {
if (!ice_agent_) {
LOG_ERROR("ice_agent_ is nullptr");
return -1;
}
auto ice_state = ice_agent_->GetIceState();
if (ice_state != NICE_COMPONENT_STATE_CONNECTED &&
ice_state != NICE_COMPONENT_STATE_READY) {
LOG_ERROR("Ice is not connected, state = [{}]",
nice_component_state_to_string(ice_state));
return -2;
}
ice_io_statistics_->UpdateAudioOutboundBytes((uint32_t)size);
return ice_agent_->Send(data, size);
});
rtp_audio_sender_->Start();
}
void AudioChannelSend::Destroy() {
if (rtp_audio_sender_) {
rtp_audio_sender_->Stop();
}
}
int AudioChannelSend::SendAudio(char *data, size_t size) {
if (rtp_audio_sender_ && rtp_packetizer_) {
std::vector<std::shared_ptr<RtpPacket>> rtp_packets =
rtp_packetizer_->Build((uint8_t *)data, (uint32_t)size, 0, true);
rtp_audio_sender_->Enqueue(rtp_packets);
}
return 0;
}

View File

@@ -0,0 +1,43 @@
/*
* @Author: DI JUNKUN
* @Date: 2025-01-03
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _AUDIO_CHANNEL_SEND_H_
#define _AUDIO_CHANNEL_SEND_H_
#include "ice_agent.h"
#include "rtp_audio_sender.h"
#include "rtp_packetizer.h"
class AudioChannelSend {
public:
AudioChannelSend();
AudioChannelSend(std::shared_ptr<IceAgent> ice_agent,
std::shared_ptr<IOStatistics> ice_io_statistics);
~AudioChannelSend();
public:
void Initialize(rtp::PAYLOAD_TYPE payload_type);
void Destroy();
uint32_t GetSsrc() {
if (rtp_audio_sender_) {
return rtp_audio_sender_->GetSsrc();
}
return 0;
}
int SendAudio(char* data, size_t size);
void OnReceiverReport(const ReceiverReport& receiver_report) {}
private:
std::shared_ptr<IceAgent> ice_agent_ = nullptr;
std::shared_ptr<IOStatistics> ice_io_statistics_ = nullptr;
std::unique_ptr<RtpPacketizer> rtp_packetizer_ = nullptr;
std::unique_ptr<RtpAudioSender> rtp_audio_sender_ = nullptr;
};
#endif

View File

@@ -0,0 +1,61 @@
#include "data_channel_receive.h"
#include "log.h"
DataChannelReceive::DataChannelReceive() {}
DataChannelReceive::DataChannelReceive(
std::shared_ptr<IceAgent> ice_agent,
std::shared_ptr<IOStatistics> ice_io_statistics,
std::function<void(const char *, size_t)> on_receive_data)
: ice_agent_(ice_agent),
ice_io_statistics_(ice_io_statistics),
on_receive_data_(on_receive_data) {}
DataChannelReceive::~DataChannelReceive() {}
void DataChannelReceive::Initialize(rtp::PAYLOAD_TYPE payload_type) {
rtp_data_receiver_ = std::make_unique<RtpDataReceiver>(ice_io_statistics_);
rtp_data_receiver_->SetOnReceiveData(
[this](const char *data, size_t size) -> void {
if (on_receive_data_) {
on_receive_data_(data, size);
}
});
rtp_data_receiver_->SetSendDataFunc(
[this](const char *data, size_t size) -> int {
if (!ice_agent_) {
LOG_ERROR("ice_agent_ is nullptr");
return -1;
}
auto ice_state = ice_agent_->GetIceState();
if (ice_state != NICE_COMPONENT_STATE_CONNECTED &&
ice_state != NICE_COMPONENT_STATE_READY) {
LOG_ERROR("Ice is not connected, state = [{}]",
nice_component_state_to_string(ice_state));
return -2;
}
ice_io_statistics_->UpdateDataOutboundBytes((uint32_t)size);
return ice_agent_->Send(data, size);
});
}
void DataChannelReceive::Destroy() {}
int DataChannelReceive::OnReceiveRtpPacket(const char *data, size_t size) {
if (ice_io_statistics_) {
ice_io_statistics_->UpdateDataInboundBytes((uint32_t)size);
}
if (rtp_data_receiver_) {
RtpPacket rtp_packet;
rtp_packet.Build((uint8_t *)data, (uint32_t)size);
rtp_data_receiver_->InsertRtpPacket(rtp_packet);
}
return -1;
}

View File

@@ -0,0 +1,54 @@
/*
* @Author: DI JUNKUN
* @Date: 2025-01-03
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _DATA_CHANNEL_RECEIVE_H_
#define _DATA_CHANNEL_RECEIVE_H_
#include "ice_agent.h"
#include "rtp_data_receiver.h"
class DataChannelReceive {
public:
DataChannelReceive();
DataChannelReceive(std::shared_ptr<IceAgent> ice_agent,
std::shared_ptr<IOStatistics> ice_io_statistics,
std::function<void(const char *, size_t)> on_receive_data);
~DataChannelReceive();
public:
void Initialize(rtp::PAYLOAD_TYPE payload_type);
void Destroy();
uint32_t GetSsrc() {
if (rtp_data_receiver_) {
return rtp_data_receiver_->GetSsrc();
}
return 0;
}
uint32_t GetRemoteSsrc() {
if (rtp_data_receiver_) {
return rtp_data_receiver_->GetRemoteSsrc();
}
return 0;
}
int OnReceiveRtpPacket(const char *data, size_t size);
void OnSenderReport(const SenderReport &sender_report) {
if (rtp_data_receiver_) {
rtp_data_receiver_->OnSenderReport(sender_report);
}
}
private:
std::shared_ptr<IceAgent> ice_agent_ = nullptr;
std::shared_ptr<IOStatistics> ice_io_statistics_ = nullptr;
std::unique_ptr<RtpDataReceiver> rtp_data_receiver_ = nullptr;
std::function<void(const char *, size_t)> on_receive_data_ = nullptr;
};
#endif

View File

@@ -0,0 +1,56 @@
#include "data_channel_send.h"
#include "log.h"
DataChannelSend::DataChannelSend() {}
DataChannelSend::~DataChannelSend() {}
DataChannelSend::DataChannelSend(
std::shared_ptr<IceAgent> ice_agent,
std::shared_ptr<IOStatistics> ice_io_statistics)
: ice_agent_(ice_agent), ice_io_statistics_(ice_io_statistics) {}
void DataChannelSend::Initialize(rtp::PAYLOAD_TYPE payload_type) {
rtp_data_sender_ = std::make_unique<RtpDataSender>(ice_io_statistics_);
rtp_packetizer_ =
RtpPacketizer::Create(payload_type, rtp_data_sender_->GetSsrc());
rtp_data_sender_->SetSendDataFunc(
[this](const char *data, size_t size) -> int {
if (!ice_agent_) {
LOG_ERROR("ice_agent_ is nullptr");
return -1;
}
auto ice_state = ice_agent_->GetIceState();
if (ice_state != NICE_COMPONENT_STATE_CONNECTED &&
ice_state != NICE_COMPONENT_STATE_READY) {
LOG_ERROR("Ice is not connected, state = [{}]",
nice_component_state_to_string(ice_state));
return -2;
}
ice_io_statistics_->UpdateDataOutboundBytes((uint32_t)size);
return ice_agent_->Send(data, size);
});
rtp_data_sender_->Start();
}
void DataChannelSend::Destroy() {
if (rtp_data_sender_) {
rtp_data_sender_->Stop();
}
}
int DataChannelSend::SendData(const char *data, size_t size) {
if (rtp_data_sender_ && rtp_packetizer_) {
std::vector<std::shared_ptr<RtpPacket>> rtp_packets =
rtp_packetizer_->Build((uint8_t *)data, (uint32_t)size, 0, true);
rtp_data_sender_->Enqueue(rtp_packets);
}
return 0;
}

View File

@@ -0,0 +1,43 @@
/*
* @Author: DI JUNKUN
* @Date: 2025-01-03
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _DATA_CHANNEL_SEND_H_
#define _DATA_CHANNEL_SEND_H_
#include "ice_agent.h"
#include "rtp_data_sender.h"
#include "rtp_packetizer.h"
class DataChannelSend {
public:
DataChannelSend();
DataChannelSend(std::shared_ptr<IceAgent> ice_agent,
std::shared_ptr<IOStatistics> ice_io_statistics);
~DataChannelSend();
public:
void Initialize(rtp::PAYLOAD_TYPE payload_type);
void Destroy();
uint32_t GetSsrc() {
if (rtp_data_sender_) {
return rtp_data_sender_->GetSsrc();
}
return 0;
}
int SendData(const char* data, size_t size);
void OnReceiverReport(const ReceiverReport& receiver_report) {}
private:
std::shared_ptr<IceAgent> ice_agent_ = nullptr;
std::shared_ptr<IOStatistics> ice_io_statistics_ = nullptr;
std::unique_ptr<RtpPacketizer> rtp_packetizer_ = nullptr;
std::unique_ptr<RtpDataSender> rtp_data_sender_ = nullptr;
};
#endif

View File

@@ -0,0 +1,67 @@
#include "video_channel_receive.h"
#include "log.h"
VideoChannelReceive::VideoChannelReceive() {}
VideoChannelReceive::VideoChannelReceive(
std::shared_ptr<SystemClock> clock, std::shared_ptr<IceAgent> ice_agent,
std::shared_ptr<IOStatistics> ice_io_statistics,
std::function<void(VideoFrame &)> on_receive_complete_frame)
: ice_agent_(ice_agent),
ice_io_statistics_(ice_io_statistics),
on_receive_complete_frame_(on_receive_complete_frame),
clock_(clock) {}
VideoChannelReceive::~VideoChannelReceive() {}
void VideoChannelReceive::Initialize(rtp::PAYLOAD_TYPE payload_type) {
rtp_video_receiver_ =
std::make_unique<RtpVideoReceiver>(clock_, ice_io_statistics_);
rtp_video_receiver_->SetOnReceiveCompleteFrame(
[this](VideoFrame &video_frame) -> void {
on_receive_complete_frame_(video_frame);
});
rtp_video_receiver_->SetSendDataFunc(
[this](const char *data, size_t size) -> int {
if (!ice_agent_) {
LOG_ERROR("ice_agent_ is nullptr");
return -1;
}
auto ice_state = ice_agent_->GetIceState();
if (ice_state != NICE_COMPONENT_STATE_CONNECTED &&
ice_state != NICE_COMPONENT_STATE_READY) {
LOG_ERROR("Ice is not connected, state = [{}]",
nice_component_state_to_string(ice_state));
return -2;
}
ice_io_statistics_->UpdateVideoOutboundBytes((uint32_t)size);
return ice_agent_->Send(data, size);
});
rtp_video_receiver_->Start();
}
void VideoChannelReceive::Destroy() {
if (rtp_video_receiver_) {
rtp_video_receiver_->Stop();
}
}
int VideoChannelReceive::OnReceiveRtpPacket(const char *data, size_t size) {
if (ice_io_statistics_) {
ice_io_statistics_->UpdateVideoInboundBytes((uint32_t)size);
}
if (rtp_video_receiver_) {
RtpPacket rtp_packet;
rtp_packet.Build((uint8_t *)data, (uint32_t)size);
rtp_video_receiver_->InsertRtpPacket(rtp_packet);
}
return 0;
}

View File

@@ -0,0 +1,60 @@
/*
* @Author: DI JUNKUN
* @Date: 2025-01-03
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _VIDEO_CHANNEL_RECEIVE_H_
#define _VIDEO_CHANNEL_RECEIVE_H_
#include "clock/system_clock.h"
#include "ice_agent.h"
#include "rtp_video_receiver.h"
class VideoChannelReceive {
public:
VideoChannelReceive();
VideoChannelReceive(
std::shared_ptr<SystemClock> clock, std::shared_ptr<IceAgent> ice_agent,
std::shared_ptr<IOStatistics> ice_io_statistics,
std::function<void(VideoFrame &)> on_receive_complete_frame);
~VideoChannelReceive();
public:
void Initialize(rtp::PAYLOAD_TYPE payload_type);
void Destroy();
uint32_t GetSsrc() {
if (rtp_video_receiver_) {
return rtp_video_receiver_->GetSsrc();
}
return 0;
}
uint32_t GetRemoteSsrc() {
if (rtp_video_receiver_) {
return rtp_video_receiver_->GetRemoteSsrc();
}
return 0;
}
int OnReceiveRtpPacket(const char *data, size_t size);
void OnSenderReport(const SenderReport &sender_report) {
if (rtp_video_receiver_) {
rtp_video_receiver_->OnSenderReport(sender_report);
}
}
private:
std::shared_ptr<IceAgent> ice_agent_ = nullptr;
std::shared_ptr<IOStatistics> ice_io_statistics_ = nullptr;
std::unique_ptr<RtpVideoReceiver> rtp_video_receiver_ = nullptr;
std::function<void(VideoFrame &)> on_receive_complete_frame_ = nullptr;
private:
std::shared_ptr<SystemClock> clock_;
};
#endif

View File

@@ -0,0 +1,71 @@
#include "video_channel_send.h"
#include "log.h"
#include "rtc_base/network/sent_packet.h"
VideoChannelSend::VideoChannelSend() {}
VideoChannelSend::~VideoChannelSend() {}
VideoChannelSend::VideoChannelSend(
std::shared_ptr<SystemClock> clock, std::shared_ptr<IceAgent> ice_agent,
std::shared_ptr<IOStatistics> ice_io_statistics,
std::function<void(const webrtc::RtpPacketToSend& packet)>
on_sent_packet_func)
: ice_agent_(ice_agent),
ice_io_statistics_(ice_io_statistics),
on_sent_packet_func_(on_sent_packet_func),
clock_(clock){};
void VideoChannelSend::Initialize(rtp::PAYLOAD_TYPE payload_type) {
rtp_video_sender_ =
std::make_unique<RtpVideoSender>(clock_, ice_io_statistics_);
rtp_packetizer_ =
RtpPacketizer::Create(payload_type, rtp_video_sender_->GetSsrc());
rtp_video_sender_->SetSendDataFunc(
[this](const char* data, size_t size) -> int {
if (!ice_agent_) {
LOG_ERROR("ice_agent_ is nullptr");
return -1;
}
auto ice_state = ice_agent_->GetIceState();
if (ice_state != NICE_COMPONENT_STATE_CONNECTED &&
ice_state != NICE_COMPONENT_STATE_READY) {
// LOG_ERROR("Ice is not connected, state = [{}]",
// nice_component_state_to_string(ice_state));
return -2;
}
ice_io_statistics_->UpdateVideoOutboundBytes((uint32_t)size);
return ice_agent_->Send(data, size);
});
rtp_video_sender_->SetOnSentPacketFunc(
[this](const webrtc::RtpPacketToSend& packet) -> void {
on_sent_packet_func_(packet);
});
rtp_video_sender_->Start();
}
void VideoChannelSend::Destroy() {
if (rtp_video_sender_) {
rtp_video_sender_->Stop();
}
}
int VideoChannelSend::SendVideo(
std::shared_ptr<VideoFrameWrapper> encoded_frame) {
if (rtp_video_sender_ && rtp_packetizer_) {
std::vector<std::shared_ptr<RtpPacket>> rtp_packets =
rtp_packetizer_->Build((uint8_t*)encoded_frame->Buffer(),
(uint32_t)encoded_frame->Size(),
encoded_frame->CaptureTimestamp(), true);
rtp_video_sender_->Enqueue(rtp_packets, encoded_frame->CaptureTimestamp());
}
return 0;
}

View File

@@ -0,0 +1,72 @@
/*
* @Author: DI JUNKUN
* @Date: 2025-01-03
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _VIDEO_CHANNEL_SEND_H_
#define _VIDEO_CHANNEL_SEND_H_
#include "api/transport/network_types.h"
#include "api/units/timestamp.h"
#include "clock/system_clock.h"
#include "congestion_control.h"
#include "congestion_control_feedback.h"
#include "ice_agent.h"
#include "rtp_packetizer.h"
#include "rtp_video_sender.h"
#include "transport_feedback_adapter.h"
#include "video_frame_wrapper.h"
class VideoChannelSend {
public:
VideoChannelSend();
VideoChannelSend(std::shared_ptr<SystemClock> clock,
std::shared_ptr<IceAgent> ice_agent,
std::shared_ptr<IOStatistics> ice_io_statistics,
std::function<void(const webrtc::RtpPacketToSend& packet)>
on_sent_packet_func_);
~VideoChannelSend();
public:
void Initialize(rtp::PAYLOAD_TYPE payload_type);
void Destroy();
uint32_t GetSsrc() {
if (rtp_video_sender_) {
return rtp_video_sender_->GetSsrc();
}
return 0;
}
int SendVideo(std::shared_ptr<VideoFrameWrapper> encoded_frame);
void OnCongestionControlFeedback(
Timestamp recv_ts,
const webrtc::rtcp::CongestionControlFeedback& feedback);
void OnReceiverReport(const ReceiverReport& receiver_report) {
if (rtp_video_sender_) {
rtp_video_sender_->OnReceiverReport(receiver_report);
}
}
private:
void PostUpdates(webrtc::NetworkControlUpdate update);
void UpdateControlState();
void UpdateCongestedState();
private:
std::shared_ptr<IceAgent> ice_agent_ = nullptr;
std::shared_ptr<IOStatistics> ice_io_statistics_ = nullptr;
std::unique_ptr<RtpPacketizer> rtp_packetizer_ = nullptr;
std::unique_ptr<RtpVideoSender> rtp_video_sender_ = nullptr;
std::function<void(const webrtc::RtpPacketToSend& packet)>
on_sent_packet_func_ = nullptr;
private:
std::shared_ptr<SystemClock> clock_;
};
#endif