mirror of
				https://github.com/kunkundi/crossdesk.git
				synced 2025-10-26 20:25:34 +08:00 
			
		
		
		
	Use abstraction to refactor remote desk gui
This commit is contained in:
		
							
								
								
									
										21
									
								
								src/config_center/config_center.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/config_center/config_center.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| #include "config_center.h" | ||||
|  | ||||
| ConfigCenter::ConfigCenter() {} | ||||
|  | ||||
| ConfigCenter::~ConfigCenter() {} | ||||
|  | ||||
| int ConfigCenter::SetVideoQuality(VIDEO_QUALITY video_quality) { | ||||
|   video_quality_ = video_quality; | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| int ConfigCenter::SetLanguage(LANGUAGE language) { | ||||
|   language_ = language; | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| ConfigCenter::VIDEO_QUALITY ConfigCenter::GetVideoQuality() { | ||||
|   return video_quality_; | ||||
| } | ||||
|  | ||||
| ConfigCenter::LANGUAGE ConfigCenter::GetLanguage() { return language_; } | ||||
							
								
								
									
										32
									
								
								src/config_center/config_center.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/config_center/config_center.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| /* | ||||
|  * @Author: DI JUNKUN | ||||
|  * @Date: 2024-05-29 | ||||
|  * Copyright (c) 2024 by DI JUNKUN, All Rights Reserved. | ||||
|  */ | ||||
|  | ||||
| #ifndef _CONFIG_CENTER_H_ | ||||
| #define _CONFIG_CENTER_H_ | ||||
|  | ||||
| class ConfigCenter { | ||||
|  public: | ||||
|   enum class VIDEO_QUALITY { LOW = 0, MEDIUM = 1, HIGH = 2 }; | ||||
|   enum class LANGUAGE { CHINESE = 0, ENGLISH = 1 }; | ||||
|  | ||||
|  public: | ||||
|   ConfigCenter(); | ||||
|   ~ConfigCenter(); | ||||
|  | ||||
|  public: | ||||
|   int SetVideoQuality(VIDEO_QUALITY video_quality); | ||||
|   int SetLanguage(LANGUAGE language); | ||||
|  | ||||
|  public: | ||||
|   VIDEO_QUALITY GetVideoQuality(); | ||||
|   LANGUAGE GetLanguage(); | ||||
|  | ||||
|  private: | ||||
|   VIDEO_QUALITY video_quality_ = VIDEO_QUALITY::MEDIUM; | ||||
|   LANGUAGE language_ = LANGUAGE::ENGLISH; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										133
									
								
								src/connection/connection.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								src/connection/connection.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,133 @@ | ||||
| #include "connection.h" | ||||
|  | ||||
| #include <fstream> | ||||
| #include <iostream> | ||||
| #include <thread> | ||||
|  | ||||
| #include "log.h" | ||||
| #include "platform.h" | ||||
|  | ||||
| void ServerReceiveVideoBuffer(const char *data, size_t size, | ||||
|                               const char *user_id, size_t user_id_size) {} | ||||
|  | ||||
| void ClientReceiveVideoBuffer(const char *data, size_t size, | ||||
|                               const char *user_id, size_t user_id_size) {} | ||||
|  | ||||
| void ServerReceiveAudioBuffer(const char *data, size_t size, | ||||
|                               const char *user_id, size_t user_id_size) {} | ||||
|  | ||||
| void ClientReceiveAudioBuffer(const char *data, size_t size, | ||||
|                               const char *user_id, size_t user_id_size) {} | ||||
|  | ||||
| void ServerReceiveDataBuffer(const char *data, size_t size, const char *user_id, | ||||
|                              size_t user_id_size) {} | ||||
|  | ||||
| void ClientReceiveDataBuffer(const char *data, size_t size, const char *user_id, | ||||
|                              size_t user_id_size) {} | ||||
|  | ||||
| void ServerSignalStatus(SignalStatus status) {} | ||||
|  | ||||
| void ClientSignalStatus(SignalStatus status) {} | ||||
|  | ||||
| void ServerConnectionStatus(ConnectionStatus status) {} | ||||
|  | ||||
| void ClientConnectionStatus(ConnectionStatus status) {} | ||||
|  | ||||
| Connection::Connection() {} | ||||
|  | ||||
| Connection::~Connection() {} | ||||
|  | ||||
| int Connection::DeskConnectionInit() { | ||||
|   std::string default_cfg_path = "../../../../config/config.ini"; | ||||
|   std::ifstream f(default_cfg_path.c_str()); | ||||
|  | ||||
|   std::string mac_addr_str = GetMac(); | ||||
|   mac_addr_str_ = mac_addr_str; | ||||
|  | ||||
|   server_params_.cfg_path = | ||||
|       f.good() ? "../../../../config/config.ini" : "config.ini"; | ||||
|   server_params_.on_receive_video_buffer = ServerReceiveVideoBuffer; | ||||
|   server_params_.on_receive_audio_buffer = ServerReceiveAudioBuffer; | ||||
|   server_params_.on_receive_data_buffer = ServerReceiveDataBuffer; | ||||
|   server_params_.on_signal_status = ServerSignalStatus; | ||||
|   server_params_.on_connection_status = ServerConnectionStatus; | ||||
|  | ||||
|   client_params_.cfg_path = | ||||
|       f.good() ? "../../../../config/config.ini" : "config.ini"; | ||||
|   client_params_.on_receive_video_buffer = ClientReceiveVideoBuffer; | ||||
|   client_params_.on_receive_audio_buffer = ClientReceiveAudioBuffer; | ||||
|   client_params_.on_receive_data_buffer = ClientReceiveDataBuffer; | ||||
|   client_params_.on_signal_status = ClientSignalStatus; | ||||
|   client_params_.on_connection_status = ClientConnectionStatus; | ||||
|  | ||||
|   peer_server_ = CreatePeer(&server_params_); | ||||
|   LOG_INFO("Create peer_server_"); | ||||
|   server_user_id_ = "S-" + mac_addr_str_; | ||||
|   Init(peer_server_, server_user_id_.c_str()); | ||||
|   LOG_INFO("peer_server_ init finish"); | ||||
|  | ||||
|   peer_client_ = CreatePeer(&client_params_); | ||||
|   LOG_INFO("Create peer_client_"); | ||||
|   client_user_id_ = "C-" + mac_addr_str_; | ||||
|   Init(peer_client_, client_user_id_.c_str()); | ||||
|   LOG_INFO("peer_client_ init finish"); | ||||
|  | ||||
|   while (SignalStatus::SignalConnected != server_signal_status_) { | ||||
|     std::this_thread::sleep_for(std::chrono::seconds(1)); | ||||
|   } | ||||
|  | ||||
| #if 0 | ||||
|   // Screen capture | ||||
|   screen_capturer_factory_ = new ScreenCapturerFactory(); | ||||
|   screen_capturer_ = (ScreenCapturer *)screen_capturer__factory_->Create(); | ||||
|  | ||||
|   last_frame_time_ = std::chrono::high_resolution_clock::now(); | ||||
|   ScreenCapturer::RECORD_DESKTOP_RECT rect; | ||||
|   rect.left = 0; | ||||
|   rect.top = 0; | ||||
|   rect.right = screen_width; | ||||
|   rect.bottom = screen_height; | ||||
|  | ||||
|   int screen_capturer_init_ret = screen_capturer_->Init( | ||||
|       rect, 60, | ||||
|       [](unsigned char *data, int size, int width, int height) -> void { | ||||
|         auto now_time = std::chrono::high_resolution_clock::now(); | ||||
|         std::chrono::duration<double> duration = now_time - last_frame_time_; | ||||
|         auto tc = duration.count() * 1000; | ||||
|  | ||||
|         if (tc >= 0) { | ||||
|           SendData(peer_server_, DATA_TYPE::VIDEO, (const char *)data, | ||||
|                    NV12_BUFFER_SIZE); | ||||
|           last_frame_time_ = now_time; | ||||
|         } | ||||
|       }); | ||||
|  | ||||
|   if (0 == screen_capturer_init_ret) { | ||||
|     screen_capturer_->Start(); | ||||
|   } else { | ||||
|     screen_capturer_->Destroy(); | ||||
|     screen_capturer_ = nullptr; | ||||
|   } | ||||
|  | ||||
|   // Mouse control | ||||
|   device_controller_factory_ = new DeviceControllerFactory(); | ||||
|   mouse_controller_ = (MouseController *)device_controller_factory_->Create( | ||||
|       DeviceControllerFactory::Device::Mouse); | ||||
|   int mouse_controller_init_ret = mouse_controller_->Init(screen_w, screen_h); | ||||
|   if (0 != mouse_controller_init_ret) { | ||||
|     mouse_controller_->Destroy(); | ||||
|     mouse_controller_ = nullptr; | ||||
|   } | ||||
| #endif | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| int Connection::DeskConnectionCreate(const char *input_password) { | ||||
|   input_password_ = input_password; | ||||
|   is_created_connection_ = CreateConnection(peer_server_, mac_addr_str_.c_str(), | ||||
|                                             input_password_.c_str()) | ||||
|                                ? false | ||||
|                                : true; | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										63
									
								
								src/connection/connection.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/connection/connection.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | ||||
| /* | ||||
|  * @Author: DI JUNKUN | ||||
|  * @Date: 2024-05-29 | ||||
|  * Copyright (c) 2024 by DI JUNKUN, All Rights Reserved. | ||||
|  */ | ||||
|  | ||||
| #ifndef _CONNECTION_H_ | ||||
| #define _CONNECTION_H_ | ||||
|  | ||||
| #include <chrono> | ||||
| #include <string> | ||||
|  | ||||
| #include "../../thirdparty/projectx/src/interface/x.h" | ||||
| #include "device_controller_factory.h" | ||||
| #include "screen_capturer_factory.h" | ||||
|  | ||||
| class Connection { | ||||
|  public: | ||||
|   Connection(); | ||||
|   ~Connection(); | ||||
|  | ||||
|  public: | ||||
|   int DeskConnectionInit(const char *input_password, int screen_width, | ||||
|                          int screen_height); | ||||
|   int DeskConnectionCreate(); | ||||
|  | ||||
|  private: | ||||
|   PeerPtr *peer_server_ = nullptr; | ||||
|   PeerPtr *peer_client_ = nullptr; | ||||
|  | ||||
|   std::string mac_addr_str_ = ""; | ||||
|  | ||||
|   Params server_params_; | ||||
|   Params client_params_; | ||||
|  | ||||
|   std::string server_user_id_ = ""; | ||||
|   std::string client_user_id_ = ""; | ||||
|  | ||||
|   std::string input_password_ = ""; | ||||
|  | ||||
|   ScreenCapturerFactory *screen_capturer_factory_ = nullptr; | ||||
|   ScreenCapturer *screen_capturer_ = nullptr; | ||||
|  | ||||
|   DeviceControllerFactory *device_controller_factory_ = nullptr; | ||||
|   MouseController *mouse_controller_ = nullptr; | ||||
|  | ||||
|   bool is_created_connection_ = false; | ||||
|  | ||||
| #ifdef __linux__ | ||||
|   std::chrono::_V2::system_clock::time_point last_frame_time_; | ||||
| #else | ||||
|   std::chrono::steady_clock::time_point last_frame_time_; | ||||
| #endif | ||||
|  | ||||
|   std::atomic<ConnectionStatus> server_connection_status_{ | ||||
|       ConnectionStatus::Closed}; | ||||
|   std::atomic<ConnectionStatus> client_connection_status_{ | ||||
|       ConnectionStatus::Closed}; | ||||
|   std::atomic<SignalStatus> server_signal_status_{SignalStatus::SignalClosed}; | ||||
|   std::atomic<SignalStatus> client_signal_status_{SignalStatus::SignalClosed}; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										925
									
								
								src/gui/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										925
									
								
								src/gui/main.cpp
									
									
									
									
									
								
							| @@ -1,926 +1,17 @@ | ||||
| #include <SDL.h> | ||||
| #include <stdio.h> | ||||
| #ifdef _WIN32 | ||||
| #ifdef REMOTE_DESK_DEBUG | ||||
| #pragma comment(linker, "/subsystem:\"console\"") | ||||
| #else | ||||
| #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"") | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #include <stdio.h> | ||||
|  | ||||
| #include <atomic> | ||||
| #include <chrono> | ||||
| #include <cstring> | ||||
| #include <fstream> | ||||
| #include <iostream> | ||||
| #include <string> | ||||
| #include <thread> | ||||
|  | ||||
| #include "../../thirdparty/projectx/src/interface/x.h" | ||||
| #include "device_controller_factory.h" | ||||
| #include "imgui.h" | ||||
| #include "imgui_impl_sdl2.h" | ||||
| #include "imgui_impl_sdlrenderer2.h" | ||||
| #include "connection.h" | ||||
| #include "log.h" | ||||
| #include "platform.h" | ||||
| #include "screen_capturer_factory.h" | ||||
|  | ||||
| #define NV12_BUFFER_SIZE 1280 * 720 * 3 / 2 | ||||
|  | ||||
| #ifdef REMOTE_DESK_DEBUG | ||||
| #define MOUSE_CONTROL 0 | ||||
| #else | ||||
| #define MOUSE_CONTROL 1 | ||||
| #endif | ||||
|  | ||||
| #define CHINESE_FONT 1 | ||||
|  | ||||
| int screen_w = 1280, screen_h = 720; | ||||
| int window_w = 1280, window_h = 720; | ||||
| const int pixel_w = 1280, pixel_h = 720; | ||||
|  | ||||
| unsigned char dst_buffer[pixel_w * pixel_h * 3 / 2]; | ||||
| unsigned char audio_buffer[960]; | ||||
| SDL_Texture *sdlTexture = nullptr; | ||||
| SDL_Renderer *sdlRenderer = nullptr; | ||||
| SDL_Rect sdlRect; | ||||
| SDL_Window *window; | ||||
| static SDL_AudioDeviceID input_dev; | ||||
| static SDL_AudioDeviceID output_dev; | ||||
|  | ||||
| uint32_t start_time, end_time, elapsed_time; | ||||
| uint32_t frame_count = 0; | ||||
| int fps = 0; | ||||
|  | ||||
| static std::atomic<bool> audio_buffer_fresh{false}; | ||||
| static uint32_t last_ts = 0; | ||||
|  | ||||
| int dst_bufsize; | ||||
| struct SwrContext *swr_ctx; | ||||
|  | ||||
| int ret; | ||||
|  | ||||
| int audio_len = 0; | ||||
|  | ||||
| std::string window_title = "Remote Desk Client"; | ||||
| std::string server_connection_status_str = "-"; | ||||
| std::string client_connection_status_str = "-"; | ||||
| std::string server_signal_status_str = "-"; | ||||
| std::string client_signal_status_str = "-"; | ||||
|  | ||||
| std::atomic<ConnectionStatus> server_connection_status{ | ||||
|     ConnectionStatus::Closed}; | ||||
| std::atomic<ConnectionStatus> client_connection_status{ | ||||
|     ConnectionStatus::Closed}; | ||||
| std::atomic<SignalStatus> server_signal_status{SignalStatus::SignalClosed}; | ||||
| std::atomic<SignalStatus> client_signal_status{SignalStatus::SignalClosed}; | ||||
|  | ||||
| // Refresh Event | ||||
| #define REFRESH_EVENT (SDL_USEREVENT + 1) | ||||
| #define QUIT_EVENT (SDL_USEREVENT + 2) | ||||
|  | ||||
| typedef struct { | ||||
|   char password[7]; | ||||
| } CDCache; | ||||
|  | ||||
| int thread_exit = 0; | ||||
| PeerPtr *peer_server = nullptr; | ||||
| PeerPtr *peer_client = nullptr; | ||||
| bool joined = false; | ||||
| bool received_frame = false; | ||||
| bool menu_hovered = false; | ||||
|  | ||||
| static bool connect_button_pressed = false; | ||||
| static bool fullscreen_button_pressed = false; | ||||
|  | ||||
| #if CHINESE_FONT | ||||
| static const char *connect_label = u8"连接"; | ||||
| static const char *fullscreen_label = u8"全屏"; | ||||
| #else | ||||
| static const char *connect_label = "Connect"; | ||||
| static const char *fullscreen_label = "FULLSCREEN"; | ||||
| #endif | ||||
| static char input_password[7] = ""; | ||||
| static FILE *cd_cache_file = nullptr; | ||||
| static CDCache cd_cache; | ||||
|  | ||||
| static bool is_create_connection = false; | ||||
| static bool done = false; | ||||
|  | ||||
| ScreenCapturerFactory *screen_capturer_factory = nullptr; | ||||
| ScreenCapturer *screen_capturer = nullptr; | ||||
|  | ||||
| DeviceControllerFactory *device_controller_factory = nullptr; | ||||
| MouseController *mouse_controller = nullptr; | ||||
|  | ||||
| char *nv12_buffer = nullptr; | ||||
|  | ||||
| #ifdef __linux__ | ||||
| std::chrono::_V2::system_clock::time_point last_frame_time_; | ||||
| #else | ||||
| std::chrono::steady_clock::time_point last_frame_time_; | ||||
| #endif | ||||
|  | ||||
| inline int ProcessMouseKeyEven(SDL_Event &ev) { | ||||
|   float ratio = (float)(1280.0 / window_w); | ||||
|  | ||||
|   RemoteAction remote_action; | ||||
|   remote_action.m.x = (size_t)(ev.button.x * ratio); | ||||
|   remote_action.m.y = (size_t)(ev.button.y * ratio); | ||||
|  | ||||
|   if (SDL_KEYDOWN == ev.type)  // SDL_KEYUP | ||||
|   { | ||||
|     // printf("SDLK_DOWN: %d\n", SDL_KeyCode(ev.key.keysym.sym)); | ||||
|     if (SDLK_DOWN == ev.key.keysym.sym) { | ||||
|       // printf("SDLK_DOWN  \n"); | ||||
|  | ||||
|     } else if (SDLK_UP == ev.key.keysym.sym) { | ||||
|       // printf("SDLK_UP  \n"); | ||||
|  | ||||
|     } else if (SDLK_LEFT == ev.key.keysym.sym) { | ||||
|       // printf("SDLK_LEFT  \n"); | ||||
|  | ||||
|     } else if (SDLK_RIGHT == ev.key.keysym.sym) { | ||||
|       // printf("SDLK_RIGHT  \n"); | ||||
|     } | ||||
|   } else if (SDL_MOUSEBUTTONDOWN == ev.type) { | ||||
|     remote_action.type = ControlType::mouse; | ||||
|     if (SDL_BUTTON_LEFT == ev.button.button) { | ||||
|       remote_action.m.flag = MouseFlag::left_down; | ||||
|     } else if (SDL_BUTTON_RIGHT == ev.button.button) { | ||||
|       remote_action.m.flag = MouseFlag::right_down; | ||||
|     } | ||||
|     SendData(peer_client, DATA_TYPE::DATA, (const char *)&remote_action, | ||||
|              sizeof(remote_action)); | ||||
|   } else if (SDL_MOUSEBUTTONUP == ev.type) { | ||||
|     remote_action.type = ControlType::mouse; | ||||
|     if (SDL_BUTTON_LEFT == ev.button.button) { | ||||
|       remote_action.m.flag = MouseFlag::left_up; | ||||
|     } else if (SDL_BUTTON_RIGHT == ev.button.button) { | ||||
|       remote_action.m.flag = MouseFlag::right_up; | ||||
|     } | ||||
|     SendData(peer_client, DATA_TYPE::DATA, (const char *)&remote_action, | ||||
|              sizeof(remote_action)); | ||||
|   } else if (SDL_MOUSEMOTION == ev.type) { | ||||
|     remote_action.type = ControlType::mouse; | ||||
|     remote_action.m.flag = MouseFlag::move; | ||||
|     SendData(peer_client, DATA_TYPE::DATA, (const char *)&remote_action, | ||||
|              sizeof(remote_action)); | ||||
|   } else if (SDL_QUIT == ev.type) { | ||||
|     SDL_Event event; | ||||
|     event.type = SDL_QUIT; | ||||
|     SDL_PushEvent(&event); | ||||
|     printf("SDL_QUIT\n"); | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| void SdlCaptureAudioIn(void *userdata, Uint8 *stream, int len) { | ||||
|   if (1) { | ||||
|     if ("ClientConnected" == client_connection_status_str) { | ||||
|       SendData(peer_client, DATA_TYPE::AUDIO, (const char *)stream, len); | ||||
|     } | ||||
|  | ||||
|     if ("ServerConnected" == server_connection_status_str) { | ||||
|       SendData(peer_server, DATA_TYPE::AUDIO, (const char *)stream, len); | ||||
|     } | ||||
|   } else { | ||||
|     memcpy(audio_buffer, stream, len); | ||||
|     audio_len = len; | ||||
|     SDL_Delay(10); | ||||
|     audio_buffer_fresh = true; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void SdlCaptureAudioOut(void *userdata, Uint8 *stream, int len) { | ||||
|   // if ("ClientConnected" != client_connection_status_str) { | ||||
|   //   return; | ||||
|   // } | ||||
|  | ||||
|   if (!audio_buffer_fresh) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   SDL_memset(stream, 0, len); | ||||
|  | ||||
|   if (audio_len == 0) { | ||||
|     return; | ||||
|   } else { | ||||
|   } | ||||
|  | ||||
|   len = (len > audio_len ? audio_len : len); | ||||
|   SDL_MixAudioFormat(stream, audio_buffer, AUDIO_S16LSB, len, | ||||
|                      SDL_MIX_MAXVOLUME); | ||||
|   audio_buffer_fresh = false; | ||||
| } | ||||
|  | ||||
| void ServerReceiveVideoBuffer(const char *data, size_t size, | ||||
|                               const char *user_id, size_t user_id_size) {} | ||||
|  | ||||
| void ClientReceiveVideoBuffer(const char *data, size_t size, | ||||
|                               const char *user_id, size_t user_id_size) { | ||||
|   // std::cout << "Receive: [" << user_id << "] " << std::endl; | ||||
|   if (joined) { | ||||
|     memcpy(dst_buffer, data, size); | ||||
|  | ||||
|     SDL_Event event; | ||||
|     event.type = REFRESH_EVENT; | ||||
|     SDL_PushEvent(&event); | ||||
|     received_frame = true; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void ServerReceiveAudioBuffer(const char *data, size_t size, | ||||
|                               const char *user_id, size_t user_id_size) { | ||||
|   // memset(audio_buffer, 0, size); | ||||
|   // memcpy(audio_buffer, data, size); | ||||
|   // audio_len = size; | ||||
|   audio_buffer_fresh = true; | ||||
|  | ||||
|   SDL_QueueAudio(output_dev, data, (Uint32)size); | ||||
|   // printf("queue audio\n"); | ||||
| } | ||||
|  | ||||
| void ClientReceiveAudioBuffer(const char *data, size_t size, | ||||
|                               const char *user_id, size_t user_id_size) { | ||||
|   // std::cout << "Client receive audio, size " << size << ", user [" << user_id | ||||
|   //           << "] " << std::endl; | ||||
|   SDL_QueueAudio(output_dev, data, (Uint32)size); | ||||
| } | ||||
|  | ||||
| void ServerReceiveDataBuffer(const char *data, size_t size, const char *user_id, | ||||
|                              size_t user_id_size) { | ||||
|   std::string user(user_id, user_id_size); | ||||
|  | ||||
|   RemoteAction remote_action; | ||||
|   memcpy(&remote_action, data, sizeof(remote_action)); | ||||
|  | ||||
|   // std::cout << "remote_action: " << remote_action.type << " " | ||||
|   //           << remote_action.m.flag << " " << remote_action.m.x << " " | ||||
|   //           << remote_action.m.y << std::endl; | ||||
| #if MOUSE_CONTROL | ||||
|   if (mouse_controller) { | ||||
|     mouse_controller->SendCommand(remote_action); | ||||
|   } | ||||
| #endif | ||||
| } | ||||
|  | ||||
| void ClientReceiveDataBuffer(const char *data, size_t size, const char *user_id, | ||||
|                              size_t user_id_size) {} | ||||
|  | ||||
| void ServerSignalStatus(SignalStatus status) { | ||||
|   server_signal_status = status; | ||||
|   if (SignalStatus::SignalConnecting == status) { | ||||
|     server_signal_status_str = "ServerSignalConnecting"; | ||||
|   } else if (SignalStatus::SignalConnected == status) { | ||||
|     server_signal_status_str = "ServerSignalConnected"; | ||||
|   } else if (SignalStatus::SignalFailed == status) { | ||||
|     server_signal_status_str = "ServerSignalFailed"; | ||||
|   } else if (SignalStatus::SignalClosed == status) { | ||||
|     server_signal_status_str = "ServerSignalClosed"; | ||||
|   } else if (SignalStatus::SignalReconnecting == status) { | ||||
|     server_signal_status_str = "ServerSignalReconnecting"; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void ClientSignalStatus(SignalStatus status) { | ||||
|   client_signal_status = status; | ||||
|   if (SignalStatus::SignalConnecting == status) { | ||||
|     client_signal_status_str = "ClientSignalConnecting"; | ||||
|   } else if (SignalStatus::SignalConnected == status) { | ||||
|     client_signal_status_str = "ClientSignalConnected"; | ||||
|   } else if (SignalStatus::SignalFailed == status) { | ||||
|     client_signal_status_str = "ClientSignalFailed"; | ||||
|   } else if (SignalStatus::SignalClosed == status) { | ||||
|     client_signal_status_str = "ClientSignalClosed"; | ||||
|   } else if (SignalStatus::SignalReconnecting == status) { | ||||
|     client_signal_status_str = "ClientSignalReconnecting"; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void ServerConnectionStatus(ConnectionStatus status) { | ||||
|   server_connection_status = status; | ||||
|   if (ConnectionStatus::Connecting == status) { | ||||
|     server_connection_status_str = "ServerConnecting"; | ||||
|   } else if (ConnectionStatus::Connected == status) { | ||||
|     server_connection_status_str = "ServerConnected"; | ||||
|   } else if (ConnectionStatus::Disconnected == status) { | ||||
|     server_connection_status_str = "ServerDisconnected"; | ||||
|   } else if (ConnectionStatus::Failed == status) { | ||||
|     server_connection_status_str = "ServerFailed"; | ||||
|   } else if (ConnectionStatus::Closed == status) { | ||||
|     server_connection_status_str = "ServerClosed"; | ||||
|   } else if (ConnectionStatus::IncorrectPassword == status) { | ||||
|     server_connection_status_str = "Incorrect password"; | ||||
|     if (connect_button_pressed) { | ||||
|       connect_button_pressed = false; | ||||
|       joined = false; | ||||
|       connect_label = connect_button_pressed ? "Disconnect" : "Connect"; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| void ClientConnectionStatus(ConnectionStatus status) { | ||||
|   client_connection_status = status; | ||||
|   if (ConnectionStatus::Connecting == status) { | ||||
|     client_connection_status_str = "ClientConnecting"; | ||||
|   } else if (ConnectionStatus::Connected == status) { | ||||
|     client_connection_status_str = "ClientConnected"; | ||||
|     joined = true; | ||||
|   } else if (ConnectionStatus::Disconnected == status) { | ||||
|     client_connection_status_str = "ClientDisconnected"; | ||||
|   } else if (ConnectionStatus::Failed == status) { | ||||
|     client_connection_status_str = "ClientFailed"; | ||||
|   } else if (ConnectionStatus::Closed == status) { | ||||
|     client_connection_status_str = "ClientClosed"; | ||||
|   } else if (ConnectionStatus::IncorrectPassword == status) { | ||||
|     client_connection_status_str = "Incorrect password"; | ||||
|     if (connect_button_pressed) { | ||||
|       connect_button_pressed = false; | ||||
|       joined = false; | ||||
|       connect_label = connect_button_pressed ? "Disconnect" : "Connect"; | ||||
|     } | ||||
|   } else if (ConnectionStatus::NoSuchTransmissionId == status) { | ||||
|     client_connection_status_str = "No such transmission id"; | ||||
|     if (connect_button_pressed) { | ||||
|       connect_button_pressed = false; | ||||
|       joined = false; | ||||
|       connect_label = connect_button_pressed ? "Disconnect" : "Connect"; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| #include "main_window.h" | ||||
|  | ||||
| int main(int argc, char *argv[]) { | ||||
|   LOG_INFO("Remote desk"); | ||||
|   MainWindow main_window; | ||||
|   Connection connection; | ||||
|  | ||||
|   last_ts = static_cast<uint32_t>( | ||||
|       std::chrono::duration_cast<std::chrono::milliseconds>( | ||||
|           std::chrono::high_resolution_clock::now().time_since_epoch()) | ||||
|           .count()); | ||||
|   connection.DeskConnectionInit(); | ||||
|   connection.DeskConnectionCreate(); | ||||
|   // connection.Create("123456", 800, 600); | ||||
|  | ||||
|   cd_cache_file = fopen("cache.cd", "r+"); | ||||
|   if (cd_cache_file) { | ||||
|     fseek(cd_cache_file, 0, SEEK_SET); | ||||
|     fread(&cd_cache.password, sizeof(cd_cache.password), 1, cd_cache_file); | ||||
|     fclose(cd_cache_file); | ||||
|     strncpy(input_password, cd_cache.password, sizeof(cd_cache.password)); | ||||
|   } | ||||
|  | ||||
|   // Setup SDL | ||||
|   if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER | | ||||
|                SDL_INIT_GAMECONTROLLER) != 0) { | ||||
|     printf("Error: %s\n", SDL_GetError()); | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   // From 2.0.18: Enable native IME. | ||||
| #ifdef SDL_HINT_IME_SHOW_UI | ||||
|   SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); | ||||
| #endif | ||||
|  | ||||
|   // Create window with SDL_Renderer graphics context | ||||
|   SDL_WindowFlags window_flags = | ||||
|       (SDL_WindowFlags)(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); | ||||
|   window = SDL_CreateWindow("Remote Desk", SDL_WINDOWPOS_CENTERED, | ||||
|                             SDL_WINDOWPOS_CENTERED, window_w, window_h, | ||||
|                             window_flags); | ||||
|  | ||||
|   SDL_DisplayMode DM; | ||||
|   SDL_GetCurrentDisplayMode(0, &DM); | ||||
|   screen_w = DM.w; | ||||
|   screen_h = DM.h; | ||||
|  | ||||
|   sdlRenderer = SDL_CreateRenderer( | ||||
|       window, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED); | ||||
|   if (sdlRenderer == nullptr) { | ||||
|     SDL_Log("Error creating SDL_Renderer!"); | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   Uint32 pixformat = 0; | ||||
|   pixformat = SDL_PIXELFORMAT_NV12; | ||||
|  | ||||
|   sdlTexture = SDL_CreateTexture(sdlRenderer, pixformat, | ||||
|                                  SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h); | ||||
|  | ||||
|   // Audio | ||||
|   SDL_AudioSpec want_in, have_in, want_out, have_out; | ||||
|   SDL_zero(want_in); | ||||
|   want_in.freq = 48000; | ||||
|   want_in.format = AUDIO_S16LSB; | ||||
|   want_in.channels = 1; | ||||
|   want_in.samples = 480; | ||||
|   want_in.callback = SdlCaptureAudioIn; | ||||
|  | ||||
|   input_dev = SDL_OpenAudioDevice(NULL, 1, &want_in, &have_in, 0); | ||||
|   if (input_dev == 0) { | ||||
|     SDL_Log("Failed to open input: %s", SDL_GetError()); | ||||
|     // return 1; | ||||
|   } | ||||
|  | ||||
|   SDL_zero(want_out); | ||||
|   want_out.freq = 48000; | ||||
|   want_out.format = AUDIO_S16LSB; | ||||
|   want_out.channels = 1; | ||||
|   // want_out.silence = 0; | ||||
|   want_out.samples = 480; | ||||
|   want_out.callback = NULL; | ||||
|  | ||||
|   output_dev = SDL_OpenAudioDevice(NULL, 0, &want_out, &have_out, 0); | ||||
|   if (output_dev == 0) { | ||||
|     SDL_Log("Failed to open input: %s", SDL_GetError()); | ||||
|     // return 1; | ||||
|   } | ||||
|  | ||||
|   SDL_PauseAudioDevice(input_dev, 0); | ||||
|   SDL_PauseAudioDevice(output_dev, 0); | ||||
|  | ||||
|   // Setup Dear ImGui context | ||||
|   IMGUI_CHECKVERSION(); | ||||
|   ImGui::CreateContext(); | ||||
|   ImGuiIO &io = ImGui::GetIO(); | ||||
|  | ||||
|   io.ConfigFlags |= | ||||
|       ImGuiConfigFlags_NavEnableKeyboard;  // Enable Keyboard Controls | ||||
|   io.ConfigFlags |= | ||||
|       ImGuiConfigFlags_NavEnableGamepad;  // Enable Gamepad Controls | ||||
|  | ||||
| #if CHINESE_FONT | ||||
|   // Load Fonts | ||||
| #ifdef _WIN32 | ||||
|   std::string default_font_path = "c:/windows/fonts/simhei.ttf"; | ||||
|   std::ifstream font_path_f(default_font_path.c_str()); | ||||
|   std::string font_path = | ||||
|       font_path_f.good() ? "c:/windows/fonts/simhei.ttf" : ""; | ||||
|   if (!font_path.empty()) { | ||||
|     io.Fonts->AddFontFromFileTTF(font_path.c_str(), 13.0f, NULL, | ||||
|                                  io.Fonts->GetGlyphRangesChineseFull()); | ||||
|   } | ||||
| #elif __APPLE__ | ||||
|   std::string default_font_path = "/System/Library/Fonts/PingFang.ttc"; | ||||
|   std::ifstream font_path_f(default_font_path.c_str()); | ||||
|   std::string font_path = | ||||
|       font_path_f.good() ? "/System/Library/Fonts/PingFang.ttc" : ""; | ||||
|   if (!font_path.empty()) { | ||||
|     io.Fonts->AddFontFromFileTTF(font_path.c_str(), 13.0f, NULL, | ||||
|                                  io.Fonts->GetGlyphRangesChineseFull()); | ||||
|   } | ||||
| #elif __linux__ | ||||
|   io.Fonts->AddFontFromFileTTF("c:/windows/fonts/msyh.ttc", 13.0f, NULL, | ||||
|                                io.Fonts->GetGlyphRangesChineseFull()); | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
|   // Setup Dear ImGui style | ||||
|   // ImGui::StyleColorsDark(); | ||||
|   ImGui::StyleColorsLight(); | ||||
|  | ||||
|   // Setup Platform/Renderer backends | ||||
|   ImGui_ImplSDL2_InitForSDLRenderer(window, sdlRenderer); | ||||
|   ImGui_ImplSDLRenderer2_Init(sdlRenderer); | ||||
|  | ||||
|   // Our state | ||||
|   bool show_demo_window = true; | ||||
|   bool show_another_window = false; | ||||
|   ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); | ||||
|  | ||||
|   std::string mac_addr_str = GetMac(); | ||||
|  | ||||
|   std::thread rtc_thread( | ||||
|       [](int screen_width, int screen_height) { | ||||
|         std::string default_cfg_path = "../../../../config/config.ini"; | ||||
|         std::ifstream f(default_cfg_path.c_str()); | ||||
|  | ||||
|         std::string mac_addr_str = GetMac(); | ||||
|  | ||||
|         Params server_params; | ||||
|         server_params.cfg_path = | ||||
|             f.good() ? "../../../../config/config.ini" : "config.ini"; | ||||
|         server_params.on_receive_video_buffer = ServerReceiveVideoBuffer; | ||||
|         server_params.on_receive_audio_buffer = ServerReceiveAudioBuffer; | ||||
|         server_params.on_receive_data_buffer = ServerReceiveDataBuffer; | ||||
|         server_params.on_signal_status = ServerSignalStatus; | ||||
|         server_params.on_connection_status = ServerConnectionStatus; | ||||
|  | ||||
|         Params client_params; | ||||
|         client_params.cfg_path = | ||||
|             f.good() ? "../../../../config/config.ini" : "config.ini"; | ||||
|         client_params.on_receive_video_buffer = ClientReceiveVideoBuffer; | ||||
|         client_params.on_receive_audio_buffer = ClientReceiveAudioBuffer; | ||||
|         client_params.on_receive_data_buffer = ClientReceiveDataBuffer; | ||||
|         client_params.on_signal_status = ClientSignalStatus; | ||||
|         client_params.on_connection_status = ClientConnectionStatus; | ||||
|  | ||||
|         std::string transmission_id = "000001"; | ||||
|  | ||||
|         peer_server = CreatePeer(&server_params); | ||||
|         LOG_INFO("Create peer_server"); | ||||
|         std::string server_user_id = "S-" + mac_addr_str; | ||||
|         Init(peer_server, server_user_id.c_str()); | ||||
|         LOG_INFO("peer_server init finish"); | ||||
|  | ||||
|         peer_client = CreatePeer(&client_params); | ||||
|         LOG_INFO("Create peer_client"); | ||||
|         std::string client_user_id = "C-" + mac_addr_str; | ||||
|         Init(peer_client, client_user_id.c_str()); | ||||
|         LOG_INFO("peer_client init finish"); | ||||
|  | ||||
|         { | ||||
|           while (SignalStatus::SignalConnected != server_signal_status && | ||||
|                  !done) { | ||||
|             std::this_thread::sleep_for(std::chrono::seconds(1)); | ||||
|           } | ||||
|  | ||||
|           if (done) { | ||||
|             return; | ||||
|           } | ||||
|  | ||||
|           std::string user_id = "S-" + mac_addr_str; | ||||
|           is_create_connection = | ||||
|               CreateConnection(peer_server, mac_addr_str.c_str(), | ||||
|                                input_password) | ||||
|                   ? false | ||||
|                   : true; | ||||
|  | ||||
|           nv12_buffer = new char[NV12_BUFFER_SIZE]; | ||||
|  | ||||
|           // Screen capture | ||||
|           screen_capturer_factory = new ScreenCapturerFactory(); | ||||
|           screen_capturer = (ScreenCapturer *)screen_capturer_factory->Create(); | ||||
|  | ||||
|           last_frame_time_ = std::chrono::high_resolution_clock::now(); | ||||
|           ScreenCapturer::RECORD_DESKTOP_RECT rect; | ||||
|           rect.left = 0; | ||||
|           rect.top = 0; | ||||
|           rect.right = screen_w; | ||||
|           rect.bottom = screen_h; | ||||
|  | ||||
|           int screen_capturer_init_ret = screen_capturer->Init( | ||||
|               rect, 60, | ||||
|               [](unsigned char *data, int size, int width, int height) -> void { | ||||
|                 auto now_time = std::chrono::high_resolution_clock::now(); | ||||
|                 std::chrono::duration<double> duration = | ||||
|                     now_time - last_frame_time_; | ||||
|                 auto tc = duration.count() * 1000; | ||||
|  | ||||
|                 if (tc >= 0) { | ||||
|                   SendData(peer_server, DATA_TYPE::VIDEO, (const char *)data, | ||||
|                            NV12_BUFFER_SIZE); | ||||
|                   last_frame_time_ = now_time; | ||||
|                 } | ||||
|               }); | ||||
|  | ||||
|           if (0 == screen_capturer_init_ret) { | ||||
|             screen_capturer->Start(); | ||||
|           } else { | ||||
|             screen_capturer->Destroy(); | ||||
|             screen_capturer = nullptr; | ||||
|           } | ||||
|  | ||||
|           // Mouse control | ||||
|           device_controller_factory = new DeviceControllerFactory(); | ||||
|           mouse_controller = | ||||
|               (MouseController *)device_controller_factory->Create( | ||||
|                   DeviceControllerFactory::Device::Mouse); | ||||
|           int mouse_controller_init_ret = | ||||
|               mouse_controller->Init(screen_w, screen_h); | ||||
|           if (0 != mouse_controller_init_ret) { | ||||
|             mouse_controller->Destroy(); | ||||
|             mouse_controller = nullptr; | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       screen_w, screen_h); | ||||
|  | ||||
|   // Main loop | ||||
|   while (!done) { | ||||
|     // Start the Dear ImGui frame | ||||
|     ImGui_ImplSDLRenderer2_NewFrame(); | ||||
|     ImGui_ImplSDL2_NewFrame(); | ||||
|     ImGui::NewFrame(); | ||||
|  | ||||
|     if (joined && !menu_hovered) { | ||||
|       ImGui::SetMouseCursor(ImGuiMouseCursor_None); | ||||
|     } | ||||
|  | ||||
|     { | ||||
|       static float f = 0.0f; | ||||
|       static int counter = 0; | ||||
|  | ||||
|       const ImGuiViewport *main_viewport = ImGui::GetMainViewport(); | ||||
|       ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Once); | ||||
|  | ||||
|       // ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f)); | ||||
|  | ||||
| #if CHINESE_FONT | ||||
|       ImGui::SetNextWindowSize(ImVec2(160, 210)); | ||||
| #else | ||||
|       ImGui::SetNextWindowSize(ImVec2(180, 210)); | ||||
| #endif | ||||
|  | ||||
| #if CHINESE_FONT | ||||
|       if (!joined) { | ||||
|         ImGui::Begin(u8"菜单", nullptr, | ||||
|                      ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | | ||||
|                          ImGuiWindowFlags_NoMove); | ||||
|       } else { | ||||
|         ImGui::SetNextWindowCollapsed(true, ImGuiCond_Once); | ||||
|         ImGui::Begin(u8"菜单", nullptr, ImGuiWindowFlags_None); | ||||
|       } | ||||
| #else | ||||
|       ImGui::Begin("Menu", nullptr, ImGuiWindowFlags_NoResize); | ||||
| #endif | ||||
|  | ||||
|       { | ||||
|         menu_hovered = ImGui::IsWindowHovered(); | ||||
| #if CHINESE_FONT | ||||
|         ImGui::Text(u8"本机ID:"); | ||||
| #else | ||||
|         ImGui::Text("LOCAL ID:"); | ||||
| #endif | ||||
|         ImGui::SameLine(); | ||||
|         ImGui::SetNextItemWidth(90); | ||||
| #if CHINESE_FONT | ||||
|         ImGui::SetCursorPosX(60.0f); | ||||
| #else | ||||
|         ImGui::SetCursorPosX(80.0f); | ||||
| #endif | ||||
|         ImGui::InputText( | ||||
|             "##local_id", (char *)mac_addr_str.c_str(), | ||||
|             mac_addr_str.length() + 1, | ||||
|             ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_ReadOnly); | ||||
|  | ||||
| #if CHINESE_FONT | ||||
|         ImGui::Text(u8"密码:"); | ||||
| #else | ||||
|         ImGui::Text("PASSWORD:"); | ||||
| #endif | ||||
|         ImGui::SameLine(); | ||||
|         char input_password_tmp[7] = ""; | ||||
|         std::string input_password_str = "123456"; | ||||
|         strncpy(input_password_tmp, input_password, sizeof(input_password)); | ||||
|         ImGui::SetNextItemWidth(90); | ||||
| #if CHINESE_FONT | ||||
|         ImGui::SetCursorPosX(60.0f); | ||||
|         ImGui::InputTextWithHint("##server_pwd", u8"最长6个字符", | ||||
|                                  input_password, IM_ARRAYSIZE(input_password), | ||||
|                                  ImGuiInputTextFlags_CharsNoBlank); | ||||
| #else | ||||
|         ImGui::SetCursorPosX(80.0f); | ||||
|         ImGui::InputTextWithHint("##server_pwd", "max 6 chars", input_password, | ||||
|                                  IM_ARRAYSIZE(input_password), | ||||
|                                  ImGuiInputTextFlags_CharsNoBlank); | ||||
| #endif | ||||
|         if (strcmp(input_password_tmp, input_password)) { | ||||
|           cd_cache_file = fopen("cache.cd", "w+"); | ||||
|           if (cd_cache_file) { | ||||
|             fseek(cd_cache_file, 0, SEEK_SET); | ||||
|             strncpy(cd_cache.password, input_password, sizeof(input_password)); | ||||
|             fwrite(&cd_cache.password, sizeof(cd_cache.password), 1, | ||||
|                    cd_cache_file); | ||||
|             fclose(cd_cache_file); | ||||
|           } | ||||
|           LeaveConnection(peer_server); | ||||
|           CreateConnection(peer_server, mac_addr_str.c_str(), input_password); | ||||
|         } | ||||
|  | ||||
|         ImGui::Spacing(); | ||||
|  | ||||
|         ImGui::Separator(); | ||||
|  | ||||
|         ImGui::Spacing(); | ||||
|         { | ||||
|           { | ||||
|             static char remote_id[20] = ""; | ||||
| #if CHINESE_FONT | ||||
|             ImGui::Text(u8"远端ID:"); | ||||
| #else | ||||
|             ImGui::Text("REMOTE ID:"); | ||||
| #endif | ||||
|             ImGui::SameLine(); | ||||
|             ImGui::SetNextItemWidth(90); | ||||
| #if CHINESE_FONT | ||||
|             ImGui::SetCursorPosX(60.0f); | ||||
| #else | ||||
|             ImGui::SetCursorPosX(80.0f); | ||||
| #endif | ||||
|             ImGui::InputTextWithHint("##remote_id", mac_addr_str.c_str(), | ||||
|                                      remote_id, IM_ARRAYSIZE(remote_id), | ||||
|                                      ImGuiInputTextFlags_CharsUppercase | | ||||
|                                          ImGuiInputTextFlags_CharsNoBlank); | ||||
|  | ||||
|             ImGui::Spacing(); | ||||
|  | ||||
| #if CHINESE_FONT | ||||
|             ImGui::Text(u8"密码:"); | ||||
| #else | ||||
|             ImGui::Text("PASSWORD:"); | ||||
| #endif | ||||
|             ImGui::SameLine(); | ||||
|             ImGui::SetNextItemWidth(90); | ||||
|             static char client_password[20] = ""; | ||||
| #if CHINESE_FONT | ||||
|             ImGui::SetCursorPosX(60.0f); | ||||
|             ImGui::InputTextWithHint("##client_pwd", u8"最长6个字符", | ||||
|                                      client_password, | ||||
|                                      IM_ARRAYSIZE(client_password), | ||||
|                                      ImGuiInputTextFlags_CharsNoBlank); | ||||
| #else | ||||
|             ImGui::SetCursorPosX(80.0f); | ||||
|             ImGui::InputTextWithHint("##client_pwd", "max 6 chars", | ||||
|                                      client_password, | ||||
|                                      IM_ARRAYSIZE(client_password), | ||||
|                                      ImGuiInputTextFlags_CharsNoBlank); | ||||
| #endif | ||||
|  | ||||
|             ImGui::Spacing(); | ||||
|             ImGui::Separator(); | ||||
|             ImGui::Spacing(); | ||||
|  | ||||
|             if (ImGui::Button(connect_label)) { | ||||
|               int ret = -1; | ||||
|               if ("ClientSignalConnected" == client_signal_status_str) { | ||||
| #if CHINESE_FONT | ||||
|                 if (strcmp(connect_label, u8"连接") == 0 && !joined) { | ||||
| #else | ||||
|                 if (strcmp(connect_label, "Connect") == 0 && !joined) { | ||||
| #endif | ||||
|                   std::string user_id = "C-" + mac_addr_str; | ||||
|                   ret = JoinConnection(peer_client, remote_id, client_password); | ||||
|                   if (0 == ret) { | ||||
|                     // joined = true; | ||||
|                   } | ||||
| #if CHINESE_FONT | ||||
|                 } else if (strcmp(connect_label, u8"断开连接") == 0 && joined) { | ||||
| #else | ||||
|                 } else if (strcmp(connect_label, "Disconnect") == 0 && joined) { | ||||
| #endif | ||||
|                   ret = LeaveConnection(peer_client); | ||||
|                   memset(audio_buffer, 0, 960); | ||||
|                   if (0 == ret) { | ||||
|                     joined = false; | ||||
|                     received_frame = false; | ||||
|                   } | ||||
|                 } | ||||
|  | ||||
|                 if (0 == ret) { | ||||
|                   connect_button_pressed = !connect_button_pressed; | ||||
| #if CHINESE_FONT | ||||
|                   connect_label = | ||||
|                       connect_button_pressed ? u8"断开连接" : u8"连接"; | ||||
| #else | ||||
|                   connect_label = | ||||
|                       connect_button_pressed ? "Disconnect" : "Connect"; | ||||
| #endif | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       ImGui::Spacing(); | ||||
|  | ||||
|       ImGui::Separator(); | ||||
|  | ||||
|       ImGui::Spacing(); | ||||
|  | ||||
|       { | ||||
| #if CHINESE_FONT | ||||
|         if (ImGui::Button(u8"重置窗口")) { | ||||
| #else | ||||
|         if (ImGui::Button("Resize Window")) { | ||||
| #endif | ||||
|           SDL_GetWindowSize(window, &window_w, &window_h); | ||||
|  | ||||
|           if (window_h != window_w * 9 / 16) { | ||||
|             window_w = window_h * 16 / 9; | ||||
|           } | ||||
|  | ||||
|           SDL_SetWindowSize(window, window_w, window_h); | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       ImGui::SameLine(); | ||||
|  | ||||
| #if CHINESE_FONT | ||||
|       if (ImGui::Button(fullscreen_label)) { | ||||
|         if (strcmp(fullscreen_label, u8"全屏") == 0) { | ||||
| #else | ||||
|       if (ImGui::Button(fullscreen_label)) { | ||||
|         if (strcmp(fullscreen_label, "FULLSCREEN") == 0) { | ||||
| #endif | ||||
|           SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); | ||||
|         } else { | ||||
|           SDL_SetWindowFullscreen(window, SDL_FALSE); | ||||
|         } | ||||
|         fullscreen_button_pressed = !fullscreen_button_pressed; | ||||
| #if CHINESE_FONT | ||||
|         fullscreen_label = fullscreen_button_pressed ? u8"退出全屏" : u8"全屏"; | ||||
| #else | ||||
|         fullscreen_label = | ||||
|             fullscreen_button_pressed ? "EXIT FULLSCREEN" : "FULLSCREEN"; | ||||
| #endif | ||||
|       } | ||||
|       ImGui::End(); | ||||
|     } | ||||
|  | ||||
|     // Rendering | ||||
|     ImGui::Render(); | ||||
|     SDL_RenderSetScale(sdlRenderer, io.DisplayFramebufferScale.x, | ||||
|                        io.DisplayFramebufferScale.y); | ||||
|  | ||||
|     SDL_Event event; | ||||
|     while (SDL_PollEvent(&event)) { | ||||
|       ImGui_ImplSDL2_ProcessEvent(&event); | ||||
|       if (event.type == SDL_QUIT) { | ||||
|         done = true; | ||||
|       } else if (event.type == SDL_WINDOWEVENT && | ||||
|                  event.window.event == SDL_WINDOWEVENT_RESIZED) { | ||||
|         SDL_GetWindowSize(window, &window_w, &window_h); | ||||
|       } else if (event.type == SDL_WINDOWEVENT && | ||||
|                  event.window.event == SDL_WINDOWEVENT_CLOSE && | ||||
|                  event.window.windowID == SDL_GetWindowID(window)) { | ||||
|         done = true; | ||||
|       } else if (event.type == REFRESH_EVENT) { | ||||
|         sdlRect.x = 0; | ||||
|         sdlRect.y = 0; | ||||
|         sdlRect.w = window_w; | ||||
|         sdlRect.h = window_h; | ||||
|  | ||||
|         SDL_UpdateTexture(sdlTexture, NULL, dst_buffer, pixel_w); | ||||
|       } else { | ||||
|         if (joined) { | ||||
|           ProcessMouseKeyEven(event); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     SDL_RenderClear(sdlRenderer); | ||||
|     SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect); | ||||
|  | ||||
|     if (!joined || !received_frame) { | ||||
|       SDL_RenderClear(sdlRenderer); | ||||
|       SDL_SetRenderDrawColor( | ||||
|           sdlRenderer, (Uint8)(clear_color.x * 0), (Uint8)(clear_color.y * 0), | ||||
|           (Uint8)(clear_color.z * 0), (Uint8)(clear_color.w * 0)); | ||||
|     } | ||||
|  | ||||
|     ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData()); | ||||
|     SDL_RenderPresent(sdlRenderer); | ||||
|  | ||||
|     frame_count++; | ||||
|     end_time = SDL_GetTicks(); | ||||
|     elapsed_time = end_time - start_time; | ||||
|     if (elapsed_time >= 1000) { | ||||
|       fps = frame_count / (elapsed_time / 1000); | ||||
|       frame_count = 0; | ||||
|       window_title = "Remote Desk Client FPS [" + std::to_string(fps) + | ||||
|                      "] status [" + server_signal_status_str + "|" + | ||||
|                      client_signal_status_str + "|" + | ||||
|                      server_connection_status_str + "|" + | ||||
|                      client_connection_status_str + "]"; | ||||
|       // For MacOS, UI frameworks can only be called from the main thread | ||||
|       SDL_SetWindowTitle(window, window_title.c_str()); | ||||
|       start_time = end_time; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Cleanup | ||||
|  | ||||
|   if (is_create_connection) { | ||||
|     LeaveConnection(peer_server); | ||||
|   } | ||||
|  | ||||
|   if (joined) { | ||||
|     LeaveConnection(peer_client); | ||||
|   } | ||||
|  | ||||
|   rtc_thread.join(); | ||||
|   SDL_CloseAudioDevice(output_dev); | ||||
|   SDL_CloseAudioDevice(input_dev); | ||||
|  | ||||
|   if (screen_capturer) { | ||||
|     screen_capturer->Destroy(); | ||||
|   } | ||||
|  | ||||
|   if (mouse_controller) { | ||||
|     mouse_controller->Destroy(); | ||||
|   } | ||||
|  | ||||
|   ImGui_ImplSDLRenderer2_Shutdown(); | ||||
|   ImGui_ImplSDL2_Shutdown(); | ||||
|   ImGui::DestroyContext(); | ||||
|  | ||||
|   SDL_DestroyRenderer(sdlRenderer); | ||||
|   SDL_DestroyWindow(window); | ||||
|  | ||||
|   SDL_CloseAudio(); | ||||
|   SDL_Quit(); | ||||
|   main_window.Run(); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										938
									
								
								src/gui/mainbak.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										938
									
								
								src/gui/mainbak.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,938 @@ | ||||
| #include <SDL.h> | ||||
| #include <stdio.h> | ||||
| #ifdef _WIN32 | ||||
| #ifdef REMOTE_DESK_DEBUG | ||||
| #pragma comment(linker, "/subsystem:\"console\"") | ||||
| #else | ||||
| #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"") | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #include <stdio.h> | ||||
|  | ||||
| #include <atomic> | ||||
| #include <chrono> | ||||
| #include <cstring> | ||||
| #include <fstream> | ||||
| #include <iostream> | ||||
| #include <string> | ||||
| #include <thread> | ||||
|  | ||||
| #include "../../thirdparty/projectx/src/interface/x.h" | ||||
| #include "config_center.h" | ||||
| #include "device_controller_factory.h" | ||||
| #include "imgui.h" | ||||
| #include "imgui_impl_sdl2.h" | ||||
| #include "imgui_impl_sdlrenderer2.h" | ||||
| #include "log.h" | ||||
| #include "platform.h" | ||||
| #include "screen_capturer_factory.h" | ||||
|  | ||||
| #define NV12_BUFFER_SIZE 1280 * 720 * 3 / 2 | ||||
|  | ||||
| #ifdef REMOTE_DESK_DEBUG | ||||
| #define MOUSE_CONTROL 0 | ||||
| #else | ||||
| #define MOUSE_CONTROL 1 | ||||
| #endif | ||||
|  | ||||
| #define CHINESE_FONT 1 | ||||
|  | ||||
| int screen_w = 1280, screen_h = 720; | ||||
| int window_w = 1280, window_h = 720; | ||||
| const int pixel_w = 1280, pixel_h = 720; | ||||
|  | ||||
| unsigned char dst_buffer[pixel_w * pixel_h * 3 / 2]; | ||||
| unsigned char audio_buffer[960]; | ||||
| SDL_Texture *sdlTexture = nullptr; | ||||
| SDL_Renderer *sdlRenderer = nullptr; | ||||
| SDL_Rect sdlRect; | ||||
| SDL_Window *window; | ||||
| static SDL_AudioDeviceID input_dev; | ||||
| static SDL_AudioDeviceID output_dev; | ||||
|  | ||||
| uint32_t start_time, end_time, elapsed_time; | ||||
| uint32_t frame_count = 0; | ||||
| int fps = 0; | ||||
|  | ||||
| static std::atomic<bool> audio_buffer_fresh{false}; | ||||
| static uint32_t last_ts = 0; | ||||
|  | ||||
| int dst_bufsize; | ||||
| struct SwrContext *swr_ctx; | ||||
|  | ||||
| int ret; | ||||
|  | ||||
| int audio_len = 0; | ||||
|  | ||||
| std::string window_title = "Remote Desk Client"; | ||||
| std::string server_connection_status_str = "-"; | ||||
| std::string client_connection_status_str = "-"; | ||||
| std::string server_signal_status_str = "-"; | ||||
| std::string client_signal_status_str = "-"; | ||||
|  | ||||
| std::atomic<ConnectionStatus> server_connection_status{ | ||||
|     ConnectionStatus::Closed}; | ||||
| std::atomic<ConnectionStatus> client_connection_status{ | ||||
|     ConnectionStatus::Closed}; | ||||
| std::atomic<SignalStatus> server_signal_status{SignalStatus::SignalClosed}; | ||||
| std::atomic<SignalStatus> client_signal_status{SignalStatus::SignalClosed}; | ||||
|  | ||||
| // Refresh Event | ||||
| #define REFRESH_EVENT (SDL_USEREVENT + 1) | ||||
| #define QUIT_EVENT (SDL_USEREVENT + 2) | ||||
|  | ||||
| typedef struct { | ||||
|   char password[7]; | ||||
| } CDCache; | ||||
|  | ||||
| int thread_exit = 0; | ||||
| PeerPtr *peer_server = nullptr; | ||||
| PeerPtr *peer_client = nullptr; | ||||
| bool joined = false; | ||||
| bool received_frame = false; | ||||
| bool menu_hovered = false; | ||||
|  | ||||
| static bool connect_button_pressed = false; | ||||
| static bool fullscreen_button_pressed = false; | ||||
|  | ||||
| #if CHINESE_FONT | ||||
| static const char *connect_label = u8"连接"; | ||||
| static const char *fullscreen_label = u8"全屏"; | ||||
| #else | ||||
| static const char *connect_label = "Connect"; | ||||
| static const char *fullscreen_label = "FULLSCREEN"; | ||||
| #endif | ||||
| static char input_password[7] = ""; | ||||
| static FILE *cd_cache_file = nullptr; | ||||
| static CDCache cd_cache; | ||||
|  | ||||
| static bool is_create_connection = false; | ||||
| static bool done = false; | ||||
|  | ||||
| ScreenCapturerFactory *screen_capturer_factory = nullptr; | ||||
| ScreenCapturer *screen_capturer = nullptr; | ||||
|  | ||||
| DeviceControllerFactory *device_controller_factory = nullptr; | ||||
| MouseController *mouse_controller = nullptr; | ||||
|  | ||||
| ConfigCenter config_center; | ||||
|  | ||||
| char *nv12_buffer = nullptr; | ||||
|  | ||||
| #ifdef __linux__ | ||||
| std::chrono::_V2::system_clock::time_point last_frame_time_; | ||||
| #else | ||||
| std::chrono::steady_clock::time_point last_frame_time_; | ||||
| #endif | ||||
|  | ||||
| inline int ProcessMouseKeyEven(SDL_Event &ev) { | ||||
|   float ratio = (float)(1280.0 / window_w); | ||||
|  | ||||
|   RemoteAction remote_action; | ||||
|   remote_action.m.x = (size_t)(ev.button.x * ratio); | ||||
|   remote_action.m.y = (size_t)(ev.button.y * ratio); | ||||
|  | ||||
|   if (SDL_KEYDOWN == ev.type)  // SDL_KEYUP | ||||
|   { | ||||
|     // printf("SDLK_DOWN: %d\n", SDL_KeyCode(ev.key.keysym.sym)); | ||||
|     if (SDLK_DOWN == ev.key.keysym.sym) { | ||||
|       // printf("SDLK_DOWN  \n"); | ||||
|  | ||||
|     } else if (SDLK_UP == ev.key.keysym.sym) { | ||||
|       // printf("SDLK_UP  \n"); | ||||
|  | ||||
|     } else if (SDLK_LEFT == ev.key.keysym.sym) { | ||||
|       // printf("SDLK_LEFT  \n"); | ||||
|  | ||||
|     } else if (SDLK_RIGHT == ev.key.keysym.sym) { | ||||
|       // printf("SDLK_RIGHT  \n"); | ||||
|     } | ||||
|   } else if (SDL_MOUSEBUTTONDOWN == ev.type) { | ||||
|     remote_action.type = ControlType::mouse; | ||||
|     if (SDL_BUTTON_LEFT == ev.button.button) { | ||||
|       remote_action.m.flag = MouseFlag::left_down; | ||||
|     } else if (SDL_BUTTON_RIGHT == ev.button.button) { | ||||
|       remote_action.m.flag = MouseFlag::right_down; | ||||
|     } | ||||
|     SendData(peer_client, DATA_TYPE::DATA, (const char *)&remote_action, | ||||
|              sizeof(remote_action)); | ||||
|   } else if (SDL_MOUSEBUTTONUP == ev.type) { | ||||
|     remote_action.type = ControlType::mouse; | ||||
|     if (SDL_BUTTON_LEFT == ev.button.button) { | ||||
|       remote_action.m.flag = MouseFlag::left_up; | ||||
|     } else if (SDL_BUTTON_RIGHT == ev.button.button) { | ||||
|       remote_action.m.flag = MouseFlag::right_up; | ||||
|     } | ||||
|     SendData(peer_client, DATA_TYPE::DATA, (const char *)&remote_action, | ||||
|              sizeof(remote_action)); | ||||
|   } else if (SDL_MOUSEMOTION == ev.type) { | ||||
|     remote_action.type = ControlType::mouse; | ||||
|     remote_action.m.flag = MouseFlag::move; | ||||
|     SendData(peer_client, DATA_TYPE::DATA, (const char *)&remote_action, | ||||
|              sizeof(remote_action)); | ||||
|   } else if (SDL_QUIT == ev.type) { | ||||
|     SDL_Event event; | ||||
|     event.type = SDL_QUIT; | ||||
|     SDL_PushEvent(&event); | ||||
|     printf("SDL_QUIT\n"); | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| void SdlCaptureAudioIn(void *userdata, Uint8 *stream, int len) { | ||||
|   if (1) { | ||||
|     if ("ClientConnected" == client_connection_status_str) { | ||||
|       SendData(peer_client, DATA_TYPE::AUDIO, (const char *)stream, len); | ||||
|     } | ||||
|  | ||||
|     if ("ServerConnected" == server_connection_status_str) { | ||||
|       SendData(peer_server, DATA_TYPE::AUDIO, (const char *)stream, len); | ||||
|     } | ||||
|   } else { | ||||
|     memcpy(audio_buffer, stream, len); | ||||
|     audio_len = len; | ||||
|     SDL_Delay(10); | ||||
|     audio_buffer_fresh = true; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void SdlCaptureAudioOut(void *userdata, Uint8 *stream, int len) { | ||||
|   // if ("ClientConnected" != client_connection_status_str) { | ||||
|   //   return; | ||||
|   // } | ||||
|  | ||||
|   if (!audio_buffer_fresh) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   SDL_memset(stream, 0, len); | ||||
|  | ||||
|   if (audio_len == 0) { | ||||
|     return; | ||||
|   } else { | ||||
|   } | ||||
|  | ||||
|   len = (len > audio_len ? audio_len : len); | ||||
|   SDL_MixAudioFormat(stream, audio_buffer, AUDIO_S16LSB, len, | ||||
|                      SDL_MIX_MAXVOLUME); | ||||
|   audio_buffer_fresh = false; | ||||
| } | ||||
|  | ||||
| void ServerReceiveVideoBuffer(const char *data, size_t size, | ||||
|                               const char *user_id, size_t user_id_size) {} | ||||
|  | ||||
| void ClientReceiveVideoBuffer(const char *data, size_t size, | ||||
|                               const char *user_id, size_t user_id_size) { | ||||
|   // std::cout << "Receive: [" << user_id << "] " << std::endl; | ||||
|   if (joined) { | ||||
|     memcpy(dst_buffer, data, size); | ||||
|  | ||||
|     SDL_Event event; | ||||
|     event.type = REFRESH_EVENT; | ||||
|     SDL_PushEvent(&event); | ||||
|     received_frame = true; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void ServerReceiveAudioBuffer(const char *data, size_t size, | ||||
|                               const char *user_id, size_t user_id_size) { | ||||
|   // memset(audio_buffer, 0, size); | ||||
|   // memcpy(audio_buffer, data, size); | ||||
|   // audio_len = size; | ||||
|   audio_buffer_fresh = true; | ||||
|  | ||||
|   SDL_QueueAudio(output_dev, data, (Uint32)size); | ||||
|   // printf("queue audio\n"); | ||||
| } | ||||
|  | ||||
| void ClientReceiveAudioBuffer(const char *data, size_t size, | ||||
|                               const char *user_id, size_t user_id_size) { | ||||
|   std::cout << "Client receive audio, size " << size << ", user [" << user_id | ||||
|             << "] " << std::endl; | ||||
|   SDL_QueueAudio(output_dev, data, (Uint32)size); | ||||
| } | ||||
|  | ||||
| void ServerReceiveDataBuffer(const char *data, size_t size, const char *user_id, | ||||
|                              size_t user_id_size) { | ||||
|   std::string user(user_id, user_id_size); | ||||
|  | ||||
|   RemoteAction remote_action; | ||||
|   memcpy(&remote_action, data, sizeof(remote_action)); | ||||
|  | ||||
|   // std::cout << "remote_action: " << remote_action.type << " " | ||||
|   //           << remote_action.m.flag << " " << remote_action.m.x << " " | ||||
|   //           << remote_action.m.y << std::endl; | ||||
| #if MOUSE_CONTROL | ||||
|   if (mouse_controller) { | ||||
|     mouse_controller->SendCommand(remote_action); | ||||
|   } | ||||
| #endif | ||||
| } | ||||
|  | ||||
| void ClientReceiveDataBuffer(const char *data, size_t size, const char *user_id, | ||||
|                              size_t user_id_size) {} | ||||
|  | ||||
| void ServerSignalStatus(SignalStatus status) { | ||||
|   server_signal_status = status; | ||||
|   if (SignalStatus::SignalConnecting == status) { | ||||
|     server_signal_status_str = "ServerSignalConnecting"; | ||||
|   } else if (SignalStatus::SignalConnected == status) { | ||||
|     server_signal_status_str = "ServerSignalConnected"; | ||||
|   } else if (SignalStatus::SignalFailed == status) { | ||||
|     server_signal_status_str = "ServerSignalFailed"; | ||||
|   } else if (SignalStatus::SignalClosed == status) { | ||||
|     server_signal_status_str = "ServerSignalClosed"; | ||||
|   } else if (SignalStatus::SignalReconnecting == status) { | ||||
|     server_signal_status_str = "ServerSignalReconnecting"; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void ClientSignalStatus(SignalStatus status) { | ||||
|   client_signal_status = status; | ||||
|   if (SignalStatus::SignalConnecting == status) { | ||||
|     client_signal_status_str = "ClientSignalConnecting"; | ||||
|   } else if (SignalStatus::SignalConnected == status) { | ||||
|     client_signal_status_str = "ClientSignalConnected"; | ||||
|   } else if (SignalStatus::SignalFailed == status) { | ||||
|     client_signal_status_str = "ClientSignalFailed"; | ||||
|   } else if (SignalStatus::SignalClosed == status) { | ||||
|     client_signal_status_str = "ClientSignalClosed"; | ||||
|   } else if (SignalStatus::SignalReconnecting == status) { | ||||
|     client_signal_status_str = "ClientSignalReconnecting"; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void ServerConnectionStatus(ConnectionStatus status) { | ||||
|   server_connection_status = status; | ||||
|   if (ConnectionStatus::Connecting == status) { | ||||
|     server_connection_status_str = "ServerConnecting"; | ||||
|   } else if (ConnectionStatus::Connected == status) { | ||||
|     server_connection_status_str = "ServerConnected"; | ||||
|   } else if (ConnectionStatus::Disconnected == status) { | ||||
|     server_connection_status_str = "ServerDisconnected"; | ||||
|   } else if (ConnectionStatus::Failed == status) { | ||||
|     server_connection_status_str = "ServerFailed"; | ||||
|   } else if (ConnectionStatus::Closed == status) { | ||||
|     server_connection_status_str = "ServerClosed"; | ||||
|   } else if (ConnectionStatus::IncorrectPassword == status) { | ||||
|     server_connection_status_str = "Incorrect password"; | ||||
|     if (connect_button_pressed) { | ||||
|       connect_button_pressed = false; | ||||
|       joined = false; | ||||
|       connect_label = connect_button_pressed ? "Disconnect" : "Connect"; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| void ClientConnectionStatus(ConnectionStatus status) { | ||||
|   client_connection_status = status; | ||||
|   if (ConnectionStatus::Connecting == status) { | ||||
|     client_connection_status_str = "ClientConnecting"; | ||||
|   } else if (ConnectionStatus::Connected == status) { | ||||
|     client_connection_status_str = "ClientConnected"; | ||||
|     joined = true; | ||||
|   } else if (ConnectionStatus::Disconnected == status) { | ||||
|     client_connection_status_str = "ClientDisconnected"; | ||||
|   } else if (ConnectionStatus::Failed == status) { | ||||
|     client_connection_status_str = "ClientFailed"; | ||||
|   } else if (ConnectionStatus::Closed == status) { | ||||
|     client_connection_status_str = "ClientClosed"; | ||||
|   } else if (ConnectionStatus::IncorrectPassword == status) { | ||||
|     client_connection_status_str = "Incorrect password"; | ||||
|     if (connect_button_pressed) { | ||||
|       connect_button_pressed = false; | ||||
|       joined = false; | ||||
|       connect_label = connect_button_pressed ? "Disconnect" : "Connect"; | ||||
|     } | ||||
|   } else if (ConnectionStatus::NoSuchTransmissionId == status) { | ||||
|     client_connection_status_str = "No such transmission id"; | ||||
|     if (connect_button_pressed) { | ||||
|       connect_button_pressed = false; | ||||
|       joined = false; | ||||
|       connect_label = connect_button_pressed ? "Disconnect" : "Connect"; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| int main(int argc, char *argv[]) { | ||||
|   LOG_INFO("Remote desk"); | ||||
|  | ||||
|   last_ts = static_cast<uint32_t>( | ||||
|       std::chrono::duration_cast<std::chrono::milliseconds>( | ||||
|           std::chrono::high_resolution_clock::now().time_since_epoch()) | ||||
|           .count()); | ||||
|  | ||||
|   cd_cache_file = fopen("cache.cd", "r+"); | ||||
|   if (cd_cache_file) { | ||||
|     fseek(cd_cache_file, 0, SEEK_SET); | ||||
|     fread(&cd_cache.password, sizeof(cd_cache.password), 1, cd_cache_file); | ||||
|     fclose(cd_cache_file); | ||||
|     strncpy(input_password, cd_cache.password, sizeof(cd_cache.password)); | ||||
|   } | ||||
|  | ||||
|   // Setup SDL | ||||
|   if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER | | ||||
|                SDL_INIT_GAMECONTROLLER) != 0) { | ||||
|     printf("Error: %s\n", SDL_GetError()); | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   // From 2.0.18: Enable native IME. | ||||
| #ifdef SDL_HINT_IME_SHOW_UI | ||||
|   SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); | ||||
| #endif | ||||
|  | ||||
|   // Create window with SDL_Renderer graphics context | ||||
|   SDL_WindowFlags window_flags = | ||||
|       (SDL_WindowFlags)(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); | ||||
|   window = SDL_CreateWindow("Remote Desk", SDL_WINDOWPOS_CENTERED, | ||||
|                             SDL_WINDOWPOS_CENTERED, window_w, window_h, | ||||
|                             window_flags); | ||||
|  | ||||
|   SDL_DisplayMode DM; | ||||
|   SDL_GetCurrentDisplayMode(0, &DM); | ||||
|   screen_w = DM.w; | ||||
|   screen_h = DM.h; | ||||
|  | ||||
|   sdlRenderer = SDL_CreateRenderer( | ||||
|       window, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED); | ||||
|   if (sdlRenderer == nullptr) { | ||||
|     SDL_Log("Error creating SDL_Renderer!"); | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   Uint32 pixformat = 0; | ||||
|   pixformat = SDL_PIXELFORMAT_NV12; | ||||
|  | ||||
|   sdlTexture = SDL_CreateTexture(sdlRenderer, pixformat, | ||||
|                                  SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h); | ||||
|  | ||||
|   // Audio | ||||
|   SDL_AudioSpec want_in, have_in, want_out, have_out; | ||||
|   SDL_zero(want_in); | ||||
|   want_in.freq = 48000; | ||||
|   want_in.format = AUDIO_S16LSB; | ||||
|   want_in.channels = 1; | ||||
|   want_in.samples = 480; | ||||
|   want_in.callback = SdlCaptureAudioIn; | ||||
|  | ||||
|   input_dev = SDL_OpenAudioDevice(NULL, 1, &want_in, &have_in, 0); | ||||
|   if (input_dev == 0) { | ||||
|     SDL_Log("Failed to open input: %s", SDL_GetError()); | ||||
|     // return 1; | ||||
|   } | ||||
|  | ||||
|   SDL_zero(want_out); | ||||
|   want_out.freq = 48000; | ||||
|   want_out.format = AUDIO_S16LSB; | ||||
|   want_out.channels = 1; | ||||
|   // want_out.silence = 0; | ||||
|   want_out.samples = 480; | ||||
|   want_out.callback = NULL; | ||||
|  | ||||
|   output_dev = SDL_OpenAudioDevice(NULL, 0, &want_out, &have_out, 0); | ||||
|   if (output_dev == 0) { | ||||
|     SDL_Log("Failed to open input: %s", SDL_GetError()); | ||||
|     // return 1; | ||||
|   } | ||||
|  | ||||
|   SDL_PauseAudioDevice(input_dev, 0); | ||||
|   SDL_PauseAudioDevice(output_dev, 0); | ||||
|  | ||||
|   // Setup Dear ImGui context | ||||
|   IMGUI_CHECKVERSION(); | ||||
|   ImGui::CreateContext(); | ||||
|   ImGuiIO &io = ImGui::GetIO(); | ||||
|  | ||||
|   io.ConfigFlags |= | ||||
|       ImGuiConfigFlags_NavEnableKeyboard;  // Enable Keyboard Controls | ||||
|   io.ConfigFlags |= | ||||
|       ImGuiConfigFlags_NavEnableGamepad;  // Enable Gamepad Controls | ||||
|  | ||||
| #if CHINESE_FONT | ||||
|   // Load Fonts | ||||
| #ifdef _WIN32 | ||||
|   std::string default_font_path = "c:/windows/fonts/simhei.ttf"; | ||||
|   std::ifstream font_path_f(default_font_path.c_str()); | ||||
|   std::string font_path = | ||||
|       font_path_f.good() ? "c:/windows/fonts/simhei.ttf" : ""; | ||||
|   if (!font_path.empty()) { | ||||
|     io.Fonts->AddFontFromFileTTF(font_path.c_str(), 13.0f, NULL, | ||||
|                                  io.Fonts->GetGlyphRangesChineseFull()); | ||||
|   } | ||||
| #elif __APPLE__ | ||||
|   std::string default_font_path = "/System/Library/Fonts/PingFang.ttc"; | ||||
|   std::ifstream font_path_f(default_font_path.c_str()); | ||||
|   std::string font_path = | ||||
|       font_path_f.good() ? "/System/Library/Fonts/PingFang.ttc" : ""; | ||||
|   if (!font_path.empty()) { | ||||
|     io.Fonts->AddFontFromFileTTF(font_path.c_str(), 13.0f, NULL, | ||||
|                                  io.Fonts->GetGlyphRangesChineseFull()); | ||||
|   } | ||||
| #elif __linux__ | ||||
|   io.Fonts->AddFontFromFileTTF("c:/windows/fonts/msyh.ttc", 13.0f, NULL, | ||||
|                                io.Fonts->GetGlyphRangesChineseFull()); | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
|   // Setup Dear ImGui style | ||||
|   // ImGui::StyleColorsDark(); | ||||
|   ImGui::StyleColorsLight(); | ||||
|  | ||||
|   // Setup Platform/Renderer backends | ||||
|   ImGui_ImplSDL2_InitForSDLRenderer(window, sdlRenderer); | ||||
|   ImGui_ImplSDLRenderer2_Init(sdlRenderer); | ||||
|  | ||||
|   // Our state | ||||
|   bool show_demo_window = true; | ||||
|   bool show_another_window = false; | ||||
|   ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); | ||||
|  | ||||
|   std::string mac_addr_str = GetMac(); | ||||
|  | ||||
|   std::thread rtc_thread( | ||||
|       [](int screen_width, int screen_height) { | ||||
|         std::string default_cfg_path = "../../../../config/config.ini"; | ||||
|         std::ifstream f(default_cfg_path.c_str()); | ||||
|  | ||||
|         std::string mac_addr_str = GetMac(); | ||||
|  | ||||
|         Params server_params; | ||||
|         server_params.cfg_path = | ||||
|             f.good() ? "../../../../config/config.ini" : "config.ini"; | ||||
|         server_params.on_receive_video_buffer = ServerReceiveVideoBuffer; | ||||
|         server_params.on_receive_audio_buffer = ServerReceiveAudioBuffer; | ||||
|         server_params.on_receive_data_buffer = ServerReceiveDataBuffer; | ||||
|         server_params.on_signal_status = ServerSignalStatus; | ||||
|         server_params.on_connection_status = ServerConnectionStatus; | ||||
|  | ||||
|         Params client_params; | ||||
|         client_params.cfg_path = | ||||
|             f.good() ? "../../../../config/config.ini" : "config.ini"; | ||||
|         client_params.on_receive_video_buffer = ClientReceiveVideoBuffer; | ||||
|         client_params.on_receive_audio_buffer = ClientReceiveAudioBuffer; | ||||
|         client_params.on_receive_data_buffer = ClientReceiveDataBuffer; | ||||
|         client_params.on_signal_status = ClientSignalStatus; | ||||
|         client_params.on_connection_status = ClientConnectionStatus; | ||||
|  | ||||
|         std::string transmission_id = "000001"; | ||||
|  | ||||
|         peer_server = CreatePeer(&server_params); | ||||
|         LOG_INFO("Create peer_server"); | ||||
|         std::string server_user_id = "S-" + mac_addr_str; | ||||
|         Init(peer_server, server_user_id.c_str()); | ||||
|         LOG_INFO("peer_server init finish"); | ||||
|  | ||||
|         peer_client = CreatePeer(&client_params); | ||||
|         LOG_INFO("Create peer_client"); | ||||
|         std::string client_user_id = "C-" + mac_addr_str; | ||||
|         Init(peer_client, client_user_id.c_str()); | ||||
|         LOG_INFO("peer_client init finish"); | ||||
|  | ||||
|         { | ||||
|           while (SignalStatus::SignalConnected != server_signal_status && | ||||
|                  !done) { | ||||
|             std::this_thread::sleep_for(std::chrono::seconds(1)); | ||||
|           } | ||||
|  | ||||
|           if (done) { | ||||
|             return; | ||||
|           } | ||||
|  | ||||
|           std::string user_id = "S-" + mac_addr_str; | ||||
|           is_create_connection = | ||||
|               CreateConnection(peer_server, mac_addr_str.c_str(), | ||||
|                                input_password) | ||||
|                   ? false | ||||
|                   : true; | ||||
|  | ||||
|           nv12_buffer = new char[NV12_BUFFER_SIZE]; | ||||
|  | ||||
|           // Screen capture | ||||
|           screen_capturer_factory = new ScreenCapturerFactory(); | ||||
|           screen_capturer = (ScreenCapturer *)screen_capturer_factory->Create(); | ||||
|  | ||||
|           last_frame_time_ = std::chrono::high_resolution_clock::now(); | ||||
|           ScreenCapturer::RECORD_DESKTOP_RECT rect; | ||||
|           rect.left = 0; | ||||
|           rect.top = 0; | ||||
|           rect.right = screen_w; | ||||
|           rect.bottom = screen_h; | ||||
|  | ||||
|           int screen_capturer_init_ret = screen_capturer->Init( | ||||
|               rect, 60, | ||||
|               [](unsigned char *data, int size, int width, int height) -> void { | ||||
|                 auto now_time = std::chrono::high_resolution_clock::now(); | ||||
|                 std::chrono::duration<double> duration = | ||||
|                     now_time - last_frame_time_; | ||||
|                 auto tc = duration.count() * 1000; | ||||
|  | ||||
|                 if (tc >= 0) { | ||||
|                   SendData(peer_server, DATA_TYPE::VIDEO, (const char *)data, | ||||
|                            NV12_BUFFER_SIZE); | ||||
|                   last_frame_time_ = now_time; | ||||
|                 } | ||||
|               }); | ||||
|  | ||||
|           if (0 == screen_capturer_init_ret) { | ||||
|             screen_capturer->Start(); | ||||
|           } else { | ||||
|             screen_capturer->Destroy(); | ||||
|             screen_capturer = nullptr; | ||||
|           } | ||||
|  | ||||
|           // Mouse control | ||||
|           device_controller_factory = new DeviceControllerFactory(); | ||||
|           mouse_controller = | ||||
|               (MouseController *)device_controller_factory->Create( | ||||
|                   DeviceControllerFactory::Device::Mouse); | ||||
|           int mouse_controller_init_ret = | ||||
|               mouse_controller->Init(screen_w, screen_h); | ||||
|           if (0 != mouse_controller_init_ret) { | ||||
|             mouse_controller->Destroy(); | ||||
|             mouse_controller = nullptr; | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       screen_w, screen_h); | ||||
|  | ||||
|   // Main loop | ||||
|   while (!done) { | ||||
|     // Start the Dear ImGui frame | ||||
|     ImGui_ImplSDLRenderer2_NewFrame(); | ||||
|     ImGui_ImplSDL2_NewFrame(); | ||||
|     ImGui::NewFrame(); | ||||
|  | ||||
|     if (joined && !menu_hovered) { | ||||
|       ImGui::SetMouseCursor(ImGuiMouseCursor_None); | ||||
|     } | ||||
|  | ||||
|     { | ||||
|       static float f = 0.0f; | ||||
|       static int counter = 0; | ||||
|  | ||||
|       const ImGuiViewport *main_viewport = ImGui::GetMainViewport(); | ||||
|       ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Once); | ||||
|  | ||||
|       // ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f)); | ||||
|  | ||||
| #if CHINESE_FONT | ||||
|       ImGui::SetNextWindowSize(ImVec2(160, 210)); | ||||
| #else | ||||
|       ImGui::SetNextWindowSize(ImVec2(180, 210)); | ||||
| #endif | ||||
|  | ||||
| #if CHINESE_FONT | ||||
|       if (!joined) { | ||||
|         ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always); | ||||
|         ImGui::Begin(u8"菜单", nullptr, | ||||
|                      ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | | ||||
|                          ImGuiWindowFlags_NoMove); | ||||
|       } else { | ||||
|         ImGui::SetNextWindowCollapsed(true, ImGuiCond_Once); | ||||
|         ImGui::Begin(u8"菜单", nullptr, ImGuiWindowFlags_None); | ||||
|       } | ||||
| #else | ||||
|       if (!joined) { | ||||
|         ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always); | ||||
|         ImGui::Begin("Menu", nullptr, | ||||
|                      ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | | ||||
|                          ImGuiWindowFlags_NoMove); | ||||
|       } else { | ||||
|         ImGui::SetNextWindowCollapsed(true, ImGuiCond_Once); | ||||
|         ImGui::Begin("Menu", nullptr, ImGuiWindowFlags_None); | ||||
|       } | ||||
| #endif | ||||
|  | ||||
|       { | ||||
|         menu_hovered = ImGui::IsWindowHovered(); | ||||
| #if CHINESE_FONT | ||||
|         ImGui::Text(u8"本机ID:"); | ||||
| #else | ||||
|         ImGui::Text("LOCAL ID:"); | ||||
| #endif | ||||
|         ImGui::SameLine(); | ||||
|         ImGui::SetNextItemWidth(90); | ||||
| #if CHINESE_FONT | ||||
|         ImGui::SetCursorPosX(60.0f); | ||||
| #else | ||||
|         ImGui::SetCursorPosX(80.0f); | ||||
| #endif | ||||
|         ImGui::InputText( | ||||
|             "##local_id", (char *)mac_addr_str.c_str(), | ||||
|             mac_addr_str.length() + 1, | ||||
|             ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_ReadOnly); | ||||
|  | ||||
| #if CHINESE_FONT | ||||
|         ImGui::Text(u8"密码:"); | ||||
| #else | ||||
|         ImGui::Text("PASSWORD:"); | ||||
| #endif | ||||
|         ImGui::SameLine(); | ||||
|         char input_password_tmp[7] = ""; | ||||
|         std::string input_password_str = "123456"; | ||||
|         strncpy(input_password_tmp, input_password, sizeof(input_password)); | ||||
|         ImGui::SetNextItemWidth(90); | ||||
| #if CHINESE_FONT | ||||
|         ImGui::SetCursorPosX(60.0f); | ||||
|         ImGui::InputTextWithHint("##server_pwd", u8"最长6个字符", | ||||
|                                  input_password, IM_ARRAYSIZE(input_password), | ||||
|                                  ImGuiInputTextFlags_CharsNoBlank); | ||||
| #else | ||||
|         ImGui::SetCursorPosX(80.0f); | ||||
|         ImGui::InputTextWithHint("##server_pwd", "max 6 chars", input_password, | ||||
|                                  IM_ARRAYSIZE(input_password), | ||||
|                                  ImGuiInputTextFlags_CharsNoBlank); | ||||
| #endif | ||||
|         if (strcmp(input_password_tmp, input_password)) { | ||||
|           cd_cache_file = fopen("cache.cd", "w+"); | ||||
|           if (cd_cache_file) { | ||||
|             fseek(cd_cache_file, 0, SEEK_SET); | ||||
|             strncpy(cd_cache.password, input_password, sizeof(input_password)); | ||||
|             fwrite(&cd_cache.password, sizeof(cd_cache.password), 1, | ||||
|                    cd_cache_file); | ||||
|             fclose(cd_cache_file); | ||||
|           } | ||||
|           LeaveConnection(peer_server); | ||||
|           CreateConnection(peer_server, mac_addr_str.c_str(), input_password); | ||||
|         } | ||||
|  | ||||
|         ImGui::Spacing(); | ||||
|  | ||||
|         ImGui::Separator(); | ||||
|  | ||||
|         ImGui::Spacing(); | ||||
|         { | ||||
|           { | ||||
|             static char remote_id[20] = ""; | ||||
| #if CHINESE_FONT | ||||
|             ImGui::Text(u8"远端ID:"); | ||||
| #else | ||||
|             ImGui::Text("REMOTE ID:"); | ||||
| #endif | ||||
|             ImGui::SameLine(); | ||||
|             ImGui::SetNextItemWidth(90); | ||||
| #if CHINESE_FONT | ||||
|             ImGui::SetCursorPosX(60.0f); | ||||
| #else | ||||
|             ImGui::SetCursorPosX(80.0f); | ||||
| #endif | ||||
|             ImGui::InputTextWithHint("##remote_id", mac_addr_str.c_str(), | ||||
|                                      remote_id, IM_ARRAYSIZE(remote_id), | ||||
|                                      ImGuiInputTextFlags_CharsUppercase | | ||||
|                                          ImGuiInputTextFlags_CharsNoBlank); | ||||
|  | ||||
|             ImGui::Spacing(); | ||||
|  | ||||
| #if CHINESE_FONT | ||||
|             ImGui::Text(u8"密码:"); | ||||
| #else | ||||
|             ImGui::Text("PASSWORD:"); | ||||
| #endif | ||||
|             ImGui::SameLine(); | ||||
|             ImGui::SetNextItemWidth(90); | ||||
|             static char client_password[20] = ""; | ||||
| #if CHINESE_FONT | ||||
|             ImGui::SetCursorPosX(60.0f); | ||||
|             ImGui::InputTextWithHint("##client_pwd", u8"最长6个字符", | ||||
|                                      client_password, | ||||
|                                      IM_ARRAYSIZE(client_password), | ||||
|                                      ImGuiInputTextFlags_CharsNoBlank); | ||||
| #else | ||||
|             ImGui::SetCursorPosX(80.0f); | ||||
|             ImGui::InputTextWithHint("##client_pwd", "max 6 chars", | ||||
|                                      client_password, | ||||
|                                      IM_ARRAYSIZE(client_password), | ||||
|                                      ImGuiInputTextFlags_CharsNoBlank); | ||||
| #endif | ||||
|  | ||||
|             ImGui::Spacing(); | ||||
|             ImGui::Separator(); | ||||
|             ImGui::Spacing(); | ||||
|  | ||||
|             if (ImGui::Button(connect_label)) { | ||||
|               int ret = -1; | ||||
|               if ("ClientSignalConnected" == client_signal_status_str) { | ||||
| #if CHINESE_FONT | ||||
|                 if (strcmp(connect_label, u8"连接") == 0 && !joined) { | ||||
| #else | ||||
|                 if (strcmp(connect_label, "Connect") == 0 && !joined) { | ||||
| #endif | ||||
|                   std::string user_id = "C-" + mac_addr_str; | ||||
|                   ret = JoinConnection(peer_client, remote_id, client_password); | ||||
|                   if (0 == ret) { | ||||
|                     // joined = true; | ||||
|                   } | ||||
| #if CHINESE_FONT | ||||
|                 } else if (strcmp(connect_label, u8"断开连接") == 0 && joined) { | ||||
| #else | ||||
|                 } else if (strcmp(connect_label, "Disconnect") == 0 && joined) { | ||||
| #endif | ||||
|                   ret = LeaveConnection(peer_client); | ||||
|                   memset(audio_buffer, 0, 960); | ||||
|                   if (0 == ret) { | ||||
|                     joined = false; | ||||
|                     received_frame = false; | ||||
|                   } | ||||
|                 } | ||||
|  | ||||
|                 if (0 == ret) { | ||||
|                   connect_button_pressed = !connect_button_pressed; | ||||
| #if CHINESE_FONT | ||||
|                   connect_label = | ||||
|                       connect_button_pressed ? u8"断开连接" : u8"连接"; | ||||
| #else | ||||
|                   connect_label = | ||||
|                       connect_button_pressed ? "Disconnect" : "Connect"; | ||||
| #endif | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       ImGui::Spacing(); | ||||
|  | ||||
|       ImGui::Separator(); | ||||
|  | ||||
|       ImGui::Spacing(); | ||||
|  | ||||
|       { | ||||
| #if CHINESE_FONT | ||||
|         if (ImGui::Button(u8"重置窗口")) { | ||||
| #else | ||||
|         if (ImGui::Button("Resize Window")) { | ||||
| #endif | ||||
|           SDL_GetWindowSize(window, &window_w, &window_h); | ||||
|  | ||||
|           if (window_h != window_w * 9 / 16) { | ||||
|             window_w = window_h * 16 / 9; | ||||
|           } | ||||
|  | ||||
|           SDL_SetWindowSize(window, window_w, window_h); | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       ImGui::SameLine(); | ||||
|  | ||||
| #if CHINESE_FONT | ||||
|       if (ImGui::Button(fullscreen_label)) { | ||||
|         if (strcmp(fullscreen_label, u8"全屏") == 0) { | ||||
| #else | ||||
|       if (ImGui::Button(fullscreen_label)) { | ||||
|         if (strcmp(fullscreen_label, "FULLSCREEN") == 0) { | ||||
| #endif | ||||
|           SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); | ||||
|         } else { | ||||
|           SDL_SetWindowFullscreen(window, SDL_FALSE); | ||||
|         } | ||||
|         fullscreen_button_pressed = !fullscreen_button_pressed; | ||||
| #if CHINESE_FONT | ||||
|         fullscreen_label = fullscreen_button_pressed ? u8"退出全屏" : u8"全屏"; | ||||
| #else | ||||
|         fullscreen_label = | ||||
|             fullscreen_button_pressed ? "EXIT FULLSCREEN" : "FULLSCREEN"; | ||||
| #endif | ||||
|       } | ||||
|       ImGui::End(); | ||||
|     } | ||||
|  | ||||
|     // Rendering | ||||
|     ImGui::Render(); | ||||
|     SDL_RenderSetScale(sdlRenderer, io.DisplayFramebufferScale.x, | ||||
|                        io.DisplayFramebufferScale.y); | ||||
|  | ||||
|     SDL_Event event; | ||||
|     while (SDL_PollEvent(&event)) { | ||||
|       ImGui_ImplSDL2_ProcessEvent(&event); | ||||
|       if (event.type == SDL_QUIT) { | ||||
|         done = true; | ||||
|       } else if (event.type == SDL_WINDOWEVENT && | ||||
|                  event.window.event == SDL_WINDOWEVENT_RESIZED) { | ||||
|         SDL_GetWindowSize(window, &window_w, &window_h); | ||||
|       } else if (event.type == SDL_WINDOWEVENT && | ||||
|                  event.window.event == SDL_WINDOWEVENT_CLOSE && | ||||
|                  event.window.windowID == SDL_GetWindowID(window)) { | ||||
|         done = true; | ||||
|       } else if (event.type == REFRESH_EVENT) { | ||||
|         sdlRect.x = 0; | ||||
|         sdlRect.y = 0; | ||||
|         sdlRect.w = window_w; | ||||
|         sdlRect.h = window_h; | ||||
|  | ||||
|         SDL_UpdateTexture(sdlTexture, NULL, dst_buffer, pixel_w); | ||||
|       } else { | ||||
|         if (joined) { | ||||
|           ProcessMouseKeyEven(event); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     SDL_RenderClear(sdlRenderer); | ||||
|     SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect); | ||||
|  | ||||
|     if (!joined || !received_frame) { | ||||
|       SDL_RenderClear(sdlRenderer); | ||||
|       SDL_SetRenderDrawColor( | ||||
|           sdlRenderer, (Uint8)(clear_color.x * 0), (Uint8)(clear_color.y * 0), | ||||
|           (Uint8)(clear_color.z * 0), (Uint8)(clear_color.w * 0)); | ||||
|     } | ||||
|  | ||||
|     ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData()); | ||||
|     SDL_RenderPresent(sdlRenderer); | ||||
|  | ||||
|     frame_count++; | ||||
|     end_time = SDL_GetTicks(); | ||||
|     elapsed_time = end_time - start_time; | ||||
|     if (elapsed_time >= 1000) { | ||||
|       fps = frame_count / (elapsed_time / 1000); | ||||
|       frame_count = 0; | ||||
|       window_title = "Remote Desk Client FPS [" + std::to_string(fps) + | ||||
|                      "] status [" + server_signal_status_str + "|" + | ||||
|                      client_signal_status_str + "|" + | ||||
|                      server_connection_status_str + "|" + | ||||
|                      client_connection_status_str + "]"; | ||||
|       // For MacOS, UI frameworks can only be called from the main thread | ||||
|       SDL_SetWindowTitle(window, window_title.c_str()); | ||||
|       start_time = end_time; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Cleanup | ||||
|  | ||||
|   if (is_create_connection) { | ||||
|     LeaveConnection(peer_server); | ||||
|   } | ||||
|  | ||||
|   if (joined) { | ||||
|     LeaveConnection(peer_client); | ||||
|   } | ||||
|  | ||||
|   rtc_thread.join(); | ||||
|   SDL_CloseAudioDevice(output_dev); | ||||
|   SDL_CloseAudioDevice(input_dev); | ||||
|  | ||||
|   if (screen_capturer) { | ||||
|     screen_capturer->Destroy(); | ||||
|   } | ||||
|  | ||||
|   if (mouse_controller) { | ||||
|     mouse_controller->Destroy(); | ||||
|   } | ||||
|  | ||||
|   ImGui_ImplSDLRenderer2_Shutdown(); | ||||
|   ImGui_ImplSDL2_Shutdown(); | ||||
|   ImGui::DestroyContext(); | ||||
|  | ||||
|   SDL_DestroyRenderer(sdlRenderer); | ||||
|   SDL_DestroyWindow(window); | ||||
|  | ||||
|   SDL_CloseAudio(); | ||||
|   SDL_Quit(); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										28
									
								
								src/localization/localization.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/localization/localization.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| /* | ||||
|  * @Author: DI JUNKUN | ||||
|  * @Date: 2024-05-29 | ||||
|  * Copyright (c) 2024 by DI JUNKUN, All Rights Reserved. | ||||
|  */ | ||||
|  | ||||
| #ifndef _LOCALIZATION_H_ | ||||
| #define _LOCALIZATION_H_ | ||||
|  | ||||
| #include <string> | ||||
| #include <vector> | ||||
|  | ||||
| namespace localization { | ||||
|  | ||||
| std::vector<std::string> menu = {u8"<EFBFBD>˵<EFBFBD>", "Menu"}; | ||||
| std::vector<std::string> local_id = {u8"<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ID:", "Local ID:"}; | ||||
| std::vector<std::string> password = {u8"<EFBFBD><EFBFBD><EFBFBD><EFBFBD>:", "Password:"}; | ||||
| std::vector<std::string> max_password_len = {u8"<EFBFBD>6<EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD>", "Max 6 chars"}; | ||||
| std::vector<std::string> remote_id = {u8"<EFBFBD>Զ<EFBFBD>ID:", "Remote ID:"}; | ||||
| std::vector<std::string> connect = {u8"<EFBFBD><EFBFBD><EFBFBD><EFBFBD>", "Connect"}; | ||||
| std::vector<std::string> disconnect = {u8"<EFBFBD>Ͽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>", "Disconnect"}; | ||||
| std::vector<std::string> reset_ratio = {u8"<EFBFBD><EFBFBD><EFBFBD>ñ<EFBFBD><EFBFBD><EFBFBD>", "Reset ratio"}; | ||||
| std::vector<std::string> fullscreen = {u8"ȫ<EFBFBD><EFBFBD>", "Fullscreen"}; | ||||
| std::vector<std::string> exit_fullscreen = {u8"<EFBFBD>˳<EFBFBD>ȫ<EFBFBD><EFBFBD>", "Exit fullscreen"}; | ||||
|  | ||||
| }  // namespace localization | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										377
									
								
								src/main_window/main_window.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										377
									
								
								src/main_window/main_window.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,377 @@ | ||||
| #include "main_window.h" | ||||
|  | ||||
| #include <fstream> | ||||
| #include <iostream> | ||||
| #include <string> | ||||
|  | ||||
| #include "localization.h" | ||||
| #include "log.h" | ||||
| #include "platform.h" | ||||
|  | ||||
| // Refresh Event | ||||
| #define REFRESH_EVENT (SDL_USEREVENT + 1) | ||||
| #define QUIT_EVENT (SDL_USEREVENT + 2) | ||||
|  | ||||
| MainWindow::MainWindow() {} | ||||
|  | ||||
| MainWindow::~MainWindow() {} | ||||
|  | ||||
| int MainWindow::Run() { | ||||
|   cd_cache_file_ = fopen("cache.cd", "r+"); | ||||
|   if (cd_cache_file_) { | ||||
|     fseek(cd_cache_file_, 0, SEEK_SET); | ||||
|     fread(&cd_cache_.password, sizeof(cd_cache_.password), 1, cd_cache_file_); | ||||
|     fclose(cd_cache_file_); | ||||
|     strncpy(input_password_, cd_cache_.password, sizeof(cd_cache_.password)); | ||||
|   } | ||||
|  | ||||
|   // Setup SDL | ||||
|   if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER | | ||||
|                SDL_INIT_GAMECONTROLLER) != 0) { | ||||
|     printf("Error: %s\n", SDL_GetError()); | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   // From 2.0.18: Enable native IME. | ||||
| #ifdef SDL_HINT_IME_SHOW_UI | ||||
|   SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); | ||||
| #endif | ||||
|  | ||||
|   // Create main window with SDL_Renderer graphics context | ||||
|   SDL_WindowFlags window_flags = | ||||
|       (SDL_WindowFlags)(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); | ||||
|   main_window_ = SDL_CreateWindow("Remote Desk", SDL_WINDOWPOS_CENTERED, | ||||
|                                   SDL_WINDOWPOS_CENTERED, main_window_width_, | ||||
|                                   main_window_height_, window_flags); | ||||
|  | ||||
|   SDL_DisplayMode DM; | ||||
|   SDL_GetCurrentDisplayMode(0, &DM); | ||||
|   screen_width_ = DM.w; | ||||
|   screen_height_ = DM.h; | ||||
|  | ||||
|   sdl_renderer_ = SDL_CreateRenderer( | ||||
|       main_window_, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED); | ||||
|   if (sdl_renderer_ == nullptr) { | ||||
|     SDL_Log("Error creating SDL_Renderer!"); | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   pixformat_ = SDL_PIXELFORMAT_NV12; | ||||
|  | ||||
|   sdl_texture_ = | ||||
|       SDL_CreateTexture(sdl_renderer_, pixformat_, SDL_TEXTUREACCESS_STREAMING, | ||||
|                         texture_width_, texture_height_); | ||||
|  | ||||
|   // Setup Dear ImGui context | ||||
|   IMGUI_CHECKVERSION(); | ||||
|   ImGui::CreateContext(); | ||||
|   ImGuiIO &io = ImGui::GetIO(); | ||||
|  | ||||
|   io.ConfigFlags |= | ||||
|       ImGuiConfigFlags_NavEnableKeyboard;  // Enable Keyboard Controls | ||||
|   io.ConfigFlags |= | ||||
|       ImGuiConfigFlags_NavEnableGamepad;  // Enable Gamepad Controls | ||||
|  | ||||
|   if (config_center_.GetLanguage() == ConfigCenter::LANGUAGE::CHINESE) { | ||||
|     // Load Fonts | ||||
| #ifdef _WIN32 | ||||
|     std::string default_font_path = "c:/windows/fonts/simhei.ttf"; | ||||
|     std::ifstream font_path_f(default_font_path.c_str()); | ||||
|     std::string font_path = | ||||
|         font_path_f.good() ? "c:/windows/fonts/simhei.ttf" : ""; | ||||
|     if (!font_path.empty()) { | ||||
|       io.Fonts->AddFontFromFileTTF(font_path.c_str(), 13.0f, NULL, | ||||
|                                    io.Fonts->GetGlyphRangesChineseFull()); | ||||
|     } | ||||
| #elif __APPLE__ | ||||
|     std::string default_font_path = "/System/Library/Fonts/PingFang.ttc"; | ||||
|     std::ifstream font_path_f(default_font_path.c_str()); | ||||
|     std::string font_path = | ||||
|         font_path_f.good() ? "/System/Library/Fonts/PingFang.ttc" : ""; | ||||
|     if (!font_path.empty()) { | ||||
|       io.Fonts->AddFontFromFileTTF(font_path.c_str(), 13.0f, NULL, | ||||
|                                    io.Fonts->GetGlyphRangesChineseFull()); | ||||
|     } | ||||
| #elif __linux__ | ||||
|     io.Fonts->AddFontFromFileTTF("c:/windows/fonts/msyh.ttc", 13.0f, NULL, | ||||
|                                  io.Fonts->GetGlyphRangesChineseFull()); | ||||
| #endif | ||||
|   } | ||||
|  | ||||
|   // Setup Dear ImGui style | ||||
|   // ImGui::StyleColorsDark(); | ||||
|   ImGui::StyleColorsLight(); | ||||
|  | ||||
|   // Setup Platform/Renderer backends | ||||
|   ImGui_ImplSDL2_InitForSDLRenderer(main_window_, sdl_renderer_); | ||||
|   ImGui_ImplSDLRenderer2_Init(sdl_renderer_); | ||||
|  | ||||
|   // Our state | ||||
|   ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); | ||||
|  | ||||
|   mac_addr_str_ = GetMac(); | ||||
|  | ||||
|   // Main loop | ||||
|   while (!exit_) { | ||||
|     localization_language_ = config_center_.GetLanguage(); | ||||
|     localization_language_index_ = (int)localization_language_; | ||||
|  | ||||
|     if (localization_language_index_last_ != localization_language_index_) { | ||||
|       LOG_ERROR("localization_language_: {}", | ||||
|                 localization_language_index_ == 0 ? "zh" : "en"); | ||||
|       localization_language_index_last_ = localization_language_index_; | ||||
|     } | ||||
|  | ||||
|     connect_button_label_ = localization::connect[localization_language_index_]; | ||||
|     fullscreen_button_label_ = | ||||
|         localization::fullscreen[localization_language_index_]; | ||||
|  | ||||
|     // Start the Dear ImGui frame | ||||
|     ImGui_ImplSDLRenderer2_NewFrame(); | ||||
|     ImGui_ImplSDL2_NewFrame(); | ||||
|     ImGui::NewFrame(); | ||||
|  | ||||
|     if (connection_established_ && !menu_hovered_) { | ||||
|       ImGui::SetMouseCursor(ImGuiMouseCursor_None); | ||||
|     } | ||||
|  | ||||
|     // main window layout | ||||
|     { | ||||
|       ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Once); | ||||
|  | ||||
|       if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { | ||||
|         ImGui::SetNextWindowSize(ImVec2(160, 210)); | ||||
|       } else { | ||||
|         ImGui::SetNextWindowSize(ImVec2(180, 210)); | ||||
|       } | ||||
|  | ||||
|       if (!connection_established_) { | ||||
|         ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always); | ||||
|         ImGui::Begin(localization::menu[localization_language_index_].c_str(), | ||||
|                      nullptr, | ||||
|                      ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | | ||||
|                          ImGuiWindowFlags_NoMove); | ||||
|       } else { | ||||
|         ImGui::SetNextWindowCollapsed(true, ImGuiCond_Once); | ||||
|         ImGui::Begin(localization::menu[localization_language_index_].c_str(), | ||||
|                      nullptr, ImGuiWindowFlags_None); | ||||
|       } | ||||
|  | ||||
|       { | ||||
|         menu_hovered_ = ImGui::IsWindowHovered(); | ||||
|  | ||||
|         // local | ||||
|         { | ||||
|           ImGui::Text( | ||||
|               localization::local_id[localization_language_index_].c_str()); | ||||
|  | ||||
|           ImGui::SameLine(); | ||||
|           ImGui::SetNextItemWidth(90); | ||||
|           if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { | ||||
|             ImGui::SetCursorPosX(60.0f); | ||||
|           } else { | ||||
|             ImGui::SetCursorPosX(80.0f); | ||||
|           } | ||||
|           ImGui::InputText("##local_id", (char *)mac_addr_str_.c_str(), | ||||
|                            mac_addr_str_.length() + 1, | ||||
|                            ImGuiInputTextFlags_CharsUppercase | | ||||
|                                ImGuiInputTextFlags_ReadOnly); | ||||
|  | ||||
|           ImGui::Text( | ||||
|               localization::password[localization_language_index_].c_str()); | ||||
|  | ||||
|           ImGui::SameLine(); | ||||
|  | ||||
|           strncpy(input_password_tmp_, input_password_, | ||||
|                   sizeof(input_password_)); | ||||
|           ImGui::SetNextItemWidth(90); | ||||
|           if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { | ||||
|             ImGui::SetCursorPosX(60.0f); | ||||
|           } else { | ||||
|             ImGui::SetCursorPosX(80.0f); | ||||
|           } | ||||
|           ImGui::InputTextWithHint( | ||||
|               "##server_pwd", | ||||
|               localization::max_password_len[localization_language_index_] | ||||
|                   .c_str(), | ||||
|               input_password_, IM_ARRAYSIZE(input_password_), | ||||
|               ImGuiInputTextFlags_CharsNoBlank); | ||||
|  | ||||
|           if (strcmp(input_password_tmp_, input_password_)) { | ||||
|             cd_cache_file_ = fopen("cache.cd", "w+"); | ||||
|             if (cd_cache_file_) { | ||||
|               fseek(cd_cache_file_, 0, SEEK_SET); | ||||
|               strncpy(cd_cache_.password, input_password_, | ||||
|                       sizeof(input_password_)); | ||||
|               fwrite(&cd_cache_.password, sizeof(cd_cache_.password), 1, | ||||
|                      cd_cache_file_); | ||||
|               fclose(cd_cache_file_); | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         ImGui::Spacing(); | ||||
|         ImGui::Separator(); | ||||
|         ImGui::Spacing(); | ||||
|  | ||||
|         // remote | ||||
|         { | ||||
|           ImGui::Text( | ||||
|               localization::remote_id[localization_language_index_].c_str()); | ||||
|  | ||||
|           ImGui::SameLine(); | ||||
|           ImGui::SetNextItemWidth(90); | ||||
|           if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { | ||||
|             ImGui::SetCursorPosX(60.0f); | ||||
|           } else { | ||||
|             ImGui::SetCursorPosX(80.0f); | ||||
|           } | ||||
|           ImGui::InputTextWithHint("##remote_id_", mac_addr_str_.c_str(), | ||||
|                                    remote_id_, IM_ARRAYSIZE(remote_id_), | ||||
|                                    ImGuiInputTextFlags_CharsUppercase | | ||||
|                                        ImGuiInputTextFlags_CharsNoBlank); | ||||
|  | ||||
|           ImGui::Spacing(); | ||||
|  | ||||
|           ImGui::Text( | ||||
|               localization::password[localization_language_index_].c_str()); | ||||
|  | ||||
|           ImGui::SameLine(); | ||||
|           ImGui::SetNextItemWidth(90); | ||||
|  | ||||
|           if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { | ||||
|             ImGui::SetCursorPosX(60.0f); | ||||
|           } else { | ||||
|             ImGui::SetCursorPosX(80.0f); | ||||
|           } | ||||
|  | ||||
|           ImGui::InputTextWithHint( | ||||
|               "##client_pwd", | ||||
|               localization::max_password_len[localization_language_index_] | ||||
|                   .c_str(), | ||||
|               client_password_, IM_ARRAYSIZE(client_password_), | ||||
|               ImGuiInputTextFlags_CharsNoBlank); | ||||
|  | ||||
|           ImGui::Spacing(); | ||||
|           ImGui::Separator(); | ||||
|           ImGui::Spacing(); | ||||
|  | ||||
|           if (ImGui::Button(connect_button_label_.c_str())) { | ||||
|             LOG_ERROR("Click connect button"); | ||||
|             int ret = -1; | ||||
|             if ("ClientSignalConnected" == client_signal_status_str_) { | ||||
|               if (connect_button_label_ == | ||||
|                       localization::connect[localization_language_index_] && | ||||
|                   !connection_established_) { | ||||
|                 std::string user_id = "C-" + mac_addr_str_; | ||||
|  | ||||
|               } else if (connect_button_label_ == | ||||
|                              localization::disconnect | ||||
|                                  [localization_language_index_] && | ||||
|                          connection_established_) { | ||||
|               } | ||||
|  | ||||
|               if (0 == ret) { | ||||
|                 connect_button_pressed_ = !connect_button_pressed_; | ||||
|  | ||||
|                 connect_button_label_ = | ||||
|                     connect_button_pressed_ | ||||
|                         ? localization::disconnect[localization_language_index_] | ||||
|  | ||||
|                         : localization::connect[localization_language_index_]; | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       ImGui::Spacing(); | ||||
|  | ||||
|       ImGui::Separator(); | ||||
|  | ||||
|       ImGui::Spacing(); | ||||
|  | ||||
|       { | ||||
|         if (ImGui::Button( | ||||
|                 localization::reset_ratio[localization_language_index_] | ||||
|                     .c_str())) { | ||||
|           SDL_GetWindowSize(main_window_, &main_window_width_, | ||||
|                             &main_window_height_); | ||||
|  | ||||
|           if (main_window_height_ != main_window_width_ * 9 / 16) { | ||||
|             main_window_width_ = main_window_height_ * 16 / 9; | ||||
|           } | ||||
|  | ||||
|           SDL_SetWindowSize(main_window_, main_window_width_, | ||||
|                             main_window_height_); | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       ImGui::SameLine(); | ||||
|  | ||||
|       if (ImGui::Button(fullscreen_button_label_.c_str())) { | ||||
|         if (fullscreen_button_label_ == | ||||
|             localization::fullscreen[localization_language_index_]) { | ||||
|           SDL_SetWindowFullscreen(main_window_, SDL_WINDOW_FULLSCREEN_DESKTOP); | ||||
|         } else { | ||||
|           SDL_SetWindowFullscreen(main_window_, SDL_FALSE); | ||||
|         } | ||||
|         fullscreen_button_pressed_ = !fullscreen_button_pressed_; | ||||
|  | ||||
|         fullscreen_button_label_ = | ||||
|             fullscreen_button_pressed_ | ||||
|                 ? localization::exit_fullscreen[localization_language_index_] | ||||
|  | ||||
|                 : localization::fullscreen[localization_language_index_]; | ||||
|       } | ||||
|       ImGui::End(); | ||||
|     } | ||||
|  | ||||
|     // Rendering | ||||
|     ImGui::Render(); | ||||
|     SDL_RenderSetScale(sdl_renderer_, io.DisplayFramebufferScale.x, | ||||
|                        io.DisplayFramebufferScale.y); | ||||
|  | ||||
|     SDL_RenderClear(sdl_renderer_); | ||||
|     SDL_RenderCopy(sdl_renderer_, sdl_texture_, NULL, &sdlRect); | ||||
|  | ||||
|     if (!connection_established_ || !received_frame_) { | ||||
|       SDL_RenderClear(sdl_renderer_); | ||||
|       SDL_SetRenderDrawColor( | ||||
|           sdl_renderer_, (Uint8)(clear_color.x * 0), (Uint8)(clear_color.y * 0), | ||||
|           (Uint8)(clear_color.z * 0), (Uint8)(clear_color.w * 0)); | ||||
|     } | ||||
|  | ||||
|     ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData()); | ||||
|     SDL_RenderPresent(sdl_renderer_); | ||||
|  | ||||
|     frame_count_++; | ||||
|     end_time_ = SDL_GetTicks(); | ||||
|     elapsed_time_ = end_time_ - start_time_; | ||||
|     if (elapsed_time_ >= 1000) { | ||||
|       fps_ = frame_count_ / (elapsed_time_ / 1000); | ||||
|       frame_count_ = 0; | ||||
|       window_title = "Remote Desk Client FPS [" + std::to_string(fps_) + | ||||
|                      "] status [" + server_signal_status_str_ + "|" + | ||||
|                      client_signal_status_str_ + "|" + | ||||
|                      server_connection_status_str_ + "|" + | ||||
|                      client_connection_status_str_ + "]"; | ||||
|       // For MacOS, UI frameworks can only be called from the main thread | ||||
|       SDL_SetWindowTitle(main_window_, window_title.c_str()); | ||||
|       start_time_ = end_time_; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Cleanup | ||||
|   ImGui_ImplSDLRenderer2_Shutdown(); | ||||
|   ImGui_ImplSDL2_Shutdown(); | ||||
|   ImGui::DestroyContext(); | ||||
|  | ||||
|   SDL_DestroyRenderer(sdl_renderer_); | ||||
|   SDL_DestroyWindow(main_window_); | ||||
|  | ||||
|   SDL_CloseAudio(); | ||||
|   SDL_Quit(); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										101
									
								
								src/main_window/main_window.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								src/main_window/main_window.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| /* | ||||
|  * @Author: DI JUNKUN | ||||
|  * @Date: 2024-05-29 | ||||
|  * Copyright (c) 2024 by DI JUNKUN, All Rights Reserved. | ||||
|  */ | ||||
|  | ||||
| #ifndef _MAIN_WINDOW_H_ | ||||
| #define _MAIN_WINDOW_H_ | ||||
|  | ||||
| #include <SDL.h> | ||||
|  | ||||
| #include <atomic> | ||||
| #include <string> | ||||
|  | ||||
| #include "config_center.h" | ||||
| #include "imgui.h" | ||||
| #include "imgui_impl_sdl2.h" | ||||
| #include "imgui_impl_sdlrenderer2.h" | ||||
|  | ||||
| class MainWindow { | ||||
|  public: | ||||
|   MainWindow(); | ||||
|   ~MainWindow(); | ||||
|  | ||||
|  public: | ||||
|   int Run(); | ||||
|  | ||||
|  private: | ||||
|   typedef struct { | ||||
|     char password[7]; | ||||
|   } CDCache; | ||||
|  | ||||
|  private: | ||||
|   FILE *cd_cache_file_ = nullptr; | ||||
|   CDCache cd_cache_; | ||||
|  | ||||
|   ConfigCenter config_center_; | ||||
|  | ||||
|   ConfigCenter::LANGUAGE localization_language_ = | ||||
|       ConfigCenter::LANGUAGE::CHINESE; | ||||
|  | ||||
|   int localization_language_index_ = -1; | ||||
|   int localization_language_index_last_ = -1; | ||||
|  | ||||
|  private: | ||||
|   int default_main_window_width_ = 1280; | ||||
|   int default_main_window_height_ = 720; | ||||
|  | ||||
|  private: | ||||
|   std::string window_title = "Remote Desk Client"; | ||||
|  | ||||
|  private: | ||||
|   int screen_width_ = 1280; | ||||
|   int screen_height_ = 720; | ||||
|   int main_window_width_ = 1280; | ||||
|   int main_window_height_ = 720; | ||||
|  | ||||
|   int texture_width_ = 1280; | ||||
|   int texture_height_ = 720; | ||||
|  | ||||
|   SDL_Texture *sdl_texture_ = nullptr; | ||||
|   SDL_Renderer *sdl_renderer_ = nullptr; | ||||
|   SDL_Rect sdlRect; | ||||
|   SDL_Window *main_window_; | ||||
|   uint32_t pixformat_ = 0; | ||||
|  | ||||
|   std::string mac_addr_str_ = ""; | ||||
|  | ||||
|   bool exit_ = false; | ||||
|  | ||||
|   std::string connect_button_label_ = "Connect"; | ||||
|   std::string fullscreen_button_label_ = "Fullscreen"; | ||||
|  | ||||
|   bool connection_established_ = false; | ||||
|   bool menu_hovered_ = false; | ||||
|  | ||||
|   char input_password_tmp_[7] = ""; | ||||
|   char input_password_[7] = ""; | ||||
|  | ||||
|   char remote_id_[20] = ""; | ||||
|   char client_password_[20] = ""; | ||||
|  | ||||
|   bool connect_button_pressed_ = false; | ||||
|   bool fullscreen_button_pressed_ = false; | ||||
|  | ||||
|   int fps_ = 0; | ||||
|   uint32_t start_time_; | ||||
|   uint32_t end_time_; | ||||
|   uint32_t elapsed_time_; | ||||
|   uint32_t frame_count_ = 0; | ||||
|  | ||||
|   bool received_frame_ = false; | ||||
|  | ||||
|  private: | ||||
|   std::string server_connection_status_str_ = "-"; | ||||
|   std::string client_connection_status_str_ = "-"; | ||||
|   std::string server_signal_status_str_ = "-"; | ||||
|   std::string client_signal_status_str_ = "-"; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										395
									
								
								src/render/render.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										395
									
								
								src/render/render.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,395 @@ | ||||
| #include "render.h" | ||||
|  | ||||
| int RenderMainWindow(int argc, char *argv[]) { | ||||
|   LOG_INFO("Remote desk"); | ||||
|  | ||||
|   last_ts = static_cast<uint32_t>( | ||||
|       std::chrono::duration_cast<std::chrono::milliseconds>( | ||||
|           std::chrono::high_resolution_clock::now().time_since_epoch()) | ||||
|           .count()); | ||||
|  | ||||
|   cd_cache_file = fopen("cache.cd", "r+"); | ||||
|   if (cd_cache_file) { | ||||
|     fseek(cd_cache_file, 0, SEEK_SET); | ||||
|     fread(&cd_cache.password, sizeof(cd_cache.password), 1, cd_cache_file); | ||||
|     fclose(cd_cache_file); | ||||
|     strncpy(input_password, cd_cache.password, sizeof(cd_cache.password)); | ||||
|   } | ||||
|  | ||||
|   // Setup SDL | ||||
|   if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER | | ||||
|                SDL_INIT_GAMECONTROLLER) != 0) { | ||||
|     printf("Error: %s\n", SDL_GetError()); | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   // From 2.0.18: Enable native IME. | ||||
| #ifdef SDL_HINT_IME_SHOW_UI | ||||
|   SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); | ||||
| #endif | ||||
|  | ||||
|   // Create window with SDL_Renderer graphics context | ||||
|   SDL_WindowFlags window_flags = | ||||
|       (SDL_WindowFlags)(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); | ||||
|   window = SDL_CreateWindow("Remote Desk", SDL_WINDOWPOS_CENTERED, | ||||
|                             SDL_WINDOWPOS_CENTERED, window_w, window_h, | ||||
|                             window_flags); | ||||
|  | ||||
|   SDL_DisplayMode DM; | ||||
|   SDL_GetCurrentDisplayMode(0, &DM); | ||||
|   screen_w = DM.w; | ||||
|   screen_h = DM.h; | ||||
|  | ||||
|   sdlRenderer = SDL_CreateRenderer( | ||||
|       window, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED); | ||||
|   if (sdlRenderer == nullptr) { | ||||
|     SDL_Log("Error creating SDL_Renderer!"); | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   Uint32 pixformat = 0; | ||||
|   pixformat = SDL_PIXELFORMAT_NV12; | ||||
|  | ||||
|   sdlTexture = SDL_CreateTexture(sdlRenderer, pixformat, | ||||
|                                  SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h); | ||||
|  | ||||
|   // Setup Dear ImGui context | ||||
|   IMGUI_CHECKVERSION(); | ||||
|   ImGui::CreateContext(); | ||||
|   ImGuiIO &io = ImGui::GetIO(); | ||||
|  | ||||
|   io.ConfigFlags |= | ||||
|       ImGuiConfigFlags_NavEnableKeyboard;  // Enable Keyboard Controls | ||||
|   io.ConfigFlags |= | ||||
|       ImGuiConfigFlags_NavEnableGamepad;  // Enable Gamepad Controls | ||||
|  | ||||
| #if CHINESE_FONT | ||||
|   // Load Fonts | ||||
| #ifdef _WIN32 | ||||
|   std::string default_font_path = "c:/windows/fonts/simhei.ttf"; | ||||
|   std::ifstream font_path_f(default_font_path.c_str()); | ||||
|   std::string font_path = | ||||
|       font_path_f.good() ? "c:/windows/fonts/simhei.ttf" : ""; | ||||
|   if (!font_path.empty()) { | ||||
|     io.Fonts->AddFontFromFileTTF(font_path.c_str(), 13.0f, NULL, | ||||
|                                  io.Fonts->GetGlyphRangesChineseFull()); | ||||
|   } | ||||
| #elif __APPLE__ | ||||
|   std::string default_font_path = "/System/Library/Fonts/PingFang.ttc"; | ||||
|   std::ifstream font_path_f(default_font_path.c_str()); | ||||
|   std::string font_path = | ||||
|       font_path_f.good() ? "/System/Library/Fonts/PingFang.ttc" : ""; | ||||
|   if (!font_path.empty()) { | ||||
|     io.Fonts->AddFontFromFileTTF(font_path.c_str(), 13.0f, NULL, | ||||
|                                  io.Fonts->GetGlyphRangesChineseFull()); | ||||
|   } | ||||
| #elif __linux__ | ||||
|   io.Fonts->AddFontFromFileTTF("c:/windows/fonts/msyh.ttc", 13.0f, NULL, | ||||
|                                io.Fonts->GetGlyphRangesChineseFull()); | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
|   // Setup Dear ImGui style | ||||
|   // ImGui::StyleColorsDark(); | ||||
|   ImGui::StyleColorsLight(); | ||||
|  | ||||
|   // Setup Platform/Renderer backends | ||||
|   ImGui_ImplSDL2_InitForSDLRenderer(window, sdlRenderer); | ||||
|   ImGui_ImplSDLRenderer2_Init(sdlRenderer); | ||||
|  | ||||
|   // Our state | ||||
|   bool show_demo_window = true; | ||||
|   bool show_another_window = false; | ||||
|   ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); | ||||
|  | ||||
|   std::string mac_addr_str = GetMac(); | ||||
|  | ||||
|   // Main loop | ||||
|   while (!done) { | ||||
|     // Start the Dear ImGui frame | ||||
|     ImGui_ImplSDLRenderer2_NewFrame(); | ||||
|     ImGui_ImplSDL2_NewFrame(); | ||||
|     ImGui::NewFrame(); | ||||
|  | ||||
|     if (joined && !menu_hovered) { | ||||
|       ImGui::SetMouseCursor(ImGuiMouseCursor_None); | ||||
|     } | ||||
|  | ||||
|     { | ||||
|       static float f = 0.0f; | ||||
|       static int counter = 0; | ||||
|  | ||||
|       const ImGuiViewport *main_viewport = ImGui::GetMainViewport(); | ||||
|       ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Once); | ||||
|  | ||||
|       // ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f)); | ||||
|  | ||||
| #if CHINESE_FONT | ||||
|       ImGui::SetNextWindowSize(ImVec2(160, 210)); | ||||
| #else | ||||
|       ImGui::SetNextWindowSize(ImVec2(180, 210)); | ||||
| #endif | ||||
|  | ||||
| #if CHINESE_FONT | ||||
|       if (!joined) { | ||||
|         ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always); | ||||
|         ImGui::Begin(u8"<EFBFBD>˵<EFBFBD>", nullptr, | ||||
|                      ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | | ||||
|                          ImGuiWindowFlags_NoMove); | ||||
|       } else { | ||||
|         ImGui::SetNextWindowCollapsed(true, ImGuiCond_Once); | ||||
|         ImGui::Begin(u8"<EFBFBD>˵<EFBFBD>", nullptr, ImGuiWindowFlags_None); | ||||
|       } | ||||
| #else | ||||
|       if (!joined) { | ||||
|         ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always); | ||||
|         ImGui::Begin("Menu", nullptr, | ||||
|                      ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | | ||||
|                          ImGuiWindowFlags_NoMove); | ||||
|       } else { | ||||
|         ImGui::SetNextWindowCollapsed(true, ImGuiCond_Once); | ||||
|         ImGui::Begin("Menu", nullptr, ImGuiWindowFlags_None); | ||||
|       } | ||||
| #endif | ||||
|  | ||||
|       { | ||||
|         menu_hovered = ImGui::IsWindowHovered(); | ||||
| #if CHINESE_FONT | ||||
|         ImGui::Text(u8"<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ID:"); | ||||
| #else | ||||
|         ImGui::Text("LOCAL ID:"); | ||||
| #endif | ||||
|         ImGui::SameLine(); | ||||
|         ImGui::SetNextItemWidth(90); | ||||
| #if CHINESE_FONT | ||||
|         ImGui::SetCursorPosX(60.0f); | ||||
| #else | ||||
|         ImGui::SetCursorPosX(80.0f); | ||||
| #endif | ||||
|         ImGui::InputText( | ||||
|             "##local_id", (char *)mac_addr_str.c_str(), | ||||
|             mac_addr_str.length() + 1, | ||||
|             ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_ReadOnly); | ||||
|  | ||||
| #if CHINESE_FONT | ||||
|         ImGui::Text(u8"<EFBFBD><EFBFBD><EFBFBD><EFBFBD>:"); | ||||
| #else | ||||
|         ImGui::Text("PASSWORD:"); | ||||
| #endif | ||||
|         ImGui::SameLine(); | ||||
|         char input_password_tmp[7] = ""; | ||||
|         std::string input_password_str = "123456"; | ||||
|         strncpy(input_password_tmp, input_password, sizeof(input_password)); | ||||
|         ImGui::SetNextItemWidth(90); | ||||
| #if CHINESE_FONT | ||||
|         ImGui::SetCursorPosX(60.0f); | ||||
|         ImGui::InputTextWithHint("##server_pwd", u8"<EFBFBD>6<EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD>", | ||||
|                                  input_password, IM_ARRAYSIZE(input_password), | ||||
|                                  ImGuiInputTextFlags_CharsNoBlank); | ||||
| #else | ||||
|         ImGui::SetCursorPosX(80.0f); | ||||
|         ImGui::InputTextWithHint("##server_pwd", "max 6 chars", input_password, | ||||
|                                  IM_ARRAYSIZE(input_password), | ||||
|                                  ImGuiInputTextFlags_CharsNoBlank); | ||||
| #endif | ||||
|         if (strcmp(input_password_tmp, input_password)) { | ||||
|           cd_cache_file = fopen("cache.cd", "w+"); | ||||
|           if (cd_cache_file) { | ||||
|             fseek(cd_cache_file, 0, SEEK_SET); | ||||
|             strncpy(cd_cache.password, input_password, sizeof(input_password)); | ||||
|             fwrite(&cd_cache.password, sizeof(cd_cache.password), 1, | ||||
|                    cd_cache_file); | ||||
|             fclose(cd_cache_file); | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         ImGui::Spacing(); | ||||
|  | ||||
|         ImGui::Separator(); | ||||
|  | ||||
|         ImGui::Spacing(); | ||||
|         { | ||||
|           { | ||||
|             static char remote_id[20] = ""; | ||||
| #if CHINESE_FONT | ||||
|             ImGui::Text(u8"Զ<EFBFBD><EFBFBD>ID:"); | ||||
| #else | ||||
|             ImGui::Text("REMOTE ID:"); | ||||
| #endif | ||||
|             ImGui::SameLine(); | ||||
|             ImGui::SetNextItemWidth(90); | ||||
| #if CHINESE_FONT | ||||
|             ImGui::SetCursorPosX(60.0f); | ||||
| #else | ||||
|             ImGui::SetCursorPosX(80.0f); | ||||
| #endif | ||||
|             ImGui::InputTextWithHint("##remote_id", mac_addr_str.c_str(), | ||||
|                                      remote_id, IM_ARRAYSIZE(remote_id), | ||||
|                                      ImGuiInputTextFlags_CharsUppercase | | ||||
|                                          ImGuiInputTextFlags_CharsNoBlank); | ||||
|  | ||||
|             ImGui::Spacing(); | ||||
|  | ||||
| #if CHINESE_FONT | ||||
|             ImGui::Text(u8"<EFBFBD><EFBFBD><EFBFBD><EFBFBD>:"); | ||||
| #else | ||||
|             ImGui::Text("PASSWORD:"); | ||||
| #endif | ||||
|             ImGui::SameLine(); | ||||
|             ImGui::SetNextItemWidth(90); | ||||
|             static char client_password[20] = ""; | ||||
| #if CHINESE_FONT | ||||
|             ImGui::SetCursorPosX(60.0f); | ||||
|             ImGui::InputTextWithHint("##client_pwd", u8"<EFBFBD>6<EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD>", | ||||
|                                      client_password, | ||||
|                                      IM_ARRAYSIZE(client_password), | ||||
|                                      ImGuiInputTextFlags_CharsNoBlank); | ||||
| #else | ||||
|             ImGui::SetCursorPosX(80.0f); | ||||
|             ImGui::InputTextWithHint("##client_pwd", "max 6 chars", | ||||
|                                      client_password, | ||||
|                                      IM_ARRAYSIZE(client_password), | ||||
|                                      ImGuiInputTextFlags_CharsNoBlank); | ||||
| #endif | ||||
|  | ||||
|             ImGui::Spacing(); | ||||
|             ImGui::Separator(); | ||||
|             ImGui::Spacing(); | ||||
|  | ||||
|             if (ImGui::Button(connect_label)) { | ||||
|               int ret = -1; | ||||
|               if ("ClientSignalConnected" == client_signal_status_str) { | ||||
| #if CHINESE_FONT | ||||
|                 if (strcmp(connect_label, u8"<EFBFBD><EFBFBD><EFBFBD><EFBFBD>") == 0 && !joined) { | ||||
| #else | ||||
|                 if (strcmp(connect_label, "Connect") == 0 && !joined) { | ||||
| #endif | ||||
|                   std::string user_id = "C-" + mac_addr_str; | ||||
|  | ||||
| #if CHINESE_FONT | ||||
|                 } else if (strcmp(connect_label, u8"<EFBFBD>Ͽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>") == 0 && joined) { | ||||
| #else | ||||
|                 } else if (strcmp(connect_label, "Disconnect") == 0 && joined) { | ||||
| #endif | ||||
|  | ||||
|                   memset(audio_buffer, 0, 960); | ||||
|                   if (0 == ret) { | ||||
|                     joined = false; | ||||
|                     received_frame = false; | ||||
|                   } | ||||
|                 } | ||||
|  | ||||
|                 if (0 == ret) { | ||||
|                   connect_button_pressed = !connect_button_pressed; | ||||
| #if CHINESE_FONT | ||||
|                   connect_label = | ||||
|                       connect_button_pressed ? u8"<EFBFBD>Ͽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>" : u8"<EFBFBD><EFBFBD><EFBFBD><EFBFBD>"; | ||||
| #else | ||||
|                   connect_label = | ||||
|                       connect_button_pressed ? "Disconnect" : "Connect"; | ||||
| #endif | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       ImGui::Spacing(); | ||||
|  | ||||
|       ImGui::Separator(); | ||||
|  | ||||
|       ImGui::Spacing(); | ||||
|  | ||||
|       { | ||||
| #if CHINESE_FONT | ||||
|         if (ImGui::Button(u8"<EFBFBD><EFBFBD><EFBFBD>ô<EFBFBD><EFBFBD><EFBFBD>")) { | ||||
| #else | ||||
|         if (ImGui::Button("Resize Window")) { | ||||
| #endif | ||||
|           SDL_GetWindowSize(window, &window_w, &window_h); | ||||
|  | ||||
|           if (window_h != window_w * 9 / 16) { | ||||
|             window_w = window_h * 16 / 9; | ||||
|           } | ||||
|  | ||||
|           SDL_SetWindowSize(window, window_w, window_h); | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       ImGui::SameLine(); | ||||
|  | ||||
| #if CHINESE_FONT | ||||
|       if (ImGui::Button(fullscreen_label)) { | ||||
|         if (strcmp(fullscreen_label, u8"ȫ<EFBFBD><EFBFBD>") == 0) { | ||||
| #else | ||||
|       if (ImGui::Button(fullscreen_label)) { | ||||
|         if (strcmp(fullscreen_label, "FULLSCREEN") == 0) { | ||||
| #endif | ||||
|           SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); | ||||
|         } else { | ||||
|           SDL_SetWindowFullscreen(window, SDL_FALSE); | ||||
|         } | ||||
|         fullscreen_button_pressed = !fullscreen_button_pressed; | ||||
| #if CHINESE_FONT | ||||
|         fullscreen_label = fullscreen_button_pressed ? u8"<EFBFBD>˳<EFBFBD>ȫ<EFBFBD><EFBFBD>" : u8"ȫ<EFBFBD><EFBFBD>"; | ||||
| #else | ||||
|         fullscreen_label = | ||||
|             fullscreen_button_pressed ? "EXIT FULLSCREEN" : "FULLSCREEN"; | ||||
| #endif | ||||
|       } | ||||
|       ImGui::End(); | ||||
|     } | ||||
|  | ||||
|     // Rendering | ||||
|     ImGui::Render(); | ||||
|     SDL_RenderSetScale(sdlRenderer, io.DisplayFramebufferScale.x, | ||||
|                        io.DisplayFramebufferScale.y); | ||||
|  | ||||
|     SDL_RenderClear(sdlRenderer); | ||||
|     SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect); | ||||
|  | ||||
|     if (!joined || !received_frame) { | ||||
|       SDL_RenderClear(sdlRenderer); | ||||
|       SDL_SetRenderDrawColor( | ||||
|           sdlRenderer, (Uint8)(clear_color.x * 0), (Uint8)(clear_color.y * 0), | ||||
|           (Uint8)(clear_color.z * 0), (Uint8)(clear_color.w * 0)); | ||||
|     } | ||||
|  | ||||
|     ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData()); | ||||
|     SDL_RenderPresent(sdlRenderer); | ||||
|  | ||||
|     frame_count++; | ||||
|     end_time = SDL_GetTicks(); | ||||
|     elapsed_time = end_time - start_time; | ||||
|     if (elapsed_time >= 1000) { | ||||
|       fps = frame_count / (elapsed_time / 1000); | ||||
|       frame_count = 0; | ||||
|       window_title = "Remote Desk Client FPS [" + std::to_string(fps) + | ||||
|                      "] status [" + server_signal_status_str + "|" + | ||||
|                      client_signal_status_str + "|" + | ||||
|                      server_connection_status_str + "|" + | ||||
|                      client_connection_status_str + "]"; | ||||
|       // For MacOS, UI frameworks can only be called from the main thread | ||||
|       SDL_SetWindowTitle(window, window_title.c_str()); | ||||
|       start_time = end_time; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Cleanup | ||||
|  | ||||
|   SDL_CloseAudioDevice(output_dev); | ||||
|   SDL_CloseAudioDevice(input_dev); | ||||
|  | ||||
|   ImGui_ImplSDLRenderer2_Shutdown(); | ||||
|   ImGui_ImplSDL2_Shutdown(); | ||||
|   ImGui::DestroyContext(); | ||||
|  | ||||
|   SDL_DestroyRenderer(sdlRenderer); | ||||
|   SDL_DestroyWindow(window); | ||||
|  | ||||
|   SDL_CloseAudio(); | ||||
|   SDL_Quit(); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										100
									
								
								src/render/render.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/render/render.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | ||||
| #include <SDL.h> | ||||
| #include <stdio.h> | ||||
| #ifdef _WIN32 | ||||
| #ifdef REMOTE_DESK_DEBUG | ||||
| #pragma comment(linker, "/subsystem:\"console\"") | ||||
| #else | ||||
| #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"") | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #include <stdio.h> | ||||
|  | ||||
| #include <atomic> | ||||
| #include <chrono> | ||||
| #include <cstring> | ||||
| #include <fstream> | ||||
| #include <iostream> | ||||
| #include <string> | ||||
| #include <thread> | ||||
|  | ||||
| #include "config_center.h" | ||||
| #include "imgui.h" | ||||
| #include "imgui_impl_sdl2.h" | ||||
| #include "imgui_impl_sdlrenderer2.h" | ||||
| #include "log.h" | ||||
| #include "platform.h" | ||||
|  | ||||
| #define NV12_BUFFER_SIZE 1280 * 720 * 3 / 2 | ||||
|  | ||||
| #ifdef REMOTE_DESK_DEBUG | ||||
| #define MOUSE_CONTROL 0 | ||||
| #else | ||||
| #define MOUSE_CONTROL 1 | ||||
| #endif | ||||
|  | ||||
| #define CHINESE_FONT 1 | ||||
|  | ||||
| int screen_w = 1280, screen_h = 720; | ||||
| int window_w = 1280, window_h = 720; | ||||
| const int pixel_w = 1280, pixel_h = 720; | ||||
|  | ||||
| unsigned char dst_buffer[pixel_w * pixel_h * 3 / 2]; | ||||
| unsigned char audio_buffer[960]; | ||||
| SDL_Texture *sdlTexture = nullptr; | ||||
| SDL_Renderer *sdlRenderer = nullptr; | ||||
| SDL_Rect sdlRect; | ||||
| SDL_Window *window; | ||||
| static SDL_AudioDeviceID input_dev; | ||||
| static SDL_AudioDeviceID output_dev; | ||||
|  | ||||
| uint32_t start_time, end_time, elapsed_time; | ||||
| uint32_t frame_count = 0; | ||||
| int fps = 0; | ||||
|  | ||||
| static std::atomic<bool> audio_buffer_fresh{false}; | ||||
| static uint32_t last_ts = 0; | ||||
|  | ||||
| int dst_bufsize; | ||||
| struct SwrContext *swr_ctx; | ||||
|  | ||||
| int ret; | ||||
|  | ||||
| int audio_len = 0; | ||||
|  | ||||
| std::string window_title = "Remote Desk Client"; | ||||
| std::string server_connection_status_str = "-"; | ||||
| std::string client_connection_status_str = "-"; | ||||
| std::string server_signal_status_str = "-"; | ||||
| std::string client_signal_status_str = "-"; | ||||
|  | ||||
| // Refresh Event | ||||
| #define REFRESH_EVENT (SDL_USEREVENT + 1) | ||||
| #define QUIT_EVENT (SDL_USEREVENT + 2) | ||||
|  | ||||
| typedef struct { | ||||
|   char password[7]; | ||||
| } CDCache; | ||||
|  | ||||
| bool joined = false; | ||||
| bool received_frame = false; | ||||
| bool menu_hovered = false; | ||||
|  | ||||
| static bool connect_button_pressed = false; | ||||
| static bool fullscreen_button_pressed = false; | ||||
|  | ||||
| #if CHINESE_FONT | ||||
| static const char *connect_label = u8"<EFBFBD><EFBFBD><EFBFBD><EFBFBD>"; | ||||
| static const char *fullscreen_label = u8"ȫ<EFBFBD><EFBFBD>"; | ||||
| #else | ||||
| static const char *connect_label = "Connect"; | ||||
| static const char *fullscreen_label = "FULLSCREEN"; | ||||
| #endif | ||||
| static char input_password[7] = ""; | ||||
| static FILE *cd_cache_file = nullptr; | ||||
| static CDCache cd_cache; | ||||
|  | ||||
| static bool is_create_connection = false; | ||||
| static bool done = false; | ||||
|  | ||||
| ConfigCenter config_center; | ||||
		Reference in New Issue
	
	Block a user