[refactor] move channel module into transport module

This commit is contained in:
dijunkun
2025-03-17 17:19:46 +08:00
parent 5c598be51d
commit b0306d510c
35 changed files with 134 additions and 98 deletions

View File

@@ -0,0 +1,59 @@
#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_NULLPTR == ice_state || ICE_STATE_DESTROYED == ice_state) {
LOG_ERROR("Ice is not connected, state = [{}]", (int)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,53 @@
#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_DESTROYED == 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::unique_ptr<RtpPacket>> rtp_packets =
rtp_packetizer_->Build((uint8_t *)data, (uint32_t)size, 0, true);
rtp_audio_sender_->Enqueue(std::move(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,59 @@
#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_NULLPTR == ice_state || ICE_STATE_DESTROYED == ice_state) {
LOG_ERROR("Ice is not connected, state = [{}]", (int)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,53 @@
#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_DESTROYED == 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::unique_ptr<RtpPacket>> rtp_packets =
rtp_packetizer_->Build((uint8_t *)data, (uint32_t)size, 0, true);
rtp_data_sender_->Enqueue(std::move(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,105 @@
#include "rtp_audio_receiver.h"
#define RTCP_RR_INTERVAL 1000
RtpAudioReceiver::RtpAudioReceiver() {}
RtpAudioReceiver::RtpAudioReceiver(std::shared_ptr<IOStatistics> io_statistics)
: io_statistics_(io_statistics) {}
RtpAudioReceiver::~RtpAudioReceiver() {
if (rtp_statistics_) {
rtp_statistics_->Stop();
}
}
void RtpAudioReceiver::InsertRtpPacket(RtpPacket& rtp_packet) {
if (!rtp_statistics_) {
rtp_statistics_ = std::make_unique<RtpStatistics>();
rtp_statistics_->Start();
}
last_recv_bytes_ = (uint32_t)rtp_packet.Size();
total_rtp_payload_recv_ += (uint32_t)rtp_packet.PayloadSize();
total_rtp_packets_recv_++;
if (rtp_statistics_) {
rtp_statistics_->UpdateReceiveBytes(last_recv_bytes_);
}
if (io_statistics_) {
io_statistics_->UpdateAudioInboundBytes(last_recv_bytes_);
io_statistics_->IncrementAudioInboundRtpPacketCount();
io_statistics_->UpdateAudioPacketLossCount(rtp_packet.SequenceNumber());
}
// if (CheckIsTimeSendRR()) {
// ReceiverReport rtcp_rr;
// RtcpReportBlock report;
// // auto duration = std::chrono::system_clock::now().time_since_epoch();
// // auto seconds =
// // std::chrono::duration_cast<std::chrono::seconds>(duration); uint32_t
// // seconds_u32 = static_cast<uint32_t>(
// // std::chrono::duration_cast<std::chrono::seconds>(duration).count());
// // uint32_t fraction_u32 = static_cast<uint32_t>(
// // std::chrono::duration_cast<std::chrono::nanoseconds>(duration -
// // seconds)
// // .count());
// report.source_ssrc = 0x00;
// report.fraction_lost = 0;
// report.cumulative_lost = 0;
// report.extended_high_seq_num = 0;
// report.jitter = 0;
// report.lsr = 0;
// report.dlsr = 0;
// rtcp_rr.SetReportBlock(report);
// rtcp_rr.Encode();
// // SendRtcpRR(rtcp_rr);
// }
if (on_receive_data_) {
on_receive_data_((const char*)rtp_packet.Payload(),
rtp_packet.PayloadSize());
}
}
void RtpAudioReceiver::SetSendDataFunc(
std::function<int(const char*, size_t)> data_send_func) {
data_send_func_ = data_send_func;
}
int RtpAudioReceiver::SendRtcpRR(ReceiverReport& rtcp_rr) {
if (!data_send_func_) {
LOG_ERROR("data_send_func_ is nullptr");
return -1;
}
if (data_send_func_((const char*)rtcp_rr.Buffer(), rtcp_rr.Size())) {
LOG_ERROR("Send RR failed");
return -1;
}
// LOG_ERROR("Send RR");
return 0;
}
bool RtpAudioReceiver::CheckIsTimeSendRR() {
uint32_t now_ts = static_cast<uint32_t>(
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count());
if (now_ts - last_send_rtcp_rr_packet_ts_ >= RTCP_RR_INTERVAL) {
last_send_rtcp_rr_packet_ts_ = now_ts;
return true;
} else {
return false;
}
}

View File

@@ -0,0 +1,62 @@
/*
* @Author: DI JUNKUN
* @Date: 2023-11-24
* Copyright (c) 2023 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _RTP_AUDIO_RECEIVER_H_
#define _RTP_AUDIO_RECEIVER_H_
#include <functional>
#include "io_statistics.h"
#include "receiver_report.h"
#include "rtp_packet.h"
#include "rtp_statistics.h"
#include "sender_report.h"
class RtpAudioReceiver {
public:
RtpAudioReceiver();
RtpAudioReceiver(std::shared_ptr<IOStatistics> io_statistics);
~RtpAudioReceiver();
public:
void InsertRtpPacket(RtpPacket& rtp_packet);
void SetSendDataFunc(std::function<int(const char*, size_t)> data_send_func);
void SetOnReceiveData(
std::function<void(const char*, size_t)> on_receive_data) {
on_receive_data_ = on_receive_data;
}
uint32_t GetSsrc() { return ssrc_; }
uint32_t GetRemoteSsrc() { return remote_ssrc_; }
void OnSenderReport(const SenderReport& sender_report) {}
private:
bool CheckIsTimeSendRR();
int SendRtcpRR(ReceiverReport& rtcp_rr);
private:
std::function<void(const char*, size_t)> on_receive_data_ = nullptr;
uint32_t last_complete_frame_ts_ = 0;
private:
std::unique_ptr<RtpStatistics> rtp_statistics_ = nullptr;
std::shared_ptr<IOStatistics> io_statistics_ = nullptr;
uint32_t last_recv_bytes_ = 0;
uint32_t total_rtp_payload_recv_ = 0;
uint32_t total_rtp_packets_recv_ = 0;
uint32_t last_send_rtcp_rr_packet_ts_ = 0;
std::function<int(const char*, size_t)> data_send_func_ = nullptr;
uint32_t ssrc_ = 0;
uint32_t remote_ssrc_ = 0;
uint32_t last_sr_ = 0;
uint32_t last_delay_ = 0;
};
#endif

View File

@@ -0,0 +1,156 @@
#include "rtp_audio_sender.h"
#include <chrono>
#include "common.h"
#include "log.h"
#define RTCP_SR_INTERVAL 1000
RtpAudioSender::RtpAudioSender() { SetPeriod(std::chrono::milliseconds(5)); }
RtpAudioSender::RtpAudioSender(std::shared_ptr<IOStatistics> io_statistics)
: ssrc_(GenerateUniqueSsrc()), io_statistics_(io_statistics) {
SetPeriod(std::chrono::milliseconds(5));
}
RtpAudioSender::~RtpAudioSender() {
if (rtp_statistics_) {
rtp_statistics_->Stop();
}
SSRCManager::Instance().DeleteSsrc(ssrc_);
}
void RtpAudioSender::Enqueue(
std::vector<std::unique_ptr<RtpPacket>> rtp_packets) {
if (!rtp_statistics_) {
rtp_statistics_ = std::make_unique<RtpStatistics>();
rtp_statistics_->Start();
}
for (auto& rtp_packet : rtp_packets) {
rtp_packet_queue_.push(std::move(rtp_packet));
}
}
void RtpAudioSender::SetSendDataFunc(
std::function<int(const char*, size_t)> data_send_func) {
data_send_func_ = data_send_func;
}
int RtpAudioSender::SendRtpPacket(std::unique_ptr<RtpPacket> rtp_packet) {
if (!data_send_func_) {
LOG_ERROR("data_send_func_ is nullptr");
return -1;
}
int ret = data_send_func_((const char*)rtp_packet->Buffer().data(),
rtp_packet->Size());
if (-2 == ret) {
rtp_packet_queue_.clear();
return -1;
}
last_send_bytes_ += (uint32_t)rtp_packet->Size();
total_rtp_payload_sent_ += (uint32_t)rtp_packet->PayloadSize();
total_rtp_packets_sent_++;
if (io_statistics_) {
io_statistics_->UpdateAudioOutboundBytes(last_send_bytes_);
io_statistics_->IncrementAudioOutboundRtpPacketCount();
}
// if (CheckIsTimeSendSR()) {
// SenderReport rtcp_sr;
// SenderInfo sender_info;
// RtcpReportBlock report;
// auto duration = std::chrono::system_clock::now().time_since_epoch();
// auto seconds =
// std::chrono::duration_cast<std::chrono::seconds>(duration); uint32_t
// seconds_u32 = static_cast<uint32_t>(
// std::chrono::duration_cast<std::chrono::seconds>(duration).count());
// uint32_t fraction_u32 = static_cast<uint32_t>(
// std::chrono::duration_cast<std::chrono::nanoseconds>(duration -
// seconds)
// .count());
// sender_info.sender_ssrc = 0x00;
// sender_info.ntp_ts_msw = (uint32_t)seconds_u32;
// sender_info.ntp_ts_lsw = (uint32_t)fraction_u32;
// sender_info.rtp_ts =
// std::chrono::system_clock::now().time_since_epoch().count() *
// 1000000;
// sender_info.sender_packet_count = total_rtp_packets_sent_;
// sender_info.sender_octet_count = total_rtp_payload_sent_;
// rtcp_sr.SetSenderInfo(sender_info);
// report.source_ssrc = 0x00;
// report.fraction_lost = 0;
// report.cumulative_lost = 0;
// report.extended_high_seq_num = 0;
// report.jitter = 0;
// report.lsr = 0;
// report.dlsr = 0;
// rtcp_sr.SetReportBlock(report);
// rtcp_sr.Encode();
// // SendRtcpSR(rtcp_sr);
// }
return 0;
}
int RtpAudioSender::SendRtcpSR(SenderReport& rtcp_sr) {
if (!data_send_func_) {
LOG_ERROR("data_send_func_ is nullptr");
return -1;
}
if (data_send_func_((const char*)rtcp_sr.Buffer(), rtcp_sr.Size())) {
LOG_ERROR("Send SR failed");
return -1;
}
// LOG_ERROR("Send SR");
return 0;
}
bool RtpAudioSender::CheckIsTimeSendSR() {
uint32_t now_ts = static_cast<uint32_t>(
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count());
if (now_ts - last_send_rtcp_sr_packet_ts_ >= RTCP_SR_INTERVAL) {
last_send_rtcp_sr_packet_ts_ = now_ts;
return true;
} else {
return false;
}
}
bool RtpAudioSender::Process() {
last_send_bytes_ = 0;
for (size_t i = 0; i < 10; i++)
if (!rtp_packet_queue_.isEmpty()) {
std::optional<std::unique_ptr<RtpPacket>> rtp_packet =
rtp_packet_queue_.pop();
if (rtp_packet) {
SendRtpPacket(std::move(*rtp_packet));
}
}
if (rtp_statistics_) {
rtp_statistics_->UpdateSentBytes(last_send_bytes_);
}
return true;
}

View File

@@ -0,0 +1,55 @@
/*
* @Author: DI JUNKUN
* @Date: 2023-11-24
* Copyright (c) 2023 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _RTP_AUDIO_SENDER_H_
#define _RTP_AUDIO_SENDER_H_
#include <functional>
#include "io_statistics.h"
#include "receiver_report.h"
#include "ringbuffer.h"
#include "rtp_packet.h"
#include "rtp_statistics.h"
#include "sender_report.h"
#include "thread_base.h"
class RtpAudioSender : public ThreadBase {
public:
RtpAudioSender();
RtpAudioSender(std::shared_ptr<IOStatistics> io_statistics);
virtual ~RtpAudioSender();
public:
void Enqueue(std::vector<std::unique_ptr<RtpPacket>> rtp_packets);
void SetSendDataFunc(std::function<int(const char *, size_t)> data_send_func);
uint32_t GetSsrc() { return ssrc_; }
void OnReceiverReport(const ReceiverReport &receiver_report) {}
private:
int SendRtpPacket(std::unique_ptr<RtpPacket> rtp_packet);
int SendRtcpSR(SenderReport &rtcp_sr);
bool CheckIsTimeSendSR();
private:
bool Process() override;
private:
std::function<int(const char *, size_t)> data_send_func_ = nullptr;
RingBuffer<std::unique_ptr<RtpPacket>> rtp_packet_queue_;
private:
uint32_t ssrc_ = 0;
std::unique_ptr<RtpStatistics> rtp_statistics_ = nullptr;
std::shared_ptr<IOStatistics> io_statistics_ = nullptr;
uint32_t last_send_bytes_ = 0;
uint32_t total_rtp_payload_sent_ = 0;
uint32_t total_rtp_packets_sent_ = 0;
uint32_t last_send_rtcp_sr_packet_ts_ = 0;
};
#endif

View File

@@ -0,0 +1,105 @@
#include "rtp_data_receiver.h"
#define RTCP_RR_INTERVAL 1000
RtpDataReceiver::RtpDataReceiver() {}
RtpDataReceiver::RtpDataReceiver(std::shared_ptr<IOStatistics> io_statistics)
: io_statistics_(io_statistics) {}
RtpDataReceiver::~RtpDataReceiver() {
if (rtp_statistics_) {
rtp_statistics_->Stop();
}
}
void RtpDataReceiver::InsertRtpPacket(RtpPacket& rtp_packet) {
if (!rtp_statistics_) {
rtp_statistics_ = std::make_unique<RtpStatistics>();
rtp_statistics_->Start();
}
last_recv_bytes_ = (uint32_t)rtp_packet.Size();
total_rtp_payload_recv_ += (uint32_t)rtp_packet.PayloadSize();
total_rtp_packets_recv_++;
if (rtp_statistics_) {
rtp_statistics_->UpdateReceiveBytes(last_recv_bytes_);
}
if (io_statistics_) {
io_statistics_->UpdateDataInboundBytes(last_recv_bytes_);
io_statistics_->IncrementDataInboundRtpPacketCount();
io_statistics_->UpdateDataPacketLossCount(rtp_packet.SequenceNumber());
}
// if (CheckIsTimeSendRR()) {
// ReceiverReport rtcp_rr;
// RtcpReportBlock report;
// // auto duration = std::chrono::system_clock::now().time_since_epoch();
// // auto seconds =
// // std::chrono::duration_cast<std::chrono::seconds>(duration); uint32_t
// // seconds_u32 = static_cast<uint32_t>(
// // std::chrono::duration_cast<std::chrono::seconds>(duration).count());
// // uint32_t fraction_u32 = static_cast<uint32_t>(
// // std::chrono::duration_cast<std::chrono::nanoseconds>(duration -
// // seconds)
// // .count());
// report.source_ssrc = 0x00;
// report.fraction_lost = 0;
// report.cumulative_lost = 0;
// report.extended_high_seq_num = 0;
// report.jitter = 0;
// report.lsr = 0;
// report.dlsr = 0;
// rtcp_rr.SetReportBlock(report);
// rtcp_rr.Encode();
// // SendRtcpRR(rtcp_rr);
// }
// if (on_receive_data_) {
// on_receive_data_((const char*)rtp_packet.Payload(),
// rtp_packet.PayloadSize());
// }
}
void RtpDataReceiver::SetSendDataFunc(
std::function<int(const char*, size_t)> data_send_func) {
data_send_func_ = data_send_func;
}
int RtpDataReceiver::SendRtcpRR(ReceiverReport& rtcp_rr) {
if (!data_send_func_) {
LOG_ERROR("data_send_func_ is nullptr");
return -1;
}
if (data_send_func_((const char*)rtcp_rr.Buffer(), rtcp_rr.Size())) {
LOG_ERROR("Send RR failed");
return -1;
}
// LOG_ERROR("Send RR");
return 0;
}
bool RtpDataReceiver::CheckIsTimeSendRR() {
uint32_t now_ts = static_cast<uint32_t>(
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count());
if (now_ts - last_send_rtcp_rr_packet_ts_ >= RTCP_RR_INTERVAL) {
last_send_rtcp_rr_packet_ts_ = now_ts;
return true;
} else {
return false;
}
}

View File

@@ -0,0 +1,55 @@
#ifndef _RTP_DATA_RECEIVER_H_
#define _RTP_DATA_RECEIVER_H_
#include <functional>
#include "io_statistics.h"
#include "receiver_report.h"
#include "rtp_packet.h"
#include "rtp_statistics.h"
#include "sender_report.h"
class RtpDataReceiver {
public:
RtpDataReceiver();
RtpDataReceiver(std::shared_ptr<IOStatistics> io_statistics);
~RtpDataReceiver();
public:
void InsertRtpPacket(RtpPacket& rtp_packet);
void SetSendDataFunc(std::function<int(const char*, size_t)> data_send_func);
void SetOnReceiveData(
std::function<void(const char*, size_t)> on_receive_data) {
on_receive_data_ = on_receive_data;
}
uint32_t GetSsrc() { return ssrc_; }
uint32_t GetRemoteSsrc() { return remote_ssrc_; }
void OnSenderReport(const SenderReport& sender_report) {}
private:
bool CheckIsTimeSendRR();
int SendRtcpRR(ReceiverReport& rtcp_rr);
private:
std::function<void(const char*, size_t)> on_receive_data_ = nullptr;
uint32_t last_complete_frame_ts_ = 0;
private:
std::unique_ptr<RtpStatistics> rtp_statistics_ = nullptr;
std::shared_ptr<IOStatistics> io_statistics_ = nullptr;
uint32_t last_recv_bytes_ = 0;
uint32_t total_rtp_payload_recv_ = 0;
uint32_t total_rtp_packets_recv_ = 0;
uint32_t ssrc_ = 0;
uint32_t remote_ssrc_ = 0;
uint32_t last_send_rtcp_rr_packet_ts_ = 0;
std::function<int(const char*, size_t)> data_send_func_ = nullptr;
uint32_t last_sr_ = 0;
uint32_t last_delay_ = 0;
};
#endif

View File

@@ -0,0 +1,156 @@
#include "rtp_data_sender.h"
#include <chrono>
#include "common.h"
#include "log.h"
#define RTCP_SR_INTERVAL 1000
RtpDataSender::RtpDataSender() {}
RtpDataSender::RtpDataSender(std::shared_ptr<IOStatistics> io_statistics)
: ssrc_(GenerateUniqueSsrc()), io_statistics_(io_statistics) {
SetPeriod(std::chrono::milliseconds(5));
}
RtpDataSender::~RtpDataSender() {
if (rtp_statistics_) {
rtp_statistics_->Stop();
}
SSRCManager::Instance().DeleteSsrc(ssrc_);
}
void RtpDataSender::Enqueue(
std::vector<std::unique_ptr<RtpPacket>> rtp_packets) {
if (!rtp_statistics_) {
rtp_statistics_ = std::make_unique<RtpStatistics>();
rtp_statistics_->Start();
}
for (auto& rtp_packet : rtp_packets) {
rtp_packet_queue_.push(std::move(rtp_packet));
}
}
void RtpDataSender::SetSendDataFunc(
std::function<int(const char*, size_t)> data_send_func) {
data_send_func_ = data_send_func;
}
int RtpDataSender::SendRtpPacket(std::unique_ptr<RtpPacket> rtp_packet) {
if (!data_send_func_) {
LOG_ERROR("data_send_func_ is nullptr");
return -1;
}
int ret = data_send_func_((const char*)rtp_packet->Buffer().data(),
rtp_packet->Size());
if (-2 == ret) {
rtp_packet_queue_.clear();
return -1;
}
last_send_bytes_ += (uint32_t)rtp_packet->Size();
total_rtp_payload_sent_ += (uint32_t)rtp_packet->PayloadSize();
total_rtp_packets_sent_++;
if (io_statistics_) {
io_statistics_->UpdateDataOutboundBytes(last_send_bytes_);
io_statistics_->IncrementDataOutboundRtpPacketCount();
}
// if (CheckIsTimeSendSR()) {
// SenderReport rtcp_sr;
// SenderInfo sender_info;
// RtcpReportBlock report;
// auto duration = std::chrono::system_clock::now().time_since_epoch();
// auto seconds =
// std::chrono::duration_cast<std::chrono::seconds>(duration); uint32_t
// seconds_u32 = static_cast<uint32_t>(
// std::chrono::duration_cast<std::chrono::seconds>(duration).count());
// uint32_t fraction_u32 = static_cast<uint32_t>(
// std::chrono::duration_cast<std::chrono::nanoseconds>(duration -
// seconds)
// .count());
// sender_info.sender_ssrc = 0x00;
// sender_info.ntp_ts_msw = (uint32_t)seconds_u32;
// sender_info.ntp_ts_lsw = (uint32_t)fraction_u32;
// sender_info.rtp_ts =
// std::chrono::system_clock::now().time_since_epoch().count() *
// 1000000;
// sender_info.sender_packet_count = total_rtp_packets_sent_;
// sender_info.sender_octet_count = total_rtp_payload_sent_;
// rtcp_sr.SetSenderInfo(sender_info);
// report.source_ssrc = 0x00;
// report.fraction_lost = 0;
// report.cumulative_lost = 0;
// report.extended_high_seq_num = 0;
// report.jitter = 0;
// report.lsr = 0;
// report.dlsr = 0;
// rtcp_sr.SetReportBlock(report);
// rtcp_sr.Encode();
// // SendRtcpSR(rtcp_sr);
// }
return 0;
}
int RtpDataSender::SendRtcpSR(SenderReport& rtcp_sr) {
if (!data_send_func_) {
LOG_ERROR("data_send_func_ is nullptr");
return -1;
}
if (data_send_func_((const char*)rtcp_sr.Buffer(), rtcp_sr.Size())) {
LOG_ERROR("Send SR failed");
return -1;
}
// LOG_ERROR("Send SR");
return 0;
}
bool RtpDataSender::CheckIsTimeSendSR() {
uint32_t now_ts = static_cast<uint32_t>(
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count());
if (now_ts - last_send_rtcp_sr_packet_ts_ >= RTCP_SR_INTERVAL) {
last_send_rtcp_sr_packet_ts_ = now_ts;
return true;
} else {
return false;
}
}
bool RtpDataSender::Process() {
last_send_bytes_ = 0;
for (size_t i = 0; i < 10; i++)
if (!rtp_packet_queue_.isEmpty()) {
std::optional<std::unique_ptr<RtpPacket>> rtp_packet =
rtp_packet_queue_.pop();
if (rtp_packet) {
SendRtpPacket(std::move(*rtp_packet));
}
}
if (rtp_statistics_) {
rtp_statistics_->UpdateSentBytes(last_send_bytes_);
}
return true;
}

View File

@@ -0,0 +1,56 @@
/*
* @Author: DI JUNKUN
* @Date: 2023-11-24
* Copyright (c) 2023 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _RTP_DATA_SENDER_H_
#define _RTP_DATA_SENDER_H_
#include <functional>
#include "io_statistics.h"
#include "receiver_report.h"
#include "ringbuffer.h"
#include "rtp_packet.h"
#include "rtp_statistics.h"
#include "sender_report.h"
#include "thread_base.h"
class RtpDataSender : public ThreadBase {
public:
RtpDataSender();
RtpDataSender(std::shared_ptr<IOStatistics> io_statistics);
virtual ~RtpDataSender();
public:
void Enqueue(std::vector<std::unique_ptr<RtpPacket>> rtp_packets);
void SetSendDataFunc(std::function<int(const char *, size_t)> data_send_func);
uint32_t GetSsrc() { return ssrc_; }
void OnReceiverReport(const ReceiverReport &receiver_report) {}
private:
private:
int SendRtpPacket(std::unique_ptr<RtpPacket> rtp_packet);
int SendRtcpSR(SenderReport &rtcp_sr);
bool CheckIsTimeSendSR();
private:
bool Process() override;
private:
std::function<int(const char *, size_t)> data_send_func_ = nullptr;
RingBuffer<std::unique_ptr<RtpPacket>> rtp_packet_queue_;
private:
uint32_t ssrc_ = 0;
std::unique_ptr<RtpStatistics> rtp_statistics_ = nullptr;
std::shared_ptr<IOStatistics> io_statistics_ = nullptr;
uint32_t last_send_bytes_ = 0;
uint32_t total_rtp_payload_sent_ = 0;
uint32_t total_rtp_packets_sent_ = 0;
uint32_t last_send_rtcp_sr_packet_ts_ = 0;
};
#endif

View File

@@ -0,0 +1,721 @@
#include "rtp_video_receiver.h"
#include "api/ntp/ntp_time_util.h"
#include "common.h"
#include "fir.h"
#include "log.h"
#include "nack.h"
#include "rtcp_sender.h"
// #define SAVE_RTP_RECV_STREAM
#define NV12_BUFFER_SIZE (1280 * 720 * 3 / 2)
#define RTCP_RR_INTERVAL 1000
RtpVideoReceiver::RtpVideoReceiver(std::shared_ptr<SystemClock> clock)
: ssrc_(GenerateUniqueSsrc()),
active_remb_module_(nullptr),
receive_side_congestion_controller_(
clock_,
[this](std::vector<std::unique_ptr<RtcpPacket>> packets) {
SendCombinedRtcpPacket(std::move(packets));
},
[this](int64_t bitrate_bps, std::vector<uint32_t> ssrcs) {
SendRemb(bitrate_bps, ssrcs);
}),
rtcp_sender_(std::make_unique<RtcpSender>(
[this](const uint8_t* buffer, size_t size) -> int {
return data_send_func_((const char*)buffer, size);
},
1200)),
nack_(std::make_unique<NackRequester>(clock_, this, this)),
clock_(webrtc::Clock::GetWebrtcClockShared(clock)) {
SetPeriod(std::chrono::milliseconds(5));
rtcp_thread_ = std::thread(&RtpVideoReceiver::RtcpThread, this);
}
RtpVideoReceiver::RtpVideoReceiver(std::shared_ptr<SystemClock> clock,
std::shared_ptr<IOStatistics> io_statistics)
: io_statistics_(io_statistics),
ssrc_(GenerateUniqueSsrc()),
receive_side_congestion_controller_(
clock_,
[this](std::vector<std::unique_ptr<RtcpPacket>> packets) {
SendCombinedRtcpPacket(std::move(packets));
},
[this](int64_t bitrate_bps, std::vector<uint32_t> ssrcs) {
SendRemb(bitrate_bps, ssrcs);
}),
rtcp_sender_(std::make_unique<RtcpSender>(
[this](const uint8_t* buffer, size_t size) -> int {
return data_send_func_((const char*)buffer, size);
},
1200)),
nack_(std::make_unique<NackRequester>(clock_, this, this)),
clock_(webrtc::Clock::GetWebrtcClockShared(clock)) {
SetPeriod(std::chrono::milliseconds(5));
rtcp_thread_ = std::thread(&RtpVideoReceiver::RtcpThread, this);
#ifdef SAVE_RTP_RECV_STREAM
file_rtp_recv_ = fopen("rtp_recv_stream.h264", "w+b");
if (!file_rtp_recv_) {
LOG_WARN("Fail to open rtp_recv_stream.h264");
}
#endif
}
RtpVideoReceiver::~RtpVideoReceiver() {
rtcp_stop_.store(true);
rtcp_cv_.notify_all();
if (rtcp_thread_.joinable()) {
rtcp_thread_.join();
}
SSRCManager::Instance().DeleteSsrc(ssrc_);
if (rtp_statistics_) {
rtp_statistics_->Stop();
}
delete[] nv12_data_;
#ifdef SAVE_RTP_RECV_STREAM
if (file_rtp_recv_) {
fflush(file_rtp_recv_);
fclose(file_rtp_recv_);
file_rtp_recv_ = nullptr;
}
#endif
}
void RtpVideoReceiver::InsertRtpPacket(RtpPacket& rtp_packet, bool padding) {
if (!rtp_statistics_) {
rtp_statistics_ = std::make_unique<RtpStatistics>();
rtp_statistics_->Start();
}
webrtc::RtpPacketReceived rtp_packet_received;
rtp_packet_received.Build(rtp_packet.Buffer().data(), rtp_packet.Size());
rtp_packet_received.set_arrival_time(clock_->CurrentTime());
rtp_packet_received.set_ecn(EcnMarking::kEct0);
rtp_packet_received.set_recovered(false);
rtp_packet_received.set_payload_type_frequency(kVideoPayloadTypeFrequency);
webrtc::Timestamp now = clock_->CurrentTime();
remote_ssrc_ = rtp_packet.Ssrc();
uint16_t sequence_number = rtp_packet.SequenceNumber();
--cumulative_loss_;
if (!last_receive_time_.has_value()) {
last_extended_high_seq_num_ = sequence_number - 1;
extended_high_seq_num_ = sequence_number - 1;
}
cumulative_loss_ += sequence_number - extended_high_seq_num_;
extended_high_seq_num_ = sequence_number;
if (rtp_packet_received.Timestamp() != last_received_timestamp_) {
webrtc::TimeDelta receive_diff = now - *last_receive_time_;
uint32_t receive_diff_rtp =
(receive_diff * rtp_packet_received.payload_type_frequency())
.seconds<uint32_t>();
int32_t time_diff_samples =
receive_diff_rtp -
(rtp_packet_received.Timestamp() - last_received_timestamp_);
ReviseFrequencyAndJitter(rtp_packet_received.payload_type_frequency());
// lib_jingle sometimes deliver crazy jumps in TS for the same stream.
// If this happens, don't update jitter value. Use 5 secs video frequency
// as the threshold.
if (time_diff_samples < 5 * kVideoPayloadTypeFrequency &&
time_diff_samples > -5 * kVideoPayloadTypeFrequency) {
// Note we calculate in Q4 to avoid using float.
int32_t jitter_diff_q4 = (std::abs(time_diff_samples) << 4) - jitter_q4_;
jitter_q4_ += ((jitter_diff_q4 + 8) >> 4);
}
jitter_ = jitter_q4_ >> 4;
}
last_received_timestamp_ = rtp_packet_received.Timestamp();
last_receive_time_ = now;
#ifdef SAVE_RTP_RECV_STREAM
fwrite((unsigned char*)rtp_packet.Payload(), 1, rtp_packet.PayloadSize(),
file_rtp_recv_);
#endif
receive_side_congestion_controller_.OnReceivedPacket(rtp_packet_received,
MediaType::VIDEO);
nack_->OnReceivedPacket(rtp_packet.SequenceNumber());
last_recv_bytes_ = (uint32_t)rtp_packet.PayloadSize();
total_rtp_payload_recv_ += (uint32_t)rtp_packet.PayloadSize();
total_rtp_packets_recv_++;
if (rtp_statistics_) {
rtp_statistics_->UpdateReceiveBytes(last_recv_bytes_);
}
if (io_statistics_) {
io_statistics_->UpdateVideoInboundBytes(last_recv_bytes_);
io_statistics_->IncrementVideoInboundRtpPacketCount();
io_statistics_->UpdateVideoPacketLossCount(rtp_packet.SequenceNumber());
}
// if (CheckIsTimeSendRR()) {
// ReceiverReport rtcp_rr;
// RtcpReportBlock report;
// // auto duration = std::chrono::system_clock::now().time_since_epoch();
// // auto seconds =
// // std::chrono::duration_cast<std::chrono::seconds>(duration); uint32_t
// // seconds_u32 = static_cast<uint32_t>(
// // std::chrono::duration_cast<std::chrono::seconds>(duration).count());
// // uint32_t fraction_u32 = static_cast<uint32_t>(
// // std::chrono::duration_cast<std::chrono::nanoseconds>(duration -
// // seconds)
// // .count());
// report.source_ssrc = 0x00;
// report.fraction_lost = 0;
// report.cumulative_lost = 0;
// report.extended_high_seq_num = 0;
// report.jitter = 0;
// report.lsr = 0;
// report.dlsr = 0;
// rtcp_rr.SetReportBlock(report);
// rtcp_rr.Encode();
// // SendRtcpRR(rtcp_rr);
// }
if (padding) {
return;
}
if (rtp_packet.PayloadType() == rtp::PAYLOAD_TYPE::AV1) {
RtpPacketAv1 rtp_packet_av1;
rtp_packet_av1.Build(rtp_packet.Buffer().data(), rtp_packet.Size());
rtp_packet_av1.GetFrameHeaderInfo();
ProcessAv1RtpPacket(rtp_packet_av1);
} else {
RtpPacketH264 rtp_packet_h264;
if (rtp_packet_h264.Build(rtp_packet.Buffer().data(), rtp_packet.Size())) {
rtp_packet_h264.GetFrameHeaderInfo();
ProcessH264RtpPacket(rtp_packet_h264);
} else {
LOG_ERROR("Invalid h264 rtp packet");
}
}
}
void RtpVideoReceiver::ProcessH264RtpPacket(RtpPacketH264& rtp_packet_h264) {
if (!fec_enable_) {
if (rtp::PAYLOAD_TYPE::H264 == rtp_packet_h264.PayloadType()) {
rtp::NAL_UNIT_TYPE nalu_type = rtp_packet_h264.NalUnitType();
if (rtp::NAL_UNIT_TYPE::NALU == nalu_type) {
compelete_video_frame_queue_.push(VideoFrame(
rtp_packet_h264.Payload(), rtp_packet_h264.PayloadSize()));
} else if (rtp::NAL_UNIT_TYPE::FU_A == nalu_type) {
incomplete_h264_frame_list_[rtp_packet_h264.SequenceNumber()] =
rtp_packet_h264;
bool complete = CheckIsH264FrameCompleted(rtp_packet_h264);
if (!complete) {
}
}
}
}
// else {
// if (rtp::PAYLOAD_TYPE::H264 == rtp_packet.PayloadType()) {
// if (rtp::NAL_UNIT_TYPE::NALU == rtp_packet.NalUnitType()) {
// compelete_video_frame_queue_.push(
// VideoFrame(rtp_packet.Payload(), rtp_packet.PayloadSize()));
// } else if (rtp::NAL_UNIT_TYPE::FU_A == rtp_packet.NalUnitType()) {
// incomplete_h264_frame_list_[rtp_packet.SequenceNumber()] =
// rtp_packet; bool complete = CheckIsH264FrameCompleted(rtp_packet); if
// (!complete) {
// }
// }
// } else if (rtp::PAYLOAD_TYPE::H264_FEC_SOURCE ==
// rtp_packet.PayloadType()) {
// if (last_packet_ts_ != rtp_packet.Timestamp()) {
// fec_decoder_.Init();
// fec_decoder_.ResetParams(rtp_packet.FecSourceSymbolNum());
// last_packet_ts_ = rtp_packet.Timestamp();
// }
// incomplete_fec_packet_list_[rtp_packet.Timestamp()]
// [rtp_packet.SequenceNumber()] = rtp_packet;
// uint8_t** complete_frame = fec_decoder_.DecodeWithNewSymbol(
// (const char*)incomplete_fec_packet_list_[rtp_packet.Timestamp()]
// [rtp_packet.SequenceNumber()]
// .Payload(),
// rtp_packet.FecSymbolId());
// if (nullptr != complete_frame) {
// if (!nv12_data_) {
// nv12_data_ = new uint8_t[NV12_BUFFER_SIZE];
// }
// size_t complete_frame_size = 0;
// for (int index = 0; index < rtp_packet.FecSourceSymbolNum(); index++)
// {
// if (nullptr == complete_frame[index]) {
// LOG_ERROR("Invalid complete_frame[{}]", index);
// }
// memcpy(nv12_data_ + complete_frame_size, complete_frame[index],
// 1400); complete_frame_size += 1400;
// }
// fec_decoder_.ReleaseSourcePackets(complete_frame);
// fec_decoder_.Release();
// LOG_ERROR("Release incomplete_fec_packet_list_");
// incomplete_fec_packet_list_.erase(rtp_packet.Timestamp());
// if (incomplete_fec_frame_list_.end() !=
// incomplete_fec_frame_list_.find(rtp_packet.Timestamp())) {
// incomplete_fec_frame_list_.erase(rtp_packet.Timestamp());
// }
// compelete_video_frame_queue_.push(
// VideoFrame(nv12_data_, complete_frame_size));
// } else {
// incomplete_fec_frame_list_.insert(rtp_packet.Timestamp());
// }
// } else if (rtp::PAYLOAD_TYPE::H264_FEC_REPAIR ==
// rtp_packet.PayloadType()) {
// if (incomplete_fec_frame_list_.end() ==
// incomplete_fec_frame_list_.find(rtp_packet.Timestamp())) {
// return;
// }
// if (last_packet_ts_ != rtp_packet.Timestamp()) {
// fec_decoder_.Init();
// fec_decoder_.ResetParams(rtp_packet.FecSourceSymbolNum());
// last_packet_ts_ = rtp_packet.Timestamp();
// }
// incomplete_fec_packet_list_[rtp_packet.Timestamp()]
// [rtp_packet.SequenceNumber()] = rtp_packet;
// uint8_t** complete_frame = fec_decoder_.DecodeWithNewSymbol(
// (const char*)incomplete_fec_packet_list_[rtp_packet.Timestamp()]
// [rtp_packet.SequenceNumber()]
// .Payload(),
// rtp_packet.FecSymbolId());
// if (nullptr != complete_frame) {
// if (!nv12_data_) {
// nv12_data_ = new uint8_t[NV12_BUFFER_SIZE];
// }
// size_t complete_frame_size = 0;
// for (int index = 0; index < rtp_packet.FecSourceSymbolNum(); index++)
// {
// if (nullptr == complete_frame[index]) {
// LOG_ERROR("Invalid complete_frame[{}]", index);
// }
// memcpy(nv12_data_ + complete_frame_size, complete_frame[index],
// 1400); complete_frame_size += 1400;
// }
// fec_decoder_.ReleaseSourcePackets(complete_frame);
// fec_decoder_.Release();
// incomplete_fec_packet_list_.erase(rtp_packet.Timestamp());
// compelete_video_frame_queue_.push(
// VideoFrame(nv12_data_, complete_frame_size));
// }
// }
// }
}
void RtpVideoReceiver::ProcessAv1RtpPacket(RtpPacketAv1& rtp_packet_av1) {
// LOG_ERROR("recv payload size = {}, sequence_number_ = {}",
// rtp_packet.PayloadSize(), rtp_packet.SequenceNumber());
if (rtp::PAYLOAD_TYPE::AV1 == rtp_packet_av1.PayloadType()) {
incomplete_av1_frame_list_[rtp_packet_av1.SequenceNumber()] =
rtp_packet_av1;
bool complete = CheckIsAv1FrameCompleted(rtp_packet_av1);
if (!complete) {
}
}
// std::vector<Obu> obus =
// ParseObus((uint8_t*)rtp_packet.Payload(), rtp_packet.PayloadSize());
// for (int i = 0; i < obus.size(); i++) {
// LOG_ERROR("2 [{}|{}] Obu size = [{}], Obu type [{}]", i, obus.size(),
// obus[i].size_,
// ObuTypeToString((OBU_TYPE)ObuType(obus[i].header_)));
// }
}
bool RtpVideoReceiver::CheckIsH264FrameCompleted(
RtpPacketH264& rtp_packet_h264) {
if (rtp_packet_h264.FuAEnd()) {
uint16_t end_seq = rtp_packet_h264.SequenceNumber();
while (end_seq--) {
auto it = incomplete_h264_frame_list_.find(end_seq);
if (it == incomplete_h264_frame_list_.end()) {
// The last fragment has already received. If all fragments are in
// order, then some fragments lost in tranmission and need to be
// repaired using FEC
return false;
} else if (!it->second.FuAStart()) {
continue;
} else if (it->second.FuAStart()) {
if (!nv12_data_) {
nv12_data_ = new uint8_t[NV12_BUFFER_SIZE];
}
size_t complete_frame_size = 0;
int frame_fragment_count = 0;
uint16_t start = it->first;
uint16_t end = rtp_packet_h264.SequenceNumber();
for (uint16_t seq = start; seq <= end; seq++) {
complete_frame_size += incomplete_h264_frame_list_[seq].PayloadSize();
}
if (!nv12_data_) {
nv12_data_ = new uint8_t[NV12_BUFFER_SIZE];
} else if (complete_frame_size > NV12_BUFFER_SIZE) {
delete[] nv12_data_;
nv12_data_ = new uint8_t[complete_frame_size];
}
uint8_t* dest = nv12_data_;
for (uint16_t seq = start; seq <= end; seq++) {
size_t payload_size = incomplete_h264_frame_list_[seq].PayloadSize();
memcpy(dest, incomplete_h264_frame_list_[seq].Payload(),
payload_size);
dest += payload_size;
incomplete_h264_frame_list_.erase(seq);
frame_fragment_count++;
}
compelete_video_frame_queue_.push(
VideoFrame(nv12_data_, complete_frame_size));
return true;
} else {
LOG_WARN("What happened?");
return false;
}
}
return true;
}
return false;
}
bool RtpVideoReceiver::CheckIsAv1FrameCompleted(RtpPacketAv1& rtp_packet_av1) {
if (rtp_packet_av1.Av1FrameEnd()) {
uint16_t end_seq = rtp_packet_av1.SequenceNumber();
uint16_t start = end_seq;
while (end_seq--) {
auto it = incomplete_av1_frame_list_.find(end_seq);
if (it == incomplete_av1_frame_list_.end()) {
// The last fragment has already received. If all fragments are in
// order, then some fragments lost in tranmission and need to be
// repaired using FEC
// return false;
} else if (!it->second.Av1FrameStart()) {
continue;
} else if (it->second.Av1FrameStart()) {
start = it->second.SequenceNumber();
break;
} else {
LOG_WARN("What happened?")
return false;
}
}
if (start <= rtp_packet_av1.SequenceNumber()) {
if (!nv12_data_) {
nv12_data_ = new uint8_t[NV12_BUFFER_SIZE];
}
size_t complete_frame_size = 0;
for (; start <= rtp_packet_av1.SequenceNumber(); start++) {
const uint8_t* obu_frame = incomplete_av1_frame_list_[start].Payload();
size_t obu_frame_size = incomplete_av1_frame_list_[start].PayloadSize();
memcpy(nv12_data_ + complete_frame_size, obu_frame, obu_frame_size);
complete_frame_size += obu_frame_size;
incomplete_av1_frame_list_.erase(start);
}
compelete_video_frame_queue_.push(
VideoFrame(nv12_data_, complete_frame_size));
return true;
}
}
return false;
}
void RtpVideoReceiver::SetSendDataFunc(
std::function<int(const char*, size_t)> data_send_func) {
data_send_func_ = data_send_func;
}
int RtpVideoReceiver::SendRtcpRR(ReceiverReport& rtcp_rr) {
if (!data_send_func_) {
LOG_ERROR("data_send_func_ is nullptr");
return -1;
}
if (data_send_func_((const char*)rtcp_rr.Buffer(), rtcp_rr.Size())) {
LOG_ERROR("Send RR failed");
return -1;
}
return 0;
}
TimeDelta AtoToTimeDelta(uint16_t receive_info) {
// receive_info
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |R|ECN| Arrival time offset |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
const uint16_t ato = receive_info & 0x1FFF;
if (ato == 0x1FFE) {
return TimeDelta::PlusInfinity();
}
if (ato == 0x1FFF) {
return TimeDelta::MinusInfinity();
}
return TimeDelta::Seconds(ato) / 1024;
}
void RtpVideoReceiver::SendCombinedRtcpPacket(
std::vector<std::unique_ptr<RtcpPacket>> rtcp_packets) {
if (!data_send_func_) {
LOG_ERROR("data_send_func_ is nullptr");
}
// LOG_ERROR("Send combined rtcp packet");
for (auto& rtcp_packet : rtcp_packets) {
rtcp_packet->SetSenderSsrc(ssrc_);
rtcp_sender_->AppendPacket(*rtcp_packet);
rtcp_sender_->Send();
}
}
void RtpVideoReceiver::SendRemb(int64_t bitrate_bps,
std::vector<uint32_t> ssrcs) {
if (!active_remb_module_) {
return;
}
// The Add* and Remove* methods above ensure that REMB is disabled on all
// other modules, because otherwise, they will send REMB with stale info.
active_remb_module_->SetRemb(bitrate_bps, std::move(ssrcs));
}
bool RtpVideoReceiver::CheckIsTimeSendRR() {
uint32_t now_ts = static_cast<uint32_t>(
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count());
if (now_ts - last_send_rtcp_rr_packet_ts_ >= RTCP_RR_INTERVAL) {
last_send_rtcp_rr_packet_ts_ = now_ts;
return true;
} else {
return false;
}
}
bool RtpVideoReceiver::Process() {
if (!compelete_video_frame_queue_.isEmpty()) {
std::optional<VideoFrame> video_frame = compelete_video_frame_queue_.pop();
if (on_receive_complete_frame_ && video_frame) {
// auto now_complete_frame_ts =
// std::chrono::duration_cast<std::chrono::milliseconds>(
// std::chrono::system_clock::now().time_since_epoch())
// .count();
// uint32_t duration = now_complete_frame_ts - last_complete_frame_ts_;
// LOG_ERROR("Duration {}", duration);
// last_complete_frame_ts_ = now_complete_frame_ts;
on_receive_complete_frame_(*video_frame);
// #ifdef SAVE_RTP_RECV_STREAM
// fwrite((unsigned char*)video_frame.Buffer(), 1,
// video_frame.Size(),
// file_rtp_recv_);
// #endif
}
}
return true;
}
void RtpVideoReceiver::ReviseFrequencyAndJitter(int payload_type_frequency) {
if (payload_type_frequency == last_payload_type_frequency_) {
return;
}
if (payload_type_frequency != 0) {
if (last_payload_type_frequency_ != 0) {
// Value in "jitter_q4_" variable is a number of samples.
// I.e. jitter = timestamp (s) * frequency (Hz).
// Since the frequency has changed we have to update the number of samples
// accordingly. The new value should rely on a new frequency.
// If we don't do such procedure we end up with the number of samples that
// cannot be converted into TimeDelta correctly
// (i.e. jitter = jitter_q4_ >> 4 / payload_type_frequency).
// In such case, the number of samples has a "mix".
// Doing so we pretend that everything prior and including the current
// packet were computed on packet's frequency.
jitter_q4_ = static_cast<int>(static_cast<uint64_t>(jitter_q4_) *
payload_type_frequency /
last_payload_type_frequency_);
}
// If last_payload_type_frequency_ is not present, the jitter_q4_
// variable has its initial value.
// Keep last_payload_type_frequency_ up to date and non-zero (set).
last_payload_type_frequency_ = payload_type_frequency;
}
}
void RtpVideoReceiver::SendRR() {
uint32_t now = CompactNtp(clock_->CurrentNtpTime());
// Calculate fraction lost.
int64_t exp_since_last = extended_high_seq_num_ - last_extended_high_seq_num_;
int32_t lost_since_last = cumulative_loss_ - last_report_cumulative_loss_;
if (exp_since_last > 0 && lost_since_last > 0) {
// Scale 0 to 255, where 255 is 100% loss.
fraction_lost_ = 255 * lost_since_last / exp_since_last;
} else {
fraction_lost_ = 0;
}
cumulative_lost_ = cumulative_loss_ + cumulative_loss_rtcp_offset_;
if (cumulative_lost_ < 0) {
// Clamp to zero. Work around to accommodate for senders that misbehave with
// negative cumulative loss.
cumulative_lost_ = 0;
cumulative_loss_rtcp_offset_ = -cumulative_loss_;
}
if (cumulative_lost_ > 0x7fffff) {
// Packets lost is a 24 bit signed field, and thus should be clamped, as
// described in https://datatracker.ietf.org/doc/html/rfc3550#appendix-A.3
cumulative_lost_ = 0x7fffff;
}
uint32_t receive_time = last_arrival_ntp_timestamp;
uint32_t delay_since_last_sr = now - receive_time;
ReceiverReport rtcp_rr;
RtcpReportBlock report;
report.SetMediaSsrc(remote_ssrc_);
report.SetFractionLost(fraction_lost_);
report.SetCumulativeLost(cumulative_lost_);
report.SetExtHighestSeqNum(extended_high_seq_num_);
report.SetJitter(jitter_);
report.SetLastSr(last_remote_ntp_timestamp);
report.SetDelayLastSr(delay_since_last_sr);
rtcp_rr.SetSenderSsrc(ssrc_);
rtcp_rr.SetReportBlock(report);
rtcp_rr.Build();
SendRtcpRR(rtcp_rr);
last_extended_high_seq_num_ = extended_high_seq_num_;
last_report_cumulative_loss_ = cumulative_loss_;
}
void RtpVideoReceiver::RtcpThread() {
while (!rtcp_stop_.load()) {
std::unique_lock<std::mutex> lock(rtcp_mtx_);
if (rtcp_cv_.wait_for(
lock, std::chrono::milliseconds(rtcp_tcc_interval_ms_),
[&]() { return send_rtcp_rr_triggered_ || rtcp_stop_; })) {
if (rtcp_stop_) break;
send_rtcp_rr_triggered_ = false;
} else {
// LOG_ERROR("Send video tcc");
auto now = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
now - last_send_rtcp_rr_ts_)
.count();
if (elapsed >= rtcp_rr_interval_ms_ && last_receive_time_.has_value()) {
SendRR();
last_send_rtcp_rr_ts_ = now;
}
}
}
}
/******************************************************************************/
void RtpVideoReceiver::SendNack(const std::vector<uint16_t>& nack_list,
bool buffering_allowed) {
if (!nack_list.empty()) {
webrtc::rtcp::Nack nack;
nack.SetSenderSsrc(ssrc_);
nack.SetMediaSsrc(remote_ssrc_);
nack.SetPacketIds(std::move(nack_list));
rtcp_sender_->AppendPacket(nack);
rtcp_sender_->Send();
}
}
void RtpVideoReceiver::RequestKeyFrame() {
++sequence_number_fir_;
webrtc::rtcp::Fir fir;
fir.SetSenderSsrc(ssrc_);
fir.AddRequestTo(remote_ssrc_, sequence_number_fir_);
rtcp_sender_->AppendPacket(fir);
rtcp_sender_->Send();
}
void RtpVideoReceiver::SendLossNotification(uint16_t last_decoded_seq_num,
uint16_t last_received_seq_num,
bool decodability_flag,
bool buffering_allowed) {}
inline uint32_t DivideRoundToNearest(int64_t dividend, int64_t divisor) {
if (dividend < 0) {
int64_t half_of_divisor = divisor / 2;
int64_t quotient = dividend / divisor;
int64_t remainder = dividend % divisor;
if (-remainder > half_of_divisor) {
--quotient;
}
return quotient;
}
int64_t half_of_divisor = (divisor - 1) / 2;
int64_t quotient = dividend / divisor;
int64_t remainder = dividend % divisor;
if (remainder > half_of_divisor) {
++quotient;
}
return quotient;
}
void RtpVideoReceiver::OnSenderReport(const SenderReport& sender_report) {
remote_ssrc = sender_report.SenderSsrc();
last_remote_ntp_timestamp = sender_report.NtpTimestamp();
last_remote_rtp_timestamp = sender_report.Timestamp();
last_arrival_timestamp = clock_->CurrentTime().ms();
last_arrival_ntp_timestamp = webrtc::CompactNtp(clock_->CurrentNtpTime());
packets_sent = sender_report.SenderPacketCount();
bytes_sent = sender_report.SenderOctetCount();
reports_count++;
}

View File

@@ -0,0 +1,165 @@
#ifndef _RTP_VIDEO_RECEIVER_H_
#define _RTP_VIDEO_RECEIVER_H_
#include <functional>
#include <map>
#include <queue>
#include <set>
#include "api/clock/clock.h"
#include "clock/system_clock.h"
#include "fec_decoder.h"
#include "io_statistics.h"
#include "nack_requester.h"
#include "receive_side_congestion_controller.h"
#include "receiver_report.h"
#include "ringbuffer.h"
#include "rtcp_sender.h"
#include "rtp_packet_av1.h"
#include "rtp_packet_h264.h"
#include "rtp_rtcp_defines.h"
#include "rtp_statistics.h"
#include "sender_report.h"
#include "thread_base.h"
#include "video_frame.h"
using namespace webrtc;
class RtpVideoReceiver : public ThreadBase,
public LossNotificationSender,
public KeyFrameRequestSender,
public NackSender {
public:
RtpVideoReceiver(std::shared_ptr<SystemClock> clock);
RtpVideoReceiver(std::shared_ptr<SystemClock> clock,
std::shared_ptr<IOStatistics> io_statistics);
virtual ~RtpVideoReceiver();
public:
void InsertRtpPacket(RtpPacket& rtp_packet, bool padding);
void SetSendDataFunc(std::function<int(const char*, size_t)> data_send_func);
void SetOnReceiveCompleteFrame(
std::function<void(VideoFrame&)> on_receive_complete_frame) {
on_receive_complete_frame_ = on_receive_complete_frame;
}
uint32_t GetSsrc() { return ssrc_; }
uint32_t GetRemoteSsrc() { return remote_ssrc_; }
void OnSenderReport(const SenderReport& sender_report);
private:
void ProcessAv1RtpPacket(RtpPacketAv1& rtp_packet_av1);
bool CheckIsAv1FrameCompleted(RtpPacketAv1& rtp_packet_av1);
private:
void ProcessH264RtpPacket(RtpPacketH264& rtp_packet_h264);
bool CheckIsH264FrameCompleted(RtpPacketH264& rtp_packet_h264);
private:
bool CheckIsTimeSendRR();
int SendRtcpRR(ReceiverReport& rtcp_rr);
void SendCombinedRtcpPacket(
std::vector<std::unique_ptr<RtcpPacket>> rtcp_packets);
void SendRemb(int64_t bitrate_bps, std::vector<uint32_t> ssrcs);
private:
bool Process() override;
void RtcpThread();
private:
void SendNack(const std::vector<uint16_t>& nack_list,
bool buffering_allowed) override;
void SendRR();
void RequestKeyFrame();
void SendLossNotification(uint16_t last_decoded_seq_num,
uint16_t last_received_seq_num,
bool decodability_flag, bool buffering_allowed);
void ReviseFrequencyAndJitter(int payload_type_frequency);
private:
std::map<uint16_t, RtpPacketH264> incomplete_h264_frame_list_;
std::map<uint16_t, RtpPacketAv1> incomplete_av1_frame_list_;
std::map<uint16_t, RtpPacket> incomplete_frame_list_;
uint8_t* nv12_data_ = nullptr;
std::function<void(VideoFrame&)> on_receive_complete_frame_ = nullptr;
uint32_t last_complete_frame_ts_ = 0;
RingBuffer<VideoFrame> compelete_video_frame_queue_;
private:
std::unique_ptr<RtpStatistics> rtp_statistics_ = nullptr;
std::shared_ptr<IOStatistics> io_statistics_ = nullptr;
uint32_t last_recv_bytes_ = 0;
uint32_t total_rtp_packets_recv_ = 0;
uint32_t total_rtp_payload_recv_ = 0;
uint32_t last_send_rtcp_rr_packet_ts_ = 0;
std::function<int(const char*, size_t)> data_send_func_ = nullptr;
private:
bool fec_enable_ = false;
FecDecoder fec_decoder_;
uint64_t last_packet_ts_ = 0;
// std::map<uint16_t, RtpPacket> incomplete_fec_frame_list_;
// std::map<uint32_t, std::map<uint16_t, RtpPacket>> fec_source_symbol_list_;
// std::map<uint32_t, std::map<uint16_t, RtpPacket>> fec_repair_symbol_list_;
std::set<uint64_t> incomplete_fec_frame_list_;
std::map<uint64_t, std::map<uint16_t, RtpPacket>> incomplete_fec_packet_list_;
private:
std::thread rtcp_thread_;
std::mutex rtcp_mtx_;
std::condition_variable rtcp_cv_;
std::chrono::steady_clock::time_point last_send_rtcp_rr_ts_;
std::atomic<bool> send_rtcp_rr_triggered_ = false;
std::atomic<bool> rtcp_stop_ = false;
int rtcp_rr_interval_ms_ = 5000;
int rtcp_tcc_interval_ms_ = 200;
private:
uint32_t ssrc_ = 0;
uint32_t remote_ssrc_ = 0;
std::shared_ptr<webrtc::Clock> clock_;
ReceiveSideCongestionController receive_side_congestion_controller_;
RtcpFeedbackSenderInterface* active_remb_module_;
std::unique_ptr<RtcpSender> rtcp_sender_;
std::unique_ptr<NackRequester> nack_;
uint8_t fraction_lost_ = 0;
int32_t cumulative_lost_ = 0;
uint32_t jitter_ = 0;
uint16_t extended_high_seq_num_ = 0;
uint32_t last_sr_ = 0;
int32_t cumulative_loss_ = 0;
int32_t last_report_cumulative_loss_ = 0;
int32_t cumulative_loss_rtcp_offset_ = 0;
std::optional<Timestamp> last_receive_time_;
int last_payload_type_frequency_ = 0;
uint16_t last_extended_high_seq_num_ = 0;
uint32_t jitter_q4_ = 0;
uint32_t last_received_timestamp_ = 0;
uint32_t remote_ssrc = 0;
uint32_t last_remote_ntp_timestamp = 0;
uint32_t last_remote_rtp_timestamp = 0;
uint32_t last_arrival_timestamp = 0;
uint32_t last_arrival_ntp_timestamp = 0;
uint32_t packets_sent = 0;
uint32_t bytes_sent = 0;
uint32_t reports_count = 0;
uint8_t sequence_number_fir_ = 0;
private:
FILE* file_rtp_recv_ = nullptr;
};
#endif

View File

@@ -0,0 +1,202 @@
#include "rtp_video_sender.h"
#include <chrono>
#include "api/clock/clock.h"
#include "common.h"
#include "log.h"
// #define SAVE_RTP_SENT_STREAM
#define RTCP_SR_INTERVAL 1000
RtpVideoSender::RtpVideoSender() {}
RtpVideoSender::RtpVideoSender(std::shared_ptr<SystemClock> clock,
std::shared_ptr<IOStatistics> io_statistics)
: ssrc_(GenerateUniqueSsrc()),
io_statistics_(io_statistics),
rtp_packet_history_(std::make_unique<RtpPacketHistory>(clock_)),
clock_(webrtc::Clock::GetWebrtcClockShared(clock)) {
SetPeriod(std::chrono::milliseconds(5));
#ifdef SAVE_RTP_SENT_STREAM
file_rtp_sent_ = fopen("rtp_sent_stream.h264", "w+b");
if (!file_rtp_sent_) {
LOG_WARN("Fail to open rtp_sent_stream.h264");
}
#endif
}
RtpVideoSender::~RtpVideoSender() {
if (rtp_statistics_) {
rtp_statistics_->Stop();
}
SSRCManager::Instance().DeleteSsrc(ssrc_);
#ifdef SAVE_RTP_SENT_STREAM
if (file_rtp_sent_) {
fflush(file_rtp_sent_);
fclose(file_rtp_sent_);
file_rtp_sent_ = nullptr;
}
#endif
}
void RtpVideoSender::Enqueue(
std::vector<std::unique_ptr<RtpPacket>>& rtp_packets,
int64_t capture_timestamp_ms) {
if (!rtp_statistics_) {
rtp_statistics_ = std::make_unique<RtpStatistics>();
rtp_statistics_->Start();
}
std::vector<std::unique_ptr<webrtc::RtpPacketToSend>> to_send_rtp_packets;
for (auto& rtp_packet : rtp_packets) {
std::unique_ptr<webrtc::RtpPacketToSend> rtp_packet_to_send(
static_cast<webrtc::RtpPacketToSend*>(rtp_packet.release()));
rtp_packet_to_send->set_capture_time(
webrtc::Timestamp::Millis(capture_timestamp_ms));
rtp_packet_to_send->set_transport_sequence_number(transport_seq_++);
rtp_packet_to_send->set_packet_type(webrtc::RtpPacketMediaType::kVideo);
// rtp_packet_queue_.push(std::move(rtp_packet_to_send));
to_send_rtp_packets.push_back(std::move(rtp_packet_to_send));
}
enqueue_packets_func_(std::move(to_send_rtp_packets));
}
void RtpVideoSender::SetSendDataFunc(
std::function<int(const char*, size_t)> data_send_func) {
data_send_func_ = data_send_func;
}
void RtpVideoSender::SetOnSentPacketFunc(
std::function<void(const webrtc::RtpPacketToSend&)> on_sent_packet_func) {
on_sent_packet_func_ = on_sent_packet_func;
}
void RtpVideoSender::SetEnqueuePacketsFunc(
std::function<void(std::vector<std::unique_ptr<webrtc::RtpPacketToSend>>&)>
enqueue_packets_func) {
enqueue_packets_func_ = enqueue_packets_func;
}
int RtpVideoSender::SendRtpPacket(
std::unique_ptr<webrtc::RtpPacketToSend> rtp_packet_to_send) {
if (!data_send_func_) {
LOG_ERROR("data_send_func_ is nullptr");
return -1;
}
last_rtp_timestamp_ = rtp_packet_to_send->capture_time().ms();
int ret = data_send_func_((const char*)rtp_packet_to_send->Buffer().data(),
rtp_packet_to_send->Size());
if (-2 == ret) {
rtp_packet_queue_.clear();
return -1;
}
#ifdef SAVE_RTP_SENT_STREAM
fwrite((unsigned char*)rtp_packet_to_send->Payload(), 1,
x rtp_packet_to_send->PayloadSize(), file_rtp_sent_);
#endif
last_send_bytes_ += (uint32_t)rtp_packet_to_send->Size();
total_rtp_payload_sent_ += (uint32_t)rtp_packet_to_send->PayloadSize();
total_rtp_packets_sent_++;
if (io_statistics_) {
io_statistics_->UpdateVideoOutboundBytes(last_send_bytes_);
io_statistics_->IncrementVideoOutboundRtpPacketCount();
}
if (CheckIsTimeSendSR()) {
SenderReport rtcp_sr;
rtcp_sr.SetSenderSsrc(ssrc_);
uint32_t rtp_timestamp =
last_rtp_timestamp_ +
((clock_->CurrentTime().us() + 500) / 1000 - last_frame_capture_time_) *
rtp::kVideoPayloadTypeFrequency;
rtcp_sr.SetTimestamp(rtp_timestamp);
rtcp_sr.SetNtpTimestamp((uint64_t)clock_->CurrentNtpTime());
rtcp_sr.SetSenderPacketCount(total_rtp_packets_sent_);
rtcp_sr.SetSenderOctetCount(total_rtp_payload_sent_);
rtcp_sr.Build();
SendRtcpSR(rtcp_sr);
}
if (on_sent_packet_func_) {
on_sent_packet_func_(*rtp_packet_to_send);
rtp_packet_history_->AddPacket(std::move(rtp_packet_to_send),
clock_->CurrentTime());
}
return 0;
}
int RtpVideoSender::SendRtcpSR(SenderReport& rtcp_sr) {
if (!data_send_func_) {
LOG_ERROR("data_send_func_ is nullptr");
return -1;
}
int ret = data_send_func_((const char*)rtcp_sr.Buffer(), rtcp_sr.Size());
if (ret != 0) {
LOG_ERROR("Send rtcp sr failed");
return -1;
}
// LOG_ERROR("Send SR");
return 0;
}
bool RtpVideoSender::CheckIsTimeSendSR() {
uint32_t now_ts = static_cast<uint32_t>(
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count());
if (now_ts - last_send_rtcp_sr_packet_ts_ >= RTCP_SR_INTERVAL) {
last_send_rtcp_sr_packet_ts_ = now_ts;
return true;
} else {
return false;
}
}
bool RtpVideoSender::Process() {
bool pop_success = false;
last_send_bytes_ = 0;
for (size_t i = 0; i < 10; i++)
if (!rtp_packet_queue_.isEmpty()) {
std::optional<std::unique_ptr<webrtc::RtpPacketToSend>>
rtp_packet_to_send = rtp_packet_queue_.pop();
if (rtp_packet_to_send) {
SendRtpPacket(std::move(*rtp_packet_to_send));
}
}
if (rtp_statistics_) {
rtp_statistics_->UpdateSentBytes(last_send_bytes_);
}
return true;
}
void RtpVideoSender::OnReceiverReport(const ReceiverReport& receiver_report) {
std::vector<RtcpReportBlock> reports = receiver_report.GetReportBlocks();
for (auto r : reports) {
LOG_WARN(
"r_ssrc [{}], f_lost [{}], c_lost [{}], h_seq [{}], jitter [{}], "
"lsr [{}], dlsr [{}] ",
r.SourceSsrc(), r.FractionLost() / 255.0, r.CumulativeLost(),
r.ExtendedHighSeqNum(), r.Jitter(), r.LastSr(), r.DelaySinceLastSr());
}
}

View File

@@ -0,0 +1,81 @@
#ifndef _RTP_VIDEO_SENDER_H_
#define _RTP_VIDEO_SENDER_H_
#include <functional>
#include "api/clock/clock.h"
#include "clock/system_clock.h"
#include "io_statistics.h"
#include "receiver_report.h"
#include "ringbuffer.h"
#include "rtp_packet.h"
#include "rtp_packet_history.h"
#include "rtp_packet_to_send.h"
#include "rtp_statistics.h"
#include "sender_report.h"
#include "thread_base.h"
class RtpVideoSender : public ThreadBase {
public:
RtpVideoSender();
RtpVideoSender(std::shared_ptr<SystemClock> clock,
std::shared_ptr<IOStatistics> io_statistics);
virtual ~RtpVideoSender();
public:
void Enqueue(std::vector<std::unique_ptr<RtpPacket>> &rtp_packets,
int64_t capture_timestamp_ms);
void SetSendDataFunc(std::function<int(const char *, size_t)> data_send_func);
void SetOnSentPacketFunc(
std::function<void(const webrtc::RtpPacketToSend &)> on_sent_packet_func);
void SetEnqueuePacketsFunc(
std::function<
void(std::vector<std::unique_ptr<webrtc::RtpPacketToSend>> &)>
enqueue_packets_func);
uint32_t GetSsrc() { return ssrc_; }
void OnReceiverReport(const ReceiverReport &receiver_report);
int64_t GetTransportSequenceNumber() { return transport_seq_; }
void IncrementTransportSequenceNumber() { transport_seq_++; }
private:
int SendRtpPacket(
std::unique_ptr<webrtc::RtpPacketToSend> rtp_packet_to_send);
int SendRtcpSR(SenderReport &rtcp_sr);
bool CheckIsTimeSendSR();
private:
bool Process() override;
private:
std::function<int(const char *, size_t)> data_send_func_ = nullptr;
std::function<void(const webrtc::RtpPacketToSend &)> on_sent_packet_func_ =
nullptr;
std::function<void(std::vector<std::unique_ptr<webrtc::RtpPacketToSend>> &)>
enqueue_packets_func_ = nullptr;
RingBuffer<std::unique_ptr<webrtc::RtpPacketToSend>> rtp_packet_queue_;
private:
uint32_t ssrc_ = 0;
std::shared_ptr<webrtc::Clock> clock_ = nullptr;
std::unique_ptr<RtpStatistics> rtp_statistics_ = nullptr;
std::shared_ptr<IOStatistics> io_statistics_ = nullptr;
std::unique_ptr<RtpPacketHistory> rtp_packet_history_ = nullptr;
uint32_t last_send_bytes_ = 0;
uint32_t last_send_rtcp_sr_packet_ts_ = 0;
uint32_t total_rtp_payload_sent_ = 0;
uint32_t total_rtp_packets_sent_ = 0;
uint32_t last_rtp_timestamp_ = 0;
int64_t last_frame_capture_time_ = 0;
private:
int64_t transport_seq_ = 0;
private:
FILE *file_rtp_sent_ = nullptr;
};
#endif

View File

@@ -0,0 +1,66 @@
#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_NULLPTR == ice_state || ICE_STATE_DESTROYED == ice_state) {
LOG_ERROR("Ice is not connected, state = [{}]", (int)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,
bool padding) {
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, padding);
}
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, bool padding);
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,84 @@
#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_DESTROYED == 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::SetEnqueuePacketsFunc(
std::function<void(std::vector<std::unique_ptr<webrtc::RtpPacketToSend>>&)>
enqueue_packets_func) {
rtp_video_sender_->SetEnqueuePacketsFunc(enqueue_packets_func);
}
std::vector<std::unique_ptr<RtpPacket>> VideoChannelSend::GeneratePadding(
uint32_t payload_size, int64_t capture_timestamp_ms) {
if (rtp_packetizer_) {
return rtp_packetizer_->BuildPadding(payload_size, capture_timestamp_ms,
true);
}
return std::vector<std::unique_ptr<RtpPacket>>{};
}
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::unique_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(std::move(rtp_packets),
encoded_frame->CaptureTimestamp());
}
return 0;
}

View File

@@ -0,0 +1,86 @@
/*
* @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();
void SetEnqueuePacketsFunc(
std::function<
void(std::vector<std::unique_ptr<webrtc::RtpPacketToSend>>&)>
enqueue_packets_func);
std::vector<std::unique_ptr<RtpPacket>> GeneratePadding(
uint32_t payload_size, int64_t capture_timestamp_ms);
int64_t GetTransportSeqAndIncrement() {
int64_t transport_seq = rtp_video_sender_->GetTransportSequenceNumber();
rtp_video_sender_->IncrementTransportSequenceNumber();
return transport_seq;
}
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

View File

@@ -194,7 +194,7 @@ void IceTransport::OnReceiveBuffer(NiceAgent *agent, guint stream_id,
if (!is_closed_) {
if (CheckIsRtpPacket(buffer, size)) {
if (CheckIsVideoPacket(buffer, size) && ice_transport_controller_) {
ice_transport_controller_->OnReceiveVideoRtpPacket(buffer, size);
ice_transport_controller_->OnReceiveVideoRtpPacket(buffer, size, false);
} else if (CheckIsAudioPacket(buffer, size) &&
ice_transport_controller_) {
ice_transport_controller_->OnReceiveAudioRtpPacket(buffer, size);
@@ -206,7 +206,7 @@ void IceTransport::OnReceiveBuffer(NiceAgent *agent, guint stream_id,
RtcpPacketInfo rtcp_packet_info;
ParseRtcpPacket((const uint8_t *)buffer, size, &rtcp_packet_info);
} else if (CheckIsRtpPaddingPacket(buffer, size)) {
// LOG_WARN("Rtp padding packet");
ice_transport_controller_->OnReceiveVideoRtpPacket(buffer, size, true);
} else {
LOG_ERROR("Unknown packet");
}

View File

@@ -53,7 +53,7 @@ void IceTransportController::Create(
CreateAudioCodec();
controller_ = std::make_unique<CongestionControl>();
packet_sender_ = std::make_unique<PacketSender>(ice_agent, webrtc_clock_);
packet_sender_ = std::make_unique<PacketSenderImp>(ice_agent, webrtc_clock_);
packet_sender_->SetPacingRates(DataRate::BitsPerSec(300000),
DataRate::Zero());
packet_sender_->SetOnSentPacketFunc(
@@ -239,9 +239,9 @@ void IceTransportController::UpdateNetworkAvaliablity(bool network_available) {
}
int IceTransportController::OnReceiveVideoRtpPacket(const char* data,
size_t size) {
size_t size, bool padding) {
if (video_channel_receive_) {
return video_channel_receive_->OnReceiveRtpPacket(data, size);
return video_channel_receive_->OnReceiveRtpPacket(data, size, padding);
}
return -1;

View File

@@ -21,7 +21,7 @@
#include "data_channel_receive.h"
#include "data_channel_send.h"
#include "ice_agent.h"
#include "packet_sender.h"
#include "packet_sender_imp.h"
#include "resolution_adapter.h"
#include "transport_feedback_adapter.h"
#include "video_channel_receive.h"
@@ -60,7 +60,7 @@ class IceTransportController
void UpdateNetworkAvaliablity(bool network_available);
int OnReceiveVideoRtpPacket(const char *data, size_t size);
int OnReceiveVideoRtpPacket(const char *data, size_t size, bool padding);
int OnReceiveAudioRtpPacket(const char *data, size_t size);
int OnReceiveDataRtpPacket(const char *data, size_t size);
@@ -107,7 +107,7 @@ class IceTransportController
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<PacketSender> packet_sender_ = nullptr;
std::unique_ptr<PacketSenderImp> packet_sender_ = nullptr;
std::string remote_user_id_;
void *user_data_ = nullptr;

View File

@@ -0,0 +1,25 @@
/*
* @Author: DI JUNKUN
* @Date: 2025-03-17
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _PACKET_SENDER_H_
#define _PACKET_SENDER_H_
#include <memory>
#include <vector>
#include "rtp_packet.h"
class PacketSender {
public:
PacketSender() {}
virtual ~PacketSender() {}
virtual int Send() = 0;
virtual int InsertRtpPacket(
std::vector<std::unique_ptr<RtpPacket>> &rtp_packets) = 0;
};
#endif

View File

@@ -1,12 +1,12 @@
#include "packet_sender.h"
#include "packet_sender_imp.h"
#include "log.h"
const int PacketSender::kNoPacketHoldback = -1;
const int PacketSenderImp::kNoPacketHoldback = -1;
PacketSender::PacketSender(std::shared_ptr<IceAgent> ice_agent,
std::shared_ptr<webrtc::Clock> clock)
PacketSenderImp::PacketSenderImp(std::shared_ptr<IceAgent> ice_agent,
std::shared_ptr<webrtc::Clock> clock)
: ice_agent_(ice_agent),
clock_(clock),
pacing_controller_(clock.get(), this),
@@ -18,10 +18,10 @@ PacketSender::PacketSender(std::shared_ptr<IceAgent> ice_agent,
packet_size_(/*alpha=*/0.95),
include_overhead_(false) {}
PacketSender::~PacketSender() {}
PacketSenderImp::~PacketSenderImp() {}
std::vector<std::unique_ptr<webrtc::RtpPacketToSend>>
PacketSender::GeneratePadding(webrtc::DataSize size) {
PacketSenderImp::GeneratePadding(webrtc::DataSize size) {
std::vector<std::unique_ptr<webrtc::RtpPacketToSend>> to_send_rtp_packets;
std::vector<std::unique_ptr<RtpPacket>> rtp_packets =
generat_padding_func_(size.bytes(), clock_->CurrentTime().ms());
@@ -39,97 +39,105 @@ PacketSender::GeneratePadding(webrtc::DataSize size) {
return to_send_rtp_packets;
}
void PacketSender::SetSendBurstInterval(webrtc::TimeDelta burst_interval) {
void PacketSenderImp::SetSendBurstInterval(webrtc::TimeDelta burst_interval) {
pacing_controller_.SetSendBurstInterval(burst_interval);
}
void PacketSender::SetAllowProbeWithoutMediaPacket(bool allow) {
void PacketSenderImp::SetAllowProbeWithoutMediaPacket(bool allow) {
pacing_controller_.SetAllowProbeWithoutMediaPacket(allow);
}
void PacketSender::EnsureStarted() {
void PacketSenderImp::EnsureStarted() {
is_started_ = true;
MaybeProcessPackets(webrtc::Timestamp::MinusInfinity());
}
void PacketSender::Pause() { pacing_controller_.Pause(); }
void PacketSenderImp::CreateProbeClusters(
std::vector<webrtc::ProbeClusterConfig> probe_cluster_configs) {
pacing_controller_.CreateProbeClusters(probe_cluster_configs);
MaybeScheduleProcessPackets();
}
void PacketSender::Resume() {
void PacketSenderImp::Pause() { pacing_controller_.Pause(); }
void PacketSenderImp::Resume() {
pacing_controller_.Resume();
MaybeProcessPackets(webrtc::Timestamp::MinusInfinity());
}
void PacketSender::SetCongested(bool congested) {
void PacketSenderImp::SetCongested(bool congested) {
pacing_controller_.SetCongested(congested);
MaybeScheduleProcessPackets();
}
void PacketSender::SetPacingRates(webrtc::DataRate pacing_rate,
webrtc::DataRate padding_rate) {
void PacketSenderImp::SetPacingRates(webrtc::DataRate pacing_rate,
webrtc::DataRate padding_rate) {
pacing_controller_.SetPacingRates(pacing_rate, padding_rate);
MaybeScheduleProcessPackets();
}
void PacketSender::EnqueuePackets(
void PacketSenderImp::EnqueuePackets(
std::vector<std::unique_ptr<webrtc::RtpPacketToSend>> packets) {
webrtc::PacedPacketInfo cluster_info;
for (auto &packet : packets) {
SendPacket(std::move(packet), cluster_info);
}
// task_queue_.PostTask([this, packets = std::move(packets)]() mutable {
// for (auto &packet : packets) {
// size_t packet_size = packet->payload_size() + packet->padding_size();
// if (include_overhead_) {
// packet_size += packet->headers_size();
// }
// packet_size_.Apply(1, packet_size);
// pacing_controller_.EnqueuePacket(std::move(packet));
// }
// MaybeProcessPackets(webrtc::Timestamp::MinusInfinity());
// });
task_queue_.PostTask([this, packets = std::move(packets)]() mutable {
for (auto &packet : packets) {
size_t packet_size = packet->payload_size() + packet->padding_size();
if (include_overhead_) {
packet_size += packet->headers_size();
}
packet_size_.Apply(1, packet_size);
pacing_controller_.EnqueuePacket(std::move(packet));
}
MaybeProcessPackets(webrtc::Timestamp::MinusInfinity());
});
// webrtc::PacedPacketInfo cluster_info;
// for (auto &packet : packets) {
// SendPacket(std::move(packet), cluster_info);
// }
}
void PacketSender::RemovePacketsForSsrc(uint32_t ssrc) {
void PacketSenderImp::RemovePacketsForSsrc(uint32_t ssrc) {
task_queue_.PostTask([this, ssrc] {
pacing_controller_.RemovePacketsForSsrc(ssrc);
MaybeProcessPackets(webrtc::Timestamp::MinusInfinity());
});
}
void PacketSender::SetAccountForAudioPackets(bool account_for_audio) {
void PacketSenderImp::SetAccountForAudioPackets(bool account_for_audio) {
pacing_controller_.SetAccountForAudioPackets(account_for_audio);
MaybeProcessPackets(webrtc::Timestamp::MinusInfinity());
}
void PacketSender::SetIncludeOverhead() {
void PacketSenderImp::SetIncludeOverhead() {
include_overhead_ = true;
pacing_controller_.SetIncludeOverhead();
MaybeProcessPackets(webrtc::Timestamp::MinusInfinity());
}
void PacketSender::SetTransportOverhead(webrtc::DataSize overhead_per_packet) {
void PacketSenderImp::SetTransportOverhead(
webrtc::DataSize overhead_per_packet) {
pacing_controller_.SetTransportOverhead(overhead_per_packet);
MaybeProcessPackets(webrtc::Timestamp::MinusInfinity());
}
void PacketSender::SetQueueTimeLimit(webrtc::TimeDelta limit) {
void PacketSenderImp::SetQueueTimeLimit(webrtc::TimeDelta limit) {
pacing_controller_.SetQueueTimeLimit(limit);
MaybeProcessPackets(webrtc::Timestamp::MinusInfinity());
}
webrtc::TimeDelta PacketSender::ExpectedQueueTime() const {
webrtc::TimeDelta PacketSenderImp::ExpectedQueueTime() const {
return GetStats().expected_queue_time;
}
webrtc::DataSize PacketSender::QueueSizeData() const {
webrtc::DataSize PacketSenderImp::QueueSizeData() const {
return GetStats().queue_size;
}
std::optional<webrtc::Timestamp> PacketSender::FirstSentPacketTime() const {
std::optional<webrtc::Timestamp> PacketSenderImp::FirstSentPacketTime() const {
return GetStats().first_sent_packet_time;
}
webrtc::TimeDelta PacketSender::OldestPacketWaitTime() const {
webrtc::TimeDelta PacketSenderImp::OldestPacketWaitTime() const {
webrtc::Timestamp oldest_packet = GetStats().oldest_packet_enqueue_time;
if (oldest_packet.IsInfinite()) {
return webrtc::TimeDelta::Zero();
@@ -144,17 +152,11 @@ webrtc::TimeDelta PacketSender::OldestPacketWaitTime() const {
return current - oldest_packet;
}
void PacketSender::CreateProbeClusters(
std::vector<webrtc::ProbeClusterConfig> probe_cluster_configs) {
pacing_controller_.CreateProbeClusters(probe_cluster_configs);
MaybeScheduleProcessPackets();
}
void PacketSender::OnStatsUpdated(const Stats &stats) {
void PacketSenderImp::OnStatsUpdated(const Stats &stats) {
current_stats_ = stats;
}
void PacketSender::MaybeScheduleProcessPackets() {
void PacketSenderImp::MaybeScheduleProcessPackets() {
LOG_ERROR("x1");
if (!processing_packets_) {
LOG_ERROR("x2");
@@ -162,7 +164,7 @@ void PacketSender::MaybeScheduleProcessPackets() {
}
}
void PacketSender::MaybeProcessPackets(
void PacketSenderImp::MaybeProcessPackets(
webrtc::Timestamp scheduled_process_time) {
if (is_shutdown_ || !is_started_) {
LOG_ERROR("shutdown {}, started {}", is_shutdown_, is_started_);
@@ -171,9 +173,8 @@ void PacketSender::MaybeProcessPackets(
// Protects against re-entry from transport feedback calling into the task
// queue pacer.
processing_packets_ = true;
// auto cleanup = std::unique_ptr<void, std::function<void(void *)>>(
// nullptr, [this](void *) { processing_packets_ = false; });
auto cleanup = std::unique_ptr<void, std::function<void(void *)>>(
nullptr, [this](void *) { processing_packets_ = false; });
webrtc::Timestamp next_send_time = pacing_controller_.NextSendTime();
const webrtc::Timestamp now = clock_->CurrentTime();
@@ -230,20 +231,14 @@ void PacketSender::MaybeProcessPackets(
if (next_process_time_.IsMinusInfinity() ||
next_process_time_ > next_send_time) {
// Prefer low precision if allowed and not probing.
// task_queue_->PostDelayedHighPrecisionTask(
// SafeTask(
// safety_.flag(),
// [this, next_send_time]() { MaybeProcessPackets(next_send_time);
// }),
MaybeProcessPackets(next_send_time);
time_to_next_process.RoundUpTo(webrtc::TimeDelta::Millis(1));
task_queue_.PostDelayedTask(
[this, next_send_time]() { MaybeProcessPackets(next_send_time); },
time_to_next_process.RoundUpTo(webrtc::TimeDelta::Millis(1)).ms());
next_process_time_ = next_send_time;
}
processing_packets_ = false;
}
void PacketSender::UpdateStats() {
void PacketSenderImp::UpdateStats() {
Stats new_stats;
new_stats.expected_queue_time = pacing_controller_.ExpectedQueueTime();
new_stats.first_sent_packet_time = pacing_controller_.FirstSentPacketTime();
@@ -253,4 +248,6 @@ void PacketSender::UpdateStats() {
OnStatsUpdated(new_stats);
}
PacketSender::Stats PacketSender::GetStats() const { return current_stats_; }
PacketSenderImp::Stats PacketSenderImp::GetStats() const {
return current_stats_;
}

View File

@@ -4,8 +4,8 @@
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _PACKET_SENDER_H_
#define _PACKET_SENDER_H_
#ifndef _PACKET_SENDER_IMP_H_
#define _PACKET_SENDER_IMP_H_
#include <memory>
@@ -18,19 +18,28 @@
#include "ice_agent.h"
#include "log.h"
#include "pacing_controller.h"
#include "packet_sender.h"
#include "rtc_base/numerics/exp_filter.h"
#include "rtp_packet_pacer.h"
#include "rtp_packet_to_send.h"
#include "task_queue.h"
class PacketSender : public webrtc::RtpPacketPacer,
public webrtc::PacingController::PacketSender {
class PacketSenderImp : public PacketSender,
public webrtc::RtpPacketPacer,
public webrtc::PacingController::PacketSender {
public:
static const int kNoPacketHoldback;
PacketSender(std::shared_ptr<IceAgent> ice_agent,
std::shared_ptr<webrtc::Clock> clock);
~PacketSender();
PacketSenderImp(std::shared_ptr<IceAgent> ice_agent,
std::shared_ptr<webrtc::Clock> clock);
~PacketSenderImp();
public:
int Send() { return 0; }
int InsertRtpPacket(std::vector<std::unique_ptr<RtpPacket>>& rtp_packets) {
return 0;
}
void SetOnSentPacketFunc(
std::function<void(const webrtc::RtpPacketToSend&)> on_sent_packet_func) {
@@ -58,7 +67,7 @@ class PacketSender : public webrtc::RtpPacketPacer,
std::vector<std::unique_ptr<webrtc::RtpPacketToSend>> GeneratePadding(
webrtc::DataSize size) override;
// TODO(bugs.webrtc.org/1439830): Make pure once subclasses adapt.
// TODO(bugs.webrtc.org/1439830): Make pure once subclasses adapt.
void OnBatchComplete() override {}
// TODO(bugs.webrtc.org/11340): Make pure once downstream projects
@@ -83,7 +92,7 @@ class PacketSender : public webrtc::RtpPacketPacer,
// Methods implementing RtpPacketSender.
// Adds the packet to the queue and calls
// PacingController::PacketSender::SendPacket() when it's time to send.
// PacingController::PacketSenderImp::SendPacket() when it's time to send.
void EnqueuePackets(
std::vector<std::unique_ptr<webrtc::RtpPacketToSend>> packets);
// Remove any pending packets matching this SSRC from the packet queue.