mirror of
https://github.com/kunkundi/crossdesk.git
synced 2025-10-28 20:06:14 +08:00
Compare commits
28 Commits
mac_screen
...
stable
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8980f0082 | ||
|
|
e88bb017fa | ||
|
|
87466d6074 | ||
|
|
fbbbfc5e6a | ||
|
|
d2cefd1827 | ||
|
|
a350e06529 | ||
|
|
8c742ffa08 | ||
|
|
475005b8a4 | ||
|
|
4da5188759 | ||
|
|
d8df4df5ae | ||
|
|
fa05bbc8f8 | ||
|
|
927f1a6d49 | ||
|
|
1d87f61d9f | ||
|
|
ce546b77f5 | ||
|
|
b9e69cde51 | ||
|
|
e3987b4a42 | ||
|
|
0034359431 | ||
|
|
cec275bbe0 | ||
|
|
fe68464cd2 | ||
|
|
181c473625 | ||
|
|
2fc89923ae | ||
|
|
9276d5bfec | ||
|
|
95ef8fe8b9 | ||
|
|
3ab0e0136e | ||
|
|
daecc0d1e9 | ||
|
|
bfecf47226 | ||
|
|
09c42dd7ed | ||
|
|
a8a3b88514 |
20
LICENSE
Normal file
20
LICENSE
Normal file
@@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2023 The Continuous Desk Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
67
README.md
Normal file
67
README.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Continuous Desk
|
||||
|
||||
#### More than remote desktop
|
||||
|
||||
----
|
||||
[中文](README_CN.md) / [English](README.md)
|
||||
|
||||

|
||||
|
||||
# Intro
|
||||
|
||||
Continuous Desk is a lightweight cross-platform remote desktop. It allows multiple users to remotely control the same computer at the same time. In addition to desktop image transmission, it also supports end-to-end voice transmission, providing collaboration capabilities on the basis of remote desktop.
|
||||
|
||||
Continuous Desk is an experimental application of [Projectx](https://github.com/dijunkun/projectx) real-time communications library. Projectx is a lightweight cross-platform real-time communications library. It has basic capabilities such as network traversal ([RFC5245](https://datatracker.ietf.org/doc/html/rfc5245)), video softwar/hardware encoding/decoding (H264), audio encoding/decoding ([Opus](https://github.com/xiph/opus)), signaling interaction, and network congestion control ([TCP over UDP](https://libnice.freedesktop.org/)).
|
||||
|
||||
## Usage
|
||||
|
||||
Enter the remote desktop ID in the 'REMOTE ID' field on the menu bar, and click 'Connect' button to initiate the remote connection.
|
||||
|
||||

|
||||
|
||||
If the remote desktop is set with a connection password, the local end needs to enter the correct password to initiate the remote connection. If the password is incorrect, an "Incorrect password" alert will appear in the status bar.
|
||||
|
||||

|
||||
|
||||
After connection successfully established, the status bar will display the message "ClientConnected."
|
||||
|
||||

|
||||
|
||||
## How to build
|
||||
|
||||
Requirements:
|
||||
- [xmake](https://xmake.io/#/guide/installation)
|
||||
- [cmake](https://cmake.org/download/)
|
||||
- [vcpkg](https://vcpkg.io/en/getting-started)
|
||||
|
||||
Following packages need to be installed on Linux:
|
||||
|
||||
```
|
||||
sudo apt-get install -y nvidia-cuda-toolkit libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev libxcb-xfixes0-dev libxcb-shm0-dev libxv-dev libasound2-dev libsndio-dev libasound2-dev libpulse-dev
|
||||
```
|
||||
|
||||
Commands:
|
||||
```
|
||||
git clone https://github.com/dijunkun/continuous-desk
|
||||
|
||||
cd continuous-desk
|
||||
|
||||
git submodule init
|
||||
|
||||
git submodule update
|
||||
|
||||
xmake b remote_desk
|
||||
```
|
||||
Run:
|
||||
```
|
||||
# Windows/MacOS
|
||||
xmake r remote_desk
|
||||
|
||||
# root privileges are required on Linux
|
||||
./remote_desk
|
||||
```
|
||||
|
||||
## LICENSE
|
||||
|
||||
Continuous Desk is licenced under MIT, and some third-party libraries are distributed under their licenses.
|
||||
|
||||
67
README_CN.md
Normal file
67
README_CN.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Continuous Desk
|
||||
|
||||
#### 不止远程桌面
|
||||
|
||||
----
|
||||
[English](README.md) / [中文](README_CN.md)
|
||||
|
||||

|
||||
|
||||
## 简介
|
||||
|
||||
Continuous Desk 是一个轻量级的跨平台远程桌面软件。它允许多个用户在同一时间远程操控同一台电脑。除桌面图像传输外,它还支持端到端的语音传输,在远程桌面基础上提供额外的协作能力。
|
||||
|
||||
Continuous Desk 是 [Projectx](https://github.com/dijunkun/projectx) 实时音视频传输库的实验性应用。Projectx 是一个轻量级的跨平台实时音视频传输库。它具有网络透传([RFC5245](https://datatracker.ietf.org/doc/html/rfc5245)),视频软硬编解码(H264),音频编解码([Opus](https://github.com/xiph/opus)),信令交互,网络拥塞控制([TCP over UDP](https://libnice.freedesktop.org/))等基础能力。
|
||||
|
||||
|
||||
## 使用
|
||||
|
||||
在菜单栏“REMOTE ID”处输入远端桌面的ID,点击“Connect”即可发起远程连接。
|
||||
|
||||

|
||||
|
||||
如果远端桌面设置了连接密码,则本端需填写正确的连接密码才能成功发起远程连接。密码错误时,状态栏会出现“Incorrect password”告警提示。
|
||||
|
||||

|
||||
|
||||
连接成功建立后,状态栏会有“ClientConnected”相关字样。
|
||||
|
||||

|
||||
|
||||
## 编译
|
||||
|
||||
依赖:
|
||||
- [xmake](https://xmake.io/#/guide/installation)
|
||||
- [cmake](https://cmake.org/download/)
|
||||
- [vcpkg](https://vcpkg.io/en/getting-started)
|
||||
|
||||
Linux环境下需安装以下包:
|
||||
|
||||
```
|
||||
sudo apt-get install -y nvidia-cuda-toolkit libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev libxcb-xfixes0-dev libxcb-shm0-dev libxv-dev libasound2-dev libsndio-dev libasound2-dev libpulse-dev
|
||||
```
|
||||
|
||||
编译命令
|
||||
```
|
||||
git clone https://github.com/dijunkun/continuous-desk
|
||||
|
||||
cd continuous-desk
|
||||
|
||||
git submodule init
|
||||
|
||||
git submodule update
|
||||
|
||||
xmake b remote_desk
|
||||
```
|
||||
运行
|
||||
```
|
||||
# Windows/MacOS
|
||||
xmake r remote_desk
|
||||
|
||||
# Linux下需使用root权限运行
|
||||
./remote_desk
|
||||
```
|
||||
|
||||
## 许可证
|
||||
|
||||
Continuous Desk 使用 MIT 许可证,其中使用到的第三方库根据自身许可证进行分发。
|
||||
BIN
icon/捕获.PNG
Normal file
BIN
icon/捕获.PNG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
BIN
icon/捕获.ico
Normal file
BIN
icon/捕获.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 84 KiB |
101
src/common/platform.cpp
Normal file
101
src/common/platform.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
#include "platform.h"
|
||||
|
||||
#include "log.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Winsock2.h>
|
||||
#include <iphlpapi.h>
|
||||
#elif __APPLE__
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#elif __linux__
|
||||
#include <fcntl.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
std::string GetMac() {
|
||||
char mac_addr[16];
|
||||
int len = 0;
|
||||
#ifdef _WIN32
|
||||
IP_ADAPTER_INFO adapterInfo[16];
|
||||
DWORD bufferSize = sizeof(adapterInfo);
|
||||
|
||||
DWORD result = GetAdaptersInfo(adapterInfo, &bufferSize);
|
||||
if (result == ERROR_SUCCESS) {
|
||||
PIP_ADAPTER_INFO adapter = adapterInfo;
|
||||
while (adapter) {
|
||||
for (UINT i = 0; i < adapter->AddressLength; i++) {
|
||||
len += sprintf(mac_addr + len, "%.2X", adapter->Address[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
#elif __APPLE__
|
||||
std::string if_name = "en0";
|
||||
|
||||
struct ifaddrs *addrs;
|
||||
struct ifaddrs *cursor;
|
||||
const struct sockaddr_dl *dlAddr;
|
||||
|
||||
if (!getifaddrs(&addrs)) {
|
||||
cursor = addrs;
|
||||
while (cursor != 0) {
|
||||
const struct sockaddr_dl *socAddr =
|
||||
(const struct sockaddr_dl *)cursor->ifa_addr;
|
||||
if ((cursor->ifa_addr->sa_family == AF_LINK) &&
|
||||
(socAddr->sdl_type == IFT_ETHER) &&
|
||||
strcmp(if_name.c_str(), cursor->ifa_name) == 0) {
|
||||
dlAddr = (const struct sockaddr_dl *)cursor->ifa_addr;
|
||||
const unsigned char *base =
|
||||
(const unsigned char *)&dlAddr->sdl_data[dlAddr->sdl_nlen];
|
||||
for (int i = 0; i < dlAddr->sdl_alen; i++) {
|
||||
len += sprintf(mac_addr + len, "%.2X", base[i]);
|
||||
}
|
||||
}
|
||||
cursor = cursor->ifa_next;
|
||||
}
|
||||
freeifaddrs(addrs);
|
||||
}
|
||||
#elif __linux__
|
||||
int sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock < 0) {
|
||||
return "";
|
||||
}
|
||||
struct ifreq ifr;
|
||||
struct ifconf ifc;
|
||||
char buf[1024];
|
||||
ifc.ifc_len = sizeof(buf);
|
||||
ifc.ifc_buf = buf;
|
||||
if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
|
||||
close(sock);
|
||||
return "";
|
||||
}
|
||||
struct ifreq *it = ifc.ifc_req;
|
||||
const struct ifreq *const end = it + (ifc.ifc_len / sizeof(struct ifreq));
|
||||
for (; it != end; ++it) {
|
||||
std::strcpy(ifr.ifr_name, it->ifr_name);
|
||||
if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
|
||||
continue;
|
||||
}
|
||||
if (ifr.ifr_flags & IFF_LOOPBACK) {
|
||||
continue;
|
||||
}
|
||||
if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {
|
||||
continue;
|
||||
}
|
||||
std::string mac_address;
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
len += sprintf(mac_addr + len, "%.2X", ifr.ifr_hwaddr.sa_data[i] & 0xff);
|
||||
}
|
||||
break;
|
||||
}
|
||||
close(sock);
|
||||
#endif
|
||||
return mac_addr;
|
||||
}
|
||||
14
src/common/platform.h
Normal file
14
src/common/platform.h
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2023-12-18
|
||||
* Copyright (c) 2023 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _PLATFORM_H_
|
||||
#define _PLATFORM_H_
|
||||
|
||||
#include <iostream>
|
||||
|
||||
std::string GetMac();
|
||||
|
||||
#endif
|
||||
44
src/device_controller/device_controller.h
Normal file
44
src/device_controller/device_controller.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2023-12-14
|
||||
* Copyright (c) 2023 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DEVICE_CONTROLLER_H_
|
||||
#define _DEVICE_CONTROLLER_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
typedef enum { mouse = 0, keyboard } ControlType;
|
||||
typedef enum { move = 0, left_down, left_up, right_down, right_up } MouseFlag;
|
||||
typedef enum { key_down = 0, key_up } KeyFlag;
|
||||
typedef struct {
|
||||
size_t x;
|
||||
size_t y;
|
||||
MouseFlag flag;
|
||||
} Mouse;
|
||||
|
||||
typedef struct {
|
||||
size_t key_value;
|
||||
KeyFlag flag;
|
||||
} Key;
|
||||
|
||||
typedef struct {
|
||||
ControlType type;
|
||||
union {
|
||||
Mouse m;
|
||||
Key k;
|
||||
};
|
||||
} RemoteAction;
|
||||
|
||||
class DeviceController {
|
||||
public:
|
||||
virtual ~DeviceController() {}
|
||||
|
||||
public:
|
||||
virtual int Init(int screen_width, int screen_height) = 0;
|
||||
virtual int Destroy() = 0;
|
||||
virtual int SendCommand(RemoteAction remote_action) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
33
src/device_controller/device_controller_factory.h
Normal file
33
src/device_controller/device_controller_factory.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2023-12-14
|
||||
* Copyright (c) 2023 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DEVICE_CONTROLLER_FACTORY_H_
|
||||
#define _DEVICE_CONTROLLER_FACTORY_H_
|
||||
|
||||
#include "device_controller.h"
|
||||
#include "mouse_controller.h"
|
||||
|
||||
class DeviceControllerFactory {
|
||||
public:
|
||||
enum Device { Mouse = 0, Keyboard };
|
||||
|
||||
public:
|
||||
virtual ~DeviceControllerFactory() {}
|
||||
|
||||
public:
|
||||
DeviceController* Create(Device device) {
|
||||
switch (device) {
|
||||
case Mouse:
|
||||
return new MouseController();
|
||||
case Keyboard:
|
||||
return nullptr;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
122
src/device_controller/mouse/linux/mouse_controller.cpp
Normal file
122
src/device_controller/mouse/linux/mouse_controller.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
#include "mouse_controller.h"
|
||||
|
||||
#include "log.h"
|
||||
|
||||
MouseController::MouseController() {}
|
||||
|
||||
MouseController::~MouseController() {}
|
||||
|
||||
int MouseController::Init(int screen_width, int screen_height) {
|
||||
screen_width_ = screen_width;
|
||||
screen_height_ = screen_height;
|
||||
|
||||
uinput_fd_ = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
|
||||
if (uinput_fd_ < 0) {
|
||||
LOG_ERROR("Cannot open device: /dev/uinput");
|
||||
}
|
||||
|
||||
ioctl(uinput_fd_, UI_SET_EVBIT, EV_KEY);
|
||||
ioctl(uinput_fd_, UI_SET_KEYBIT, BTN_RIGHT);
|
||||
ioctl(uinput_fd_, UI_SET_KEYBIT, BTN_LEFT);
|
||||
ioctl(uinput_fd_, UI_SET_EVBIT, EV_ABS);
|
||||
ioctl(uinput_fd_, UI_SET_ABSBIT, ABS_X);
|
||||
ioctl(uinput_fd_, UI_SET_ABSBIT, ABS_Y);
|
||||
ioctl(uinput_fd_, UI_SET_EVBIT, EV_REL);
|
||||
|
||||
struct uinput_user_dev uidev;
|
||||
memset(&uidev, 0, sizeof(uidev));
|
||||
snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "VirtualMouse");
|
||||
uidev.id.bustype = BUS_USB;
|
||||
uidev.id.version = 1;
|
||||
uidev.id.vendor = 0x1;
|
||||
uidev.id.product = 0x1;
|
||||
uidev.absmin[ABS_X] = 0;
|
||||
uidev.absmax[ABS_X] = screen_width_;
|
||||
uidev.absmin[ABS_Y] = 0;
|
||||
uidev.absmax[ABS_Y] = screen_height_;
|
||||
|
||||
write(uinput_fd_, &uidev, sizeof(uidev));
|
||||
ioctl(uinput_fd_, UI_DEV_CREATE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MouseController::Destroy() {
|
||||
ioctl(uinput_fd_, UI_DEV_DESTROY);
|
||||
close(uinput_fd_);
|
||||
}
|
||||
|
||||
int MouseController::SendCommand(RemoteAction remote_action) {
|
||||
int mouse_pos_x = remote_action.m.x * screen_width_ / 1280;
|
||||
int mouse_pos_y = remote_action.m.y * screen_height_ / 720;
|
||||
|
||||
if (remote_action.type == ControlType::mouse) {
|
||||
struct input_event event;
|
||||
memset(&event, 0, sizeof(event));
|
||||
gettimeofday(&event.time, NULL);
|
||||
|
||||
if (remote_action.m.flag == MouseFlag::left_down) {
|
||||
SimulateKeyDown(uinput_fd_, BTN_LEFT);
|
||||
} else if (remote_action.m.flag == MouseFlag::left_up) {
|
||||
SimulateKeyUp(uinput_fd_, BTN_LEFT);
|
||||
} else if (remote_action.m.flag == MouseFlag::right_down) {
|
||||
SimulateKeyDown(uinput_fd_, BTN_RIGHT);
|
||||
} else if (remote_action.m.flag == MouseFlag::right_up) {
|
||||
SimulateKeyUp(uinput_fd_, BTN_RIGHT);
|
||||
} else {
|
||||
SetMousePosition(uinput_fd_, mouse_pos_x, mouse_pos_y);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MouseController::SimulateKeyDown(int fd, int kval) {
|
||||
struct input_event event;
|
||||
memset(&event, 0, sizeof(event));
|
||||
gettimeofday(&event.time, 0);
|
||||
|
||||
event.type = EV_KEY;
|
||||
event.value = 1;
|
||||
event.code = kval;
|
||||
write(fd, &event, sizeof(event));
|
||||
|
||||
event.type = EV_SYN;
|
||||
event.value = 0;
|
||||
event.code = SYN_REPORT;
|
||||
write(fd, &event, sizeof(event));
|
||||
}
|
||||
|
||||
void MouseController::SimulateKeyUp(int fd, int kval) {
|
||||
struct input_event event;
|
||||
memset(&event, 0, sizeof(event));
|
||||
gettimeofday(&event.time, 0);
|
||||
|
||||
event.type = EV_KEY;
|
||||
event.value = 0;
|
||||
event.code = kval;
|
||||
write(fd, &event, sizeof(event));
|
||||
|
||||
event.type = EV_SYN;
|
||||
event.value = 0;
|
||||
event.code = SYN_REPORT;
|
||||
write(fd, &event, sizeof(event));
|
||||
}
|
||||
|
||||
void MouseController::SetMousePosition(int fd, int x, int y) {
|
||||
struct input_event ev[2], ev_sync;
|
||||
memset(ev, 0, sizeof(ev));
|
||||
memset(&ev_sync, 0, sizeof(ev_sync));
|
||||
|
||||
ev[0].type = EV_ABS;
|
||||
ev[0].code = ABS_X;
|
||||
ev[0].value = x;
|
||||
ev[1].type = EV_ABS;
|
||||
ev[1].code = ABS_Y;
|
||||
ev[1].value = y;
|
||||
int res_w = write(fd, ev, sizeof(ev));
|
||||
|
||||
ev_sync.type = EV_SYN;
|
||||
ev_sync.value = 0;
|
||||
ev_sync.code = 0;
|
||||
int res_ev_sync = write(fd, &ev_sync, sizeof(ev_sync));
|
||||
}
|
||||
41
src/device_controller/mouse/linux/mouse_controller.h
Normal file
41
src/device_controller/mouse/linux/mouse_controller.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2023-12-14
|
||||
* Copyright (c) 2023 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MOUSE_CONTROLLER_H_
|
||||
#define _MOUSE_CONTROLLER_H_
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <linux/uinput.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "device_controller.h"
|
||||
|
||||
class MouseController : public DeviceController {
|
||||
public:
|
||||
MouseController();
|
||||
virtual ~MouseController();
|
||||
|
||||
public:
|
||||
virtual int Init(int screen_width, int screen_height);
|
||||
virtual int Destroy();
|
||||
virtual int SendCommand(RemoteAction remote_action);
|
||||
|
||||
private:
|
||||
void SimulateKeyDown(int fd, int kval);
|
||||
void SimulateKeyUp(int fd, int kval);
|
||||
void SetMousePosition(int fd, int x, int y);
|
||||
|
||||
private:
|
||||
int uinput_fd_;
|
||||
struct uinput_user_dev uinput_dev_;
|
||||
int screen_width_ = 0;
|
||||
int screen_height_ = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
49
src/device_controller/mouse/mac/mouse_controller.cpp
Normal file
49
src/device_controller/mouse/mac/mouse_controller.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include "mouse_controller.h"
|
||||
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
MouseController::MouseController() {}
|
||||
|
||||
MouseController::~MouseController() {}
|
||||
|
||||
int MouseController::Init(int screen_width, int screen_height) {
|
||||
screen_width_ = screen_width;
|
||||
screen_height_ = screen_height;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MouseController::Destroy() { return 0; }
|
||||
|
||||
int MouseController::SendCommand(RemoteAction remote_action) {
|
||||
int mouse_pos_x = remote_action.m.x * screen_width_ / 1280;
|
||||
int mouse_pos_y = remote_action.m.y * screen_height_ / 720;
|
||||
|
||||
if (remote_action.type == ControlType::mouse) {
|
||||
CGEventRef mouse_event;
|
||||
CGEventType mouse_type;
|
||||
|
||||
if (remote_action.m.flag == MouseFlag::left_down) {
|
||||
mouse_type = kCGEventLeftMouseDown;
|
||||
} else if (remote_action.m.flag == MouseFlag::left_up) {
|
||||
mouse_type = kCGEventLeftMouseUp;
|
||||
} else if (remote_action.m.flag == MouseFlag::right_down) {
|
||||
mouse_type = kCGEventRightMouseDown;
|
||||
} else if (remote_action.m.flag == MouseFlag::right_up) {
|
||||
mouse_type = kCGEventRightMouseUp;
|
||||
} else {
|
||||
mouse_type = kCGEventMouseMoved;
|
||||
}
|
||||
|
||||
mouse_event = CGEventCreateMouseEvent(NULL, mouse_type,
|
||||
CGPointMake(mouse_pos_x, mouse_pos_y),
|
||||
kCGMouseButtonLeft);
|
||||
|
||||
CGEventPost(kCGHIDEventTap, mouse_event);
|
||||
CFRelease(mouse_event);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
27
src/device_controller/mouse/mac/mouse_controller.h
Normal file
27
src/device_controller/mouse/mac/mouse_controller.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2023-12-14
|
||||
* Copyright (c) 2023 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MOUSE_CONTROLLER_H_
|
||||
#define _MOUSE_CONTROLLER_H_
|
||||
|
||||
#include "device_controller.h"
|
||||
|
||||
class MouseController : public DeviceController {
|
||||
public:
|
||||
MouseController();
|
||||
virtual ~MouseController();
|
||||
|
||||
public:
|
||||
virtual int Init(int screen_width, int screen_height);
|
||||
virtual int Destroy();
|
||||
virtual int SendCommand(RemoteAction remote_action);
|
||||
|
||||
private:
|
||||
int screen_width_ = 0;
|
||||
int screen_height_ = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
47
src/device_controller/mouse/windows/mouse_controller.cpp
Normal file
47
src/device_controller/mouse/windows/mouse_controller.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
#include "mouse_controller.h"
|
||||
|
||||
#include "log.h"
|
||||
|
||||
MouseController::MouseController() {}
|
||||
|
||||
MouseController::~MouseController() {}
|
||||
|
||||
int MouseController::Init(int screen_width, int screen_height) {
|
||||
screen_width_ = screen_width;
|
||||
screen_height_ = screen_height;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MouseController::Destroy() { return 0; }
|
||||
|
||||
int MouseController::SendCommand(RemoteAction remote_action) {
|
||||
INPUT ip;
|
||||
|
||||
if (remote_action.type == ControlType::mouse) {
|
||||
ip.type = INPUT_MOUSE;
|
||||
ip.mi.dx = remote_action.m.x * screen_width_ / 1280;
|
||||
ip.mi.dy = remote_action.m.y * screen_height_ / 720;
|
||||
if (remote_action.m.flag == MouseFlag::left_down) {
|
||||
ip.mi.dwFlags = MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE;
|
||||
} else if (remote_action.m.flag == MouseFlag::left_up) {
|
||||
ip.mi.dwFlags = MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE;
|
||||
} else if (remote_action.m.flag == MouseFlag::right_down) {
|
||||
ip.mi.dwFlags = MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_ABSOLUTE;
|
||||
} else if (remote_action.m.flag == MouseFlag::right_up) {
|
||||
ip.mi.dwFlags = MOUSEEVENTF_RIGHTUP | MOUSEEVENTF_ABSOLUTE;
|
||||
} else {
|
||||
ip.mi.dwFlags = MOUSEEVENTF_MOVE;
|
||||
}
|
||||
ip.mi.mouseData = 0;
|
||||
ip.mi.time = 0;
|
||||
|
||||
SetCursorPos(ip.mi.dx, ip.mi.dy);
|
||||
|
||||
if (ip.mi.dwFlags != MOUSEEVENTF_MOVE) {
|
||||
SendInput(1, &ip, sizeof(INPUT));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
27
src/device_controller/mouse/windows/mouse_controller.h
Normal file
27
src/device_controller/mouse/windows/mouse_controller.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2023-12-14
|
||||
* Copyright (c) 2023 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MOUSE_CONTROLLER_H_
|
||||
#define _MOUSE_CONTROLLER_H_
|
||||
|
||||
#include "device_controller.h"
|
||||
|
||||
class MouseController : public DeviceController {
|
||||
public:
|
||||
MouseController();
|
||||
virtual ~MouseController();
|
||||
|
||||
public:
|
||||
virtual int Init(int screen_width, int screen_height);
|
||||
virtual int Destroy();
|
||||
virtual int SendCommand(RemoteAction remote_action);
|
||||
|
||||
private:
|
||||
int screen_width_ = 0;
|
||||
int screen_height_ = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
693
src/gui/main.cpp
693
src/gui/main.cpp
@@ -1,22 +1,11 @@
|
||||
#include <SDL.h>
|
||||
#include <stdio.h>
|
||||
#ifdef _WIN32
|
||||
// #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
|
||||
#ifdef REMOTE_DESK_DEBUG
|
||||
#pragma comment(linker, "/subsystem:\"console\"")
|
||||
#include <Winsock2.h>
|
||||
#include <iphlpapi.h>
|
||||
#elif __APPLE__
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#elif __linux__
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <atomic>
|
||||
@@ -27,33 +16,23 @@
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavdevice/avdevice.h>
|
||||
#include <libavfilter/avfilter.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/channel_layout.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libavutil/opt.h>
|
||||
#include <libavutil/samplefmt.h>
|
||||
#include <libswresample/swresample.h>
|
||||
#include <libswscale/swscale.h>
|
||||
};
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#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 "log.h"
|
||||
#ifdef _WIN32
|
||||
#include "screen_capture_wgc.h"
|
||||
#elif __linux__
|
||||
#include "screen_capture_x11.h"
|
||||
#elif __APPLE__
|
||||
#include "screen_capture_avf.h"
|
||||
#endif
|
||||
#include "../../thirdparty/projectx/src/interface/x.h"
|
||||
#include "screen_capturer_factory.h"
|
||||
|
||||
#define NV12_BUFFER_SIZE 1280 * 720 * 3 / 2
|
||||
|
||||
@@ -80,72 +59,52 @@ uint32_t start_time, end_time, elapsed_time;
|
||||
uint32_t frame_count = 0;
|
||||
int fps = 0;
|
||||
|
||||
#if 1
|
||||
static Uint8 *buffer = 0;
|
||||
static int in_pos = 0;
|
||||
static int out_pos = 0;
|
||||
static std::atomic<bool> audio_buffer_fresh = false;
|
||||
static std::atomic<bool> audio_buffer_fresh{false};
|
||||
static uint32_t last_ts = 0;
|
||||
|
||||
char *out = "audio_old.pcm";
|
||||
FILE *outfile = fopen(out, "wb+");
|
||||
|
||||
int64_t src_ch_layout = AV_CH_LAYOUT_MONO;
|
||||
int src_rate = 48000;
|
||||
enum AVSampleFormat src_sample_fmt = AV_SAMPLE_FMT_S16;
|
||||
int src_nb_channels = 0;
|
||||
uint8_t **src_data = NULL; // <20><><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8>
|
||||
uint8_t **src_data = NULL;
|
||||
int src_linesize;
|
||||
int src_nb_samples = 480;
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
int64_t dst_ch_layout = AV_CH_LAYOUT_MONO;
|
||||
int dst_rate = 48000;
|
||||
enum AVSampleFormat dst_sample_fmt = AV_SAMPLE_FMT_S16;
|
||||
int dst_nb_channels = 0;
|
||||
uint8_t **dst_data = NULL; // <20><><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8>
|
||||
uint8_t **dst_data = NULL;
|
||||
int dst_linesize;
|
||||
int dst_nb_samples;
|
||||
int max_dst_nb_samples;
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>
|
||||
const char *dst_filename = NULL; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>pcm<63><6D><EFBFBD><EFBFBD><EFBFBD>أ<EFBFBD>Ȼ<EFBFBD><EFBFBD><F3B2A5B7><EFBFBD>֤
|
||||
FILE *dst_file;
|
||||
|
||||
int dst_bufsize;
|
||||
|
||||
// <20>ز<EFBFBD><D8B2><EFBFBD>ʵ<EFBFBD><CAB5>
|
||||
struct SwrContext *swr_ctx;
|
||||
|
||||
double t;
|
||||
int ret;
|
||||
#endif
|
||||
|
||||
int audio_len = 0;
|
||||
#define MAX_FRAME_SIZE 6 * 960
|
||||
#define CHANNELS 2
|
||||
unsigned char pcm_bytes[MAX_FRAME_SIZE * CHANNELS * 2];
|
||||
|
||||
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;
|
||||
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[16];
|
||||
char password[7];
|
||||
} CDCache;
|
||||
|
||||
int thread_exit = 0;
|
||||
@@ -153,23 +112,22 @@ 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 const char *connect_label = "Connect";
|
||||
static char input_password[7] = "";
|
||||
static FILE *cd_cache_file = nullptr;
|
||||
static CDCache cd_cache;
|
||||
static char mac_addr[16];
|
||||
|
||||
static bool is_create_connection = false;
|
||||
static bool done = false;
|
||||
|
||||
#ifdef _WIN32
|
||||
ScreenCaptureWgc *screen_capture = nullptr;
|
||||
#elif __linux__
|
||||
ScreenCaptureX11 *screen_capture = nullptr;
|
||||
#elif __APPLE__
|
||||
ScreenCaptureAvf *screen_capture = nullptr;
|
||||
#endif
|
||||
ScreenCapturerFactory *screen_capturer_factory = nullptr;
|
||||
ScreenCapturer *screen_capturer = nullptr;
|
||||
|
||||
DeviceControllerFactory *device_controller_factory = nullptr;
|
||||
MouseController *mouse_controller = nullptr;
|
||||
|
||||
char *nv12_buffer = nullptr;
|
||||
|
||||
@@ -179,32 +137,12 @@ std::chrono::_V2::system_clock::time_point last_frame_time_;
|
||||
std::chrono::steady_clock::time_point last_frame_time_;
|
||||
#endif
|
||||
|
||||
typedef enum { mouse = 0, keyboard } ControlType;
|
||||
typedef enum { move = 0, left_down, left_up, right_down, right_up } MouseFlag;
|
||||
typedef enum { key_down = 0, key_up } KeyFlag;
|
||||
typedef struct {
|
||||
size_t x;
|
||||
size_t y;
|
||||
MouseFlag flag;
|
||||
} Mouse;
|
||||
|
||||
typedef struct {
|
||||
size_t key_value;
|
||||
KeyFlag flag;
|
||||
} Key;
|
||||
|
||||
typedef struct {
|
||||
ControlType type;
|
||||
union {
|
||||
Mouse m;
|
||||
Key k;
|
||||
};
|
||||
} RemoteAction;
|
||||
|
||||
inline int ProcessMouseKeyEven(SDL_Event &ev) {
|
||||
float ratio = 1280.0 / window_w;
|
||||
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
|
||||
{
|
||||
@@ -222,70 +160,26 @@ inline int ProcessMouseKeyEven(SDL_Event &ev) {
|
||||
// printf("SDLK_RIGHT \n");
|
||||
}
|
||||
} else if (SDL_MOUSEBUTTONDOWN == ev.type) {
|
||||
remote_action.type = ControlType::mouse;
|
||||
if (SDL_BUTTON_LEFT == ev.button.button) {
|
||||
int px = ev.button.x;
|
||||
int py = ev.button.y;
|
||||
// printf("SDL_MOUSEBUTTONDOWN x, y %d %d \n", px, py);
|
||||
|
||||
remote_action.type = ControlType::mouse;
|
||||
remote_action.m.flag = MouseFlag::left_down;
|
||||
remote_action.m.x = ev.button.x * ratio;
|
||||
remote_action.m.y = ev.button.y * ratio;
|
||||
|
||||
SendData(peer_client, DATA_TYPE::DATA, (const char *)&remote_action,
|
||||
sizeof(remote_action));
|
||||
|
||||
} else if (SDL_BUTTON_RIGHT == ev.button.button) {
|
||||
int px = ev.button.x;
|
||||
int py = ev.button.y;
|
||||
// printf("SDL_BUTTON_RIGHT x, y %d %d \n", px, py);
|
||||
|
||||
remote_action.type = ControlType::mouse;
|
||||
remote_action.m.flag = MouseFlag::right_down;
|
||||
remote_action.m.x = ev.button.x * ratio;
|
||||
remote_action.m.y = ev.button.y * ratio;
|
||||
|
||||
SendData(peer_client, DATA_TYPE::DATA, (const char *)&remote_action,
|
||||
sizeof(remote_action));
|
||||
}
|
||||
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) {
|
||||
int px = ev.button.x;
|
||||
int py = ev.button.y;
|
||||
// printf("SDL_MOUSEBUTTONUP x, y %d %d \n", px, py);
|
||||
|
||||
remote_action.type = ControlType::mouse;
|
||||
remote_action.m.flag = MouseFlag::left_up;
|
||||
remote_action.m.x = ev.button.x * ratio;
|
||||
remote_action.m.y = ev.button.y * ratio;
|
||||
|
||||
SendData(peer_client, DATA_TYPE::DATA, (const char *)&remote_action,
|
||||
sizeof(remote_action));
|
||||
|
||||
} else if (SDL_BUTTON_RIGHT == ev.button.button) {
|
||||
int px = ev.button.x;
|
||||
int py = ev.button.y;
|
||||
// printf("SDL_MOUSEBUTTONUP x, y %d %d \n", px, py);
|
||||
|
||||
remote_action.type = ControlType::mouse;
|
||||
remote_action.m.flag = MouseFlag::right_up;
|
||||
remote_action.m.x = ev.button.x * ratio;
|
||||
remote_action.m.y = ev.button.y * ratio;
|
||||
|
||||
SendData(peer_client, DATA_TYPE::DATA, (const char *)&remote_action,
|
||||
sizeof(remote_action));
|
||||
}
|
||||
SendData(peer_client, DATA_TYPE::DATA, (const char *)&remote_action,
|
||||
sizeof(remote_action));
|
||||
} else if (SDL_MOUSEMOTION == ev.type) {
|
||||
int px = ev.motion.x;
|
||||
int py = ev.motion.y;
|
||||
|
||||
// printf("SDL_MOUSEMOTION x, y %d %d \n", px, py);
|
||||
|
||||
remote_action.type = ControlType::mouse;
|
||||
remote_action.m.flag = MouseFlag::move;
|
||||
remote_action.m.x = ev.button.x * ratio;
|
||||
remote_action.m.y = ev.button.y * ratio;
|
||||
|
||||
SendData(peer_client, DATA_TYPE::DATA, (const char *)&remote_action,
|
||||
sizeof(remote_action));
|
||||
} else if (SDL_QUIT == ev.type) {
|
||||
@@ -301,8 +195,8 @@ inline int ProcessMouseKeyEven(SDL_Event &ev) {
|
||||
|
||||
void SdlCaptureAudioIn(void *userdata, Uint8 *stream, int len) {
|
||||
int64_t delay = swr_get_delay(swr_ctx, src_rate);
|
||||
dst_nb_samples =
|
||||
av_rescale_rnd(delay + src_nb_samples, dst_rate, src_rate, AV_ROUND_UP);
|
||||
dst_nb_samples = (int)av_rescale_rnd(delay + src_nb_samples, dst_rate,
|
||||
src_rate, AV_ROUND_UP);
|
||||
if (dst_nb_samples > max_dst_nb_samples) {
|
||||
av_freep(&dst_data[0]);
|
||||
ret = av_samples_alloc(dst_data, &dst_linesize, dst_nb_channels,
|
||||
@@ -387,7 +281,7 @@ void ServerReceiveAudioBuffer(const char *data, size_t size,
|
||||
// audio_len = size;
|
||||
audio_buffer_fresh = true;
|
||||
|
||||
SDL_QueueAudio(output_dev, data, size);
|
||||
SDL_QueueAudio(output_dev, data, (Uint32)size);
|
||||
// printf("queue audio\n");
|
||||
}
|
||||
|
||||
@@ -395,7 +289,7 @@ 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, size);
|
||||
SDL_QueueAudio(output_dev, data, (Uint32)size);
|
||||
}
|
||||
|
||||
void ServerReceiveDataBuffer(const char *data, size_t size, const char *user_id,
|
||||
@@ -408,129 +302,13 @@ void ServerReceiveDataBuffer(const char *data, size_t size, const char *user_id,
|
||||
// std::cout << "remote_action: " << remote_action.type << " "
|
||||
// << remote_action.m.flag << " " << remote_action.m.x << " "
|
||||
// << remote_action.m.y << std::endl;
|
||||
|
||||
int mouse_pos_x = remote_action.m.x * screen_w / 1280;
|
||||
int mouse_pos_y = remote_action.m.y * screen_h / 720;
|
||||
#if 1
|
||||
#ifdef _WIN32
|
||||
INPUT ip;
|
||||
|
||||
if (remote_action.type == ControlType::mouse) {
|
||||
ip.type = INPUT_MOUSE;
|
||||
ip.mi.dx = remote_action.m.x * screen_w / 1280;
|
||||
ip.mi.dy = remote_action.m.y * screen_h / 720;
|
||||
if (remote_action.m.flag == MouseFlag::left_down) {
|
||||
ip.mi.dwFlags = MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE;
|
||||
} else if (remote_action.m.flag == MouseFlag::left_up) {
|
||||
ip.mi.dwFlags = MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE;
|
||||
} else if (remote_action.m.flag == MouseFlag::right_down) {
|
||||
ip.mi.dwFlags = MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_ABSOLUTE;
|
||||
} else if (remote_action.m.flag == MouseFlag::right_up) {
|
||||
ip.mi.dwFlags = MOUSEEVENTF_RIGHTUP | MOUSEEVENTF_ABSOLUTE;
|
||||
} else {
|
||||
ip.mi.dwFlags = MOUSEEVENTF_MOVE;
|
||||
}
|
||||
ip.mi.mouseData = 0;
|
||||
ip.mi.time = 0;
|
||||
|
||||
// Set cursor pos
|
||||
SetCursorPos(ip.mi.dx, ip.mi.dy);
|
||||
// Send the press
|
||||
if (ip.mi.dwFlags != MOUSEEVENTF_MOVE) {
|
||||
SendInput(1, &ip, sizeof(INPUT));
|
||||
}
|
||||
|
||||
// std::cout << "Receive data from [" << user << "], " << ip.type << " "
|
||||
// << ip.mi.dwFlags << " " << ip.mi.dx << " " << ip.mi.dy
|
||||
// << std::endl;
|
||||
}
|
||||
|
||||
#elif __APPLE__
|
||||
if (remote_action.type == ControlType::mouse) {
|
||||
CGEventRef mouse_event;
|
||||
CGEventType mouse_type;
|
||||
|
||||
if (remote_action.m.flag == MouseFlag::left_down) {
|
||||
mouse_type = kCGEventLeftMouseDown;
|
||||
} else if (remote_action.m.flag == MouseFlag::left_up) {
|
||||
mouse_type = kCGEventLeftMouseUp;
|
||||
} else if (remote_action.m.flag == MouseFlag::right_down) {
|
||||
mouse_type = kCGEventRightMouseDown;
|
||||
} else if (remote_action.m.flag == MouseFlag::right_up) {
|
||||
mouse_type = kCGEventRightMouseUp;
|
||||
} else {
|
||||
mouse_type = kCGEventMouseMoved;
|
||||
}
|
||||
|
||||
mouse_event = CGEventCreateMouseEvent(NULL, mouse_type,
|
||||
CGPointMake(mouse_pos_x, mouse_pos_y),
|
||||
kCGMouseButtonLeft);
|
||||
|
||||
CGEventPost(kCGHIDEventTap, mouse_event);
|
||||
CFRelease(mouse_event);
|
||||
}
|
||||
#endif
|
||||
#if MOUSE_CONTROL
|
||||
mouse_controller->SendCommand(remote_action);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ClientReceiveDataBuffer(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;
|
||||
|
||||
int mouse_pos_x = remote_action.m.x * screen_w / 1280;
|
||||
int mouse_pos_y = remote_action.m.y * screen_h / 720;
|
||||
|
||||
#ifdef _WIN32
|
||||
INPUT ip;
|
||||
|
||||
if (remote_action.type == ControlType::mouse) {
|
||||
ip.type = INPUT_MOUSE;
|
||||
ip.mi.dx = mouse_pos_x;
|
||||
ip.mi.dy = mouse_pos_y;
|
||||
if (remote_action.m.flag == MouseFlag::left_down) {
|
||||
ip.mi.dwFlags = MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE;
|
||||
} else if (remote_action.m.flag == MouseFlag::left_up) {
|
||||
ip.mi.dwFlags = MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE;
|
||||
} else if (remote_action.m.flag == MouseFlag::right_down) {
|
||||
ip.mi.dwFlags = MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_ABSOLUTE;
|
||||
} else if (remote_action.m.flag == MouseFlag::right_up) {
|
||||
ip.mi.dwFlags = MOUSEEVENTF_RIGHTUP | MOUSEEVENTF_ABSOLUTE;
|
||||
} else {
|
||||
ip.mi.dwFlags = MOUSEEVENTF_MOVE;
|
||||
}
|
||||
ip.mi.mouseData = 0;
|
||||
ip.mi.time = 0;
|
||||
|
||||
#if MOUSE_CONTROL
|
||||
// Set cursor pos
|
||||
SetCursorPos(ip.mi.dx, ip.mi.dy);
|
||||
// Send the press
|
||||
if (ip.mi.dwFlags != MOUSEEVENTF_MOVE) {
|
||||
SendInput(1, &ip, sizeof(INPUT));
|
||||
}
|
||||
#endif
|
||||
// std::cout << "Receive data from [" << user << "], " << ip.type << " "
|
||||
// << ip.mi.dwFlags << " " << ip.mi.dx << " " << ip.mi.dy
|
||||
// << std::endl;
|
||||
}
|
||||
|
||||
#elif __APPLE__
|
||||
CGEventRef mouse_event;
|
||||
mouse_event = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved,
|
||||
CGPointMake(mouse_pos_x, mouse_pos_y),
|
||||
kCGMouseButtonLeft);
|
||||
CGEventPost(kCGHIDEventTap, mouse_event);
|
||||
CFRelease(mouse_event);
|
||||
|
||||
#endif
|
||||
}
|
||||
size_t user_id_size) {}
|
||||
|
||||
void ServerSignalStatus(SignalStatus status) {
|
||||
server_signal_status = status;
|
||||
@@ -590,6 +368,7 @@ void ClientConnectionStatus(ConnectionStatus 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) {
|
||||
@@ -614,15 +393,6 @@ void ClientConnectionStatus(ConnectionStatus status) {
|
||||
}
|
||||
|
||||
int initResampler() {
|
||||
// dst_filename = "res.pcm";
|
||||
|
||||
// dst_file = fopen(dst_filename, "wb");
|
||||
// if (!dst_file) {
|
||||
// fprintf(stderr, "Could not open destination file %s\n", dst_filename);
|
||||
// exit(1);
|
||||
// }
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD>ز<EFBFBD><D8B2><EFBFBD><EFBFBD><EFBFBD>
|
||||
/* create resampler context */
|
||||
swr_ctx = swr_alloc();
|
||||
if (!swr_ctx) {
|
||||
@@ -631,18 +401,15 @@ int initResampler() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD>ز<EFBFBD><D8B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
/* set options */
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
av_opt_set_int(swr_ctx, "in_channel_layout", src_ch_layout, 0);
|
||||
av_opt_set_int(swr_ctx, "in_sample_rate", src_rate, 0);
|
||||
av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", src_sample_fmt, 0);
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
av_opt_set_int(swr_ctx, "out_channel_layout", dst_ch_layout, 0);
|
||||
av_opt_set_int(swr_ctx, "out_sample_rate", dst_rate, 0);
|
||||
av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", dst_sample_fmt, 0);
|
||||
|
||||
// <20><>ʼ<EFBFBD><CABC><EFBFBD>ز<EFBFBD><D8B2><EFBFBD>
|
||||
/* initialize the resampling context */
|
||||
if ((ret = swr_init(swr_ctx)) < 0) {
|
||||
fprintf(stderr, "Failed to initialize the resampling context\n");
|
||||
@@ -650,9 +417,8 @@ int initResampler() {
|
||||
}
|
||||
|
||||
/* allocate source and destination samples buffers */
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><D4B4>ͨ<EFBFBD><CDA8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
src_nb_channels = av_get_channel_layout_nb_channels(src_ch_layout);
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><D4B4><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD><DAB4>ռ<EFBFBD>
|
||||
|
||||
ret = av_samples_alloc_array_and_samples(&src_data, &src_linesize,
|
||||
src_nb_channels, src_nb_samples,
|
||||
src_sample_fmt, 0);
|
||||
@@ -661,13 +427,12 @@ int initResampler() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
max_dst_nb_samples = dst_nb_samples =
|
||||
av_rescale_rnd(src_nb_samples, dst_rate, src_rate, AV_ROUND_UP);
|
||||
|
||||
/* buffer is going to be directly written to a rawaudio file, no alignment */
|
||||
dst_nb_channels = av_get_channel_layout_nb_channels(dst_ch_layout);
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>
|
||||
|
||||
ret = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize,
|
||||
dst_nb_channels, dst_nb_samples,
|
||||
dst_sample_fmt, 0);
|
||||
@@ -677,110 +442,6 @@ int initResampler() {
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetMac(char *mac_addr) {
|
||||
int len = 0;
|
||||
#ifdef _WIN32
|
||||
IP_ADAPTER_INFO adapterInfo[16];
|
||||
DWORD bufferSize = sizeof(adapterInfo);
|
||||
|
||||
DWORD result = GetAdaptersInfo(adapterInfo, &bufferSize);
|
||||
if (result == ERROR_SUCCESS) {
|
||||
PIP_ADAPTER_INFO adapter = adapterInfo;
|
||||
while (adapter) {
|
||||
for (UINT i = 0; i < adapter->AddressLength; i++) {
|
||||
len += sprintf(mac_addr + len, "%.2X", adapter->Address[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
#elif __APPLE__
|
||||
std::string if_name = "en0";
|
||||
|
||||
struct ifaddrs *addrs;
|
||||
struct ifaddrs *cursor;
|
||||
const struct sockaddr_dl *dlAddr;
|
||||
|
||||
if (!getifaddrs(&addrs)) {
|
||||
cursor = addrs;
|
||||
while (cursor != 0) {
|
||||
const struct sockaddr_dl *socAddr =
|
||||
(const struct sockaddr_dl *)cursor->ifa_addr;
|
||||
if ((cursor->ifa_addr->sa_family == AF_LINK) &&
|
||||
(socAddr->sdl_type == IFT_ETHER) &&
|
||||
strcmp(if_name.c_str(), cursor->ifa_name) == 0) {
|
||||
dlAddr = (const struct sockaddr_dl *)cursor->ifa_addr;
|
||||
const unsigned char *base =
|
||||
(const unsigned char *)&dlAddr->sdl_data[dlAddr->sdl_nlen];
|
||||
for (int i = 0; i < dlAddr->sdl_alen; i++) {
|
||||
len += sprintf(mac_addr + len, "%.2X", base[i]);
|
||||
}
|
||||
}
|
||||
cursor = cursor->ifa_next;
|
||||
}
|
||||
freeifaddrs(addrs);
|
||||
}
|
||||
#elif __linux__
|
||||
int sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock < 0) {
|
||||
return "";
|
||||
}
|
||||
struct ifreq ifr;
|
||||
struct ifconf ifc;
|
||||
char buf[1024];
|
||||
ifc.ifc_len = sizeof(buf);
|
||||
ifc.ifc_buf = buf;
|
||||
if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
|
||||
close(sock);
|
||||
return "";
|
||||
}
|
||||
struct ifreq *it = ifc.ifc_req;
|
||||
const struct ifreq *const end = it + (ifc.ifc_len / sizeof(struct ifreq));
|
||||
for (; it != end; ++it) {
|
||||
std::strcpy(ifr.ifr_name, it->ifr_name);
|
||||
if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
|
||||
continue;
|
||||
}
|
||||
if (ifr.ifr_flags & IFF_LOOPBACK) {
|
||||
continue;
|
||||
}
|
||||
if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {
|
||||
continue;
|
||||
}
|
||||
std::string mac_address;
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
len += sprintf(mac_addr + len, "%.2X", ifr.ifr_hwaddr.sa_data[i] & 0xff);
|
||||
}
|
||||
break;
|
||||
}
|
||||
close(sock);
|
||||
#endif
|
||||
return mac_addr;
|
||||
}
|
||||
|
||||
int BGRAToNV12FFmpeg(unsigned char *src_buffer, int width, int height,
|
||||
unsigned char *dst_buffer) {
|
||||
AVFrame *Input_pFrame = av_frame_alloc();
|
||||
AVFrame *Output_pFrame = av_frame_alloc();
|
||||
struct SwsContext *img_convert_ctx =
|
||||
sws_getContext(width, height, AV_PIX_FMT_BGRA, 1280, 720, AV_PIX_FMT_NV12,
|
||||
SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
|
||||
|
||||
av_image_fill_arrays(Input_pFrame->data, Input_pFrame->linesize, src_buffer,
|
||||
AV_PIX_FMT_BGRA, width, height, 1);
|
||||
av_image_fill_arrays(Output_pFrame->data, Output_pFrame->linesize, dst_buffer,
|
||||
AV_PIX_FMT_NV12, 1280, 720, 1);
|
||||
|
||||
sws_scale(img_convert_ctx, (uint8_t const **)Input_pFrame->data,
|
||||
Input_pFrame->linesize, 0, height, Output_pFrame->data,
|
||||
Output_pFrame->linesize);
|
||||
|
||||
if (Input_pFrame) av_free(Input_pFrame);
|
||||
if (Output_pFrame) av_free(Output_pFrame);
|
||||
if (img_convert_ctx) sws_freeContext(img_convert_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
LOG_INFO("Remote desk");
|
||||
|
||||
@@ -799,141 +460,6 @@ int main() {
|
||||
strncpy(input_password, cd_cache.password, sizeof(cd_cache.password));
|
||||
}
|
||||
|
||||
std::thread rtc_thread([] {
|
||||
std::string default_cfg_path = "../../../../config/config.ini";
|
||||
std::ifstream f(default_cfg_path.c_str());
|
||||
|
||||
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";
|
||||
GetMac(mac_addr);
|
||||
|
||||
peer_server = CreatePeer(&server_params);
|
||||
LOG_INFO("Create peer_server");
|
||||
std::string server_user_id = "S-" + std::string(GetMac(mac_addr));
|
||||
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-" + std::string(GetMac(mac_addr));
|
||||
Init(peer_client, client_user_id.c_str());
|
||||
LOG_INFO("peer_client init finish");
|
||||
|
||||
{
|
||||
while (SignalStatus::SignalConnected != server_signal_status && !done) {
|
||||
}
|
||||
|
||||
if (done) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string user_id = "S-" + std::string(GetMac(mac_addr));
|
||||
is_create_connection =
|
||||
CreateConnection(peer_server, mac_addr, input_password) ? false
|
||||
: true;
|
||||
|
||||
nv12_buffer = new char[NV12_BUFFER_SIZE];
|
||||
#ifdef _WIN32
|
||||
screen_capture = new ScreenCaptureWgc();
|
||||
|
||||
RECORD_DESKTOP_RECT rect;
|
||||
rect.left = 0;
|
||||
rect.top = 0;
|
||||
rect.right = GetSystemMetrics(SM_CXSCREEN);
|
||||
rect.bottom = GetSystemMetrics(SM_CYSCREEN);
|
||||
|
||||
last_frame_time_ = std::chrono::high_resolution_clock::now();
|
||||
screen_capture->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) {
|
||||
BGRAToNV12FFmpeg(data, width, height,
|
||||
(unsigned char *)nv12_buffer);
|
||||
SendData(peer_server, DATA_TYPE::VIDEO, (const char *)nv12_buffer,
|
||||
NV12_BUFFER_SIZE);
|
||||
// std::cout << "Send" << std::endl;
|
||||
last_frame_time_ = now_time;
|
||||
}
|
||||
});
|
||||
|
||||
screen_capture->Start();
|
||||
|
||||
#elif __linux__
|
||||
screen_capture = new ScreenCaptureX11();
|
||||
|
||||
RECORD_DESKTOP_RECT rect;
|
||||
rect.left = 0;
|
||||
rect.top = 0;
|
||||
rect.right = 0;
|
||||
rect.bottom = 0;
|
||||
|
||||
last_frame_time_ = std::chrono::high_resolution_clock::now();
|
||||
screen_capture->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;
|
||||
}
|
||||
});
|
||||
screen_capture->Start();
|
||||
#elif __APPLE__
|
||||
screen_capture = new ScreenCaptureAvf();
|
||||
|
||||
RECORD_DESKTOP_RECT rect;
|
||||
rect.left = 0;
|
||||
rect.top = 0;
|
||||
rect.right = 0;
|
||||
rect.bottom = 0;
|
||||
|
||||
last_frame_time_ = std::chrono::high_resolution_clock::now();
|
||||
screen_capture->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;
|
||||
}
|
||||
});
|
||||
screen_capture->Start();
|
||||
#endif
|
||||
}
|
||||
});
|
||||
|
||||
// Setup SDL
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER |
|
||||
SDL_INIT_GAMECONTROLLER) != 0) {
|
||||
@@ -1026,6 +552,104 @@ int main() {
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
});
|
||||
|
||||
screen_capturer->Start();
|
||||
|
||||
// Mouse control
|
||||
device_controller_factory = new DeviceControllerFactory();
|
||||
mouse_controller =
|
||||
(MouseController *)device_controller_factory->Create(
|
||||
DeviceControllerFactory::Device::Mouse);
|
||||
mouse_controller->Init(screen_w, screen_h);
|
||||
}
|
||||
},
|
||||
screen_w, screen_h);
|
||||
|
||||
// Main loop
|
||||
while (!done) {
|
||||
// Start the Dear ImGui frame
|
||||
@@ -1033,6 +657,10 @@ int main() {
|
||||
ImGui_ImplSDL2_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
if (joined && !menu_hovered) {
|
||||
ImGui::SetMouseCursor(ImGuiMouseCursor_None);
|
||||
}
|
||||
|
||||
{
|
||||
static float f = 0.0f;
|
||||
static int counter = 0;
|
||||
@@ -1044,11 +672,14 @@ int main() {
|
||||
ImGui::Begin("Menu", nullptr, ImGuiWindowFlags_NoResize);
|
||||
|
||||
{
|
||||
menu_hovered = ImGui::IsWindowHovered();
|
||||
ImGui::Text(" LOCAL ID:");
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(95);
|
||||
ImGui::InputText("##local_id", mac_addr, IM_ARRAYSIZE(mac_addr),
|
||||
ImGuiInputTextFlags_CharsUppercase);
|
||||
ImGui::InputText(
|
||||
"##local_id", (char *)mac_addr_str.c_str(),
|
||||
mac_addr_str.length() + 1,
|
||||
ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_ReadOnly);
|
||||
|
||||
ImGui::Text(" PASSWORD:");
|
||||
ImGui::SameLine();
|
||||
@@ -1070,7 +701,7 @@ int main() {
|
||||
fclose(cd_cache_file);
|
||||
}
|
||||
LeaveConnection(peer_server);
|
||||
CreateConnection(peer_server, mac_addr, input_password);
|
||||
CreateConnection(peer_server, mac_addr_str.c_str(), input_password);
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
@@ -1081,15 +712,13 @@ int main() {
|
||||
{
|
||||
{
|
||||
static char remote_id[20] = "";
|
||||
// if (strcmp(remote_id, "") == 0) {
|
||||
// strcpy(remote_id, GetMac(mac_addr).c_str());
|
||||
// }
|
||||
ImGui::Text("REMOTE ID:");
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(95);
|
||||
ImGui::InputTextWithHint("##remote_id", mac_addr, remote_id,
|
||||
IM_ARRAYSIZE(remote_id),
|
||||
ImGuiInputTextFlags_CharsNoBlank);
|
||||
ImGui::InputTextWithHint("##remote_id", mac_addr_str.c_str(),
|
||||
remote_id, IM_ARRAYSIZE(remote_id),
|
||||
ImGuiInputTextFlags_CharsUppercase |
|
||||
ImGuiInputTextFlags_CharsNoBlank);
|
||||
|
||||
ImGui::Spacing();
|
||||
|
||||
@@ -1106,10 +735,10 @@ int main() {
|
||||
int ret = -1;
|
||||
if ("ClientSignalConnected" == client_signal_status_str) {
|
||||
if (strcmp(connect_label, "Connect") == 0 && !joined) {
|
||||
std::string user_id = "C-" + std::string(GetMac(mac_addr));
|
||||
std::string user_id = "C-" + mac_addr_str;
|
||||
ret = JoinConnection(peer_client, remote_id, client_password);
|
||||
if (0 == ret) {
|
||||
joined = true;
|
||||
// joined = true;
|
||||
}
|
||||
} else if (strcmp(connect_label, "Disconnect") == 0 && joined) {
|
||||
ret = LeaveConnection(peer_client);
|
||||
@@ -1227,6 +856,8 @@ int main() {
|
||||
SDL_CloseAudioDevice(output_dev);
|
||||
SDL_CloseAudioDevice(input_dev);
|
||||
|
||||
mouse_controller->Destroy();
|
||||
|
||||
ImGui_ImplSDLRenderer2_Shutdown();
|
||||
ImGui_ImplSDL2_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "screen_capture_x11.h"
|
||||
#include "screen_capturer_x11.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
@@ -7,20 +7,18 @@
|
||||
#define NV12_BUFFER_SIZE 1280 * 720 * 3 / 2
|
||||
unsigned char nv12_buffer_[NV12_BUFFER_SIZE];
|
||||
|
||||
ScreenCaptureX11::ScreenCaptureX11() {}
|
||||
ScreenCapturerX11::ScreenCapturerX11() {}
|
||||
|
||||
ScreenCaptureX11::~ScreenCaptureX11() {
|
||||
if (capture_thread_->joinable()) {
|
||||
capture_thread_->join();
|
||||
}
|
||||
}
|
||||
ScreenCapturerX11::~ScreenCapturerX11() {}
|
||||
|
||||
int ScreenCaptureX11::Init(const RECORD_DESKTOP_RECT &rect, const int fps,
|
||||
cb_desktop_data cb) {
|
||||
int ScreenCapturerX11::Init(const RECORD_DESKTOP_RECT &rect, const int fps,
|
||||
cb_desktop_data cb) {
|
||||
if (cb) {
|
||||
_on_data = cb;
|
||||
}
|
||||
|
||||
fps_ = fps;
|
||||
|
||||
av_log_set_level(AV_LOG_QUIET);
|
||||
|
||||
pFormatCtx_ = avformat_alloc_context();
|
||||
@@ -33,9 +31,10 @@ int ScreenCaptureX11::Init(const RECORD_DESKTOP_RECT &rect, const int fps,
|
||||
// av_dict_set(&options_, "follow_mouse", "centered", 0);
|
||||
// Video frame size. The default is to capture the full screen
|
||||
// av_dict_set(&options_, "video_size", "1280x720", 0);
|
||||
ifmt_ = (AVInputFormat *)av_find_input_format("x11grab");
|
||||
std::string capture_method = "x11grab";
|
||||
ifmt_ = (AVInputFormat *)av_find_input_format(capture_method.c_str());
|
||||
if (!ifmt_) {
|
||||
printf("Couldn't find_input_format\n");
|
||||
LOG_ERROR("Couldn't find_input_format [{}]", capture_method.c_str());
|
||||
}
|
||||
|
||||
// Grab at position 10,20
|
||||
@@ -95,7 +94,15 @@ int ScreenCaptureX11::Init(const RECORD_DESKTOP_RECT &rect, const int fps,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ScreenCaptureX11::Start() {
|
||||
int ScreenCapturerX11::Destroy() {
|
||||
if (capture_thread_->joinable()) {
|
||||
capture_thread_->join();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ScreenCapturerX11::Start() {
|
||||
capture_thread_.reset(new std::thread([this]() {
|
||||
while (1) {
|
||||
if (av_read_frame(pFormatCtx_, packet_) >= 0) {
|
||||
@@ -125,12 +132,12 @@ int ScreenCaptureX11::Start() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ScreenCaptureX11::Pause() { return 0; }
|
||||
int ScreenCapturerX11::Pause() { return 0; }
|
||||
|
||||
int ScreenCaptureX11::Resume() { return 0; }
|
||||
int ScreenCapturerX11::Resume() { return 0; }
|
||||
|
||||
int ScreenCaptureX11::Stop() { return 0; }
|
||||
int ScreenCapturerX11::Stop() { return 0; }
|
||||
|
||||
void ScreenCaptureX11::OnFrame() {}
|
||||
void ScreenCapturerX11::OnFrame() {}
|
||||
|
||||
void ScreenCaptureX11::CleanUp() {}
|
||||
void ScreenCapturerX11::CleanUp() {}
|
||||
@@ -1,11 +1,12 @@
|
||||
#ifndef _SCREEN_CAPTURE_X11_H_
|
||||
#define _SCREEN_CAPTURE_X11_H_
|
||||
#ifndef _SCREEN_CAPTURER_X11_H_
|
||||
#define _SCREEN_CAPTURER_X11_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include "screen_capturer.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -18,25 +19,19 @@ extern "C" {
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int left;
|
||||
int top;
|
||||
int right;
|
||||
int bottom;
|
||||
} RECORD_DESKTOP_RECT;
|
||||
|
||||
typedef std::function<void(unsigned char *, int, int, int)> cb_desktop_data;
|
||||
typedef std::function<void(int)> cb_desktop_error;
|
||||
|
||||
class ScreenCaptureX11 {
|
||||
class ScreenCapturerX11 : public ScreenCapturer {
|
||||
public:
|
||||
ScreenCaptureX11();
|
||||
~ScreenCaptureX11();
|
||||
ScreenCapturerX11();
|
||||
~ScreenCapturerX11();
|
||||
|
||||
public:
|
||||
int Init(const RECORD_DESKTOP_RECT &rect, const int fps, cb_desktop_data cb);
|
||||
virtual int Init(const RECORD_DESKTOP_RECT &rect, const int fps,
|
||||
cb_desktop_data cb);
|
||||
|
||||
virtual int Destroy();
|
||||
|
||||
virtual int Start();
|
||||
|
||||
int Start();
|
||||
int Pause();
|
||||
int Resume();
|
||||
int Stop();
|
||||
@@ -60,12 +55,12 @@ class ScreenCaptureX11 {
|
||||
int _fps;
|
||||
|
||||
cb_desktop_data _on_data;
|
||||
cb_desktop_error _on_error;
|
||||
|
||||
private:
|
||||
int i_ = 0;
|
||||
int videoindex_ = 0;
|
||||
int got_picture_ = 0;
|
||||
int fps_ = 0;
|
||||
// ffmpeg
|
||||
AVFormatContext *pFormatCtx_ = nullptr;
|
||||
AVCodecContext *pCodecCtx_ = nullptr;
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "screen_capture_avf.h"
|
||||
#include "screen_capturer_avf.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
@@ -7,16 +7,12 @@
|
||||
#define NV12_BUFFER_SIZE 1280 * 720 * 3 / 2
|
||||
unsigned char nv12_buffer_[NV12_BUFFER_SIZE];
|
||||
|
||||
ScreenCaptureAvf::ScreenCaptureAvf() {}
|
||||
ScreenCapturerAvf::ScreenCapturerAvf() {}
|
||||
|
||||
ScreenCaptureAvf::~ScreenCaptureAvf() {
|
||||
if (capture_thread_->joinable()) {
|
||||
capture_thread_->join();
|
||||
}
|
||||
}
|
||||
ScreenCapturerAvf::~ScreenCapturerAvf() {}
|
||||
|
||||
int ScreenCaptureAvf::Init(const RECORD_DESKTOP_RECT &rect, const int fps,
|
||||
cb_desktop_data cb) {
|
||||
int ScreenCapturerAvf::Init(const RECORD_DESKTOP_RECT &rect, const int fps,
|
||||
cb_desktop_data cb) {
|
||||
if (cb) {
|
||||
_on_data = cb;
|
||||
}
|
||||
@@ -99,7 +95,15 @@ int ScreenCaptureAvf::Init(const RECORD_DESKTOP_RECT &rect, const int fps,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ScreenCaptureAvf::Start() {
|
||||
int ScreenCapturerAvf::Destroy() {
|
||||
if (capture_thread_->joinable()) {
|
||||
capture_thread_->join();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ScreenCapturerAvf::Start() {
|
||||
capture_thread_.reset(new std::thread([this]() {
|
||||
while (1) {
|
||||
if (av_read_frame(pFormatCtx_, packet_) >= 0) {
|
||||
@@ -129,12 +133,12 @@ int ScreenCaptureAvf::Start() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ScreenCaptureAvf::Pause() { return 0; }
|
||||
int ScreenCapturerAvf::Pause() { return 0; }
|
||||
|
||||
int ScreenCaptureAvf::Resume() { return 0; }
|
||||
int ScreenCapturerAvf::Resume() { return 0; }
|
||||
|
||||
int ScreenCaptureAvf::Stop() { return 0; }
|
||||
int ScreenCapturerAvf::Stop() { return 0; }
|
||||
|
||||
void ScreenCaptureAvf::OnFrame() {}
|
||||
void ScreenCapturerAvf::OnFrame() {}
|
||||
|
||||
void ScreenCaptureAvf::CleanUp() {}
|
||||
void ScreenCapturerAvf::CleanUp() {}
|
||||
@@ -4,14 +4,16 @@
|
||||
* Copyright (c) 2023 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _SCREEN_CAPTURE_AVF_H_
|
||||
#define _SCREEN_CAPTURE_AVF_H_
|
||||
#ifndef _SCREEN_CAPTURER_AVF_H_
|
||||
#define _SCREEN_CAPTURER_AVF_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include "screen_capturer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -24,25 +26,18 @@ extern "C" {
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int left;
|
||||
int top;
|
||||
int right;
|
||||
int bottom;
|
||||
} RECORD_DESKTOP_RECT;
|
||||
|
||||
typedef std::function<void(unsigned char *, int, int, int)> cb_desktop_data;
|
||||
typedef std::function<void(int)> cb_desktop_error;
|
||||
|
||||
class ScreenCaptureAvf {
|
||||
class ScreenCapturerAvf : public ScreenCapturer {
|
||||
public:
|
||||
ScreenCaptureAvf();
|
||||
~ScreenCaptureAvf();
|
||||
ScreenCapturerAvf();
|
||||
~ScreenCapturerAvf();
|
||||
|
||||
public:
|
||||
int Init(const RECORD_DESKTOP_RECT &rect, const int fps, cb_desktop_data cb);
|
||||
virtual int Init(const RECORD_DESKTOP_RECT &rect, const int fps,
|
||||
cb_desktop_data cb);
|
||||
virtual int Destroy();
|
||||
|
||||
virtual int Start();
|
||||
|
||||
int Start();
|
||||
int Pause();
|
||||
int Resume();
|
||||
int Stop();
|
||||
@@ -66,7 +61,6 @@ class ScreenCaptureAvf {
|
||||
int _fps;
|
||||
|
||||
cb_desktop_data _on_data;
|
||||
cb_desktop_error _on_error;
|
||||
|
||||
private:
|
||||
int i_ = 0;
|
||||
33
src/screen_capturer/screen_capturer.h
Normal file
33
src/screen_capturer/screen_capturer.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2023-12-15
|
||||
* Copyright (c) 2023 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _SCREEN_CAPTURER_H_
|
||||
#define _SCREEN_CAPTURER_H_
|
||||
|
||||
#include <functional>
|
||||
|
||||
class ScreenCapturer {
|
||||
public:
|
||||
typedef struct {
|
||||
int left;
|
||||
int top;
|
||||
int right;
|
||||
int bottom;
|
||||
} RECORD_DESKTOP_RECT;
|
||||
typedef std::function<void(unsigned char *, int, int, int)> cb_desktop_data;
|
||||
|
||||
public:
|
||||
virtual ~ScreenCapturer() {}
|
||||
|
||||
public:
|
||||
virtual int Init(const RECORD_DESKTOP_RECT &rect, const int fps,
|
||||
cb_desktop_data cb) = 0;
|
||||
virtual int Destroy() = 0;
|
||||
|
||||
virtual int Start() = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
37
src/screen_capturer/screen_capturer_factory.h
Normal file
37
src/screen_capturer/screen_capturer_factory.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2023-12-15
|
||||
* Copyright (c) 2023 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _SCREEN_CAPTURER_FACTORY_H_
|
||||
#define _SCREEN_CAPTURER_FACTORY_H_
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "screen_capturer_wgc.h"
|
||||
#elif __linux__
|
||||
#include "screen_capturer_x11.h"
|
||||
#elif __APPLE__
|
||||
#include "screen_capturer_avf.h"
|
||||
#endif
|
||||
|
||||
class ScreenCapturerFactory {
|
||||
public:
|
||||
virtual ~ScreenCapturerFactory() {}
|
||||
|
||||
public:
|
||||
ScreenCapturer* Create() {
|
||||
#ifdef _WIN32
|
||||
return new ScreenCapturerWgc();
|
||||
#elif __linux__
|
||||
return new ScreenCapturerX11();
|
||||
#elif __APPLE__
|
||||
return new ScreenCapturerAvf();
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,12 +1,41 @@
|
||||
#include "screen_capture_wgc.h"
|
||||
#include "screen_capturer_wgc.h"
|
||||
|
||||
#include <Windows.h>
|
||||
#include <d3d11_4.h>
|
||||
#include <winrt/Windows.Foundation.Metadata.h>
|
||||
#include <winrt/Windows.Graphics.Capture.h>
|
||||
|
||||
extern "C" {
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libswscale/swscale.h>
|
||||
};
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int BGRAToNV12FFmpeg(unsigned char *src_buffer, int width, int height,
|
||||
unsigned char *dst_buffer) {
|
||||
AVFrame *Input_pFrame = av_frame_alloc();
|
||||
AVFrame *Output_pFrame = av_frame_alloc();
|
||||
struct SwsContext *img_convert_ctx =
|
||||
sws_getContext(width, height, AV_PIX_FMT_BGRA, 1280, 720, AV_PIX_FMT_NV12,
|
||||
SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
|
||||
|
||||
av_image_fill_arrays(Input_pFrame->data, Input_pFrame->linesize, src_buffer,
|
||||
AV_PIX_FMT_BGRA, width, height, 1);
|
||||
av_image_fill_arrays(Output_pFrame->data, Output_pFrame->linesize, dst_buffer,
|
||||
AV_PIX_FMT_NV12, 1280, 720, 1);
|
||||
|
||||
sws_scale(img_convert_ctx, (uint8_t const **)Input_pFrame->data,
|
||||
Input_pFrame->linesize, 0, height, Output_pFrame->data,
|
||||
Output_pFrame->linesize);
|
||||
|
||||
if (Input_pFrame) av_free(Input_pFrame);
|
||||
if (Output_pFrame) av_free(Output_pFrame);
|
||||
if (img_convert_ctx) sws_freeContext(img_convert_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL WINAPI EnumMonitorProc(HMONITOR hmonitor, HDC hdc, LPRECT lprc,
|
||||
LPARAM data) {
|
||||
MONITORINFOEX info_ex;
|
||||
@@ -31,14 +60,11 @@ HMONITOR GetPrimaryMonitor() {
|
||||
return hmonitor;
|
||||
}
|
||||
|
||||
ScreenCaptureWgc::ScreenCaptureWgc() {}
|
||||
ScreenCapturerWgc::ScreenCapturerWgc() {}
|
||||
|
||||
ScreenCaptureWgc::~ScreenCaptureWgc() {
|
||||
Stop();
|
||||
CleanUp();
|
||||
}
|
||||
ScreenCapturerWgc::~ScreenCapturerWgc() {}
|
||||
|
||||
bool ScreenCaptureWgc::IsWgcSupported() {
|
||||
bool ScreenCapturerWgc::IsWgcSupported() {
|
||||
try {
|
||||
/* no contract for IGraphicsCaptureItemInterop, verify 10.0.18362.0 */
|
||||
return winrt::Windows::Foundation::Metadata::ApiInformation::
|
||||
@@ -50,11 +76,13 @@ bool ScreenCaptureWgc::IsWgcSupported() {
|
||||
}
|
||||
}
|
||||
|
||||
int ScreenCaptureWgc::Init(const RECORD_DESKTOP_RECT &rect, const int fps,
|
||||
cb_desktop_data cb) {
|
||||
int ScreenCapturerWgc::Init(const RECORD_DESKTOP_RECT &rect, const int fps,
|
||||
cb_desktop_data cb) {
|
||||
int error = 0;
|
||||
if (_inited == true) return error;
|
||||
|
||||
nv12_frame_ = new unsigned char[rect.right * rect.bottom * 4];
|
||||
|
||||
_fps = fps;
|
||||
|
||||
_on_data = cb;
|
||||
@@ -86,7 +114,19 @@ int ScreenCaptureWgc::Init(const RECORD_DESKTOP_RECT &rect, const int fps,
|
||||
return error;
|
||||
}
|
||||
|
||||
int ScreenCaptureWgc::Start() {
|
||||
int ScreenCapturerWgc::Destroy() {
|
||||
if (nv12_frame_) {
|
||||
delete nv12_frame_;
|
||||
nv12_frame_ = nullptr;
|
||||
}
|
||||
|
||||
Stop();
|
||||
CleanUp();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ScreenCapturerWgc::Start() {
|
||||
if (_running == true) {
|
||||
std::cout << "record desktop duplication is already running" << std::endl;
|
||||
return 0;
|
||||
@@ -103,19 +143,19 @@ int ScreenCaptureWgc::Start() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ScreenCaptureWgc::Pause() {
|
||||
int ScreenCapturerWgc::Pause() {
|
||||
_paused = true;
|
||||
if (session_) session_->Pause();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ScreenCaptureWgc::Resume() {
|
||||
int ScreenCapturerWgc::Resume() {
|
||||
_paused = false;
|
||||
if (session_) session_->Resume();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ScreenCaptureWgc::Stop() {
|
||||
int ScreenCapturerWgc::Stop() {
|
||||
_running = false;
|
||||
|
||||
if (session_) session_->Stop();
|
||||
@@ -123,13 +163,15 @@ int ScreenCaptureWgc::Stop() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ScreenCaptureWgc::OnFrame(const WgcSession::wgc_session_frame &frame) {
|
||||
void ScreenCapturerWgc::OnFrame(const WgcSession::wgc_session_frame &frame) {
|
||||
if (_on_data)
|
||||
_on_data((unsigned char *)frame.data, frame.width * frame.height * 4,
|
||||
frame.width, frame.height);
|
||||
BGRAToNV12FFmpeg((unsigned char *)frame.data, frame.width, frame.height,
|
||||
nv12_frame_);
|
||||
_on_data(nv12_frame_, frame.width * frame.height * 4, frame.width,
|
||||
frame.height);
|
||||
}
|
||||
|
||||
void ScreenCaptureWgc::CleanUp() {
|
||||
void ScreenCapturerWgc::CleanUp() {
|
||||
_inited = false;
|
||||
|
||||
if (session_) session_->Release();
|
||||
@@ -1,35 +1,30 @@
|
||||
#ifndef _SCREEN_CAPTURE_WGC_H_
|
||||
#define _SCREEN_CAPTURE_WGC_H_
|
||||
#ifndef _SCREEN_CAPTURER_WGC_H_
|
||||
#define _SCREEN_CAPTURER_WGC_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include "screen_capturer.h"
|
||||
#include "wgc_session.h"
|
||||
#include "wgc_session_impl.h"
|
||||
|
||||
typedef struct {
|
||||
int left;
|
||||
int top;
|
||||
int right;
|
||||
int bottom;
|
||||
} RECORD_DESKTOP_RECT;
|
||||
|
||||
typedef std::function<void(unsigned char *, int, int, int)> cb_desktop_data;
|
||||
typedef std::function<void(int)> cb_desktop_error;
|
||||
|
||||
class ScreenCaptureWgc : public WgcSession::wgc_session_observer {
|
||||
class ScreenCapturerWgc : public ScreenCapturer,
|
||||
public WgcSession::wgc_session_observer {
|
||||
public:
|
||||
ScreenCaptureWgc();
|
||||
~ScreenCaptureWgc();
|
||||
ScreenCapturerWgc();
|
||||
~ScreenCapturerWgc();
|
||||
|
||||
public:
|
||||
bool IsWgcSupported();
|
||||
|
||||
int Init(const RECORD_DESKTOP_RECT &rect, const int fps, cb_desktop_data cb);
|
||||
virtual int Init(const RECORD_DESKTOP_RECT &rect, const int fps,
|
||||
cb_desktop_data cb);
|
||||
virtual int Destroy();
|
||||
|
||||
virtual int Start();
|
||||
|
||||
int Start();
|
||||
int Pause();
|
||||
int Resume();
|
||||
int Stop();
|
||||
@@ -55,7 +50,8 @@ class ScreenCaptureWgc : public WgcSession::wgc_session_observer {
|
||||
int _fps;
|
||||
|
||||
cb_desktop_data _on_data;
|
||||
cb_desktop_error _on_error;
|
||||
|
||||
unsigned char *nv12_frame_ = nullptr;
|
||||
};
|
||||
|
||||
#endif
|
||||
150
test/linux_mouse_control/mouse_control.cpp
Normal file
150
test/linux_mouse_control/mouse_control.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
#include <X11/Xlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/uinput.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int fd;
|
||||
Display *dpy;
|
||||
|
||||
void initMouse();
|
||||
void destroyMouse();
|
||||
void mouseLeftClick();
|
||||
void mouseRightClick();
|
||||
void mouseGetPosition(int &x, int &y);
|
||||
void mouseMove(int xdelta, int ydelta);
|
||||
|
||||
void initMouse() {
|
||||
fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
|
||||
ioctl(fd, UI_SET_EVBIT, EV_KEY);
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_RIGHT);
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_LEFT);
|
||||
ioctl(fd, UI_SET_EVBIT, EV_ABS);
|
||||
ioctl(fd, UI_SET_ABSBIT, ABS_X);
|
||||
ioctl(fd, UI_SET_ABSBIT, ABS_Y);
|
||||
ioctl(fd, UI_SET_EVBIT, EV_REL);
|
||||
|
||||
struct uinput_user_dev uidev;
|
||||
memset(&uidev, 0, sizeof(uidev));
|
||||
snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "VirtualMouse");
|
||||
uidev.id.bustype = BUS_USB;
|
||||
uidev.id.version = 1;
|
||||
uidev.id.vendor = 0x1;
|
||||
uidev.id.product = 0x1;
|
||||
uidev.absmin[ABS_X] = 0;
|
||||
uidev.absmax[ABS_X] = 3200;
|
||||
uidev.absmin[ABS_Y] = 0;
|
||||
uidev.absmax[ABS_Y] = 900;
|
||||
|
||||
write(fd, &uidev, sizeof(uidev));
|
||||
ioctl(fd, UI_DEV_CREATE);
|
||||
|
||||
sleep(2);
|
||||
}
|
||||
|
||||
void mouseLeftClick() {
|
||||
struct input_event ev_click, ev_sync;
|
||||
memset(&ev_click, 0, sizeof(ev_click));
|
||||
memset(&ev_sync, 0, sizeof(ev_sync));
|
||||
|
||||
ev_click.type = EV_KEY;
|
||||
ev_click.code = BTN_LEFT;
|
||||
ev_click.value = 1;
|
||||
|
||||
// write left click event
|
||||
write(fd, &ev_click, sizeof(ev_click));
|
||||
|
||||
// sync left click event
|
||||
ev_sync.type = EV_SYN;
|
||||
write(fd, &ev_sync, sizeof(ev_sync));
|
||||
}
|
||||
|
||||
void mouseRightClick() {
|
||||
struct input_event ev_click, ev_sync;
|
||||
memset(&ev_click, 0, sizeof(ev_click));
|
||||
memset(&ev_sync, 0, sizeof(ev_sync));
|
||||
|
||||
ev_click.type = EV_KEY;
|
||||
ev_click.code = BTN_RIGHT;
|
||||
ev_click.value = 1;
|
||||
|
||||
// write right click event
|
||||
write(fd, &ev_click, sizeof(ev_click));
|
||||
|
||||
// sync right click event
|
||||
ev_sync.type = EV_SYN;
|
||||
write(fd, &ev_sync, sizeof(ev_sync));
|
||||
}
|
||||
|
||||
void mouseSetPosition(int x, int y) {
|
||||
struct input_event ev[2], ev_sync;
|
||||
memset(ev, 0, sizeof(ev));
|
||||
memset(&ev_sync, 0, sizeof(ev_sync));
|
||||
|
||||
ev[0].type = EV_ABS;
|
||||
ev[0].code = ABS_X;
|
||||
ev[0].value = x;
|
||||
ev[1].type = EV_ABS;
|
||||
ev[1].code = ABS_Y;
|
||||
ev[1].value = y;
|
||||
|
||||
int res_w = write(fd, ev, sizeof(ev));
|
||||
|
||||
std::cout << "res w : " << res_w << "\n";
|
||||
|
||||
ev_sync.type = EV_SYN;
|
||||
ev_sync.value = 0;
|
||||
ev_sync.code = 0;
|
||||
int res_ev_sync = write(fd, &ev_sync, sizeof(ev_sync));
|
||||
|
||||
std::cout << "res syn : " << res_ev_sync << "\n";
|
||||
}
|
||||
|
||||
void initDisplay() { dpy = XOpenDisplay(NULL); }
|
||||
|
||||
void destroyMouse() { ioctl(fd, UI_DEV_DESTROY); }
|
||||
|
||||
void mouseMove(int xdelta, int ydelta) {
|
||||
int xx, yy;
|
||||
mouseGetPosition(xx, yy);
|
||||
|
||||
mouseSetPosition(xx + xdelta, yy + ydelta);
|
||||
}
|
||||
|
||||
void mouseGetPosition(int &x, int &y) {
|
||||
Window root, child;
|
||||
int rootX, rootY, winX, winY;
|
||||
unsigned int mask;
|
||||
|
||||
XQueryPointer(dpy, DefaultRootWindow(dpy), &root, &child, &rootX, &rootY,
|
||||
&winX, &winY, &mask);
|
||||
|
||||
std::cout << "root x : " << rootX << "\n";
|
||||
std::cout << "root y : " << rootY << "\n";
|
||||
|
||||
x = rootX;
|
||||
y = rootY;
|
||||
}
|
||||
|
||||
int main() {
|
||||
initMouse();
|
||||
initDisplay();
|
||||
|
||||
int tempx, tempy;
|
||||
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
mouseMove(100, 100);
|
||||
sleep(1);
|
||||
std::cout << "i : " << i << "\n";
|
||||
}
|
||||
|
||||
destroyMouse();
|
||||
return 0;
|
||||
}
|
||||
1
thirdparty/ffmpeg/xmake.lua
vendored
1
thirdparty/ffmpeg/xmake.lua
vendored
@@ -43,6 +43,7 @@ package("ffmpeg")
|
||||
add_configs("hardcoded-tables", {description = "Enable hardcoded tables.", default = true, type = "boolean"})
|
||||
add_configs("asm", {description = "Enable asm", default = false, type = "boolean"})
|
||||
add_configs("libopenh264", {description = "Enable libopenh264", default = false, type = "boolean"})
|
||||
add_configs("libxcb", {description = "Enable libxcb", default = true, type = "boolean"})
|
||||
end
|
||||
|
||||
add_links("avfilter", "avdevice", "avformat", "avcodec", "swscale", "swresample", "avutil", "postproc")
|
||||
|
||||
2
thirdparty/projectx
vendored
2
thirdparty/projectx
vendored
Submodule thirdparty/projectx updated: d4abc318a4...a309627ca3
1
thirdparty/sdl2/xmake.lua
vendored
1
thirdparty/sdl2/xmake.lua
vendored
@@ -2,7 +2,6 @@ package("sdl2")
|
||||
add_urls("https://github.com/libsdl-org/SDL/archive/refs/tags/release-2.28.3.tar.gz", {alias = "github"})
|
||||
add_versions("github:2.28.3", "c17455d6e0c484bfe634b8de6af4c608e86ee449c28e40af04064aa6643fe382")
|
||||
|
||||
add_deps("cmake")
|
||||
on_install(function (package)
|
||||
local configs = {}
|
||||
table.insert(configs, "-DSDL_SHARED_ENABLED_BY_DEFAULT=OFF -DSDL_TEST_ENABLED_BY_DEFAULT=OFF")
|
||||
|
||||
61
xmake.lua
61
xmake.lua
@@ -5,6 +5,9 @@ set_license("LGPL-3.0")
|
||||
add_rules("mode.release", "mode.debug")
|
||||
set_languages("c++17")
|
||||
|
||||
-- set_policy("build.warning", true)
|
||||
-- set_warnings("all", "extra")
|
||||
|
||||
add_defines("UNICODE")
|
||||
if is_mode("debug") then
|
||||
add_defines("REMOTE_DESK_DEBUG")
|
||||
@@ -24,11 +27,12 @@ elseif is_os("linux") then
|
||||
add_requires("ffmpeg 5.1.2", {system = false})
|
||||
add_packages("ffmpeg")
|
||||
add_syslinks("pthread", "dl")
|
||||
add_links("SDL2")
|
||||
add_linkdirs("thirdparty/projectx/thirdparty/nvcodec/Lib/x64")
|
||||
add_links("SDL2", "cuda", "nvidia-encode", "nvcuvid")
|
||||
add_ldflags("-lavformat", "-lavdevice", "-lavfilter", "-lavcodec",
|
||||
"-lswscale", "-lavutil", "-lswresample",
|
||||
"-lasound", "-lxcb-shape", "-lxcb-xfixes", "-lsndio", "-lxcb",
|
||||
"-lxcb-shm", "-lXext", "-lX11", "-lXv", "-ldl", "-lpthread",
|
||||
"-lxcb-shm", "-lXext", "-lX11", "-lXv", "-ldl", "-lpthread",
|
||||
{force = true})
|
||||
elseif is_os("macosx") then
|
||||
add_requires("ffmpeg 5.1.2", {system = false})
|
||||
@@ -49,23 +53,45 @@ target("log")
|
||||
add_headerfiles("src/log/log.h")
|
||||
add_includedirs("src/log", {public = true})
|
||||
|
||||
target("screen_capture")
|
||||
target("common")
|
||||
set_kind("object")
|
||||
add_deps("log")
|
||||
add_files("src/common/*.cpp")
|
||||
add_includedirs("src/common", {public = true})
|
||||
|
||||
target("screen_capturer")
|
||||
set_kind("object")
|
||||
add_deps("log")
|
||||
add_includedirs("src/screen_capturer", {public = true})
|
||||
if is_os("windows") then
|
||||
add_files("src/screen_capture/windows/*.cpp")
|
||||
add_includedirs("src/screen_capture/windows", {public = true})
|
||||
add_files("src/screen_capturer/windows/*.cpp")
|
||||
add_includedirs("src/screen_capturer/windows", {public = true})
|
||||
elseif is_os("macosx") then
|
||||
add_files("src/screen_capture/macosx/*.cpp")
|
||||
add_includedirs("src/screen_capture/macosx", {public = true})
|
||||
add_files("src/screen_capturer/macosx/*.cpp")
|
||||
add_includedirs("src/screen_capturer/macosx", {public = true})
|
||||
elseif is_os("linux") then
|
||||
add_files("src/screen_capture/linux/*.cpp")
|
||||
add_includedirs("src/screen_capture/linux", {public = true})
|
||||
add_files("src/screen_capturer/linux/*.cpp")
|
||||
add_includedirs("src/screen_capturer/linux", {public = true})
|
||||
end
|
||||
|
||||
target("device_controller")
|
||||
set_kind("object")
|
||||
add_deps("log")
|
||||
add_includedirs("src/device_controller", {public = true})
|
||||
if is_os("windows") then
|
||||
add_files("src/device_controller/mouse/windows/*.cpp")
|
||||
add_includedirs("src/device_controller/mouse/windows", {public = true})
|
||||
elseif is_os("macosx") then
|
||||
add_files("src/device_controller/mouse/mac/*.cpp")
|
||||
add_includedirs("src/device_controller/mouse/mac", {public = true})
|
||||
elseif is_os("linux") then
|
||||
add_files("src/device_controller/mouse/linux/*.cpp")
|
||||
add_includedirs("src/device_controller/mouse/linux", {public = true})
|
||||
end
|
||||
|
||||
target("remote_desk")
|
||||
set_kind("binary")
|
||||
add_deps("log", "screen_capture", "projectx")
|
||||
add_deps("log", "common", "screen_capturer", "device_controller", "projectx")
|
||||
add_files("src/gui/main.cpp")
|
||||
|
||||
-- after_install(function (target)
|
||||
@@ -76,20 +102,20 @@ target("remote_desk")
|
||||
-- os.rm("$(projectdir)/out/lib")
|
||||
-- end)
|
||||
|
||||
-- target("screen_capture")
|
||||
-- target("screen_capturer")
|
||||
-- set_kind("binary")
|
||||
-- add_packages("sdl2", "imgui", "ffmpeg", "openh264")
|
||||
-- add_files("test/screen_capture/linux_capture.cpp")
|
||||
-- add_files("test/screen_capturer/linux_capture.cpp")
|
||||
-- add_ldflags("-lavformat", "-lavdevice", "-lavfilter", "-lavcodec",
|
||||
-- "-lswscale", "-lavutil", "-lswresample",
|
||||
-- "-lasound", "-lxcb-shape", "-lxcb-xfixes", "-lsndio", "-lxcb",
|
||||
-- "-lxcb-shm", "-lXext", "-lX11", "-lXv", "-lpthread", "-lSDL2", "-lopenh264",
|
||||
-- "-ldl", {force = true})
|
||||
|
||||
-- target("screen_capture")
|
||||
-- target("screen_capturer")
|
||||
-- set_kind("binary")
|
||||
-- add_packages("sdl2", "imgui", "ffmpeg", "openh264")
|
||||
-- add_files("test/screen_capture/mac_capture.cpp")
|
||||
-- add_files("test/screen_capturer/mac_capture.cpp")
|
||||
-- add_ldflags("-lavformat", "-lavdevice", "-lavfilter", "-lavcodec",
|
||||
-- "-lswscale", "-lavutil", "-lswresample",
|
||||
-- "-lasound", "-lxcb-shape", "-lxcb-xfixes", "-lsndio", "-lxcb",
|
||||
@@ -129,4 +155,9 @@ target("remote_desk")
|
||||
-- "-lswscale", "-lavutil", "-lswresample",
|
||||
-- "-lasound", "-lxcb-shape", "-lxcb-xfixes", "-lsndio", "-lxcb",
|
||||
-- "-lxcb-shm", "-lXext", "-lX11", "-lXv", "-lpthread", "-lSDL2", "-lopenh264",
|
||||
-- "-ldl", {force = true})
|
||||
-- "-ldl", {force = true})
|
||||
|
||||
target("mouse_control")
|
||||
set_kind("binary")
|
||||
add_files("test/linux_mouse_control/mouse_control.cpp")
|
||||
add_includedirs("test/linux_mouse_control")
|
||||
Reference in New Issue
Block a user