diff --git a/src/config_center/config_center.cpp b/src/config_center/config_center.cpp new file mode 100644 index 0000000..1d381c4 --- /dev/null +++ b/src/config_center/config_center.cpp @@ -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_; } \ No newline at end of file diff --git a/src/config_center/config_center.h b/src/config_center/config_center.h new file mode 100644 index 0000000..207c499 --- /dev/null +++ b/src/config_center/config_center.h @@ -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 \ No newline at end of file diff --git a/src/connection/connection.cpp b/src/connection/connection.cpp new file mode 100644 index 0000000..ba39ee7 --- /dev/null +++ b/src/connection/connection.cpp @@ -0,0 +1,133 @@ +#include "connection.h" + +#include +#include +#include + +#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 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; +} \ No newline at end of file diff --git a/src/connection/connection.h b/src/connection/connection.h new file mode 100644 index 0000000..2ab881c --- /dev/null +++ b/src/connection/connection.h @@ -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 +#include + +#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 server_connection_status_{ + ConnectionStatus::Closed}; + std::atomic client_connection_status_{ + ConnectionStatus::Closed}; + std::atomic server_signal_status_{SignalStatus::SignalClosed}; + std::atomic client_signal_status_{SignalStatus::SignalClosed}; +}; + +#endif \ No newline at end of file diff --git a/src/gui/main.cpp b/src/gui/main.cpp index 4c68a9b..347c823 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -1,926 +1,17 @@ -#include -#include -#ifdef _WIN32 -#ifdef REMOTE_DESK_DEBUG -#pragma comment(linker, "/subsystem:\"console\"") -#else -#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"") -#endif -#endif - -#include - -#include -#include -#include -#include -#include -#include -#include - -#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 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 server_connection_status{ - ConnectionStatus::Closed}; -std::atomic client_connection_status{ - ConnectionStatus::Closed}; -std::atomic server_signal_status{SignalStatus::SignalClosed}; -std::atomic 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( - std::chrono::duration_cast( - 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 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; } \ No newline at end of file diff --git a/src/gui/mainbak.cpp b/src/gui/mainbak.cpp new file mode 100644 index 0000000..eda6278 --- /dev/null +++ b/src/gui/mainbak.cpp @@ -0,0 +1,938 @@ +#include +#include +#ifdef _WIN32 +#ifdef REMOTE_DESK_DEBUG +#pragma comment(linker, "/subsystem:\"console\"") +#else +#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"") +#endif +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include + +#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 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 server_connection_status{ + ConnectionStatus::Closed}; +std::atomic client_connection_status{ + ConnectionStatus::Closed}; +std::atomic server_signal_status{SignalStatus::SignalClosed}; +std::atomic 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( + std::chrono::duration_cast( + 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 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; +} \ No newline at end of file diff --git a/src/localization/localization.h b/src/localization/localization.h new file mode 100644 index 0000000..6608756 --- /dev/null +++ b/src/localization/localization.h @@ -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 +#include + +namespace localization { + +std::vector menu = {u8"˵", "Menu"}; +std::vector local_id = {u8"ID:", "Local ID:"}; +std::vector password = {u8":", "Password:"}; +std::vector max_password_len = {u8"6ַ", "Max 6 chars"}; +std::vector remote_id = {u8"ԶID:", "Remote ID:"}; +std::vector connect = {u8"", "Connect"}; +std::vector disconnect = {u8"Ͽ", "Disconnect"}; +std::vector reset_ratio = {u8"ñ", "Reset ratio"}; +std::vector fullscreen = {u8"ȫ", "Fullscreen"}; +std::vector exit_fullscreen = {u8"˳ȫ", "Exit fullscreen"}; + +} // namespace localization + +#endif \ No newline at end of file diff --git a/src/main_window/main_window.cpp b/src/main_window/main_window.cpp new file mode 100644 index 0000000..99f18d2 --- /dev/null +++ b/src/main_window/main_window.cpp @@ -0,0 +1,377 @@ +#include "main_window.h" + +#include +#include +#include + +#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; +} \ No newline at end of file diff --git a/src/main_window/main_window.h b/src/main_window/main_window.h new file mode 100644 index 0000000..02bee5c --- /dev/null +++ b/src/main_window/main_window.h @@ -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 + +#include +#include + +#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 \ No newline at end of file diff --git a/src/render/render.cpp b/src/render/render.cpp new file mode 100644 index 0000000..6a56764 --- /dev/null +++ b/src/render/render.cpp @@ -0,0 +1,395 @@ +#include "render.h" + +int RenderMainWindow(int argc, char *argv[]) { + LOG_INFO("Remote desk"); + + last_ts = static_cast( + std::chrono::duration_cast( + 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"˵", 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); + } + } + + 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; + +#if CHINESE_FONT + } else if (strcmp(connect_label, u8"Ͽ") == 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"Ͽ" : 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_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; +} \ No newline at end of file diff --git a/src/render/render.h b/src/render/render.h new file mode 100644 index 0000000..27f077b --- /dev/null +++ b/src/render/render.h @@ -0,0 +1,100 @@ +#include +#include +#ifdef _WIN32 +#ifdef REMOTE_DESK_DEBUG +#pragma comment(linker, "/subsystem:\"console\"") +#else +#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"") +#endif +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include + +#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 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""; +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; + +ConfigCenter config_center; \ No newline at end of file diff --git a/xmake.lua b/xmake.lua index db6ea4e..74f8f01 100644 --- a/xmake.lua +++ b/xmake.lua @@ -89,9 +89,37 @@ target("device_controller") add_includedirs("src/device_controller/mouse/linux", {public = true}) end +target("config_center") + set_kind("object") + add_deps("log") + add_files("src/config_center/*.cpp") + add_includedirs("src/config_center", {public = true}) + +target("render") + set_kind("object") + add_deps("log", "common", "config_center") + add_files("src/render/*.cpp") + add_includedirs("src/render", {public = true}) + +target("localization") + set_kind("headeronly") + add_includedirs("src/localization", {public = true}) + +target("connection") + set_kind("object") + add_deps("log", "common", "screen_capturer", "device_controller") + add_files("src/connection/*.cpp") + add_includedirs("src/connection", {public = true}) + +target("main_window") + set_kind("object") + add_deps("log", "common", "localization", "config_center") + add_files("src/main_window/*.cpp") + add_includedirs("src/main_window", {public = true}) + target("remote_desk") set_kind("binary") - add_deps("log", "common", "screen_capturer", "device_controller", "projectx") + add_deps("log", "common", "projectx", "screen_capturer", "device_controller", "render", "main_window", "connection") if is_os("macosx") then add_packages("ffmpeg") elseif is_os("linux") then @@ -99,6 +127,16 @@ target("remote_desk") end add_files("src/gui/main.cpp") +-- target("remote_desk") +-- set_kind("binary") +-- add_deps("log", "common", "projectx", "screen_capturer", "device_controller", "config_center") +-- if is_os("macosx") then +-- add_packages("ffmpeg") +-- elseif is_os("linux") then +-- add_packages("ffmpeg") +-- end +-- add_files("src/gui/main.cpp") + -- after_install(function (target) -- os.cp("$(projectdir)/thirdparty/nvcodec/Lib/x64/*.so", "$(projectdir)/out/bin") -- os.cp("$(projectdir)/thirdparty/nvcodec/Lib/x64/*.so.1", "$(projectdir)/out/bin")