#include "runtime/gui_runtime.h" #include #include #include #include #include #include #include #include #include #include "localization.h" #include "rd_log.h" namespace crossdesk { GuiRuntime::GuiRuntime() : clipboard_(*this), devices_(*this), transfers_(*this), settings_(*this), keyboard_(*this), peer_events_(*this) {} GuiRuntime::~GuiRuntime() = default; int GuiRuntime::CreateConnectionPeer() { params_.use_cfg_file = false; std::string signal_server_ip; int signal_server_port; int coturn_server_port; if (config_center_->IsSelfHosted()) { signal_server_ip = config_center_->GetSignalServerHost(); signal_server_port = config_center_->GetSignalServerPort(); coturn_server_port = config_center_->GetCoturnServerPort(); std::string current_self_hosted_ip = config_center_->GetSignalServerHost(); const bool use_cached_id = settings_.LoadCachedSelfHostedIdentity(); if (!use_cached_id) { LOG_INFO( "secure_cache_v2.enc not found, will use empty id to get new id from " "server"); } if (use_cached_id && strlen(self_hosted_id_) > 0) { memset(&self_hosted_user_id_, 0, sizeof(self_hosted_user_id_)); strncpy(self_hosted_user_id_, self_hosted_id_, sizeof(self_hosted_user_id_) - 1); self_hosted_user_id_[sizeof(self_hosted_user_id_) - 1] = '\0'; params_.user_id = self_hosted_user_id_; } else { memset(&self_hosted_user_id_, 0, sizeof(self_hosted_user_id_)); params_.user_id = self_hosted_user_id_; LOG_INFO( "Using empty id for self-hosted server, server will assign new id"); } } else { signal_server_ip = config_center_->GetDefaultServerHost(); signal_server_port = config_center_->GetDefaultSignalServerPort(); coturn_server_port = config_center_->GetDefaultCoturnServerPort(); params_.user_id = client_id_with_password_; } // self hosted server config strncpy(signal_server_ip_self_, config_center_->GetSignalServerHost().c_str(), sizeof(signal_server_ip_self_) - 1); signal_server_ip_self_[sizeof(signal_server_ip_self_) - 1] = '\0'; int signal_port = config_center_->GetSignalServerPort(); if (signal_port > 0) { strncpy(signal_server_port_self_, std::to_string(signal_port).c_str(), sizeof(signal_server_port_self_) - 1); signal_server_port_self_[sizeof(signal_server_port_self_) - 1] = '\0'; } else { signal_server_port_self_[0] = '\0'; } int coturn_port = config_center_->GetCoturnServerPort(); if (coturn_port > 0) { strncpy(coturn_server_port_self_, std::to_string(coturn_port).c_str(), sizeof(coturn_server_port_self_) - 1); coturn_server_port_self_[sizeof(coturn_server_port_self_) - 1] = '\0'; } else { coturn_server_port_self_[0] = '\0'; } // peer config strncpy((char *)params_.signal_server_ip, signal_server_ip.c_str(), sizeof(params_.signal_server_ip) - 1); params_.signal_server_ip[sizeof(params_.signal_server_ip) - 1] = '\0'; params_.signal_server_port = signal_server_port; strncpy((char *)params_.stun_server_ip, signal_server_ip.c_str(), sizeof(params_.stun_server_ip) - 1); params_.stun_server_ip[sizeof(params_.stun_server_ip) - 1] = '\0'; params_.stun_server_port = coturn_server_port; strncpy((char *)params_.turn_server_ip, signal_server_ip.c_str(), sizeof(params_.turn_server_ip) - 1); params_.turn_server_ip[sizeof(params_.turn_server_ip) - 1] = '\0'; params_.turn_server_port = coturn_server_port; strncpy((char *)params_.turn_server_username, "crossdesk", sizeof(params_.turn_server_username) - 1); params_.turn_server_username[sizeof(params_.turn_server_username) - 1] = '\0'; strncpy((char *)params_.turn_server_password, "crossdeskpw", sizeof(params_.turn_server_password) - 1); params_.turn_server_password[sizeof(params_.turn_server_password) - 1] = '\0'; strncpy(params_.log_path, dll_log_path_.c_str(), sizeof(params_.log_path) - 1); params_.log_path[sizeof(params_.log_path) - 1] = '\0'; params_.hardware_acceleration = config_center_->IsHardwareVideoCodec(); params_.av1_encoding = config_center_->GetVideoEncodeFormat() == ConfigCenter::VIDEO_ENCODE_FORMAT::AV1 ? true : false; params_.turn_mode = static_cast(config_center_->GetTurnMode()); params_.enable_srtp = config_center_->IsEnableSrtp(); params_.video_quality = static_cast(config_center_->GetVideoQuality()); params_.on_receive_video_buffer = nullptr; params_.on_receive_audio_buffer = PeerEventHandler::OnReceiveAudioBuffer; params_.on_receive_data_buffer = PeerEventHandler::OnReceiveDataBuffer; params_.on_receive_video_frame = PeerEventHandler::OnReceiveVideoBuffer; params_.on_signal_status = PeerEventHandler::OnSignalStatus; params_.on_signal_message = PeerEventHandler::OnSignalMessage; params_.on_connection_status = PeerEventHandler::OnConnectionStatus; params_.on_net_status_report = PeerEventHandler::OnNetStatusReport; params_.user_data = &peer_events_; peer_ = CreatePeer(¶ms_); if (peer_) { LOG_INFO("Create peer instance [{}] successful", client_id_); Init(peer_); LOG_INFO("Peer [{}] init finish", client_id_); } else { LOG_INFO("Create peer [{}] instance failed", client_id_); } if (0 == devices_.InitializeScreenCapturer()) { for (const auto &display_info : devices_.display_info_list()) { AddVideoStream(peer_, display_info.name.c_str()); } AddAudioStream(peer_, audio_label_.c_str()); AddDataStream(peer_, data_label_.c_str(), false); AddDataStream(peer_, mouse_label_.c_str(), false); AddDataStream(peer_, keyboard_label_.c_str(), true); AddDataStream(peer_, control_data_label_.c_str(), true); AddDataStream(peer_, file_label_.c_str(), true); AddDataStream(peer_, file_feedback_label_.c_str(), true); AddDataStream(peer_, clipboard_label_.c_str(), true); return 0; } else { return -1; } } void GuiRuntime::UpdateLabels() { if (!label_inited_ || localization_language_index_last_ != localization_language_index_) { connect_button_label_ = connect_button_pressed_ ? localization::disconnect[localization_language_index_] : localization::connect[localization_language_index_]; label_inited_ = true; localization_language_index_last_ = localization_language_index_; } } void GuiRuntime::HandleRecentConnections() { if (reload_recent_connections_ && thumbnail_) { uint32_t now_time = SDL_GetTicks(); if (now_time - recent_connection_image_save_time_ >= 50) { int ret = thumbnail_->LoadThumbnail(recent_connections_, &recent_connection_image_width_, &recent_connection_image_height_); if (!ret) { LOG_INFO("Load recent connection thumbnails"); } reload_recent_connections_ = false; recent_connection_ids_.clear(); for (const auto &conn : recent_connections_) { recent_connection_ids_.push_back(conn.first); } need_to_send_recent_connections_ = true; } } } void GuiRuntime::SdlCaptureAudioIn(void *userdata, Uint8 *stream, int len) { GuiRuntime *runtime = static_cast(userdata); if (!runtime) { return; } if (1) { std::shared_lock lock(runtime->remote_sessions_mutex_); for (const auto &it : runtime->remote_sessions_) { auto props = it.second; if (props->connection_status_.load() == ConnectionStatus::Connected) { if (props->peer_) { SendAudioFrame(props->peer_, (const char *)stream, len, runtime->audio_label_.c_str()); } } } } else { memcpy(runtime->audio_buffer_, stream, len); runtime->audio_len_ = len; SDL_Delay(10); runtime->audio_buffer_fresh_ = true; } } void GuiRuntime::SdlCaptureAudioOut([[maybe_unused]] void *userdata, [[maybe_unused]] Uint8 *stream, [[maybe_unused]] int len) { // GuiApplication *runtime = (GuiApplication *)userdata; // for (auto it : runtime->remote_sessions_) { // auto props = it.second; // if (props->connection_status_ == SignalStatus::SignalConnected) { // SendAudioFrame(props->peer_, (const char *)stream, len); // } // } // if (!runtime->audio_buffer_fresh_) { // return; // } // SDL_memset(stream, 0, len); // if (runtime->audio_len_ == 0) { // return; // } else { // } // len = (len > runtime->audio_len_ ? runtime->audio_len_ : len); // SDL_MixAudioFormat(stream, runtime->audio_buffer_, AUDIO_S16LSB, len, // SDL_MIX_MAXVOLUME); // runtime->audio_buffer_fresh_ = false; } } // namespace crossdesk