[fix] move codecs from pc into transmission module

This commit is contained in:
dijunkun
2024-11-26 15:06:05 +08:00
parent 98c6501846
commit 09c0ab9235
7 changed files with 323 additions and 359 deletions

View File

@@ -115,11 +115,12 @@ DLLAPI int JoinConnection(PeerPtr* peer_ptr, const char* transmission_id,
DLLAPI int LeaveConnection(PeerPtr* peer_ptr, const char* transmission_id); DLLAPI int LeaveConnection(PeerPtr* peer_ptr, const char* transmission_id);
DLLAPI int SendData(PeerPtr* peer_ptr, DATA_TYPE data_type, const char* data,
size_t size);
DLLAPI int SendVideoFrame(PeerPtr* peer_ptr, const XVideoFrame* video_frame); DLLAPI int SendVideoFrame(PeerPtr* peer_ptr, const XVideoFrame* video_frame);
DLLAPI int SendAudioFrame(PeerPtr* peer_ptr, const char* data, size_t size);
DLLAPI int SendData(PeerPtr* peer_ptr, const char* data, size_t size);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -7,11 +7,6 @@
#include "log.h" #include "log.h"
#include "nlohmann/json.hpp" #include "nlohmann/json.hpp"
#if __APPLE__
#else
#include "nvcodec_api.h"
#endif
using nlohmann::json; using nlohmann::json;
PeerConnection::PeerConnection() {} PeerConnection::PeerConnection() {}
@@ -22,10 +17,6 @@ PeerConnection::~PeerConnection() {
nv12_data_ = nullptr; nv12_data_ = nullptr;
} }
video_codec_inited_ = false;
audio_codec_inited_ = false;
load_nvcodec_dll_success = false;
user_data_ = nullptr; user_data_ = nullptr;
} }
@@ -143,41 +134,6 @@ int PeerConnection::Init(PeerConnectionParams params,
} }
}; };
on_receive_video_ = [this](const char *data, size_t size,
const std::string &user_id) {
int num_frame_returned = video_decoder_->Decode(
(uint8_t *)data, size, [this, user_id](VideoFrame video_frame) {
if (on_receive_video_frame_) {
XVideoFrame x_video_frame;
x_video_frame.data = (const char *)video_frame.Buffer();
x_video_frame.width = video_frame.Width();
x_video_frame.height = video_frame.Height();
x_video_frame.size = video_frame.Size();
on_receive_video_frame_(&x_video_frame, user_id.data(),
user_id.size(), user_data_);
}
});
};
on_receive_audio_ = [this](const char *data, size_t size,
const std::string &user_id) {
int num_frame_returned = audio_decoder_->Decode(
(uint8_t *)data, size, [this, user_id](uint8_t *data, int size) {
if (on_receive_audio_buffer_) {
on_receive_audio_buffer_((const char *)data, size, user_id.data(),
user_id.size(), user_data_);
}
});
};
on_receive_data_ = [this](const char *data, size_t size,
const std::string &user_id) {
if (on_receive_data_buffer_) {
on_receive_data_buffer_(data, size, user_id.data(), user_id.size(),
user_data_);
}
};
on_ice_status_change_ = [this](std::string ice_status, on_ice_status_change_ = [this](std::string ice_status,
const std::string &user_id) { const std::string &user_id) {
if ("connecting" == ice_status) { if ("connecting" == ice_status) {
@@ -277,102 +233,6 @@ int PeerConnection::Init(PeerConnectionParams params,
return 0; return 0;
} }
int PeerConnection::CreateVideoCodec(bool av1, bool hardware_acceleration) {
if (video_codec_inited_) {
return 0;
}
hardware_acceleration_ = hardware_acceleration;
if (av1) {
if (hardware_acceleration_) {
hardware_acceleration_ = false;
LOG_WARN("Only support software codec for AV1");
}
video_encoder_ = VideoEncoderFactory::CreateVideoEncoder(false, true);
video_decoder_ = VideoDecoderFactory::CreateVideoDecoder(false, true);
} else {
#ifdef __APPLE__
if (hardware_acceleration_) {
hardware_acceleration_ = false;
LOG_WARN(
"MacOS not support hardware acceleration, use default software "
"codec");
video_encoder_ = VideoEncoderFactory::CreateVideoEncoder(false, false);
video_decoder_ = VideoDecoderFactory::CreateVideoDecoder(false, false);
} else {
video_encoder_ = VideoEncoderFactory::CreateVideoEncoder(false, false);
video_decoder_ = VideoDecoderFactory::CreateVideoDecoder(false, false);
}
#else
if (hardware_acceleration_) {
if (0 == LoadNvCodecDll()) {
load_nvcodec_dll_success = true;
video_encoder_ = VideoEncoderFactory::CreateVideoEncoder(true, false);
video_decoder_ = VideoDecoderFactory::CreateVideoDecoder(true, false);
} else {
LOG_WARN(
"Hardware accelerated codec not available, use default software "
"codec");
video_encoder_ = VideoEncoderFactory::CreateVideoEncoder(false, false);
video_decoder_ = VideoDecoderFactory::CreateVideoDecoder(false, false);
}
} else {
video_encoder_ = VideoEncoderFactory::CreateVideoEncoder(false, false);
video_decoder_ = VideoDecoderFactory::CreateVideoDecoder(false, false);
}
#endif
}
if (!video_encoder_) {
video_encoder_ = VideoEncoderFactory::CreateVideoEncoder(false, false);
LOG_ERROR("Create encoder failed, try to use software H.264 encoder");
}
if (!video_encoder_ || 0 != video_encoder_->Init()) {
LOG_ERROR("Encoder init failed");
return -1;
}
if (!video_decoder_) {
video_decoder_ = VideoDecoderFactory::CreateVideoDecoder(false, false);
LOG_ERROR("Create decoder failed, try to use software H.264 decoder");
}
if (!video_decoder_ || video_decoder_->Init()) {
LOG_ERROR("Decoder init failed");
return -1;
}
video_codec_inited_ = true;
LOG_INFO("Create video codec [{}|{}] finish",
video_encoder_->GetEncoderName(), video_decoder_->GetDecoderName());
return 0;
}
int PeerConnection::CreateAudioCodec() {
if (audio_codec_inited_) {
return 0;
}
audio_encoder_ = std::make_unique<AudioEncoder>(AudioEncoder(48000, 1, 480));
if (!audio_encoder_ || 0 != audio_encoder_->Init()) {
LOG_ERROR("Audio encoder init failed");
return -1;
}
audio_decoder_ = std::make_unique<AudioDecoder>(AudioDecoder(48000, 1, 480));
if (!audio_decoder_ || 0 != audio_decoder_->Init()) {
LOG_ERROR("Audio decoder init failed");
return -1;
}
audio_codec_inited_ = true;
LOG_INFO("Create audio codec [{}|{}] finish",
audio_encoder_->GetEncoderName(), audio_decoder_->GetDecoderName());
return 0;
}
int PeerConnection::Login() { int PeerConnection::Login() {
if (WsStatus::WsOpened != ws_status_) { if (WsStatus::WsOpened != ws_status_) {
LOG_ERROR("Websocket not opened"); LOG_ERROR("Websocket not opened");
@@ -494,12 +354,6 @@ int PeerConnection::Destroy() {
nv12_data_ = nullptr; nv12_data_ = nullptr;
} }
#ifdef __APPLE__
#else
if (hardware_acceleration_ && load_nvcodec_dll_success) {
ReleaseNvCodecDll();
}
#endif
return 0; return 0;
} }
@@ -527,36 +381,18 @@ SignalStatus PeerConnection::GetSignalStatus() {
return signal_status_; return signal_status_;
} }
int PeerConnection::SendVideoData(const char *data, size_t size) { // media send
int PeerConnection::SendVideoData(const XVideoFrame *video_frame) {
if (ice_transmission_list_.empty()) { if (ice_transmission_list_.empty()) {
return -1; return -1;
} }
if (b_force_i_frame_) { for (auto &ice_trans : ice_transmission_list_) {
LOG_INFO("Force I frame"); if (!is_ice_transmission_ready_[ice_trans.first]) {
video_encoder_->ForceIdr(); continue;
b_force_i_frame_ = false; }
}
int ret = video_encoder_->Encode( ice_trans.second->SendVideoData(video_frame);
(uint8_t *)data, size,
[this](char *encoded_frame, size_t size,
VideoEncoder::VideoFrameType frame_type) -> int {
for (auto &ice_trans : ice_transmission_list_) {
if (!is_ice_transmission_ready_[ice_trans.first]) {
continue;
}
// LOG_ERROR("Send frame size: [{}]", size);
ice_trans.second->SendVideoData(
static_cast<IceTransmission::VideoFrameType>(frame_type),
encoded_frame, size);
}
return 0;
});
if (0 != ret) {
LOG_ERROR("Encode failed");
return -1;
} }
return 0; return 0;
@@ -567,19 +403,12 @@ int PeerConnection::SendAudioData(const char *data, size_t size) {
return -1; return -1;
} }
int ret = audio_encoder_->Encode( for (auto &ice_trans : ice_transmission_list_) {
(uint8_t *)data, size, if (!is_ice_transmission_ready_[ice_trans.first]) {
[this](char *encoded_audio_buffer, size_t size) -> int { continue;
for (auto &ice_trans : ice_transmission_list_) { }
if (!is_ice_transmission_ready_[ice_trans.first]) { ice_trans.second->SendAudioData(data, size);
continue; }
}
// LOG_ERROR("opus frame size: [{}]", size);
ice_trans.second->SendData(IceTransmission::DATA_TYPE::AUDIO,
encoded_audio_buffer, size);
}
return 0;
});
return 0; return 0;
} }
@@ -589,46 +418,11 @@ int PeerConnection::SendUserData(const char *data, size_t size) {
if (!is_ice_transmission_ready_[ice_trans.first]) { if (!is_ice_transmission_ready_[ice_trans.first]) {
continue; continue;
} }
ice_trans.second->SendData(IceTransmission::DATA_TYPE::DATA, data, size); ice_trans.second->SendUserData(data, size);
} }
return 0; return 0;
} }
int PeerConnection::SendVideoData(const XVideoFrame *video_frame) {
if (ice_transmission_list_.empty()) {
return -1;
}
if (b_force_i_frame_) {
video_encoder_->ForceIdr();
LOG_INFO("Force I frame");
b_force_i_frame_ = false;
}
int ret = video_encoder_->Encode(
video_frame,
[this](char *encoded_frame, size_t size,
VideoEncoder::VideoFrameType frame_type) -> int {
for (auto &ice_trans : ice_transmission_list_) {
if (!is_ice_transmission_ready_[ice_trans.first]) {
continue;
}
// LOG_ERROR("Send frame size: [{}]", size);
ice_trans.second->SendVideoData(
static_cast<IceTransmission::VideoFrameType>(frame_type),
encoded_frame, size);
}
return 0;
});
if (0 != ret) {
LOG_ERROR("Encode failed");
return -1;
}
return 0;
}
void PeerConnection::ProcessSignal(const std::string &signal) { void PeerConnection::ProcessSignal(const std::string &signal) {
auto j = json::parse(signal); auto j = json::parse(signal);
std::string type = j["type"]; std::string type = j["type"];
@@ -842,20 +636,21 @@ void PeerConnection::ProcessIceWorkMsg(const IceWorkMsg &msg) {
for (auto &remote_user_id : user_id_list) { for (auto &remote_user_id : user_id_list) {
ice_transmission_list_[remote_user_id] = ice_transmission_list_[remote_user_id] =
std::make_unique<IceTransmission>(true, transmission_id, user_id_, std::make_unique<IceTransmission>(
remote_user_id, ws_transport_, true, transmission_id, user_id_, remote_user_id, ws_transport_,
on_ice_status_change_); on_ice_status_change_, user_data_);
ice_transmission_list_[remote_user_id]->SetLocalCapabilities( ice_transmission_list_[remote_user_id]->SetLocalCapabilities(
trickle_ice_, reliable_ice_, enable_turn_, false, hardware_acceleration_, trickle_ice_, reliable_ice_, enable_turn_,
video_payload_types_, audio_payload_types_); false, video_payload_types_, audio_payload_types_);
ice_transmission_list_[remote_user_id]->SetOnReceiveVideoFunc( ice_transmission_list_[remote_user_id]->SetOnReceiveVideoFunc(
on_receive_video_); on_receive_video_frame_);
ice_transmission_list_[remote_user_id]->SetOnReceiveAudioFunc( ice_transmission_list_[remote_user_id]->SetOnReceiveAudioFunc(
on_receive_audio_); on_receive_audio_buffer_);
ice_transmission_list_[remote_user_id]->SetOnReceiveDataFunc( ice_transmission_list_[remote_user_id]->SetOnReceiveDataFunc(
on_receive_data_); on_receive_data_buffer_);
ice_transmission_list_[remote_user_id]->SetOnReceiveNetStatusReportFunc( ice_transmission_list_[remote_user_id]->SetOnReceiveNetStatusReportFunc(
on_net_status_report_); on_net_status_report_);
@@ -889,20 +684,21 @@ void PeerConnection::ProcessIceWorkMsg(const IceWorkMsg &msg) {
ice_transmission_list_.find(remote_user_id)) { ice_transmission_list_.find(remote_user_id)) {
// Enable TURN for answer peer by default // Enable TURN for answer peer by default
ice_transmission_list_[remote_user_id] = ice_transmission_list_[remote_user_id] =
std::make_unique<IceTransmission>(false, transmission_id, user_id_, std::make_unique<IceTransmission>(
remote_user_id, ws_transport_, false, transmission_id, user_id_, remote_user_id, ws_transport_,
on_ice_status_change_); on_ice_status_change_, user_data_);
ice_transmission_list_[remote_user_id]->SetLocalCapabilities( ice_transmission_list_[remote_user_id]->SetLocalCapabilities(
trickle_ice_, reliable_ice_, enable_turn_, false, hardware_acceleration_, trickle_ice_, reliable_ice_, enable_turn_,
video_payload_types_, audio_payload_types_); false, video_payload_types_, audio_payload_types_);
ice_transmission_list_[remote_user_id]->SetOnReceiveVideoFunc( ice_transmission_list_[remote_user_id]->SetOnReceiveVideoFunc(
on_receive_video_); on_receive_video_frame_);
ice_transmission_list_[remote_user_id]->SetOnReceiveAudioFunc( ice_transmission_list_[remote_user_id]->SetOnReceiveAudioFunc(
on_receive_audio_); on_receive_audio_buffer_);
ice_transmission_list_[remote_user_id]->SetOnReceiveDataFunc( ice_transmission_list_[remote_user_id]->SetOnReceiveDataFunc(
on_receive_data_); on_receive_data_buffer_);
ice_transmission_list_[remote_user_id]->SetOnReceiveNetStatusReportFunc( ice_transmission_list_[remote_user_id]->SetOnReceiveNetStatusReportFunc(
on_net_status_report_); on_net_status_report_);
@@ -921,18 +717,6 @@ void PeerConnection::ProcessIceWorkMsg(const IceWorkMsg &msg) {
if (0 != ret) { if (0 != ret) {
NegotiationFailed(); NegotiationFailed();
break; break;
} else {
std::vector<RtpPacket::PAYLOAD_TYPE> negotiated_payload_types =
ice_transmission_list_[remote_user_id]->GetNegotiatedCapabilities();
if (0 != CreateVideoCodec(RtpPacket::PAYLOAD_TYPE::AV1 ==
negotiated_payload_types[0],
hardware_acceleration_)) {
LOG_ERROR("Create video codec failed");
}
if (0 != CreateAudioCodec()) {
LOG_ERROR("Create audio codec failed");
}
} }
if (trickle_ice_) { if (trickle_ice_) {
@@ -953,19 +737,6 @@ void PeerConnection::ProcessIceWorkMsg(const IceWorkMsg &msg) {
if (0 != ret) { if (0 != ret) {
Leave(remote_transmission_id_); Leave(remote_transmission_id_);
break; break;
} else {
std::vector<RtpPacket::PAYLOAD_TYPE> negotiated_payload_types =
ice_transmission_list_[remote_user_id]
->GetNegotiatedCapabilities();
if (0 != CreateVideoCodec(RtpPacket::PAYLOAD_TYPE::AV1 ==
negotiated_payload_types[0],
hardware_acceleration_)) {
LOG_ERROR("Create video codec failed");
}
if (0 != CreateAudioCodec()) {
LOG_ERROR("Create audio codec failed");
}
} }
if (trickle_ice_) { if (trickle_ice_) {

View File

@@ -104,9 +104,6 @@ class PeerConnection {
private: private:
int Login(); int Login();
int CreateVideoCodec(bool av1, bool hardware_acceleration);
int CreateAudioCodec();
void ProcessSignal(const std::string &signal); void ProcessSignal(const std::string &signal);
int RequestTransmissionMemberList(const std::string &transmission_id, int RequestTransmissionMemberList(const std::string &transmission_id,
@@ -168,12 +165,7 @@ class PeerConnection {
std::map<std::string, std::unique_ptr<IceTransmission>> std::map<std::string, std::unique_ptr<IceTransmission>>
ice_transmission_list_; ice_transmission_list_;
std::map<std::string, bool> is_ice_transmission_ready_; std::map<std::string, bool> is_ice_transmission_ready_;
std::function<void(const char *, size_t, const std::string &)>
on_receive_video_ = nullptr;
std::function<void(const char *, size_t, const std::string &)>
on_receive_audio_ = nullptr;
std::function<void(const char *, size_t, const std::string &)>
on_receive_data_ = nullptr;
std::function<void(std::string, const std::string &)> on_ice_status_change_ = std::function<void(std::string, const std::string &)> on_ice_status_change_ =
nullptr; nullptr;
std::function<void(const std::string &, IceTransmission::TraversalType, std::function<void(const std::string &, IceTransmission::TraversalType,
@@ -199,18 +191,7 @@ class PeerConnection {
std::string password_; std::string password_;
private: private:
std::unique_ptr<VideoEncoder> video_encoder_ = nullptr;
std::unique_ptr<VideoDecoder> video_decoder_ = nullptr;
bool hardware_accelerated_encode_ = false;
bool hardware_accelerated_decode_ = false;
bool b_force_i_frame_ = false; bool b_force_i_frame_ = false;
bool video_codec_inited_ = false;
bool load_nvcodec_dll_success = false;
private:
std::unique_ptr<AudioEncoder> audio_encoder_ = nullptr;
std::unique_ptr<AudioDecoder> audio_decoder_ = nullptr;
bool audio_codec_inited_ = false;
private: private:
std::thread ice_worker_; std::thread ice_worker_;

View File

@@ -98,23 +98,6 @@ int LeaveConnection(PeerPtr *peer_ptr, const char *transmission_id) {
return 0; return 0;
} }
int SendData(PeerPtr *peer_ptr, DATA_TYPE data_type, const char *data,
size_t size) {
if (!peer_ptr) {
LOG_ERROR("peer_ptr not created");
return -1;
}
if (DATA_TYPE::VIDEO == data_type) {
peer_ptr->peer_connection->SendVideoData(data, size);
} else if (DATA_TYPE::AUDIO == data_type) {
peer_ptr->peer_connection->SendAudioData(data, size);
} else if (DATA_TYPE::DATA == data_type) {
peer_ptr->peer_connection->SendUserData(data, size);
}
return 0;
}
DLLAPI int SendVideoFrame(PeerPtr *peer_ptr, const XVideoFrame *video_frame) { DLLAPI int SendVideoFrame(PeerPtr *peer_ptr, const XVideoFrame *video_frame) {
if (!peer_ptr) { if (!peer_ptr) {
LOG_ERROR("peer_ptr not created"); LOG_ERROR("peer_ptr not created");
@@ -124,9 +107,44 @@ DLLAPI int SendVideoFrame(PeerPtr *peer_ptr, const XVideoFrame *video_frame) {
if (!video_frame) { if (!video_frame) {
LOG_ERROR("Invaild video frame"); LOG_ERROR("Invaild video frame");
return -1; return -1;
} else if (!video_frame->data || video_frame->size <= 0) {
LOG_ERROR("Invaild video frame");
return -1;
} }
peer_ptr->peer_connection->SendVideoData(video_frame); peer_ptr->peer_connection->SendVideoData(video_frame);
return 0;
}
DLLAPI int SendAudioFrame(PeerPtr *peer_ptr, const char *data, size_t size) {
if (!peer_ptr) {
LOG_ERROR("peer_ptr not created");
return -1;
}
if (!data || size <= 0) {
LOG_ERROR("Invaild video frame");
return -1;
}
peer_ptr->peer_connection->SendAudioData(data, size);
return 0;
}
int SendData(PeerPtr *peer_ptr, const char *data, size_t size) {
if (!peer_ptr) {
LOG_ERROR("peer_ptr not created");
return -1;
}
if (!data || size <= 0) {
LOG_ERROR("Invaild data");
return -1;
}
peer_ptr->peer_connection->SendUserData(data, size);
return 0; return 0;
} }

View File

@@ -8,26 +8,44 @@
#include "common.h" #include "common.h"
#include "ikcp.h" #include "ikcp.h"
#include "log.h" #include "log.h"
#if __APPLE__
#else
#include "nvcodec_api.h"
#endif
using nlohmann::json; using nlohmann::json;
IceTransmission::IceTransmission( IceTransmission::IceTransmission(
bool offer_peer, std::string &transmission_id, std::string &user_id, bool offer_peer, std::string &transmission_id, std::string &user_id,
std::string &remote_user_id, std::shared_ptr<WsClient> ice_ws_transmission, std::string &remote_user_id, std::shared_ptr<WsClient> ice_ws_transmission,
std::function<void(std::string, const std::string &)> on_ice_status_change) std::function<void(std::string, const std::string &)> on_ice_status_change,
void *user_data)
: offer_peer_(offer_peer), : offer_peer_(offer_peer),
transmission_id_(transmission_id), transmission_id_(transmission_id),
user_id_(user_id), user_id_(user_id),
remote_user_id_(remote_user_id), remote_user_id_(remote_user_id),
ice_ws_transport_(ice_ws_transmission), ice_ws_transport_(ice_ws_transmission),
on_ice_status_change_(on_ice_status_change) {} on_ice_status_change_(on_ice_status_change),
user_data_(user_data) {}
IceTransmission::~IceTransmission() {} IceTransmission::~IceTransmission() {
video_codec_inited_ = false;
audio_codec_inited_ = false;
load_nvcodec_dll_success_ = false;
#ifdef __APPLE__
#else
if (hardware_acceleration_ && load_nvcodec_dll_success_) {
ReleaseNvCodecDll();
}
#endif
}
int IceTransmission::SetLocalCapabilities( int IceTransmission::SetLocalCapabilities(
bool use_trickle_ice, bool use_reliable_ice, bool enable_turn, bool hardware_acceleration, bool use_trickle_ice, bool use_reliable_ice,
bool force_turn, std::vector<int> &video_payload_types, bool enable_turn, bool force_turn, std::vector<int> &video_payload_types,
std::vector<int> &audio_payload_types) { std::vector<int> &audio_payload_types) {
hardware_acceleration_ = hardware_acceleration;
use_trickle_ice_ = use_trickle_ice; use_trickle_ice_ = use_trickle_ice;
use_reliable_ice_ = use_reliable_ice; use_reliable_ice_ = use_reliable_ice;
enable_turn_ = force_turn; enable_turn_ = force_turn;
@@ -81,8 +99,20 @@ int IceTransmission::InitIceTransmission(
[this](VideoFrame &video_frame) -> void { [this](VideoFrame &video_frame) -> void {
// LOG_ERROR("OnReceiveCompleteFrame {}", video_frame.Size()); // LOG_ERROR("OnReceiveCompleteFrame {}", video_frame.Size());
ice_io_statistics_->UpdateVideoInboundBytes(video_frame.Size()); ice_io_statistics_->UpdateVideoInboundBytes(video_frame.Size());
on_receive_video_((const char *)video_frame.Buffer(),
video_frame.Size(), remote_user_id_); int num_frame_returned = video_decoder_->Decode(
(uint8_t *)video_frame.Buffer(), video_frame.Size(),
[this](VideoFrame video_frame) {
if (on_receive_video_) {
XVideoFrame x_video_frame;
x_video_frame.data = (const char *)video_frame.Buffer();
x_video_frame.width = video_frame.Width();
x_video_frame.height = video_frame.Height();
x_video_frame.size = video_frame.Size();
on_receive_video_(&x_video_frame, remote_user_id_.data(),
remote_user_id_.size(), user_data_);
}
});
}); });
rtp_video_receiver_->Start(); rtp_video_receiver_->Start();
@@ -126,11 +156,18 @@ int IceTransmission::InitIceTransmission(
return ice_agent_->Send(data, size); return ice_agent_->Send(data, size);
}); });
rtp_audio_receiver_->SetOnReceiveData( rtp_audio_receiver_->SetOnReceiveData([this](const char *data,
[this](const char *data, size_t size) -> void { size_t size) -> void {
ice_io_statistics_->UpdateAudioInboundBytes(size); ice_io_statistics_->UpdateAudioInboundBytes(size);
on_receive_audio_(data, size, remote_user_id_);
}); int num_frame_returned = audio_decoder_->Decode(
(uint8_t *)data, size, [this](uint8_t *data, int size) {
if (on_receive_audio_) {
on_receive_audio_((const char *)data, size, remote_user_id_.data(),
remote_user_id_.size(), user_data_);
}
});
});
rtp_audio_sender_ = std::make_unique<RtpAudioSender>(); rtp_audio_sender_ = std::make_unique<RtpAudioSender>();
rtp_audio_sender_->SetSendDataFunc( rtp_audio_sender_->SetSendDataFunc(
@@ -174,7 +211,11 @@ int IceTransmission::InitIceTransmission(
rtp_data_receiver_->SetOnReceiveData( rtp_data_receiver_->SetOnReceiveData(
[this](const char *data, size_t size) -> void { [this](const char *data, size_t size) -> void {
ice_io_statistics_->UpdateDataInboundBytes(size); ice_io_statistics_->UpdateDataInboundBytes(size);
on_receive_data_(data, size, remote_user_id_);
if (on_receive_data_) {
on_receive_data_(data, size, remote_user_id_.data(),
remote_user_id_.size(), user_data_);
}
}); });
rtp_data_sender_ = std::make_unique<RtpDataSender>(); rtp_data_sender_ = std::make_unique<RtpDataSender>();
@@ -372,6 +413,103 @@ int IceTransmission::CreateMediaCodec() {
return 0; return 0;
} }
int IceTransmission::CreateVideoCodec(RtpPacket::PAYLOAD_TYPE video_pt,
bool hardware_acceleration) {
if (video_codec_inited_) {
return 0;
}
hardware_acceleration_ = hardware_acceleration;
if (RtpPacket::PAYLOAD_TYPE::AV1 == video_pt) {
if (hardware_acceleration_) {
hardware_acceleration_ = false;
LOG_WARN("Only support software codec for AV1");
}
video_encoder_ = VideoEncoderFactory::CreateVideoEncoder(false, true);
video_decoder_ = VideoDecoderFactory::CreateVideoDecoder(false, true);
} else if (RtpPacket::PAYLOAD_TYPE::H264 == video_pt) {
#ifdef __APPLE__
if (hardware_acceleration_) {
hardware_acceleration_ = false;
LOG_WARN(
"MacOS not support hardware acceleration, use default software "
"codec");
video_encoder_ = VideoEncoderFactory::CreateVideoEncoder(false, false);
video_decoder_ = VideoDecoderFactory::CreateVideoDecoder(false, false);
} else {
video_encoder_ = VideoEncoderFactory::CreateVideoEncoder(false, false);
video_decoder_ = VideoDecoderFactory::CreateVideoDecoder(false, false);
}
#else
if (hardware_acceleration_) {
if (0 == LoadNvCodecDll()) {
load_nvcodec_dll_success_ = true;
video_encoder_ = VideoEncoderFactory::CreateVideoEncoder(true, false);
video_decoder_ = VideoDecoderFactory::CreateVideoDecoder(true, false);
} else {
LOG_WARN(
"Hardware accelerated codec not available, use default software "
"codec");
video_encoder_ = VideoEncoderFactory::CreateVideoEncoder(false, false);
video_decoder_ = VideoDecoderFactory::CreateVideoDecoder(false, false);
}
} else {
video_encoder_ = VideoEncoderFactory::CreateVideoEncoder(false, false);
video_decoder_ = VideoDecoderFactory::CreateVideoDecoder(false, false);
}
#endif
}
if (!video_encoder_) {
video_encoder_ = VideoEncoderFactory::CreateVideoEncoder(false, false);
LOG_ERROR("Create encoder failed, try to use software H.264 encoder");
}
if (!video_encoder_ || 0 != video_encoder_->Init()) {
LOG_ERROR("Encoder init failed");
return -1;
}
if (!video_decoder_) {
video_decoder_ = VideoDecoderFactory::CreateVideoDecoder(false, false);
LOG_ERROR("Create decoder failed, try to use software H.264 decoder");
}
if (!video_decoder_ || video_decoder_->Init()) {
LOG_ERROR("Decoder init failed");
return -1;
}
video_codec_inited_ = true;
LOG_INFO("Create video codec [{}|{}] finish",
video_encoder_->GetEncoderName(), video_decoder_->GetDecoderName());
return 0;
}
int IceTransmission::CreateAudioCodec() {
if (audio_codec_inited_) {
return 0;
}
audio_encoder_ = std::make_unique<AudioEncoder>(AudioEncoder(48000, 1, 480));
if (!audio_encoder_ || 0 != audio_encoder_->Init()) {
LOG_ERROR("Audio encoder init failed");
return -1;
}
audio_decoder_ = std::make_unique<AudioDecoder>(AudioDecoder(48000, 1, 480));
if (!audio_decoder_ || 0 != audio_decoder_->Init()) {
LOG_ERROR("Audio decoder init failed");
return -1;
}
audio_codec_inited_ = true;
LOG_INFO("Create audio codec [{}|{}] finish",
audio_encoder_->GetEncoderName(), audio_decoder_->GetDecoderName());
return 0;
}
int IceTransmission::SetTransmissionId(const std::string &transmission_id) { int IceTransmission::SetTransmissionId(const std::string &transmission_id) {
transmission_id_ = transmission_id; transmission_id_ = transmission_id;
@@ -570,6 +708,8 @@ std::string IceTransmission::GetRemoteCapabilities(
} }
CreateMediaCodec(); CreateMediaCodec();
CreateVideoCodec(negotiated_video_pt_, hardware_acceleration_);
CreateAudioCodec();
remote_capabilities_got_ = true; remote_capabilities_got_ = true;
} }
@@ -795,7 +935,7 @@ IceTransmission::GetNegotiatedCapabilities() {
return {negotiated_video_pt_, negotiated_audio_pt_, negotiated_data_pt_}; return {negotiated_video_pt_, negotiated_audio_pt_, negotiated_data_pt_};
} }
int IceTransmission::SendData(DATA_TYPE type, const char *data, size_t size) { int IceTransmission::SendVideoData(const XVideoFrame *video_frame) {
if (state_ != NICE_COMPONENT_STATE_CONNECTED && if (state_ != NICE_COMPONENT_STATE_CONNECTED &&
state_ != NICE_COMPONENT_STATE_READY) { state_ != NICE_COMPONENT_STATE_READY) {
LOG_ERROR("Ice is not connected, state = [{}]", LOG_ERROR("Ice is not connected, state = [{}]",
@@ -803,36 +943,63 @@ int IceTransmission::SendData(DATA_TYPE type, const char *data, size_t size) {
return -2; return -2;
} }
std::vector<RtpPacket> packets; if (b_force_i_frame_) {
video_encoder_->ForceIdr();
LOG_INFO("Force I frame");
b_force_i_frame_ = false;
}
if (DATA_TYPE::VIDEO == type) { int ret = video_encoder_->Encode(
if (rtp_video_sender_) { video_frame,
if (video_rtp_codec_) { [this](char *encoded_frame, size_t size,
video_rtp_codec_->Encode((uint8_t *)data, size, packets); VideoEncoder::VideoFrameType frame_type) -> int {
} std::vector<RtpPacket> packets;
rtp_video_sender_->Enqueue(packets); if (rtp_video_sender_) {
} if (video_rtp_codec_) {
} else if (DATA_TYPE::AUDIO == type) { video_rtp_codec_->Encode(
if (rtp_audio_sender_) { static_cast<RtpCodec::VideoFrameType>(frame_type),
if (audio_rtp_codec_) { (uint8_t *)encoded_frame, size, packets);
audio_rtp_codec_->Encode((uint8_t *)data, size, packets); }
rtp_audio_sender_->Enqueue(packets); rtp_video_sender_->Enqueue(packets);
} }
}
} else if (DATA_TYPE::DATA == type) { return 0;
if (rtp_data_sender_) { });
if (data_rtp_codec_) {
data_rtp_codec_->Encode((uint8_t *)data, size, packets); if (0 != ret) {
rtp_data_sender_->Enqueue(packets); LOG_ERROR("Encode failed");
} return -1;
}
} }
return 0; return 0;
} }
int IceTransmission::SendVideoData(VideoFrameType frame_type, const char *data, int IceTransmission::SendAudioData(const char *data, size_t size) {
size_t size) { if (state_ != NICE_COMPONENT_STATE_CONNECTED &&
state_ != NICE_COMPONENT_STATE_READY) {
LOG_ERROR("Ice is not connected, state = [{}]",
nice_component_state_to_string(state_));
return -2;
}
int ret = audio_encoder_->Encode(
(uint8_t *)data, size,
[this](char *encoded_audio_buffer, size_t size) -> int {
if (rtp_audio_sender_) {
if (audio_rtp_codec_) {
std::vector<RtpPacket> packets;
audio_rtp_codec_->Encode((uint8_t *)encoded_audio_buffer, size,
packets);
rtp_audio_sender_->Enqueue(packets);
}
}
return 0;
});
return 0;
}
int IceTransmission::SendUserData(const char *data, size_t size) {
if (state_ != NICE_COMPONENT_STATE_CONNECTED && if (state_ != NICE_COMPONENT_STATE_CONNECTED &&
state_ != NICE_COMPONENT_STATE_READY) { state_ != NICE_COMPONENT_STATE_READY) {
LOG_ERROR("Ice is not connected, state = [{}]", LOG_ERROR("Ice is not connected, state = [{}]",
@@ -842,13 +1009,11 @@ int IceTransmission::SendVideoData(VideoFrameType frame_type, const char *data,
std::vector<RtpPacket> packets; std::vector<RtpPacket> packets;
if (rtp_video_sender_) { if (rtp_data_sender_) {
if (video_rtp_codec_) { if (data_rtp_codec_) {
video_rtp_codec_->Encode( data_rtp_codec_->Encode((uint8_t *)data, size, packets);
static_cast<RtpCodec::VideoFrameType>(frame_type), (uint8_t *)data, rtp_data_sender_->Enqueue(packets);
size, packets);
} }
rtp_video_sender_->Enqueue(packets);
} }
return 0; return 0;

View File

@@ -9,6 +9,8 @@
#include <iostream> #include <iostream>
#include "audio_decoder.h"
#include "audio_encoder.h"
#include "congestion_control.h" #include "congestion_control.h"
#include "ice_agent.h" #include "ice_agent.h"
#include "io_statistics.h" #include "io_statistics.h"
@@ -21,11 +23,14 @@
#include "rtp_packet.h" #include "rtp_packet.h"
#include "rtp_video_receiver.h" #include "rtp_video_receiver.h"
#include "rtp_video_sender.h" #include "rtp_video_sender.h"
#include "video_decoder_factory.h"
#include "video_encoder_factory.h"
#include "ws_client.h" #include "ws_client.h"
class IceTransmission { class IceTransmission {
public: public:
typedef enum { VIDEO = 96, AUDIO = 97, DATA = 127 } DATA_TYPE; typedef enum { VIDEO = 96, AUDIO = 97, DATA = 127 } DATA_TYPE;
typedef enum { H264 = 96, AV1 = 99 } VIDEO_TYPE;
enum VideoFrameType { enum VideoFrameType {
kEmptyFrame = 0, kEmptyFrame = 0,
kVideoFrameKey = 3, kVideoFrameKey = 3,
@@ -39,12 +44,14 @@ class IceTransmission {
std::string &user_id, std::string &remote_user_id, std::string &user_id, std::string &remote_user_id,
std::shared_ptr<WsClient> ice_ws_transmission, std::shared_ptr<WsClient> ice_ws_transmission,
std::function<void(std::string, const std::string &)> std::function<void(std::string, const std::string &)>
on_ice_status_change); on_ice_status_change,
void *user_data);
~IceTransmission(); ~IceTransmission();
public: public:
int SetLocalCapabilities(bool use_trickle_ice, bool use_reliable_ice, int SetLocalCapabilities(bool hardware_acceleration, bool use_trickle_ice,
bool enable_turn, bool force_turn, bool use_reliable_ice, bool enable_turn,
bool force_turn,
std::vector<int> &video_payload_types, std::vector<int> &video_payload_types,
std::vector<int> &audio_payload_types); std::vector<int> &audio_payload_types);
@@ -57,19 +64,22 @@ class IceTransmission {
int DestroyIceTransmission(); int DestroyIceTransmission();
void SetOnReceiveVideoFunc( void SetOnReceiveVideoFunc(
std::function<void(const char *, size_t, const std::string &)> std::function<void(const XVideoFrame *, const char *, const size_t,
void *)>
on_receive_video) { on_receive_video) {
on_receive_video_ = on_receive_video; on_receive_video_ = on_receive_video;
} }
void SetOnReceiveAudioFunc( void SetOnReceiveAudioFunc(
std::function<void(const char *, size_t, const std::string &)> std::function<void(const char *, size_t, const char *, const size_t,
void *)>
on_receive_audio) { on_receive_audio) {
on_receive_audio_ = on_receive_audio; on_receive_audio_ = on_receive_audio;
} }
void SetOnReceiveDataFunc( void SetOnReceiveDataFunc(
std::function<void(const char *, size_t, const std::string &)> std::function<void(const char *, size_t, const char *, const size_t,
void *)>
on_receive_data) { on_receive_data) {
on_receive_data_ = on_receive_data; on_receive_data_ = on_receive_data;
} }
@@ -87,9 +97,7 @@ class IceTransmission {
int SetTransmissionId(const std::string &transmission_id); int SetTransmissionId(const std::string &transmission_id);
int SendData(DATA_TYPE type, const char *data, size_t size); int SendVideoData(const XVideoFrame *video_frame);
int SendVideoData(VideoFrameType frame_type, const char *data, size_t size);
int SendAudioData(const char *data, size_t size); int SendAudioData(const char *data, size_t size);
@@ -119,6 +127,10 @@ class IceTransmission {
int CreateMediaCodec(); int CreateMediaCodec();
int CreateVideoCodec(RtpPacket::PAYLOAD_TYPE video_pt,
bool hardware_acceleration);
int CreateAudioCodec();
private: private:
uint8_t CheckIsRtcpPacket(const char *buffer, size_t size); uint8_t CheckIsRtcpPacket(const char *buffer, size_t size);
uint8_t CheckIsVideoPacket(const char *buffer, size_t size); uint8_t CheckIsVideoPacket(const char *buffer, size_t size);
@@ -147,20 +159,23 @@ class IceTransmission {
std::string remote_ice_username_ = ""; std::string remote_ice_username_ = "";
NiceComponentState state_ = NICE_COMPONENT_STATE_DISCONNECTED; NiceComponentState state_ = NICE_COMPONENT_STATE_DISCONNECTED;
TraversalType traversal_type_ = TraversalType::TP2P; TraversalType traversal_type_ = TraversalType::TP2P;
void *user_data_ = nullptr;
private: private:
std::unique_ptr<IceAgent> ice_agent_ = nullptr; std::unique_ptr<IceAgent> ice_agent_ = nullptr;
bool is_closed_ = false; bool is_closed_ = false;
std::shared_ptr<WsClient> ice_ws_transport_ = nullptr; std::shared_ptr<WsClient> ice_ws_transport_ = nullptr;
CongestionControl *congestion_control_ = nullptr; CongestionControl *congestion_control_ = nullptr;
std::function<void(const char *, size_t, const std::string &)> std::function<void(const XVideoFrame *, const char *, const size_t, void *)>
on_receive_video_ = nullptr; on_receive_video_ = nullptr;
std::function<void(const char *, size_t, const std::string &)> std::function<void(const char *, size_t, const char *, const size_t, void *)>
on_receive_audio_ = nullptr; on_receive_audio_ = nullptr;
std::function<void(const char *, size_t, const std::string &)> std::function<void(const char *, size_t, const char *, const size_t, void *)>
on_receive_data_ = nullptr; on_receive_data_ = nullptr;
std::function<void(std::string, const std::string &)> on_ice_status_change_ = std::function<void(std::string, const std::string &)> on_ice_status_change_ =
nullptr; nullptr;
std::function<void(const std::string &, TraversalType, const uint64_t, std::function<void(const std::string &, TraversalType, const uint64_t,
const uint64_t, const uint64_t, const uint64_t, const uint64_t, const uint64_t, const uint64_t,
const uint64_t, const uint64_t, const uint64_t, const uint64_t, const uint64_t, const uint64_t,
@@ -200,6 +215,19 @@ class IceTransmission {
RtpPacket::PAYLOAD_TYPE::UNDEFINED; RtpPacket::PAYLOAD_TYPE::UNDEFINED;
RtpPacket::PAYLOAD_TYPE negotiated_data_pt_ = RtpPacket::PAYLOAD_TYPE negotiated_data_pt_ =
RtpPacket::PAYLOAD_TYPE::UNDEFINED; RtpPacket::PAYLOAD_TYPE::UNDEFINED;
private:
std::unique_ptr<VideoEncoder> video_encoder_ = nullptr;
std::unique_ptr<VideoDecoder> video_decoder_ = nullptr;
bool b_force_i_frame_ = false;
bool video_codec_inited_ = false;
bool load_nvcodec_dll_success_ = false;
bool hardware_acceleration_ = false;
private:
std::unique_ptr<AudioEncoder> audio_encoder_ = nullptr;
std::unique_ptr<AudioDecoder> audio_decoder_ = nullptr;
bool audio_codec_inited_ = false;
}; };
#endif #endif

View File

@@ -184,13 +184,13 @@ target("statistics")
target("transmission") target("transmission")
set_kind("object") set_kind("object")
add_deps("log", "ws", "ice", "qos", "rtp", "rtcp", "statistics") add_deps("log", "ws", "ice", "qos", "rtp", "rtcp", "statistics", "media")
add_files("src/transmission/*.cpp") add_files("src/transmission/*.cpp")
add_includedirs("src/ws", "src/ice", "src/qos", {public = true}) add_includedirs("src/ws", "src/ice", "src/qos", {public = true})
target("pc") target("pc")
set_kind("object") set_kind("object")
add_deps("log", "ws", "ice", "transmission", "inih", "common", "media") add_deps("log", "ws", "ice", "transmission", "inih", "common")
add_files("src/pc/*.cpp") add_files("src/pc/*.cpp")
add_includedirs("src/transmission", "src/interface", {public = true}) add_includedirs("src/transmission", "src/interface", {public = true})