mirror of
				https://github.com/kunkundi/crossdesk.git
				synced 2025-10-26 20:25:34 +08:00 
			
		
		
		
	[feat] update transport module and channel module
This commit is contained in:
		| @@ -1 +1,59 @@ | ||||
| #include "audio_channel_receive.h" | ||||
| #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(RtpPacket::PAYLOAD_TYPE payload_type) { | ||||
|   audio_rtp_codec_ = std::make_unique<RtpCodec>(payload_type); | ||||
|   rtp_audio_receiver_ = std::make_unique<RtpAudioReceiver>(ice_io_statistics_); | ||||
|  | ||||
|   rtp_audio_receiver_->SetOnReceiveData( | ||||
|       [this](const char *data, size_t size) -> void { | ||||
|         ice_io_statistics_->UpdateAudioInboundBytes((uint32_t)size); | ||||
|  | ||||
|         if (on_receive_audio_) { | ||||
|           on_receive_audio_(data, size); | ||||
|         } | ||||
|       }); | ||||
|  | ||||
|   rtp_audio_receiver_->SetSendDataFunc( | ||||
|       [this](const char *data, size_t size) -> int { | ||||
|         if (!ice_agent_) { | ||||
|           LOG_ERROR("ice_agent_ is nullptr"); | ||||
|           return -1; | ||||
|         } | ||||
|  | ||||
|         auto ice_state = ice_agent_->GetIceState(); | ||||
|  | ||||
|         if (ice_state != NICE_COMPONENT_STATE_CONNECTED && | ||||
|             ice_state != NICE_COMPONENT_STATE_READY) { | ||||
|           LOG_ERROR("Ice is not connected, state = [{}]", | ||||
|                     nice_component_state_to_string(ice_state)); | ||||
|           return -2; | ||||
|         } | ||||
|  | ||||
|         ice_io_statistics_->UpdateAudioOutboundBytes((uint32_t)size); | ||||
|         return ice_agent_->Send(data, size); | ||||
|       }); | ||||
| } | ||||
|  | ||||
| void AudioChannelReceive::Destroy() {} | ||||
|  | ||||
| int AudioChannelReceive::OnReceiveRtpPacket(const char *data, size_t size) { | ||||
|   if (rtp_audio_receiver_) { | ||||
|     rtp_audio_receiver_->InsertRtpPacket(RtpPacket((uint8_t *)data, size)); | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
| @@ -7,12 +7,30 @@ | ||||
| #ifndef _AUDIO_CHANNEL_RECEIVE_H_ | ||||
| #define _AUDIO_CHANNEL_RECEIVE_H_ | ||||
|  | ||||
| #include "ice_agent.h" | ||||
| #include "rtp_audio_receiver.h" | ||||
| #include "rtp_codec.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(RtpPacket::PAYLOAD_TYPE payload_type); | ||||
|   void Destroy(); | ||||
|   int OnReceiveRtpPacket(const char *data, size_t size); | ||||
|  | ||||
|  private: | ||||
|   std::shared_ptr<IceAgent> ice_agent_ = nullptr; | ||||
|   std::shared_ptr<IOStatistics> ice_io_statistics_ = nullptr; | ||||
|   std::unique_ptr<RtpCodec> audio_rtp_codec_ = nullptr; | ||||
|   std::unique_ptr<RtpAudioReceiver> rtp_audio_receiver_ = nullptr; | ||||
|   std::function<void(const char *, size_t)> on_receive_audio_ = nullptr; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
| @@ -1 +1,55 @@ | ||||
| #include "audio_channel_send.h" | ||||
| #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(RtpPacket::PAYLOAD_TYPE payload_type) { | ||||
|   audio_rtp_codec_ = std::make_unique<RtpCodec>(payload_type); | ||||
|  | ||||
|   rtp_audio_sender_ = std::make_unique<RtpAudioSender>(ice_io_statistics_); | ||||
|   rtp_audio_sender_->SetSendDataFunc( | ||||
|       [this](const char *data, size_t size) -> int { | ||||
|         if (!ice_agent_) { | ||||
|           LOG_ERROR("ice_agent_ is nullptr"); | ||||
|           return -1; | ||||
|         } | ||||
|  | ||||
|         auto ice_state = ice_agent_->GetIceState(); | ||||
|  | ||||
|         if (ice_state != NICE_COMPONENT_STATE_CONNECTED && | ||||
|             ice_state != NICE_COMPONENT_STATE_READY) { | ||||
|           LOG_ERROR("Ice is not connected, state = [{}]", | ||||
|                     nice_component_state_to_string(ice_state)); | ||||
|           return -2; | ||||
|         } | ||||
|  | ||||
|         ice_io_statistics_->UpdateAudioOutboundBytes((uint32_t)size); | ||||
|         return ice_agent_->Send(data, size); | ||||
|       }); | ||||
|  | ||||
|   rtp_audio_sender_->Start(); | ||||
| } | ||||
|  | ||||
| void AudioChannelSend::Destroy() { | ||||
|   if (rtp_audio_sender_) { | ||||
|     rtp_audio_sender_->Stop(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| int AudioChannelSend::SendAudio(char *data, size_t size) { | ||||
|   if (audio_rtp_codec_) { | ||||
|     std::vector<RtpPacket> packets; | ||||
|     audio_rtp_codec_->Encode((uint8_t *)data, (uint32_t)size, packets); | ||||
|     rtp_audio_sender_->Enqueue(packets); | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
| @@ -7,12 +7,27 @@ | ||||
| #ifndef _AUDIO_CHANNEL_SEND_H_ | ||||
| #define _AUDIO_CHANNEL_SEND_H_ | ||||
|  | ||||
| #include "ice_agent.h" | ||||
| #include "rtp_audio_sender.h" | ||||
| #include "rtp_codec.h" | ||||
|  | ||||
| class AudioChannelSend { | ||||
|  public: | ||||
|   AudioChannelSend(); | ||||
|   AudioChannelSend(std::shared_ptr<IceAgent> ice_agent, | ||||
|                    std::shared_ptr<IOStatistics> ice_io_statistics); | ||||
|   ~AudioChannelSend(); | ||||
|  | ||||
|  public: | ||||
|   void Initialize(RtpPacket::PAYLOAD_TYPE payload_type); | ||||
|   void Destroy(); | ||||
|   int SendAudio(char *data, size_t size); | ||||
|  | ||||
|  private: | ||||
|   std::shared_ptr<IceAgent> ice_agent_ = nullptr; | ||||
|   std::shared_ptr<IOStatistics> ice_io_statistics_ = nullptr; | ||||
|   std::unique_ptr<RtpCodec> audio_rtp_codec_ = nullptr; | ||||
|   std::unique_ptr<RtpAudioSender> rtp_audio_sender_ = nullptr; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
| @@ -1 +1,60 @@ | ||||
| #include "data_channel_receive.h" | ||||
| #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(RtpPacket::PAYLOAD_TYPE payload_type) { | ||||
|   data_rtp_codec_ = std::make_unique<RtpCodec>(payload_type); | ||||
|  | ||||
|   rtp_data_receiver_ = std::make_unique<RtpDataReceiver>(ice_io_statistics_); | ||||
|  | ||||
|   rtp_data_receiver_->SetOnReceiveData( | ||||
|       [this](const char *data, size_t size) -> void { | ||||
|         ice_io_statistics_->UpdateDataInboundBytes((uint32_t)size); | ||||
|  | ||||
|         if (on_receive_data_) { | ||||
|           on_receive_data_(data, size); | ||||
|         } | ||||
|       }); | ||||
|  | ||||
|   rtp_data_receiver_->SetSendDataFunc( | ||||
|       [this](const char *data, size_t size) -> int { | ||||
|         if (!ice_agent_) { | ||||
|           LOG_ERROR("ice_agent_ is nullptr"); | ||||
|           return -1; | ||||
|         } | ||||
|  | ||||
|         auto ice_state = ice_agent_->GetIceState(); | ||||
|  | ||||
|         if (ice_state != NICE_COMPONENT_STATE_CONNECTED && | ||||
|             ice_state != NICE_COMPONENT_STATE_READY) { | ||||
|           LOG_ERROR("Ice is not connected, state = [{}]", | ||||
|                     nice_component_state_to_string(ice_state)); | ||||
|           return -2; | ||||
|         } | ||||
|  | ||||
|         ice_io_statistics_->UpdateDataOutboundBytes((uint32_t)size); | ||||
|         return ice_agent_->Send(data, size); | ||||
|       }); | ||||
| } | ||||
|  | ||||
| void DataChannelReceive::Destroy() {} | ||||
|  | ||||
| int DataChannelReceive::OnReceiveRtpPacket(const char *data, size_t size) { | ||||
|   if (rtp_data_receiver_) { | ||||
|     rtp_data_receiver_->InsertRtpPacket(RtpPacket((uint8_t *)data, size)); | ||||
|   } | ||||
|  | ||||
|   return -1; | ||||
| } | ||||
| @@ -7,12 +7,29 @@ | ||||
| #ifndef _DATA_CHANNEL_RECEIVE_H_ | ||||
| #define _DATA_CHANNEL_RECEIVE_H_ | ||||
|  | ||||
| #include "ice_agent.h" | ||||
| #include "rtp_codec.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(RtpPacket::PAYLOAD_TYPE payload_type); | ||||
|   void Destroy(); | ||||
|   int OnReceiveRtpPacket(const char *data, size_t size); | ||||
|  | ||||
|  private: | ||||
|   std::shared_ptr<IceAgent> ice_agent_ = nullptr; | ||||
|   std::shared_ptr<IOStatistics> ice_io_statistics_ = nullptr; | ||||
|   std::unique_ptr<RtpCodec> data_rtp_codec_ = nullptr; | ||||
|   std::unique_ptr<RtpDataReceiver> rtp_data_receiver_ = nullptr; | ||||
|   std::function<void(const char *, size_t)> on_receive_data_ = nullptr; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
| @@ -1 +1,58 @@ | ||||
| #include "data_channel_send.h" | ||||
| #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(RtpPacket::PAYLOAD_TYPE payload_type) { | ||||
|   data_rtp_codec_ = std::make_unique<RtpCodec>(payload_type); | ||||
|  | ||||
|   rtp_data_sender_ = std::make_unique<RtpDataSender>(ice_io_statistics_); | ||||
|   rtp_data_sender_->SetSendDataFunc( | ||||
|       [this](const char *data, size_t size) -> int { | ||||
|         if (!ice_agent_) { | ||||
|           LOG_ERROR("ice_agent_ is nullptr"); | ||||
|           return -1; | ||||
|         } | ||||
|  | ||||
|         auto ice_state = ice_agent_->GetIceState(); | ||||
|  | ||||
|         if (ice_state != NICE_COMPONENT_STATE_CONNECTED && | ||||
|             ice_state != NICE_COMPONENT_STATE_READY) { | ||||
|           LOG_ERROR("Ice is not connected, state = [{}]", | ||||
|                     nice_component_state_to_string(ice_state)); | ||||
|           return -2; | ||||
|         } | ||||
|  | ||||
|         ice_io_statistics_->UpdateDataOutboundBytes((uint32_t)size); | ||||
|         return ice_agent_->Send(data, size); | ||||
|       }); | ||||
|  | ||||
|   rtp_data_sender_->Start(); | ||||
| } | ||||
|  | ||||
| void DataChannelSend::Destroy() { | ||||
|   if (rtp_data_sender_) { | ||||
|     rtp_data_sender_->Stop(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| int DataChannelSend::SendData(const char *data, size_t size) { | ||||
|   std::vector<RtpPacket> packets; | ||||
|  | ||||
|   if (rtp_data_sender_) { | ||||
|     if (data_rtp_codec_) { | ||||
|       data_rtp_codec_->Encode((uint8_t *)data, (uint32_t)size, packets); | ||||
|       rtp_data_sender_->Enqueue(packets); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
| @@ -7,12 +7,27 @@ | ||||
| #ifndef _DATA_CHANNEL_SEND_H_ | ||||
| #define _DATA_CHANNEL_SEND_H_ | ||||
|  | ||||
| #include "ice_agent.h" | ||||
| #include "rtp_codec.h" | ||||
| #include "rtp_data_sender.h" | ||||
|  | ||||
| class DataChannelSend { | ||||
|  public: | ||||
|   DataChannelSend(); | ||||
|   DataChannelSend(std::shared_ptr<IceAgent> ice_agent, | ||||
|                   std::shared_ptr<IOStatistics> ice_io_statistics); | ||||
|   ~DataChannelSend(); | ||||
|  | ||||
|  public: | ||||
|   void Initialize(RtpPacket::PAYLOAD_TYPE payload_type); | ||||
|   void Destroy(); | ||||
|   int SendData(const char *data, size_t size); | ||||
|  | ||||
|  private: | ||||
|   std::shared_ptr<IceAgent> ice_agent_ = nullptr; | ||||
|   std::shared_ptr<IOStatistics> ice_io_statistics_ = nullptr; | ||||
|   std::unique_ptr<RtpCodec> data_rtp_codec_ = nullptr; | ||||
|   std::unique_ptr<RtpDataSender> rtp_data_sender_ = nullptr; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
| @@ -1 +1,59 @@ | ||||
| #include "video_channel_receive.h" | ||||
| #include "video_channel_receive.h" | ||||
|  | ||||
| #include "log.h" | ||||
|  | ||||
| VideoChannelReceive::VideoChannelReceive() {} | ||||
|  | ||||
| VideoChannelReceive::VideoChannelReceive( | ||||
|     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) {} | ||||
|  | ||||
| VideoChannelReceive::~VideoChannelReceive() {} | ||||
|  | ||||
| void VideoChannelReceive::Initialize(RtpPacket::PAYLOAD_TYPE payload_type) { | ||||
|   video_rtp_codec_ = std::make_unique<RtpCodec>(payload_type); | ||||
|   rtp_video_receiver_ = std::make_unique<RtpVideoReceiver>(ice_io_statistics_); | ||||
|  | ||||
|   rtp_video_receiver_->SetOnReceiveCompleteFrame( | ||||
|       [this](VideoFrame &video_frame) -> void { | ||||
|         ice_io_statistics_->UpdateVideoInboundBytes( | ||||
|             (uint32_t)video_frame.Size()); | ||||
|         on_receive_complete_frame_(video_frame); | ||||
|       }); | ||||
|  | ||||
|   rtp_video_receiver_->SetSendDataFunc( | ||||
|       [this](const char *data, size_t size) -> int { | ||||
|         if (!ice_agent_) { | ||||
|           LOG_ERROR("ice_agent_ is nullptr"); | ||||
|           return -1; | ||||
|         } | ||||
|  | ||||
|         auto ice_state = ice_agent_->GetIceState(); | ||||
|  | ||||
|         if (ice_state != NICE_COMPONENT_STATE_CONNECTED && | ||||
|             ice_state != NICE_COMPONENT_STATE_READY) { | ||||
|           LOG_ERROR("Ice is not connected, state = [{}]", | ||||
|                     nice_component_state_to_string(ice_state)); | ||||
|           return -2; | ||||
|         } | ||||
|  | ||||
|         ice_io_statistics_->UpdateVideoInboundBytes((uint32_t)size); | ||||
|         return ice_agent_->Send(data, size); | ||||
|       }); | ||||
|  | ||||
|   rtp_video_receiver_->Start(); | ||||
| } | ||||
|  | ||||
| void VideoChannelReceive::Destroy() {} | ||||
|  | ||||
| int VideoChannelReceive::OnReceiveRtpPacket(const char *data, size_t size) { | ||||
|   if (rtp_video_receiver_) { | ||||
|     rtp_video_receiver_->InsertRtpPacket(RtpPacket((uint8_t *)data, size)); | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
| @@ -7,12 +7,32 @@ | ||||
| #ifndef _VIDEO_CHANNEL_RECEIVE_H_ | ||||
| #define _VIDEO_CHANNEL_RECEIVE_H_ | ||||
|  | ||||
| #include "ice_agent.h" | ||||
| #include "rtp_codec.h" | ||||
| #include "rtp_video_receiver.h" | ||||
|  | ||||
| class VideoChannelReceive { | ||||
|  public: | ||||
|   VideoChannelReceive(); | ||||
|   VideoChannelReceive( | ||||
|       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(RtpPacket::PAYLOAD_TYPE payload_type); | ||||
|   void Destroy(); | ||||
|  | ||||
|   int OnReceiveRtpPacket(const char *data, size_t size); | ||||
|  | ||||
|  private: | ||||
|   std::shared_ptr<IceAgent> ice_agent_ = nullptr; | ||||
|   std::shared_ptr<IOStatistics> ice_io_statistics_ = nullptr; | ||||
|   std::unique_ptr<RtpCodec> video_rtp_codec_ = nullptr; | ||||
|   std::unique_ptr<RtpVideoReceiver> rtp_video_receiver_ = nullptr; | ||||
|   std::function<void(VideoFrame &)> on_receive_complete_frame_ = nullptr; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
| @@ -1,11 +1,18 @@ | ||||
| #include "video_channel_send.h" | ||||
|  | ||||
| #include "log.h" | ||||
|  | ||||
| VideoChannelSend::VideoChannelSend() {} | ||||
|  | ||||
| VideoChannelSend::~VideoChannelSend() {} | ||||
|  | ||||
| void VideoChannelSend::Initialize(RtpPacket::PAYLOAD_TYPE negotiated_video_pt) { | ||||
|   video_rtp_codec_ = std::make_unique<RtpCodec>(negotiated_video_pt); | ||||
| VideoChannelSend::VideoChannelSend( | ||||
|     std::shared_ptr<IceAgent> ice_agent, | ||||
|     std::shared_ptr<IOStatistics> ice_io_statistics) | ||||
|     : ice_agent_(ice_agent), ice_io_statistics_(ice_io_statistics){}; | ||||
|  | ||||
| void VideoChannelSend::Initialize(RtpPacket::PAYLOAD_TYPE payload_type) { | ||||
|   video_rtp_codec_ = std::make_unique<RtpCodec>(payload_type); | ||||
|  | ||||
|   rtp_video_sender_ = std::make_unique<RtpVideoSender>(ice_io_statistics_); | ||||
|   rtp_video_sender_->SetSendDataFunc( | ||||
| @@ -15,10 +22,12 @@ void VideoChannelSend::Initialize(RtpPacket::PAYLOAD_TYPE negotiated_video_pt) { | ||||
|           return -1; | ||||
|         } | ||||
|  | ||||
|         if (state_ != NICE_COMPONENT_STATE_CONNECTED && | ||||
|             state_ != NICE_COMPONENT_STATE_READY) { | ||||
|         auto ice_state = ice_agent_->GetIceState(); | ||||
|  | ||||
|         if (ice_state != NICE_COMPONENT_STATE_CONNECTED && | ||||
|             ice_state != NICE_COMPONENT_STATE_READY) { | ||||
|           LOG_ERROR("Ice is not connected, state = [{}]", | ||||
|                     nice_component_state_to_string(state_)); | ||||
|                     nice_component_state_to_string(ice_state)); | ||||
|           return -2; | ||||
|         } | ||||
|  | ||||
| @@ -35,13 +44,11 @@ void VideoChannelSend::Destroy() { | ||||
|   } | ||||
| } | ||||
|  | ||||
| int VideoChannelSend::SendVideo(char *encoded_frame, size_t size) { | ||||
| int VideoChannelSend::SendVideo(char *data, size_t size) { | ||||
|   std::vector<RtpPacket> packets; | ||||
|   if (rtp_video_sender_) { | ||||
|     if (video_rtp_codec_) { | ||||
|       video_rtp_codec_->Encode( | ||||
|           static_cast<RtpCodec::VideoFrameType>(frame_type), | ||||
|           (uint8_t *)encoded_frame, (uint32_t)size, packets); | ||||
|       video_rtp_codec_->Encode((uint8_t *)data, (uint32_t)size, packets); | ||||
|     } | ||||
|     rtp_video_sender_->Enqueue(packets); | ||||
|   } | ||||
|   | ||||
| @@ -7,21 +7,26 @@ | ||||
| #ifndef _VIDEO_CHANNEL_SEND_H_ | ||||
| #define _VIDEO_CHANNEL_SEND_H_ | ||||
|  | ||||
| #include "ice_agent.h" | ||||
| #include "rtp_codec.h" | ||||
| #include "rtp_video_sender.h" | ||||
|  | ||||
| class VideoChannelSend { | ||||
|  public: | ||||
|   VideoChannelSend(); | ||||
|   VideoChannelSend(std::shared_ptr<IceAgent> ice_agent, | ||||
|                    std::shared_ptr<IOStatistics> ice_io_statistics); | ||||
|   ~VideoChannelSend(); | ||||
|  | ||||
|  public: | ||||
|   void Initialize(RtpPacket::PAYLOAD_TYPE negotiated_video_pt); | ||||
|   void Initialize(RtpPacket::PAYLOAD_TYPE payload_type); | ||||
|   void Destroy(); | ||||
|  | ||||
|   int SendVideo(char *encoded_frame, size_t size); | ||||
|   int SendVideo(char *data, size_t size); | ||||
|  | ||||
|  private: | ||||
|   std::shared_ptr<IceAgent> ice_agent_ = nullptr; | ||||
|   std::shared_ptr<IOStatistics> ice_io_statistics_ = nullptr; | ||||
|   std::unique_ptr<RtpCodec> video_rtp_codec_ = nullptr; | ||||
|   std::unique_ptr<RtpVideoSender> rtp_video_sender_ = nullptr; | ||||
| }; | ||||
|   | ||||
| @@ -55,6 +55,310 @@ RtpCodec::~RtpCodec() { | ||||
|   // } | ||||
| } | ||||
|  | ||||
| // void RtpCodec::Encode(uint8_t* buffer, uint32_t size, | ||||
| //                       std::vector<RtpPacket>& packets) { | ||||
| //   if (RtpPacket::PAYLOAD_TYPE::H264 == payload_type_) { | ||||
| //     if (fec_enable_ && IsKeyFrame((const uint8_t*)buffer, size)) { | ||||
| //       uint8_t** fec_packets = fec_encoder_.Encode((const char*)buffer, size); | ||||
| //       if (nullptr == fec_packets) { | ||||
| //         LOG_ERROR("Invalid fec_packets"); | ||||
| //         return; | ||||
| //       } | ||||
| //       uint8_t num_of_total_packets = 0; | ||||
| //       uint8_t num_of_source_packets = 0; | ||||
| //       unsigned int last_packet_size = 0; | ||||
| //       fec_encoder_.GetFecPacketsParams(size, num_of_total_packets, | ||||
| //                                        num_of_source_packets, | ||||
| //                                        last_packet_size); | ||||
|  | ||||
| //       timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>( | ||||
| //                        std::chrono::system_clock::now().time_since_epoch()) | ||||
| //                        .count(); | ||||
|  | ||||
| //       for (uint8_t index = 0; index < num_of_total_packets; index++) { | ||||
| //         RtpPacket rtp_packet; | ||||
| //         if (index < num_of_source_packets) { | ||||
| //           rtp_packet.SetVerion(version_); | ||||
| //           rtp_packet.SetHasPadding(has_padding_); | ||||
| //           rtp_packet.SetHasExtension(has_extension_); | ||||
| //           rtp_packet.SetMarker((index == (num_of_source_packets - 1)) ? 1 : | ||||
| //           0); | ||||
| //           rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE::H264_FEC_SOURCE); | ||||
| //           rtp_packet.SetSequenceNumber(sequence_number_++); | ||||
| //           rtp_packet.SetTimestamp(timestamp_); | ||||
| //           rtp_packet.SetSsrc(ssrc_); | ||||
|  | ||||
| //           if (!csrcs_.empty()) { | ||||
| //             rtp_packet.SetCsrcs(csrcs_); | ||||
| //           } | ||||
|  | ||||
| //           if (has_extension_) { | ||||
| //             rtp_packet.SetExtensionProfile(extension_profile_); | ||||
| //             rtp_packet.SetExtensionData(extension_data_, extension_len_); | ||||
| //           } | ||||
|  | ||||
| //           RtpPacket::FU_INDICATOR fu_indicator; | ||||
| //           fu_indicator.forbidden_bit = 0; | ||||
| //           fu_indicator.nal_reference_idc = 0; | ||||
| //           fu_indicator.nal_unit_type = FU_A; | ||||
|  | ||||
| //           RtpPacket::FU_HEADER fu_header; | ||||
| //           fu_header.start = index == 0 ? 1 : 0; | ||||
| //           fu_header.end = index == num_of_source_packets - 1 ? 1 : 0; | ||||
| //           fu_header.remain_bit = 0; | ||||
| //           fu_header.nal_unit_type = FU_A; | ||||
|  | ||||
| //           rtp_packet.SetFuIndicator(fu_indicator); | ||||
| //           rtp_packet.SetFuHeader(fu_header); | ||||
|  | ||||
| //           if (index == num_of_source_packets - 1) { | ||||
| //             if (last_packet_size > 0) { | ||||
| //               rtp_packet.EncodeH264FecSource(fec_packets[index], | ||||
| //                                              last_packet_size, index, | ||||
| //                                              num_of_source_packets); | ||||
| //             } else { | ||||
| //               rtp_packet.EncodeH264FecSource(fec_packets[index], | ||||
| //               MAX_NALU_LEN, | ||||
| //                                              index, num_of_source_packets); | ||||
| //             } | ||||
| //           } else { | ||||
| //             rtp_packet.EncodeH264FecSource(fec_packets[index], MAX_NALU_LEN, | ||||
| //                                            index, num_of_source_packets); | ||||
| //           } | ||||
|  | ||||
| //         } else if (index >= num_of_source_packets && | ||||
| //                    index < num_of_total_packets) { | ||||
| //           rtp_packet.SetVerion(version_); | ||||
| //           rtp_packet.SetHasPadding(has_padding_); | ||||
| //           rtp_packet.SetHasExtension(has_extension_); | ||||
| //           rtp_packet.SetMarker(index == num_of_total_packets - 1 ? 1 : 0); | ||||
| //           rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE::H264_FEC_REPAIR); | ||||
| //           rtp_packet.SetSequenceNumber(sequence_number_++); | ||||
| //           rtp_packet.SetTimestamp(timestamp_); | ||||
| //           rtp_packet.SetSsrc(ssrc_); | ||||
|  | ||||
| //           if (!csrcs_.empty()) { | ||||
| //             rtp_packet.SetCsrcs(csrcs_); | ||||
| //           } | ||||
|  | ||||
| //           if (has_extension_) { | ||||
| //             rtp_packet.SetExtensionProfile(extension_profile_); | ||||
| //             rtp_packet.SetExtensionData(extension_data_, extension_len_); | ||||
| //           } | ||||
| //           rtp_packet.EncodeH264FecRepair(fec_packets[index], MAX_NALU_LEN, | ||||
| //                                          index, num_of_source_packets); | ||||
| //         } | ||||
| //         packets.emplace_back(rtp_packet); | ||||
|  | ||||
| //         // if (index < num_of_source_packets) { | ||||
| //         //   rtp_packet.EncodeH264Fua(fec_packets[index], MAX_NALU_LEN); | ||||
| //         //   packets.emplace_back(rtp_packet); | ||||
| //         // } | ||||
| //       } | ||||
|  | ||||
| //       fec_encoder_.ReleaseFecPackets(fec_packets, size); | ||||
| //       return; | ||||
| //     } | ||||
| //     if (size <= MAX_NALU_LEN) { | ||||
| //       RtpPacket rtp_packet; | ||||
| //       rtp_packet.SetVerion(version_); | ||||
| //       rtp_packet.SetHasPadding(has_padding_); | ||||
| //       rtp_packet.SetHasExtension(has_extension_); | ||||
| //       rtp_packet.SetMarker(1); | ||||
| //       rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_)); | ||||
| //       rtp_packet.SetSequenceNumber(sequence_number_++); | ||||
|  | ||||
| //       timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>( | ||||
| //                        std::chrono::system_clock::now().time_since_epoch()) | ||||
| //                        .count(); | ||||
| //       rtp_packet.SetTimestamp(timestamp_); | ||||
| //       rtp_packet.SetSsrc(ssrc_); | ||||
|  | ||||
| //       if (!csrcs_.empty()) { | ||||
| //         rtp_packet.SetCsrcs(csrcs_); | ||||
| //       } | ||||
|  | ||||
| //       if (has_extension_) { | ||||
| //         rtp_packet.SetExtensionProfile(extension_profile_); | ||||
| //         rtp_packet.SetExtensionData(extension_data_, extension_len_); | ||||
| //       } | ||||
|  | ||||
| //       RtpPacket::FU_INDICATOR fu_indicator; | ||||
| //       fu_indicator.forbidden_bit = 0; | ||||
| //       fu_indicator.nal_reference_idc = 1; | ||||
| //       fu_indicator.nal_unit_type = NALU; | ||||
| //       rtp_packet.SetFuIndicator(fu_indicator); | ||||
|  | ||||
| //       rtp_packet.EncodeH264Nalu(buffer, size); | ||||
| //       packets.emplace_back(rtp_packet); | ||||
|  | ||||
| //     } else { | ||||
| //       uint32_t last_packet_size = size % MAX_NALU_LEN; | ||||
| //       uint32_t packet_num = size / MAX_NALU_LEN + (last_packet_size ? 1 : 0); | ||||
| //       timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>( | ||||
| //                        std::chrono::system_clock::now().time_since_epoch()) | ||||
| //                        .count(); | ||||
|  | ||||
| //       for (uint32_t index = 0; index < packet_num; index++) { | ||||
| //         RtpPacket rtp_packet; | ||||
| //         rtp_packet.SetVerion(version_); | ||||
| //         rtp_packet.SetHasPadding(has_padding_); | ||||
| //         rtp_packet.SetHasExtension(has_extension_); | ||||
| //         rtp_packet.SetMarker(index == packet_num - 1 ? 1 : 0); | ||||
| //         rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_)); | ||||
| //         rtp_packet.SetSequenceNumber(sequence_number_++); | ||||
| //         rtp_packet.SetTimestamp(timestamp_); | ||||
| //         rtp_packet.SetSsrc(ssrc_); | ||||
|  | ||||
| //         if (!csrcs_.empty()) { | ||||
| //           rtp_packet.SetCsrcs(csrcs_); | ||||
| //         } | ||||
|  | ||||
| //         if (has_extension_) { | ||||
| //           rtp_packet.SetExtensionProfile(extension_profile_); | ||||
| //           rtp_packet.SetExtensionData(extension_data_, extension_len_); | ||||
| //         } | ||||
|  | ||||
| //         RtpPacket::FU_INDICATOR fu_indicator; | ||||
| //         fu_indicator.forbidden_bit = 0; | ||||
| //         fu_indicator.nal_reference_idc = 0; | ||||
| //         fu_indicator.nal_unit_type = FU_A; | ||||
|  | ||||
| //         RtpPacket::FU_HEADER fu_header; | ||||
| //         fu_header.start = index == 0 ? 1 : 0; | ||||
| //         fu_header.end = index == packet_num - 1 ? 1 : 0; | ||||
| //         fu_header.remain_bit = 0; | ||||
| //         fu_header.nal_unit_type = FU_A; | ||||
|  | ||||
| //         rtp_packet.SetFuIndicator(fu_indicator); | ||||
| //         rtp_packet.SetFuHeader(fu_header); | ||||
|  | ||||
| //         if (index == packet_num - 1 && last_packet_size > 0) { | ||||
| //           rtp_packet.EncodeH264Fua(buffer + index * MAX_NALU_LEN, | ||||
| //                                    last_packet_size); | ||||
| //         } else { | ||||
| //           rtp_packet.EncodeH264Fua(buffer + index * MAX_NALU_LEN, | ||||
| //           MAX_NALU_LEN); | ||||
| //         } | ||||
| //         packets.emplace_back(rtp_packet); | ||||
| //       } | ||||
| //     } | ||||
| //   } else if (RtpPacket::PAYLOAD_TYPE::AV1 == payload_type_) { | ||||
| //     std::vector<Obu> obus = ParseObus(buffer, size); | ||||
| //     LOG_ERROR("Total size = [{}]", size); | ||||
| //     for (int i = 0; i < obus.size(); i++) { | ||||
| //       LOG_ERROR("[{}] Obu size = [{}], Obu type [{}]", i, obus[i].size, | ||||
| //                 ObuTypeToString((OBU_TYPE)ObuType(obus[i].header))); | ||||
| //       if (obus[i].size <= MAX_NALU_LEN) { | ||||
| //         RtpPacket rtp_packet; | ||||
| //         rtp_packet.SetVerion(version_); | ||||
| //         rtp_packet.SetHasPadding(has_padding_); | ||||
| //         rtp_packet.SetHasExtension(has_extension_); | ||||
| //         rtp_packet.SetMarker(1); | ||||
| //         rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_)); | ||||
| //         rtp_packet.SetSequenceNumber(sequence_number_++); | ||||
|  | ||||
| //         timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>( | ||||
| //                          std::chrono::system_clock::now().time_since_epoch()) | ||||
| //                          .count(); | ||||
| //         rtp_packet.SetTimestamp(timestamp_); | ||||
| //         rtp_packet.SetSsrc(ssrc_); | ||||
|  | ||||
| //         if (!csrcs_.empty()) { | ||||
| //           rtp_packet.SetCsrcs(csrcs_); | ||||
| //         } | ||||
|  | ||||
| //         if (has_extension_) { | ||||
| //           rtp_packet.SetExtensionProfile(extension_profile_); | ||||
| //           rtp_packet.SetExtensionData(extension_data_, extension_len_); | ||||
| //         } | ||||
|  | ||||
| //         rtp_packet.SetAv1AggrHeader(0, 0, 1, 0); | ||||
|  | ||||
| //         rtp_packet.EncodeAv1(obus[i].payload.data(), obus[i].payload.size()); | ||||
| //         packets.emplace_back(rtp_packet); | ||||
| //       } else { | ||||
| //         uint32_t last_packet_size = obus[i].payload.size() % MAX_NALU_LEN; | ||||
| //         size_t packet_num = | ||||
| //             obus[i].payload.size() / MAX_NALU_LEN + (last_packet_size ? 1 : | ||||
| //             0); | ||||
| //         timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>( | ||||
| //                          std::chrono::system_clock::now().time_since_epoch()) | ||||
| //                          .count(); | ||||
| //         for (uint32_t index = 0; index < packet_num; index++) { | ||||
| //           RtpPacket rtp_packet; | ||||
| //           rtp_packet.SetVerion(version_); | ||||
| //           rtp_packet.SetHasPadding(has_padding_); | ||||
| //           rtp_packet.SetHasExtension(has_extension_); | ||||
| //           rtp_packet.SetMarker(index == packet_num - 1 ? 1 : 0); | ||||
| //           rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_)); | ||||
| //           rtp_packet.SetSequenceNumber(sequence_number_++); | ||||
| //           rtp_packet.SetTimestamp(timestamp_); | ||||
| //           rtp_packet.SetSsrc(ssrc_); | ||||
| //           if (!csrcs_.empty()) { | ||||
| //             rtp_packet.SetCsrcs(csrcs_); | ||||
| //           } | ||||
| //           if (has_extension_) { | ||||
| //             rtp_packet.SetExtensionProfile(extension_profile_); | ||||
| //             rtp_packet.SetExtensionData(extension_data_, extension_len_); | ||||
| //           } | ||||
|  | ||||
| //           int z = index != 0 ? 1 : 0; | ||||
| //           int y = index != packet_num - 1 ? 1 : 0; | ||||
| //           int w = 1; | ||||
| //           int n = 0; | ||||
| //           rtp_packet.SetAv1AggrHeader(z, y, w, n); | ||||
|  | ||||
| //           if (index == packet_num - 1 && last_packet_size > 0) { | ||||
| //             rtp_packet.EncodeAv1(obus[i].payload.data() + index * | ||||
| //             MAX_NALU_LEN, | ||||
| //                                  last_packet_size); | ||||
| //           } else { | ||||
| //             rtp_packet.EncodeAv1(obus[i].payload.data() + index * | ||||
| //             MAX_NALU_LEN, | ||||
| //                                  MAX_NALU_LEN); | ||||
| //           } | ||||
| //           packets.emplace_back(rtp_packet); | ||||
| //         } | ||||
| //       } | ||||
| //     } | ||||
| //   } else if (RtpPacket::PAYLOAD_TYPE::OPUS == payload_type_) { | ||||
| //     RtpPacket rtp_packet; | ||||
| //     rtp_packet.SetVerion(version_); | ||||
| //     rtp_packet.SetHasPadding(has_padding_); | ||||
| //     rtp_packet.SetHasExtension(has_extension_); | ||||
| //     rtp_packet.SetMarker(1); | ||||
| //     rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_)); | ||||
| //     rtp_packet.SetSequenceNumber(sequence_number_++); | ||||
|  | ||||
| //     timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>( | ||||
| //                      std::chrono::system_clock::now().time_since_epoch()) | ||||
| //                      .count(); | ||||
| //     rtp_packet.SetTimestamp(timestamp_); | ||||
| //     rtp_packet.SetSsrc(ssrc_); | ||||
|  | ||||
| //     rtp_packet.Encode(buffer, size); | ||||
| //     packets.emplace_back(rtp_packet); | ||||
| //   } else if (RtpPacket::PAYLOAD_TYPE::DATA == payload_type_) { | ||||
| //     RtpPacket rtp_packet; | ||||
| //     rtp_packet.SetVerion(version_); | ||||
| //     rtp_packet.SetHasPadding(has_padding_); | ||||
| //     rtp_packet.SetHasExtension(has_extension_); | ||||
| //     rtp_packet.SetMarker(1); | ||||
| //     rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_)); | ||||
| //     rtp_packet.SetSequenceNumber(sequence_number_++); | ||||
|  | ||||
| //     timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>( | ||||
| //                      std::chrono::system_clock::now().time_since_epoch()) | ||||
| //                      .count(); | ||||
| //     rtp_packet.SetTimestamp(timestamp_); | ||||
| //     rtp_packet.SetSsrc(ssrc_); | ||||
|  | ||||
| //     rtp_packet.Encode(buffer, size); | ||||
| //     packets.emplace_back(rtp_packet); | ||||
| //   } | ||||
| // } | ||||
|  | ||||
| void RtpCodec::Encode(uint8_t* buffer, uint32_t size, | ||||
|                       std::vector<RtpPacket>& packets) { | ||||
|   if (RtpPacket::PAYLOAD_TYPE::H264 == payload_type_) { | ||||
| @@ -74,303 +378,6 @@ void RtpCodec::Encode(uint8_t* buffer, uint32_t size, | ||||
|                        std::chrono::system_clock::now().time_since_epoch()) | ||||
|                        .count(); | ||||
|  | ||||
|       for (uint8_t index = 0; index < num_of_total_packets; index++) { | ||||
|         RtpPacket rtp_packet; | ||||
|         if (index < num_of_source_packets) { | ||||
|           rtp_packet.SetVerion(version_); | ||||
|           rtp_packet.SetHasPadding(has_padding_); | ||||
|           rtp_packet.SetHasExtension(has_extension_); | ||||
|           rtp_packet.SetMarker((index == (num_of_source_packets - 1)) ? 1 : 0); | ||||
|           rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE::H264_FEC_SOURCE); | ||||
|           rtp_packet.SetSequenceNumber(sequence_number_++); | ||||
|           rtp_packet.SetTimestamp(timestamp_); | ||||
|           rtp_packet.SetSsrc(ssrc_); | ||||
|  | ||||
|           if (!csrcs_.empty()) { | ||||
|             rtp_packet.SetCsrcs(csrcs_); | ||||
|           } | ||||
|  | ||||
|           if (has_extension_) { | ||||
|             rtp_packet.SetExtensionProfile(extension_profile_); | ||||
|             rtp_packet.SetExtensionData(extension_data_, extension_len_); | ||||
|           } | ||||
|  | ||||
|           RtpPacket::FU_INDICATOR fu_indicator; | ||||
|           fu_indicator.forbidden_bit = 0; | ||||
|           fu_indicator.nal_reference_idc = 0; | ||||
|           fu_indicator.nal_unit_type = FU_A; | ||||
|  | ||||
|           RtpPacket::FU_HEADER fu_header; | ||||
|           fu_header.start = index == 0 ? 1 : 0; | ||||
|           fu_header.end = index == num_of_source_packets - 1 ? 1 : 0; | ||||
|           fu_header.remain_bit = 0; | ||||
|           fu_header.nal_unit_type = FU_A; | ||||
|  | ||||
|           rtp_packet.SetFuIndicator(fu_indicator); | ||||
|           rtp_packet.SetFuHeader(fu_header); | ||||
|  | ||||
|           if (index == num_of_source_packets - 1) { | ||||
|             if (last_packet_size > 0) { | ||||
|               rtp_packet.EncodeH264FecSource(fec_packets[index], | ||||
|                                              last_packet_size, index, | ||||
|                                              num_of_source_packets); | ||||
|             } else { | ||||
|               rtp_packet.EncodeH264FecSource(fec_packets[index], MAX_NALU_LEN, | ||||
|                                              index, num_of_source_packets); | ||||
|             } | ||||
|           } else { | ||||
|             rtp_packet.EncodeH264FecSource(fec_packets[index], MAX_NALU_LEN, | ||||
|                                            index, num_of_source_packets); | ||||
|           } | ||||
|  | ||||
|         } else if (index >= num_of_source_packets && | ||||
|                    index < num_of_total_packets) { | ||||
|           rtp_packet.SetVerion(version_); | ||||
|           rtp_packet.SetHasPadding(has_padding_); | ||||
|           rtp_packet.SetHasExtension(has_extension_); | ||||
|           rtp_packet.SetMarker(index == num_of_total_packets - 1 ? 1 : 0); | ||||
|           rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE::H264_FEC_REPAIR); | ||||
|           rtp_packet.SetSequenceNumber(sequence_number_++); | ||||
|           rtp_packet.SetTimestamp(timestamp_); | ||||
|           rtp_packet.SetSsrc(ssrc_); | ||||
|  | ||||
|           if (!csrcs_.empty()) { | ||||
|             rtp_packet.SetCsrcs(csrcs_); | ||||
|           } | ||||
|  | ||||
|           if (has_extension_) { | ||||
|             rtp_packet.SetExtensionProfile(extension_profile_); | ||||
|             rtp_packet.SetExtensionData(extension_data_, extension_len_); | ||||
|           } | ||||
|           rtp_packet.EncodeH264FecRepair(fec_packets[index], MAX_NALU_LEN, | ||||
|                                          index, num_of_source_packets); | ||||
|         } | ||||
|         packets.emplace_back(rtp_packet); | ||||
|  | ||||
|         // if (index < num_of_source_packets) { | ||||
|         //   rtp_packet.EncodeH264Fua(fec_packets[index], MAX_NALU_LEN); | ||||
|         //   packets.emplace_back(rtp_packet); | ||||
|         // } | ||||
|       } | ||||
|  | ||||
|       fec_encoder_.ReleaseFecPackets(fec_packets, size); | ||||
|       return; | ||||
|     } | ||||
|     if (size <= MAX_NALU_LEN) { | ||||
|       RtpPacket rtp_packet; | ||||
|       rtp_packet.SetVerion(version_); | ||||
|       rtp_packet.SetHasPadding(has_padding_); | ||||
|       rtp_packet.SetHasExtension(has_extension_); | ||||
|       rtp_packet.SetMarker(1); | ||||
|       rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_)); | ||||
|       rtp_packet.SetSequenceNumber(sequence_number_++); | ||||
|  | ||||
|       timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>( | ||||
|                        std::chrono::system_clock::now().time_since_epoch()) | ||||
|                        .count(); | ||||
|       rtp_packet.SetTimestamp(timestamp_); | ||||
|       rtp_packet.SetSsrc(ssrc_); | ||||
|  | ||||
|       if (!csrcs_.empty()) { | ||||
|         rtp_packet.SetCsrcs(csrcs_); | ||||
|       } | ||||
|  | ||||
|       if (has_extension_) { | ||||
|         rtp_packet.SetExtensionProfile(extension_profile_); | ||||
|         rtp_packet.SetExtensionData(extension_data_, extension_len_); | ||||
|       } | ||||
|  | ||||
|       RtpPacket::FU_INDICATOR fu_indicator; | ||||
|       fu_indicator.forbidden_bit = 0; | ||||
|       fu_indicator.nal_reference_idc = 1; | ||||
|       fu_indicator.nal_unit_type = NALU; | ||||
|       rtp_packet.SetFuIndicator(fu_indicator); | ||||
|  | ||||
|       rtp_packet.EncodeH264Nalu(buffer, size); | ||||
|       packets.emplace_back(rtp_packet); | ||||
|  | ||||
|     } else { | ||||
|       uint32_t last_packet_size = size % MAX_NALU_LEN; | ||||
|       uint32_t packet_num = size / MAX_NALU_LEN + (last_packet_size ? 1 : 0); | ||||
|       timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>( | ||||
|                        std::chrono::system_clock::now().time_since_epoch()) | ||||
|                        .count(); | ||||
|  | ||||
|       for (uint32_t index = 0; index < packet_num; index++) { | ||||
|         RtpPacket rtp_packet; | ||||
|         rtp_packet.SetVerion(version_); | ||||
|         rtp_packet.SetHasPadding(has_padding_); | ||||
|         rtp_packet.SetHasExtension(has_extension_); | ||||
|         rtp_packet.SetMarker(index == packet_num - 1 ? 1 : 0); | ||||
|         rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_)); | ||||
|         rtp_packet.SetSequenceNumber(sequence_number_++); | ||||
|         rtp_packet.SetTimestamp(timestamp_); | ||||
|         rtp_packet.SetSsrc(ssrc_); | ||||
|  | ||||
|         if (!csrcs_.empty()) { | ||||
|           rtp_packet.SetCsrcs(csrcs_); | ||||
|         } | ||||
|  | ||||
|         if (has_extension_) { | ||||
|           rtp_packet.SetExtensionProfile(extension_profile_); | ||||
|           rtp_packet.SetExtensionData(extension_data_, extension_len_); | ||||
|         } | ||||
|  | ||||
|         RtpPacket::FU_INDICATOR fu_indicator; | ||||
|         fu_indicator.forbidden_bit = 0; | ||||
|         fu_indicator.nal_reference_idc = 0; | ||||
|         fu_indicator.nal_unit_type = FU_A; | ||||
|  | ||||
|         RtpPacket::FU_HEADER fu_header; | ||||
|         fu_header.start = index == 0 ? 1 : 0; | ||||
|         fu_header.end = index == packet_num - 1 ? 1 : 0; | ||||
|         fu_header.remain_bit = 0; | ||||
|         fu_header.nal_unit_type = FU_A; | ||||
|  | ||||
|         rtp_packet.SetFuIndicator(fu_indicator); | ||||
|         rtp_packet.SetFuHeader(fu_header); | ||||
|  | ||||
|         if (index == packet_num - 1 && last_packet_size > 0) { | ||||
|           rtp_packet.EncodeH264Fua(buffer + index * MAX_NALU_LEN, | ||||
|                                    last_packet_size); | ||||
|         } else { | ||||
|           rtp_packet.EncodeH264Fua(buffer + index * MAX_NALU_LEN, MAX_NALU_LEN); | ||||
|         } | ||||
|         packets.emplace_back(rtp_packet); | ||||
|       } | ||||
|     } | ||||
|   } else if (RtpPacket::PAYLOAD_TYPE::AV1 == payload_type_) { | ||||
|     std::vector<Obu> obus = ParseObus(buffer, size); | ||||
|     LOG_ERROR("Total size = [{}]", size); | ||||
|     for (int i = 0; i < obus.size(); i++) { | ||||
|       LOG_ERROR("[{}] Obu size = [{}], Obu type [{}]", i, obus[i].size, | ||||
|                 ObuTypeToString((OBU_TYPE)ObuType(obus[i].header))); | ||||
|       if (obus[i].size <= MAX_NALU_LEN) { | ||||
|         RtpPacket rtp_packet; | ||||
|         rtp_packet.SetVerion(version_); | ||||
|         rtp_packet.SetHasPadding(has_padding_); | ||||
|         rtp_packet.SetHasExtension(has_extension_); | ||||
|         rtp_packet.SetMarker(1); | ||||
|         rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_)); | ||||
|         rtp_packet.SetSequenceNumber(sequence_number_++); | ||||
|  | ||||
|         timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>( | ||||
|                          std::chrono::system_clock::now().time_since_epoch()) | ||||
|                          .count(); | ||||
|         rtp_packet.SetTimestamp(timestamp_); | ||||
|         rtp_packet.SetSsrc(ssrc_); | ||||
|  | ||||
|         if (!csrcs_.empty()) { | ||||
|           rtp_packet.SetCsrcs(csrcs_); | ||||
|         } | ||||
|  | ||||
|         if (has_extension_) { | ||||
|           rtp_packet.SetExtensionProfile(extension_profile_); | ||||
|           rtp_packet.SetExtensionData(extension_data_, extension_len_); | ||||
|         } | ||||
|  | ||||
|         rtp_packet.SetAv1AggrHeader(0, 0, 1, 0); | ||||
|  | ||||
|         rtp_packet.EncodeAv1(obus[i].payload.data(), obus[i].payload.size()); | ||||
|         packets.emplace_back(rtp_packet); | ||||
|       } else { | ||||
|         uint32_t last_packet_size = obus[i].payload.size() % MAX_NALU_LEN; | ||||
|         size_t packet_num = | ||||
|             obus[i].payload.size() / MAX_NALU_LEN + (last_packet_size ? 1 : 0); | ||||
|         timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>( | ||||
|                          std::chrono::system_clock::now().time_since_epoch()) | ||||
|                          .count(); | ||||
|         for (uint32_t index = 0; index < packet_num; index++) { | ||||
|           RtpPacket rtp_packet; | ||||
|           rtp_packet.SetVerion(version_); | ||||
|           rtp_packet.SetHasPadding(has_padding_); | ||||
|           rtp_packet.SetHasExtension(has_extension_); | ||||
|           rtp_packet.SetMarker(index == packet_num - 1 ? 1 : 0); | ||||
|           rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_)); | ||||
|           rtp_packet.SetSequenceNumber(sequence_number_++); | ||||
|           rtp_packet.SetTimestamp(timestamp_); | ||||
|           rtp_packet.SetSsrc(ssrc_); | ||||
|           if (!csrcs_.empty()) { | ||||
|             rtp_packet.SetCsrcs(csrcs_); | ||||
|           } | ||||
|           if (has_extension_) { | ||||
|             rtp_packet.SetExtensionProfile(extension_profile_); | ||||
|             rtp_packet.SetExtensionData(extension_data_, extension_len_); | ||||
|           } | ||||
|  | ||||
|           int z = index != 0 ? 1 : 0; | ||||
|           int y = index != packet_num - 1 ? 1 : 0; | ||||
|           int w = 1; | ||||
|           int n = 0; | ||||
|           rtp_packet.SetAv1AggrHeader(z, y, w, n); | ||||
|  | ||||
|           if (index == packet_num - 1 && last_packet_size > 0) { | ||||
|             rtp_packet.EncodeAv1(obus[i].payload.data() + index * MAX_NALU_LEN, | ||||
|                                  last_packet_size); | ||||
|           } else { | ||||
|             rtp_packet.EncodeAv1(obus[i].payload.data() + index * MAX_NALU_LEN, | ||||
|                                  MAX_NALU_LEN); | ||||
|           } | ||||
|           packets.emplace_back(rtp_packet); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } else if (RtpPacket::PAYLOAD_TYPE::OPUS == payload_type_) { | ||||
|     RtpPacket rtp_packet; | ||||
|     rtp_packet.SetVerion(version_); | ||||
|     rtp_packet.SetHasPadding(has_padding_); | ||||
|     rtp_packet.SetHasExtension(has_extension_); | ||||
|     rtp_packet.SetMarker(1); | ||||
|     rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_)); | ||||
|     rtp_packet.SetSequenceNumber(sequence_number_++); | ||||
|  | ||||
|     timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>( | ||||
|                      std::chrono::system_clock::now().time_since_epoch()) | ||||
|                      .count(); | ||||
|     rtp_packet.SetTimestamp(timestamp_); | ||||
|     rtp_packet.SetSsrc(ssrc_); | ||||
|  | ||||
|     rtp_packet.Encode(buffer, size); | ||||
|     packets.emplace_back(rtp_packet); | ||||
|   } else if (RtpPacket::PAYLOAD_TYPE::DATA == payload_type_) { | ||||
|     RtpPacket rtp_packet; | ||||
|     rtp_packet.SetVerion(version_); | ||||
|     rtp_packet.SetHasPadding(has_padding_); | ||||
|     rtp_packet.SetHasExtension(has_extension_); | ||||
|     rtp_packet.SetMarker(1); | ||||
|     rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_)); | ||||
|     rtp_packet.SetSequenceNumber(sequence_number_++); | ||||
|  | ||||
|     timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>( | ||||
|                      std::chrono::system_clock::now().time_since_epoch()) | ||||
|                      .count(); | ||||
|     rtp_packet.SetTimestamp(timestamp_); | ||||
|     rtp_packet.SetSsrc(ssrc_); | ||||
|  | ||||
|     rtp_packet.Encode(buffer, size); | ||||
|     packets.emplace_back(rtp_packet); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void RtpCodec::Encode(VideoFrameType frame_type, uint8_t* buffer, uint32_t size, | ||||
|                       std::vector<RtpPacket>& packets) { | ||||
|   if (RtpPacket::PAYLOAD_TYPE::H264 == payload_type_) { | ||||
|     if (fec_enable_ && IsKeyFrame((const uint8_t*)buffer, size)) { | ||||
|       uint8_t** fec_packets = fec_encoder_.Encode((const char*)buffer, size); | ||||
|       if (nullptr == fec_packets) { | ||||
|         LOG_ERROR("Invalid fec_packets"); | ||||
|         return; | ||||
|       } | ||||
|       uint8_t num_of_total_packets = 0; | ||||
|       uint8_t num_of_source_packets = 0; | ||||
|       unsigned int last_packet_size = 0; | ||||
|       fec_encoder_.GetFecPacketsParams(size, num_of_total_packets, | ||||
|                                        num_of_source_packets, last_packet_size); | ||||
|  | ||||
|       timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>( | ||||
|                        std::chrono::system_clock::now().time_since_epoch()) | ||||
|                        .count(); | ||||
|  | ||||
|       for (uint8_t index = 0; index < num_of_total_packets; index++) { | ||||
|         RtpPacket rtp_packet; | ||||
|         if (index < num_of_source_packets) { | ||||
| @@ -595,10 +602,7 @@ void RtpCodec::Encode(VideoFrameType frame_type, uint8_t* buffer, uint32_t size, | ||||
|           int z = index != 0 ? 1 : 0; | ||||
|           int y = index != packet_num - 1 ? 1 : 0; | ||||
|           int w = 1; | ||||
|           int n = (frame_type == VideoFrameType::kVideoFrameKey) && | ||||
|                           (ObuType(obus[i].header) == kObuTypeSequenceHeader) | ||||
|                       ? 1 | ||||
|                       : 0; | ||||
|           int n = (ObuType(obus[i].header) == kObuTypeSequenceHeader) ? 1 : 0; | ||||
|           rtp_packet.SetAv1AggrHeader(z, y, w, n); | ||||
|           if (index == packet_num - 1 && last_packet_size > 0) { | ||||
|             rtp_packet.EncodeAv1(obus[i].payload.data() + index * MAX_NALU_LEN, | ||||
|   | ||||
| @@ -23,8 +23,6 @@ class RtpCodec { | ||||
|  | ||||
|  public: | ||||
|   void Encode(uint8_t* buffer, uint32_t size, std::vector<RtpPacket>& packets); | ||||
|   void Encode(VideoFrameType frame_type, uint8_t* buffer, uint32_t size, | ||||
|               std::vector<RtpPacket>& packets); | ||||
|   size_t Decode(RtpPacket& packet, uint8_t* payload); | ||||
|  | ||||
|   //  protected: | ||||
|   | ||||
| @@ -62,11 +62,49 @@ int IceTransport::InitIceTransmission( | ||||
|     std::string &stun_ip, int stun_port, std::string &turn_ip, int turn_port, | ||||
|     std::string &turn_username, std::string &turn_password, | ||||
|     RtpPacket::PAYLOAD_TYPE video_codec_payload_type) { | ||||
|   ice_agent_ = std::make_unique<IceAgent>( | ||||
|       offer_peer_, use_trickle_ice_, use_reliable_ice_, enable_turn_, | ||||
|       force_turn_, stun_ip, stun_port, turn_ip, turn_port, turn_username, | ||||
|       turn_password); | ||||
|  | ||||
|   InitializeIOStatistics(); | ||||
|   InitializeChannels(video_codec_payload_type); | ||||
|  | ||||
|   ice_agent_->CreateIceAgent( | ||||
|       [](NiceAgent *agent, guint stream_id, guint component_id, | ||||
|          NiceComponentState state, gpointer user_ptr) { | ||||
|         static_cast<IceTransport *>(user_ptr)->OnIceStateChange( | ||||
|             agent, stream_id, component_id, state, user_ptr); | ||||
|       }, | ||||
|       [](NiceAgent *agent, guint stream_id, guint component_id, | ||||
|          gchar *foundation, gpointer user_ptr) { | ||||
|         static_cast<IceTransport *>(user_ptr)->OnNewLocalCandidate( | ||||
|             agent, stream_id, component_id, foundation, user_ptr); | ||||
|       }, | ||||
|       [](NiceAgent *agent, guint stream_id, gpointer user_ptr) { | ||||
|         static_cast<IceTransport *>(user_ptr)->OnGatheringDone(agent, stream_id, | ||||
|                                                                user_ptr); | ||||
|       }, | ||||
|       [](NiceAgent *agent, guint stream_id, guint component_id, | ||||
|          const char *lfoundation, const char *rfoundation, gpointer user_ptr) { | ||||
|         static_cast<IceTransport *>(user_ptr)->OnNewSelectedPair( | ||||
|             agent, stream_id, component_id, lfoundation, rfoundation, user_ptr); | ||||
|       }, | ||||
|       [](NiceAgent *agent, guint stream_id, guint component_id, guint size, | ||||
|          gchar *buffer, gpointer user_ptr) { | ||||
|         static_cast<IceTransport *>(user_ptr)->OnReceiveBuffer( | ||||
|             agent, stream_id, component_id, size, buffer, user_ptr); | ||||
|       }, | ||||
|       this); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| void IceTransport::InitializeIOStatistics() { | ||||
|   ice_io_statistics_ = std::make_unique<IOStatistics>( | ||||
|       [this](const IOStatistics::NetTrafficStats &net_traffic_stats) { | ||||
|         if (on_receive_net_status_report_) { | ||||
|           XNetTrafficStats xnet_traffic_stats; | ||||
|  | ||||
|           memcpy(&xnet_traffic_stats, &net_traffic_stats, | ||||
|                  sizeof(XNetTrafficStats)); | ||||
|           on_receive_net_status_report_( | ||||
| @@ -75,299 +113,180 @@ int IceTransport::InitIceTransmission( | ||||
|               remote_user_id_.size(), user_data_); | ||||
|         } | ||||
|       }); | ||||
| } | ||||
|  | ||||
| void IceTransport::InitializeChannels( | ||||
|     RtpPacket::PAYLOAD_TYPE video_codec_payload_type) { | ||||
|   video_codec_payload_type_ = video_codec_payload_type; | ||||
|  | ||||
|   rtp_video_receiver_ = std::make_unique<RtpVideoReceiver>(ice_io_statistics_); | ||||
|   // rr sender | ||||
|   rtp_video_receiver_->SetSendDataFunc( | ||||
|       [this](const char *data, size_t size) -> int { | ||||
|         if (!ice_agent_) { | ||||
|           LOG_ERROR("ice_agent_ is nullptr"); | ||||
|           return -1; | ||||
|         } | ||||
|   video_channel_send_ = | ||||
|       std::make_unique<VideoChannelSend>(ice_agent_, ice_io_statistics_); | ||||
|   audio_channel_send_ = | ||||
|       std::make_unique<AudioChannelSend>(ice_agent_, ice_io_statistics_); | ||||
|   data_channel_send_ = | ||||
|       std::make_unique<DataChannelSend>(ice_agent_, ice_io_statistics_); | ||||
|  | ||||
|         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; | ||||
|         } | ||||
|   video_channel_send_->Initialize(video_codec_payload_type_); | ||||
|   audio_channel_send_->Initialize(RtpPacket::PAYLOAD_TYPE::OPUS); | ||||
|   data_channel_send_->Initialize(RtpPacket::PAYLOAD_TYPE::DATA); | ||||
|  | ||||
|         return ice_agent_->Send(data, size); | ||||
|       }); | ||||
|   rtp_video_receiver_->SetOnReceiveCompleteFrame( | ||||
|       [this](VideoFrame &video_frame) -> void { | ||||
|         ice_io_statistics_->UpdateVideoInboundBytes( | ||||
|             (uint32_t)video_frame.Size()); | ||||
|         [[maybe_unused]] 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_); | ||||
|               } | ||||
|             }); | ||||
|   video_channel_receive_ = std::make_unique<VideoChannelReceive>( | ||||
|       ice_agent_, ice_io_statistics_, | ||||
|       [this](VideoFrame &video_frame) { OnReceiveCompleteFrame(video_frame); }); | ||||
|  | ||||
|   audio_channel_receive_ = std::make_unique<AudioChannelReceive>( | ||||
|       ice_agent_, ice_io_statistics_, [this](const char *data, size_t size) { | ||||
|         OnReceiveCompleteAudio(data, size); | ||||
|       }); | ||||
|  | ||||
|   rtp_video_receiver_->Start(); | ||||
|  | ||||
|   rtp_video_sender_ = std::make_unique<RtpVideoSender>(ice_io_statistics_); | ||||
|   rtp_video_sender_->SetSendDataFunc( | ||||
|       [this](const char *data, size_t size) -> int { | ||||
|         if (!ice_agent_) { | ||||
|           LOG_ERROR("ice_agent_ is nullptr"); | ||||
|           return -1; | ||||
|         } | ||||
|  | ||||
|         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; | ||||
|         } | ||||
|  | ||||
|         ice_io_statistics_->UpdateVideoOutboundBytes((uint32_t)size); | ||||
|         return ice_agent_->Send(data, size); | ||||
|   data_channel_receive_ = std::make_unique<DataChannelReceive>( | ||||
|       ice_agent_, ice_io_statistics_, [this](const char *data, size_t size) { | ||||
|         OnReceiveCompleteData(data, size); | ||||
|       }); | ||||
|  | ||||
|   rtp_video_sender_->Start(); | ||||
|   video_channel_receive_->Initialize(video_codec_payload_type_); | ||||
|   audio_channel_receive_->Initialize(RtpPacket::PAYLOAD_TYPE::OPUS); | ||||
|   data_channel_receive_->Initialize(RtpPacket::PAYLOAD_TYPE::DATA); | ||||
| } | ||||
|  | ||||
|   rtp_audio_receiver_ = std::make_unique<RtpAudioReceiver>(ice_io_statistics_); | ||||
|   // rr sender | ||||
|   rtp_audio_receiver_->SetSendDataFunc( | ||||
|       [this](const char *data, size_t size) -> int { | ||||
|         if (!ice_agent_) { | ||||
|           LOG_ERROR("ice_agent_ is nullptr"); | ||||
|           return -1; | ||||
| void IceTransport::OnIceStateChange(NiceAgent *agent, guint stream_id, | ||||
|                                     guint component_id, | ||||
|                                     NiceComponentState state, | ||||
|                                     gpointer user_ptr) { | ||||
|   if (!is_closed_) { | ||||
|     LOG_INFO("[{}->{}] state_change: {}", user_id_, remote_user_id_, | ||||
|              nice_component_state_to_string(state)); | ||||
|     state_ = state; | ||||
|  | ||||
|     if (state == NICE_COMPONENT_STATE_READY || | ||||
|         state == NICE_COMPONENT_STATE_CONNECTED) { | ||||
|       ice_io_statistics_->Start(); | ||||
|     } | ||||
|  | ||||
|     on_ice_status_change_(nice_component_state_to_string(state), | ||||
|                           remote_user_id_); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void IceTransport::OnNewLocalCandidate(NiceAgent *agent, guint stream_id, | ||||
|                                        guint component_id, gchar *foundation, | ||||
|                                        gpointer user_ptr) { | ||||
|   if (use_trickle_ice_) { | ||||
|     GSList *cands = | ||||
|         nice_agent_get_local_candidates(agent, stream_id, component_id); | ||||
|     NiceCandidate *cand; | ||||
|     for (GSList *i = cands; i; i = i->next) { | ||||
|       cand = (NiceCandidate *)i->data; | ||||
|       if (g_strcmp0(cand->foundation, foundation) == 0) { | ||||
|         new_local_candidate_ = | ||||
|             nice_agent_generate_local_candidate_sdp(agent, cand); | ||||
|  | ||||
|         json message = {{"type", "new_candidate"}, | ||||
|                         {"transmission_id", transmission_id_}, | ||||
|                         {"user_id", user_id_}, | ||||
|                         {"remote_user_id", remote_user_id_}, | ||||
|                         {"sdp", new_local_candidate_}}; | ||||
|  | ||||
|         if (ice_ws_transport_) { | ||||
|           ice_ws_transport_->Send(message.dump()); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|         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; | ||||
|         } | ||||
|     g_slist_free_full(cands, (GDestroyNotify)nice_candidate_free); | ||||
|   } | ||||
| } | ||||
|  | ||||
|         return ice_agent_->Send(data, size); | ||||
|       }); | ||||
|   rtp_audio_receiver_->SetOnReceiveData([this](const char *data, | ||||
|                                                size_t size) -> void { | ||||
|     ice_io_statistics_->UpdateAudioInboundBytes((uint32_t)size); | ||||
| void IceTransport::OnGatheringDone(NiceAgent *agent, guint stream_id, | ||||
|                                    gpointer user_ptr) { | ||||
|   LOG_INFO("[{}->{}] gather_done", user_id_, remote_user_id_); | ||||
|  | ||||
|     [[maybe_unused]] 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_); | ||||
|           } | ||||
|         }); | ||||
|   }); | ||||
|   if (!use_trickle_ice_) { | ||||
|     if (offer_peer_) { | ||||
|       SendOffer(); | ||||
|     } else { | ||||
|       SendAnswer(); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|   rtp_audio_sender_ = std::make_unique<RtpAudioSender>(ice_io_statistics_); | ||||
|   rtp_audio_sender_->SetSendDataFunc( | ||||
|       [this](const char *data, size_t size) -> int { | ||||
|         if (!ice_agent_) { | ||||
|           LOG_ERROR("ice_agent_ is nullptr"); | ||||
|           return -1; | ||||
|         } | ||||
| void IceTransport::OnNewSelectedPair(NiceAgent *agent, guint stream_id, | ||||
|                                      guint component_id, | ||||
|                                      const char *lfoundation, | ||||
|                                      const char *rfoundation, | ||||
|                                      gpointer user_ptr) { | ||||
|   LOG_INFO("new selected pair: [{}] [{}]", lfoundation, rfoundation); | ||||
|   NiceCandidate *local = nullptr; | ||||
|   NiceCandidate *remote = nullptr; | ||||
|   nice_agent_get_selected_pair(agent, stream_id, component_id, &local, &remote); | ||||
|   if (local->type == NICE_CANDIDATE_TYPE_RELAYED && | ||||
|       remote->type == NICE_CANDIDATE_TYPE_RELAYED) { | ||||
|     LOG_INFO("Traversal using relay server"); | ||||
|     traversal_type_ = TraversalType::TRelay; | ||||
|   } else { | ||||
|     LOG_INFO("Traversal using p2p"); | ||||
|     traversal_type_ = TraversalType::TP2P; | ||||
|   } | ||||
|   XNetTrafficStats net_traffic_stats; | ||||
|   memset(&net_traffic_stats, 0, sizeof(net_traffic_stats)); | ||||
|  | ||||
|         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; | ||||
|         } | ||||
|   on_receive_net_status_report_(user_id_.data(), user_id_.size(), | ||||
|                                 TraversalMode(traversal_type_), | ||||
|                                 &net_traffic_stats, remote_user_id_.data(), | ||||
|                                 remote_user_id_.size(), user_data_); | ||||
| } | ||||
|  | ||||
|         ice_io_statistics_->UpdateAudioOutboundBytes((uint32_t)size); | ||||
|         return ice_agent_->Send(data, size); | ||||
|       }); | ||||
| void IceTransport::OnReceiveBuffer(NiceAgent *agent, guint stream_id, | ||||
|                                    guint component_id, guint size, | ||||
|                                    gchar *buffer, gpointer user_ptr) { | ||||
|   if (!is_closed_) { | ||||
|     if (CheckIsRtpPacket(buffer, size)) { | ||||
|       if (CheckIsVideoPacket(buffer, size)) { | ||||
|         video_channel_receive_->OnReceiveRtpPacket(buffer, size); | ||||
|       } else if (CheckIsAudioPacket(buffer, size)) { | ||||
|         audio_channel_receive_->OnReceiveRtpPacket(buffer, size); | ||||
|       } else if (CheckIsDataPacket(buffer, size)) { | ||||
|         data_channel_receive_->OnReceiveRtpPacket(buffer, size); | ||||
|       } | ||||
|     } else if (CheckIsRtcpPacket(buffer, size)) { | ||||
|       LOG_ERROR("Rtcp packet [{}]", (uint8_t)(buffer[1])); | ||||
|     } else { | ||||
|       LOG_ERROR("Unknown packet"); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|   rtp_audio_sender_->Start(); | ||||
|  | ||||
|   rtp_data_receiver_ = std::make_unique<RtpDataReceiver>(ice_io_statistics_); | ||||
|   // rr sender | ||||
|   rtp_data_receiver_->SetSendDataFunc( | ||||
|       [this](const char *data, size_t size) -> int { | ||||
|         if (!ice_agent_) { | ||||
|           LOG_ERROR("ice_agent_ is nullptr"); | ||||
|           return -1; | ||||
|         } | ||||
|  | ||||
|         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; | ||||
|         } | ||||
|  | ||||
|         return ice_agent_->Send(data, size); | ||||
|       }); | ||||
|   rtp_data_receiver_->SetOnReceiveData( | ||||
|       [this](const char *data, size_t size) -> void { | ||||
|         ice_io_statistics_->UpdateDataInboundBytes((uint32_t)size); | ||||
|  | ||||
|         if (on_receive_data_) { | ||||
|           on_receive_data_(data, size, remote_user_id_.data(), | ||||
|                            remote_user_id_.size(), user_data_); | ||||
| void IceTransport::OnReceiveCompleteFrame(VideoFrame &video_frame) { | ||||
|   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_data_sender_ = std::make_unique<RtpDataSender>(ice_io_statistics_); | ||||
|   rtp_data_sender_->SetSendDataFunc( | ||||
|       [this](const char *data, size_t size) -> int { | ||||
|         if (!ice_agent_) { | ||||
|           LOG_ERROR("ice_agent_ is nullptr"); | ||||
|           return -1; | ||||
| void IceTransport::OnReceiveCompleteAudio(const char *data, size_t size) { | ||||
|   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_); | ||||
|         } | ||||
|  | ||||
|         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; | ||||
|         } | ||||
|  | ||||
|         ice_io_statistics_->UpdateDataOutboundBytes((uint32_t)size); | ||||
|         return ice_agent_->Send(data, size); | ||||
|       }); | ||||
| } | ||||
|  | ||||
|   rtp_data_sender_->Start(); | ||||
|  | ||||
|   ice_agent_ = std::make_unique<IceAgent>( | ||||
|       offer_peer_, use_trickle_ice_, use_reliable_ice_, enable_turn_, | ||||
|       force_turn_, stun_ip, stun_port, turn_ip, turn_port, turn_username, | ||||
|       turn_password); | ||||
|  | ||||
|   ice_agent_->CreateIceAgent( | ||||
|       []([[maybe_unused]] NiceAgent *agent, [[maybe_unused]] guint stream_id, | ||||
|          [[maybe_unused]] guint component_id, NiceComponentState state, | ||||
|          gpointer user_ptr) { | ||||
|         if (auto ice_transport = static_cast<IceTransport *>(user_ptr)) { | ||||
|           if (!ice_transport->is_closed_) { | ||||
|             LOG_INFO("[{}->{}] state_change: {}", ice_transport->user_id_, | ||||
|                      ice_transport->remote_user_id_, | ||||
|                      nice_component_state_to_string(state)); | ||||
|             ice_transport->state_ = state; | ||||
|  | ||||
|             if (state == NICE_COMPONENT_STATE_READY || | ||||
|                 state == NICE_COMPONENT_STATE_CONNECTED) { | ||||
|               ice_transport->ice_io_statistics_->Start(); | ||||
|             } | ||||
|  | ||||
|             ice_transport->on_ice_status_change_( | ||||
|                 nice_component_state_to_string(state), | ||||
|                 ice_transport->remote_user_id_); | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       [](NiceAgent *agent, guint stream_id, guint component_id, | ||||
|          gchar *foundation, gpointer user_ptr) { | ||||
|         if (auto ice_transport = static_cast<IceTransport *>(user_ptr)) { | ||||
|           if (ice_transport->use_trickle_ice_) { | ||||
|             GSList *cands = | ||||
|                 nice_agent_get_local_candidates(agent, stream_id, component_id); | ||||
|             NiceCandidate *cand; | ||||
|             for (GSList *i = cands; i; i = i->next) { | ||||
|               cand = (NiceCandidate *)i->data; | ||||
|               if (g_strcmp0(cand->foundation, foundation) == 0) { | ||||
|                 ice_transport->new_local_candidate_ = | ||||
|                     nice_agent_generate_local_candidate_sdp(agent, cand); | ||||
|  | ||||
|                 json message = { | ||||
|                     {"type", "new_candidate"}, | ||||
|                     {"transmission_id", ice_transport->transmission_id_}, | ||||
|                     {"user_id", ice_transport->user_id_}, | ||||
|                     {"remote_user_id", ice_transport->remote_user_id_}, | ||||
|                     {"sdp", ice_transport->new_local_candidate_}}; | ||||
|                 // LOG_INFO("[{}] Send new candidate to [{}]]:[{}]", | ||||
|                 //          ice_transport->user_id_, | ||||
|                 //          ice_transport->remote_user_id_, | ||||
|                 //          ice_transport->new_local_candidate_); | ||||
|  | ||||
|                 if (ice_transport->ice_ws_transport_) { | ||||
|                   ice_transport->ice_ws_transport_->Send(message.dump()); | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
|  | ||||
|             g_slist_free_full(cands, (GDestroyNotify)nice_candidate_free); | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       []([[maybe_unused]] NiceAgent *agent, [[maybe_unused]] guint stream_id, | ||||
|          gpointer user_ptr) { | ||||
|         // non-trickle | ||||
|         if (auto ice_transport = static_cast<IceTransport *>(user_ptr)) { | ||||
|           LOG_INFO("[{}->{}] gather_done", ice_transport->user_id_, | ||||
|                    ice_transport->remote_user_id_); | ||||
|  | ||||
|           if (!ice_transport->use_trickle_ice_) { | ||||
|             if (ice_transport->offer_peer_) { | ||||
|               ice_transport->SendOffer(); | ||||
|             } else { | ||||
|               ice_transport->SendAnswer(); | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       [](NiceAgent *agent, guint stream_id, guint component_id, | ||||
|          const char *lfoundation, const char *rfoundation, gpointer user_ptr) { | ||||
|         LOG_INFO("new selected pair: [{}] [{}]", lfoundation, rfoundation); | ||||
|         NiceCandidate *local = nullptr; | ||||
|         NiceCandidate *remote = nullptr; | ||||
|         nice_agent_get_selected_pair(agent, stream_id, component_id, &local, | ||||
|                                      &remote); | ||||
|         if (auto ice_transport = static_cast<IceTransport *>(user_ptr)) { | ||||
|           if (local->type == NICE_CANDIDATE_TYPE_RELAYED && | ||||
|               remote->type == NICE_CANDIDATE_TYPE_RELAYED) { | ||||
|             LOG_INFO("Traversal using relay server"); | ||||
|             ice_transport->traversal_type_ = TraversalType::TRelay; | ||||
|           } else { | ||||
|             LOG_INFO("Traversal using p2p"); | ||||
|             ice_transport->traversal_type_ = TraversalType::TP2P; | ||||
|           } | ||||
|           XNetTrafficStats net_traffic_stats; | ||||
|           memset(&net_traffic_stats, 0, sizeof(net_traffic_stats)); | ||||
|  | ||||
|           ice_transport->on_receive_net_status_report_( | ||||
|               ice_transport->user_id_.data(), ice_transport->user_id_.size(), | ||||
|               TraversalMode(ice_transport->traversal_type_), &net_traffic_stats, | ||||
|               ice_transport->remote_user_id_.data(), | ||||
|               ice_transport->remote_user_id_.size(), ice_transport->user_data_); | ||||
|         } | ||||
|       }, | ||||
|       []([[maybe_unused]] NiceAgent *agent, [[maybe_unused]] guint stream_id, | ||||
|          [[maybe_unused]] guint component_id, guint size, gchar *buffer, | ||||
|          gpointer user_ptr) { | ||||
|         if (auto ice_transport = static_cast<IceTransport *>(user_ptr)) { | ||||
|           if (ice_transport && !ice_transport->is_closed_) { | ||||
|             if (ice_transport->CheckIsRtpPacket(buffer, size)) { | ||||
|               if (ice_transport->CheckIsVideoPacket(buffer, size)) { | ||||
|                 RtpPacket packet((uint8_t *)buffer, size); | ||||
|                 ice_transport->rtp_video_receiver_->InsertRtpPacket(packet); | ||||
|               } else if (ice_transport->CheckIsAudioPacket(buffer, size)) { | ||||
|                 RtpPacket packet((uint8_t *)buffer, size); | ||||
|                 ice_transport->rtp_audio_receiver_->InsertRtpPacket(packet); | ||||
|               } else if (ice_transport->CheckIsDataPacket(buffer, size)) { | ||||
|                 RtpPacket packet((uint8_t *)buffer, size); | ||||
|                 ice_transport->rtp_data_receiver_->InsertRtpPacket(packet); | ||||
|               } | ||||
|             } else if (ice_transport->CheckIsRtcpPacket(buffer, size)) { | ||||
|               LOG_ERROR("Rtcp packet [{}]", (uint8_t)(buffer[1])); | ||||
|             } else { | ||||
|               LOG_ERROR("Unknown packet"); | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       this); | ||||
|   return 0; | ||||
| void IceTransport::OnReceiveCompleteData(const char *data, size_t size) { | ||||
|   if (on_receive_data_) { | ||||
|     on_receive_data_(data, size, remote_user_id_.data(), remote_user_id_.size(), | ||||
|                      user_data_); | ||||
|   } | ||||
| } | ||||
|  | ||||
| int IceTransport::DestroyIceTransmission() { | ||||
| @@ -972,14 +891,10 @@ int IceTransport::SendAudioFrame(const char *data, size_t size) { | ||||
|   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, | ||||
|                                      (uint32_t)size, packets); | ||||
|             rtp_audio_sender_->Enqueue(packets); | ||||
|           } | ||||
|         if (audio_channel_send_) { | ||||
|           audio_channel_send_->SendAudio(encoded_audio_buffer, size); | ||||
|         } | ||||
|  | ||||
|         return 0; | ||||
|       }); | ||||
|  | ||||
| @@ -994,13 +909,8 @@ int IceTransport::SendDataFrame(const char *data, size_t size) { | ||||
|     return -2; | ||||
|   } | ||||
|  | ||||
|   std::vector<RtpPacket> packets; | ||||
|  | ||||
|   if (rtp_data_sender_) { | ||||
|     if (data_rtp_codec_) { | ||||
|       data_rtp_codec_->Encode((uint8_t *)data, (uint32_t)size, packets); | ||||
|       rtp_data_sender_->Enqueue(packets); | ||||
|     } | ||||
|   if (data_channel_send_) { | ||||
|     data_channel_send_->SendData(data, size); | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
|   | ||||
| @@ -143,6 +143,33 @@ class IceTransport { | ||||
|   uint8_t CheckIsAudioPacket(const char *buffer, size_t size); | ||||
|   uint8_t CheckIsDataPacket(const char *buffer, size_t size); | ||||
|  | ||||
|  private: | ||||
|   void InitializeIOStatistics(); | ||||
|  | ||||
|   void InitializeChannels(RtpPacket::PAYLOAD_TYPE video_codec_payload_type); | ||||
|  | ||||
|   void OnIceStateChange(NiceAgent *agent, guint stream_id, guint component_id, | ||||
|                         NiceComponentState state, gpointer user_ptr); | ||||
|  | ||||
|   void OnNewLocalCandidate(NiceAgent *agent, guint stream_id, | ||||
|                            guint component_id, gchar *foundation, | ||||
|                            gpointer user_ptr); | ||||
|  | ||||
|   void OnGatheringDone(NiceAgent *agent, guint stream_id, gpointer user_ptr); | ||||
|  | ||||
|   void OnNewSelectedPair(NiceAgent *agent, guint stream_id, guint component_id, | ||||
|                          const char *lfoundation, const char *rfoundation, | ||||
|                          gpointer user_ptr); | ||||
|  | ||||
|   void OnReceiveBuffer(NiceAgent *agent, guint stream_id, guint component_id, | ||||
|                        guint size, gchar *buffer, gpointer user_ptr); | ||||
|  | ||||
|   void OnReceiveCompleteFrame(VideoFrame &video_frame); | ||||
|  | ||||
|   void OnReceiveCompleteAudio(const char *data, size_t size); | ||||
|  | ||||
|   void OnReceiveCompleteData(const char *data, size_t size); | ||||
|  | ||||
|  private: | ||||
|   bool use_trickle_ice_ = true; | ||||
|   bool enable_turn_ = false; | ||||
| @@ -168,7 +195,7 @@ class IceTransport { | ||||
|   void *user_data_ = nullptr; | ||||
|  | ||||
|  private: | ||||
|   std::unique_ptr<IceAgent> ice_agent_ = nullptr; | ||||
|   std::shared_ptr<IceAgent> ice_agent_ = nullptr; | ||||
|   bool is_closed_ = false; | ||||
|   std::shared_ptr<WsClient> ice_ws_transport_ = nullptr; | ||||
|   //   CongestionControl *congestion_control_ = nullptr; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user