@@ -7,6 +7,3 @@
|
|||||||
[submodule "ViGEmClient"]
|
[submodule "ViGEmClient"]
|
||||||
path = ViGEmClient
|
path = ViGEmClient
|
||||||
url = https://github.com/ViGEm/ViGEmClient
|
url = https://github.com/ViGEm/ViGEmClient
|
||||||
[submodule "pre-compiled"]
|
|
||||||
path = pre-compiled
|
|
||||||
url = https://github.com/TheElixZammuto/sunshine-prebuilt.git
|
|
||||||
|
|||||||
+71
-42
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 2.8)
|
cmake_minimum_required(VERSION 3.0)
|
||||||
|
|
||||||
project(Sunshine)
|
project(Sunshine)
|
||||||
|
|
||||||
@@ -7,56 +7,65 @@ set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
|
|||||||
# On MSYS2, building a stand-alone binary that links with ffmpeg is not possible,
|
# On MSYS2, building a stand-alone binary that links with ffmpeg is not possible,
|
||||||
# Therefore, ffmpeg, libx264 and libx265 must be build from source
|
# Therefore, ffmpeg, libx264 and libx265 must be build from source
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
option(SUNSHINE_STANDALONE "Compile stand-alone binary of Sunshine" OFF)
|
file(
|
||||||
if(SUNSHINE_STANDALONE)
|
DOWNLOAD "https://github.com/TheElixZammuto/sunshine-prebuilt/releases/download/1.0.0/pre-compiled.zip" "${CMAKE_CURRENT_BINARY_DIR}/pre-compiled.zip"
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
|
TIMEOUT 60
|
||||||
|
EXPECTED_HASH SHA256=5d59986bd7f619eaaf82b2dd56b5127b747c9cbe8db61e3b898ff6b485298ed6)
|
||||||
|
|
||||||
|
file(ARCHIVE_EXTRACT
|
||||||
|
INPUT "${CMAKE_CURRENT_BINARY_DIR}/pre-compiled.zip"
|
||||||
|
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/pre-compiled)
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
|
||||||
|
|
||||||
if(NOT DEFINED SUNSHINE_PREPARED_BINARIES)
|
if(NOT DEFINED SUNSHINE_PREPARED_BINARIES)
|
||||||
set(SUNSHINE_PREPARED_BINARIES "${CMAKE_CURRENT_SOURCE_DIR}/pre-compiled/windows")
|
set(SUNSHINE_PREPARED_BINARIES "${CMAKE_CURRENT_BINARY_DIR}/pre-compiled/windows")
|
||||||
endif()
|
|
||||||
list(PREPEND PLATFORM_LIBRARIES
|
|
||||||
C:/msys64/mingw64/lib/gcc/x86_64-w64-mingw32/${CMAKE_CXX_COMPILER_VERSION}/libstdc++.a
|
|
||||||
C:/msys64/mingw64/x86_64-w64-mingw32/lib/libwinpthread.a
|
|
||||||
)
|
|
||||||
|
|
||||||
set(FFMPEG_INCLUDE_DIRS
|
|
||||||
${SUNSHINE_PREPARED_BINARIES}/include)
|
|
||||||
set(FFMPEG_LIBRARIES
|
|
||||||
${SUNSHINE_PREPARED_BINARIES}/lib/libavcodec.a
|
|
||||||
${SUNSHINE_PREPARED_BINARIES}/lib/libavdevice.a
|
|
||||||
${SUNSHINE_PREPARED_BINARIES}/lib/libavfilter.a
|
|
||||||
${SUNSHINE_PREPARED_BINARIES}/lib/libavformat.a
|
|
||||||
${SUNSHINE_PREPARED_BINARIES}/lib/libavutil.a
|
|
||||||
${SUNSHINE_PREPARED_BINARIES}/lib/libpostproc.a
|
|
||||||
${SUNSHINE_PREPARED_BINARIES}/lib/libswresample.a
|
|
||||||
${SUNSHINE_PREPARED_BINARIES}/lib/libswscale.a
|
|
||||||
${SUNSHINE_PREPARED_BINARIES}/lib/libx264.a
|
|
||||||
${SUNSHINE_PREPARED_BINARIES}/lib/libx265.a
|
|
||||||
${SUNSHINE_PREPARED_BINARIES}/lib/libhdr10plus.a
|
|
||||||
z lzma bcrypt C:/msys64/mingw64/lib/libiconv.a)
|
|
||||||
endif()
|
endif()
|
||||||
else()
|
|
||||||
set(SUNSHINE_STANDALONE OFF)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
set(FFMPEG_INCLUDE_DIRS
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/include)
|
||||||
|
set(FFMPEG_LIBRARIES
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libavcodec.a
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libavdevice.a
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libavfilter.a
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libavformat.a
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libavutil.a
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libpostproc.a
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libswresample.a
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libswscale.a
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libx264.a
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libx265.a
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libhdr10plus.a
|
||||||
|
z lzma bcrypt libiconv.a)
|
||||||
|
endif()
|
||||||
add_subdirectory(Simple-Web-Server)
|
add_subdirectory(Simple-Web-Server)
|
||||||
add_subdirectory(moonlight-common-c/enet)
|
add_subdirectory(moonlight-common-c/enet)
|
||||||
|
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
find_package(OpenSSL REQUIRED)
|
find_package(OpenSSL REQUIRED)
|
||||||
|
|
||||||
if(NOT SUNSHINE_STANDALONE)
|
|
||||||
find_package(FFmpeg REQUIRED)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
list(APPEND SUNSHINE_COMPILE_OPTIONS -fPIC -Wall -Wno-missing-braces -Wno-maybe-uninitialized -Wno-sign-compare)
|
list(APPEND SUNSHINE_COMPILE_OPTIONS -fPIC -Wall -Wno-missing-braces -Wno-maybe-uninitialized -Wno-sign-compare)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
|
file(
|
||||||
|
DOWNLOAD "https://github.com/TheElixZammuto/sunshine-prebuilt/releases/download/1.0.0/pre-compiled.zip" "${CMAKE_CURRENT_BINARY_DIR}/pre-compiled.zip"
|
||||||
|
TIMEOUT 60
|
||||||
|
EXPECTED_HASH SHA256=5d59986bd7f619eaaf82b2dd56b5127b747c9cbe8db61e3b898ff6b485298ed6)
|
||||||
|
|
||||||
|
file(ARCHIVE_EXTRACT
|
||||||
|
INPUT "${CMAKE_CURRENT_BINARY_DIR}/pre-compiled.zip"
|
||||||
|
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/pre-compiled)
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
|
||||||
|
|
||||||
|
if(NOT DEFINED SUNSHINE_PREPARED_BINARIES)
|
||||||
|
set(SUNSHINE_PREPARED_BINARIES "${CMAKE_CURRENT_BINARY_DIR}/pre-compiled/windows")
|
||||||
|
endif()
|
||||||
|
|
||||||
add_subdirectory(tools) #This is temporary, only tools for Windows are needed, for now
|
add_subdirectory(tools) #This is temporary, only tools for Windows are needed, for now
|
||||||
|
|
||||||
list(APPEND SUNSHINE_DEFINITIONS APPS_JSON="apps_windows.json")
|
list(APPEND SUNSHINE_DEFINITIONS APPS_JSON="apps_windows.json")
|
||||||
include_directories(
|
|
||||||
ViGEmClient/include)
|
include_directories(ViGEmClient/include)
|
||||||
|
|
||||||
set(PLATFORM_TARGET_FILES
|
set(PLATFORM_TARGET_FILES
|
||||||
sunshine/platform/windows/input.cpp
|
sunshine/platform/windows/input.cpp
|
||||||
sunshine/platform/windows/display.h
|
sunshine/platform/windows/display.h
|
||||||
@@ -69,7 +78,31 @@ if(WIN32)
|
|||||||
ViGEmClient/include/ViGEm/Common.h
|
ViGEmClient/include/ViGEm/Common.h
|
||||||
ViGEmClient/include/ViGEm/Util.h
|
ViGEmClient/include/ViGEm/Util.h
|
||||||
ViGEmClient/include/ViGEm/km/BusShared.h)
|
ViGEmClient/include/ViGEm/km/BusShared.h)
|
||||||
|
|
||||||
|
set(OPENSSL_LIBRARIES
|
||||||
|
libssl.a
|
||||||
|
libcrypto.a)
|
||||||
|
|
||||||
|
set(FFMPEG_INCLUDE_DIRS
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/include)
|
||||||
|
set(FFMPEG_LIBRARIES
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libavcodec.a
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libavdevice.a
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libavfilter.a
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libavformat.a
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libavutil.a
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libpostproc.a
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libswresample.a
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libswscale.a
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libx264.a
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libx265.a
|
||||||
|
${SUNSHINE_PREPARED_BINARIES}/lib/libhdr10plus.a
|
||||||
|
z lzma bcrypt libiconv.a)
|
||||||
|
|
||||||
list(PREPEND PLATFORM_LIBRARIES
|
list(PREPEND PLATFORM_LIBRARIES
|
||||||
|
libstdc++.a
|
||||||
|
libwinpthread.a
|
||||||
|
libssp.a
|
||||||
winmm
|
winmm
|
||||||
ksuser
|
ksuser
|
||||||
wsock32
|
wsock32
|
||||||
@@ -85,6 +118,7 @@ else()
|
|||||||
list(APPEND SUNSHINE_DEFINITIONS APPS_JSON="apps_linux.json")
|
list(APPEND SUNSHINE_DEFINITIONS APPS_JSON="apps_linux.json")
|
||||||
|
|
||||||
find_package(X11 REQUIRED)
|
find_package(X11 REQUIRED)
|
||||||
|
find_package(FFmpeg REQUIRED)
|
||||||
set(PLATFORM_TARGET_FILES
|
set(PLATFORM_TARGET_FILES
|
||||||
sunshine/platform/linux/display.cpp
|
sunshine/platform/linux/display.cpp
|
||||||
sunshine/platform/linux/input.cpp)
|
sunshine/platform/linux/input.cpp)
|
||||||
@@ -95,6 +129,7 @@ else()
|
|||||||
xcb
|
xcb
|
||||||
xcb-shm
|
xcb-shm
|
||||||
xcb-xfixes
|
xcb-xfixes
|
||||||
|
Xrandr
|
||||||
${X11_LIBRARIES}
|
${X11_LIBRARIES}
|
||||||
evdev
|
evdev
|
||||||
pulse
|
pulse
|
||||||
@@ -179,12 +214,6 @@ if(NOT SUNSHINE_ASSETS_DIR)
|
|||||||
set(SUNSHINE_ASSETS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/assets")
|
set(SUNSHINE_ASSETS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/assets")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(SUNSHINE_STANDALONE)
|
|
||||||
set(OPENSSL_LIBRARIES
|
|
||||||
C:/msys64/mingw64/lib/libssl.a
|
|
||||||
C:/msys64/mingw64/lib/libcrypto.a)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
list(APPEND SUNSHINE_EXTERNAL_LIBRARIES
|
list(APPEND SUNSHINE_EXTERNAL_LIBRARIES
|
||||||
${CMAKE_THREAD_LIBS_INIT}
|
${CMAKE_THREAD_LIBS_INIT}
|
||||||
stdc++fs
|
stdc++fs
|
||||||
|
|||||||
@@ -50,10 +50,10 @@ sunshine needs access to uinput to create mouse and gamepad events:
|
|||||||
|
|
||||||
### Requirements:
|
### Requirements:
|
||||||
|
|
||||||
MSYS2 : mingw-w64-x86_64-openssl mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain mingw-w64-x86_64-ffmpeg mingw-w64-x86_64-boost
|
mingw-w64-x86_64-openssl mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain mingw-w64-x86_64-opus mingw-w64-x86_64-x265 mingw-w64-x86_64-boost git yasm nasm diffutils make
|
||||||
|
|
||||||
### Compilation:
|
### Compilation:
|
||||||
- `git clone https://github.com/loki-47-6F-64/sunshine.git --recurse-submodules`
|
- `git clone https://github.com/loki-47-6F-64/sunshine.git --recursive`
|
||||||
- `cd sunshine && mkdir build && cd build`
|
- `cd sunshine && mkdir build && cd build`
|
||||||
- `cmake -G"Unix Makefiles" ..`
|
- `cmake -G"Unix Makefiles" ..`
|
||||||
- `make`
|
- `make`
|
||||||
@@ -61,17 +61,6 @@ sunshine needs access to uinput to create mouse and gamepad events:
|
|||||||
### Setup:
|
### Setup:
|
||||||
- **OPTIONAL** Gamepad support: Download and run 'ViGEmBus_Setup_1.16.116.exe' from [https://github.com/ViGEm/ViGEmBus/releases]
|
- **OPTIONAL** Gamepad support: Download and run 'ViGEmBus_Setup_1.16.116.exe' from [https://github.com/ViGEm/ViGEmBus/releases]
|
||||||
|
|
||||||
### Static build
|
|
||||||
#### Requirements:
|
|
||||||
MSYS2 : mingw-w64-x86_64-openssl mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain mingw-w64-x86_64-ffmpeg mingw-w64-x86_64-boost git-lfs
|
|
||||||
|
|
||||||
#### Compilation:
|
|
||||||
- `git lfs install`
|
|
||||||
- `git clone https://github.com/loki-47-6F-64/sunshine.git --recurse-submodules`
|
|
||||||
- `cd sunshine && mkdir build && cd build`
|
|
||||||
- `cmake -DSUNSHINE_STANDALONE=ON -G"Unix Makefiles" ..`
|
|
||||||
- `make`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Common
|
# Common
|
||||||
|
|||||||
+4
-4
@@ -1,5 +1,5 @@
|
|||||||
image:
|
image:
|
||||||
- Ubuntu
|
- Ubuntu2004
|
||||||
- Visual Studio 2019
|
- Visual Studio 2019
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
@@ -8,8 +8,8 @@ environment:
|
|||||||
- BUILD_TYPE: Release
|
- BUILD_TYPE: Release
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- sh: sudo apt update
|
- sh: sudo apt update --ignore-missing
|
||||||
- sh: sudo apt install -y build-essential cmake libssl-dev libavdevice-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libpulse-dev libopus-dev libxtst-dev libx11-dev libxfixes-dev libevdev-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev
|
- sh: sudo apt install -y build-essential cmake libssl-dev libavdevice-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libpulse-dev libopus-dev libxtst-dev libx11-dev libxrandr-dev libxfixes-dev libevdev-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev
|
||||||
- cmd: C:\msys64\usr\bin\bash -lc "pacman --needed --noconfirm -S mingw-w64-x86_64-openssl mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain mingw-w64-x86_64-opus mingw-w64-x86_64-x265 mingw-w64-x86_64-boost git yasm nasm diffutils make"
|
- cmd: C:\msys64\usr\bin\bash -lc "pacman --needed --noconfirm -S mingw-w64-x86_64-openssl mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain mingw-w64-x86_64-opus mingw-w64-x86_64-x265 mingw-w64-x86_64-boost git yasm nasm diffutils make"
|
||||||
|
|
||||||
before_build:
|
before_build:
|
||||||
@@ -21,7 +21,7 @@ build_script:
|
|||||||
- cmd: set OLDPATH=%PATH%
|
- cmd: set OLDPATH=%PATH%
|
||||||
- cmd: set PATH=C:\msys64\mingw64\bin
|
- cmd: set PATH=C:\msys64\mingw64\bin
|
||||||
- sh: cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSUNSHINE_EXECUTABLE_PATH=sunshine -DSUNSHINE_ASSETS_DIR=/etc/sunshine ..
|
- sh: cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSUNSHINE_EXECUTABLE_PATH=sunshine -DSUNSHINE_ASSETS_DIR=/etc/sunshine ..
|
||||||
- cmd: cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSUNSHINE_STANDALONE=ON -DSUNSHINE_ASSETS_DIR=assets -G "MinGW Makefiles" ..
|
- cmd: cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSUNSHINE_ASSETS_DIR=assets -G "MinGW Makefiles" ..
|
||||||
- sh: make -j$(nproc)
|
- sh: make -j$(nproc)
|
||||||
- cmd: mingw32-make -j2
|
- cmd: mingw32-make -j2
|
||||||
- cmd: set PATH=%OLDPATH%
|
- cmd: set PATH=%OLDPATH%
|
||||||
|
|||||||
+30
-2
@@ -93,6 +93,9 @@
|
|||||||
# adapter_name = Radeon RX 580 Series
|
# adapter_name = Radeon RX 580 Series
|
||||||
# output_name = \\.\DISPLAY1
|
# output_name = \\.\DISPLAY1
|
||||||
|
|
||||||
|
# !! Linux only !!
|
||||||
|
# Set the display number to stream. I have no idea how they are numbered. They start from 1, usually.
|
||||||
|
# output_name = 1
|
||||||
|
|
||||||
###############################################
|
###############################################
|
||||||
# FFmpeg software encoding parameters
|
# FFmpeg software encoding parameters
|
||||||
@@ -121,12 +124,12 @@
|
|||||||
# If set to 1, Sunshine will not advertise support for HEVC
|
# If set to 1, Sunshine will not advertise support for HEVC
|
||||||
# If set to 2, Sunshine will advertise support for HEVC Main profile
|
# If set to 2, Sunshine will advertise support for HEVC Main profile
|
||||||
# If set to 3, Sunshine will advertise support for HEVC Main and Main10 (HDR) profiles
|
# If set to 3, Sunshine will advertise support for HEVC Main and Main10 (HDR) profiles
|
||||||
# hevc_mode = 0
|
# hevc_mode = 2
|
||||||
|
|
||||||
# Force a specific encoder, otherwise Sunshine will use the first encoder that is available
|
# Force a specific encoder, otherwise Sunshine will use the first encoder that is available
|
||||||
# supported encoders:
|
# supported encoders:
|
||||||
# nvenc
|
# nvenc
|
||||||
# amdvce
|
# amdvce # NOTE: alpha stage. The cursor is not yet displayed
|
||||||
# software
|
# software
|
||||||
#
|
#
|
||||||
# encoder = nvenc
|
# encoder = nvenc
|
||||||
@@ -171,6 +174,31 @@
|
|||||||
##########################
|
##########################
|
||||||
# nv_coder = auto
|
# nv_coder = auto
|
||||||
|
|
||||||
|
##################################### AMD #####################################
|
||||||
|
###### presets ###########
|
||||||
|
# default
|
||||||
|
# speed
|
||||||
|
# balanced
|
||||||
|
##########################
|
||||||
|
# amd_preset = balanced
|
||||||
|
#
|
||||||
|
####### rate control #####
|
||||||
|
# auto -- let ffmpeg decide rate control
|
||||||
|
# constqp -- constant QP mode
|
||||||
|
# vbr -- variable bitrate
|
||||||
|
# cbr -- constant bitrate
|
||||||
|
# cbr_hq -- cbr high quality
|
||||||
|
# cbr_ld_hq -- cbr low delay high quality
|
||||||
|
# vbr_hq -- vbr high quality
|
||||||
|
##########################
|
||||||
|
# amd_rc = auto
|
||||||
|
|
||||||
|
###### h264 entropy ######
|
||||||
|
# auto -- let ffmpeg nvenc decide the entropy encoding
|
||||||
|
# cabac
|
||||||
|
# cavlc
|
||||||
|
##########################
|
||||||
|
# amd_coder = auto
|
||||||
|
|
||||||
##############################################
|
##############################################
|
||||||
# Some configurable parameters, are merely toggles for specific features
|
# Some configurable parameters, are merely toggles for specific features
|
||||||
|
|||||||
-1
Submodule pre-compiled deleted from 36f6872712
+4
-1
@@ -165,7 +165,7 @@ video_t video {
|
|||||||
|
|
||||||
{}, // encoder
|
{}, // encoder
|
||||||
{}, // adapter_name
|
{}, // adapter_name
|
||||||
{} // output_name
|
{}, // output_name
|
||||||
};
|
};
|
||||||
|
|
||||||
audio_t audio {};
|
audio_t audio {};
|
||||||
@@ -392,6 +392,9 @@ int apply_flags(const char *line) {
|
|||||||
case '1':
|
case '1':
|
||||||
config::sunshine.flags[config::flag::FRESH_STATE].flip();
|
config::sunshine.flags[config::flag::FRESH_STATE].flip();
|
||||||
break;
|
break;
|
||||||
|
case 'p':
|
||||||
|
config::sunshine.flags[config::flag::CONST_PIN].flip();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
std::cout << "Warning: Unrecognized flag: ["sv << *line << ']' << std::endl;
|
std::cout << "Warning: Unrecognized flag: ["sv << *line << ']' << std::endl;
|
||||||
ret = -1;
|
ret = -1;
|
||||||
|
|||||||
+2
-1
@@ -77,7 +77,8 @@ namespace flag {
|
|||||||
enum flag_e : std::size_t {
|
enum flag_e : std::size_t {
|
||||||
PIN_STDIN = 0, // Read PIN from stdin instead of http
|
PIN_STDIN = 0, // Read PIN from stdin instead of http
|
||||||
FRESH_STATE, // Do not load or save state
|
FRESH_STATE, // Do not load or save state
|
||||||
FLAG_SIZE
|
FLAG_SIZE,
|
||||||
|
CONST_PIN= 4 // Use "universal" pin
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-1
@@ -360,7 +360,11 @@ void pair(std::shared_ptr<safe::queue_t<crypto::x509_t>> &add_cert, std::shared_
|
|||||||
|
|
||||||
ptr->second.async_insert_pin.salt = std::move(args.at("salt"s));
|
ptr->second.async_insert_pin.salt = std::move(args.at("salt"s));
|
||||||
|
|
||||||
if(config::sunshine.flags[config::flag::PIN_STDIN]) {
|
if(config::sunshine.flags[config::flag::CONST_PIN]) {
|
||||||
|
std::string pin("6174");
|
||||||
|
getservercert(ptr->second, tree, pin);
|
||||||
|
}
|
||||||
|
else if(config::sunshine.flags[config::flag::PIN_STDIN]) {
|
||||||
std::string pin;
|
std::string pin;
|
||||||
|
|
||||||
std::cout << "Please insert pin: "sv;
|
std::cout << "Please insert pin: "sv;
|
||||||
|
|||||||
+217
-128
@@ -14,6 +14,7 @@
|
|||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
#include <X11/extensions/Xfixes.h>
|
#include <X11/extensions/Xfixes.h>
|
||||||
|
#include <X11/extensions/Xrandr.h>
|
||||||
#include <xcb/shm.h>
|
#include <xcb/shm.h>
|
||||||
#include <xcb/xfixes.h>
|
#include <xcb/xfixes.h>
|
||||||
#include <sys/ipc.h>
|
#include <sys/ipc.h>
|
||||||
@@ -26,11 +27,12 @@
|
|||||||
#include "sunshine/config.h"
|
#include "sunshine/config.h"
|
||||||
#include "sunshine/main.h"
|
#include "sunshine/main.h"
|
||||||
|
|
||||||
namespace platf {
|
namespace platf
|
||||||
|
{
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
|
|
||||||
void freeImage(XImage *);
|
void freeImage(XImage*);
|
||||||
void freeX(XFixesCursorImage *);
|
void freeX(XFixesCursorImage*);
|
||||||
|
|
||||||
using ifaddr_t = util::safe_ptr<ifaddrs, freeifaddrs>;
|
using ifaddr_t = util::safe_ptr<ifaddrs, freeifaddrs>;
|
||||||
using xcb_connect_t = util::safe_ptr<xcb_connection_t, xcb_disconnect>;
|
using xcb_connect_t = util::safe_ptr<xcb_connection_t, xcb_disconnect>;
|
||||||
@@ -44,13 +46,13 @@ using xcursor_t = util::safe_ptr<XFixesCursorImage, freeX>;
|
|||||||
class shm_id_t {
|
class shm_id_t {
|
||||||
public:
|
public:
|
||||||
shm_id_t() : id { -1 } {}
|
shm_id_t() : id { -1 } {}
|
||||||
shm_id_t(int id) : id {id } {}
|
shm_id_t(int id) : id { id } {}
|
||||||
shm_id_t(shm_id_t &&other) noexcept : id(other.id) {
|
shm_id_t(shm_id_t &&other) noexcept : id(other.id) {
|
||||||
other.id = -1;
|
other.id = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
~shm_id_t() {
|
~shm_id_t() {
|
||||||
if(id != -1) {
|
if (id != -1) {
|
||||||
shmctl(id, IPC_RMID, nullptr);
|
shmctl(id, IPC_RMID, nullptr);
|
||||||
id = -1;
|
id = -1;
|
||||||
}
|
}
|
||||||
@@ -60,83 +62,114 @@ public:
|
|||||||
|
|
||||||
class shm_data_t {
|
class shm_data_t {
|
||||||
public:
|
public:
|
||||||
shm_data_t() : data {(void*)-1 } {}
|
shm_data_t() : data { (void*) -1 }
|
||||||
shm_data_t(void *data) : data {data } {}
|
{
|
||||||
|
}
|
||||||
shm_data_t(shm_data_t &&other) noexcept : data(other.data) {
|
shm_data_t(void *data) : data { data }
|
||||||
other.data = (void*)-1;
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
~shm_data_t() {
|
shm_data_t(shm_data_t &&other) noexcept : data(other.data)
|
||||||
if((std::uintptr_t)data != -1) {
|
{
|
||||||
|
other.data = (void*) -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
~shm_data_t()
|
||||||
|
{
|
||||||
|
if ((std::uintptr_t) data != -1)
|
||||||
|
{
|
||||||
shmdt(data);
|
shmdt(data);
|
||||||
data = (void*)-1;
|
data = (void*) -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *data;
|
void *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct x11_img_t : public img_t {
|
struct x11_img_t: public img_t {
|
||||||
ximg_t img;
|
ximg_t img;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct shm_img_t : public img_t {
|
struct shm_img_t: public img_t {
|
||||||
~shm_img_t() override {
|
~shm_img_t() override
|
||||||
|
{
|
||||||
delete[] data;
|
delete[] data;
|
||||||
data = nullptr;
|
data = nullptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void blend_cursor(Display *display, img_t &img) {
|
void blend_cursor(Display *display, img_t &img, int offsetX, int offsetY) {
|
||||||
xcursor_t overlay { XFixesGetCursorImage(display) };
|
xcursor_t overlay { XFixesGetCursorImage(display) };
|
||||||
|
|
||||||
if(!overlay) {
|
if (!overlay) {
|
||||||
BOOST_LOG(error) << "Couldn't get cursor from XFixesGetCursorImage"sv;
|
BOOST_LOG(error)
|
||||||
|
<< "Couldn't get cursor from XFixesGetCursorImage"sv;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
overlay->x -= overlay->xhot;
|
overlay->x -= overlay->xhot;
|
||||||
overlay->y -= overlay->yhot;
|
overlay->y -= overlay->yhot;
|
||||||
|
|
||||||
overlay->x = std::max((short)0, overlay->x);
|
overlay->x -= offsetX;
|
||||||
overlay->y = std::max((short)0, overlay->y);
|
overlay->y -= offsetY;
|
||||||
|
|
||||||
auto pixels = (int*)img.data;
|
overlay->x = std::max((short) 0, overlay->x);
|
||||||
|
overlay->y = std::max((short) 0, overlay->y);
|
||||||
|
|
||||||
|
auto pixels = (int*) img.data;
|
||||||
|
|
||||||
auto screen_height = img.height;
|
auto screen_height = img.height;
|
||||||
auto screen_width = img.width;
|
auto screen_width = img.width;
|
||||||
|
|
||||||
auto delta_height = std::min<uint16_t>(overlay->height, std::max(0, screen_height - overlay->y));
|
|
||||||
auto delta_width = std::min<uint16_t>(overlay->width, std::max(0, screen_width - overlay->x));
|
|
||||||
for(auto y = 0; y < delta_height; ++y) {
|
|
||||||
|
|
||||||
|
auto delta_height = std::min<uint16_t>(overlay->height,std::max(0, screen_height - overlay->y));
|
||||||
|
auto delta_width = std::min<uint16_t>(overlay->width,std::max(0, screen_width - overlay->x));
|
||||||
|
for (auto y = 0; y < delta_height; ++y) {
|
||||||
auto overlay_begin = &overlay->pixels[y * overlay->width];
|
auto overlay_begin = &overlay->pixels[y * overlay->width];
|
||||||
auto overlay_end = &overlay->pixels[y * overlay->width + delta_width];
|
auto overlay_end = &overlay->pixels[y * overlay->width + delta_width];
|
||||||
|
|
||||||
auto pixels_begin = &pixels[(y + overlay->y) * (img.row_pitch / img.pixel_pitch) + overlay->x];
|
auto pixels_begin = &pixels[(y + overlay->y)* (img.row_pitch / img.pixel_pitch) + overlay->x];
|
||||||
std::for_each(overlay_begin, overlay_end, [&](long pixel) {
|
|
||||||
int *pixel_p = (int*)&pixel;
|
|
||||||
|
|
||||||
auto colors_in = (uint8_t*)pixels_begin;
|
std::for_each(overlay_begin, overlay_end,[&](long pixel) {
|
||||||
|
int *pixel_p = (int*) &pixel;
|
||||||
|
|
||||||
auto alpha = (*(uint*)pixel_p) >> 24u;
|
auto colors_in = (uint8_t*) pixels_begin;
|
||||||
if(alpha == 255) {
|
|
||||||
|
auto alpha = (*(uint*) pixel_p) >> 24u;
|
||||||
|
if (alpha == 255) {
|
||||||
*pixels_begin = *pixel_p;
|
*pixels_begin = *pixel_p;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
auto colors_out = (uint8_t*)pixel_p;
|
auto colors_out = (uint8_t*) pixel_p;
|
||||||
colors_in[0] = colors_out[0] + (colors_in[0] * (255 - alpha) + 255/2) / 255;
|
colors_in[0] = colors_out[0] + (colors_in[0] * (255 - alpha) +255 /2) / 255;
|
||||||
colors_in[1] = colors_out[1] + (colors_in[1] * (255 - alpha) + 255/2) / 255;
|
colors_in[1] = colors_out[1] + (colors_in[1] * (255 - alpha) + 255 / 2) / 255;
|
||||||
colors_in[2] = colors_out[2] + (colors_in[2] * (255 - alpha) + 255/2) / 255;
|
colors_in[2] = colors_out[2] + (colors_in[2] * (255 - alpha) + 255 / 2) / 255;
|
||||||
}
|
}
|
||||||
++pixels_begin;
|
++pixels_begin;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
struct x11_attr_t : public display_t {
|
struct x11_attr_t: public display_t
|
||||||
x11_attr_t() : xdisplay {XOpenDisplay(nullptr) }, xwindow { }, xattr {} {
|
{
|
||||||
if(!xdisplay) {
|
xdisplay_t xdisplay;
|
||||||
|
Window xwindow;
|
||||||
|
XWindowAttributes xattr;
|
||||||
|
|
||||||
|
Display* displayDisplay;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remember last X (NOT the streamed monitor!) size. This way we can trigger reinitialization if the dimensions changed while streaming
|
||||||
|
*/
|
||||||
|
int lastWidth,lastHeight;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Offsets for when streaming a specific monitor. By default, they are 0.
|
||||||
|
*/
|
||||||
|
int displayOffsetX,displayOffsetY;
|
||||||
|
|
||||||
|
x11_attr_t() : xdisplay { displayDisplay = XOpenDisplay(nullptr) }, xwindow { }, xattr { }
|
||||||
|
{
|
||||||
|
XInitThreads();
|
||||||
|
if (!xdisplay) {
|
||||||
BOOST_LOG(fatal) << "Could not open x11 display"sv;
|
BOOST_LOG(fatal) << "Could not open x11 display"sv;
|
||||||
log_flush();
|
log_flush();
|
||||||
std::abort();
|
std::abort();
|
||||||
@@ -146,39 +179,81 @@ struct x11_attr_t : public display_t {
|
|||||||
|
|
||||||
refresh();
|
refresh();
|
||||||
|
|
||||||
width = xattr.width;
|
int streamedMonitor = -1;
|
||||||
height = xattr.height;
|
if(!config::video.output_name.empty()) {
|
||||||
|
streamedMonitor = (int)util::from_view(config::video.output_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
//If the value has been set at all
|
||||||
|
if (streamedMonitor != -1) {
|
||||||
|
|
||||||
|
BOOST_LOG(info) << "Configuring selected monitor ("<< streamedMonitor<<") to stream. If it fails here, you may need Xrandr >= 1.5"sv;
|
||||||
|
XRRScreenResources *screenr = XRRGetScreenResources(displayDisplay, xwindow);
|
||||||
|
// This is the key right here. Use XRRScreenResources::noutput
|
||||||
|
int output = screenr->noutput;
|
||||||
|
|
||||||
|
if (streamedMonitor >= output) {
|
||||||
|
BOOST_LOG(error)<< "Could not stream selected display number because there aren't so many."sv;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
XRROutputInfo* out_info = XRRGetOutputInfo(displayDisplay, screenr, screenr->outputs[streamedMonitor]);
|
||||||
|
if (NULL == out_info || out_info->connection != RR_Connected)
|
||||||
|
{
|
||||||
|
BOOST_LOG(error)<< "Could not stream selected display because it doesn't seem to be connected"sv;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
XRRCrtcInfo* crt_info = XRRGetCrtcInfo(displayDisplay, screenr, out_info->crtc);
|
||||||
|
BOOST_LOG(info)<<"Streaming display: "<<out_info->name<<" with res "<<crt_info->width<<" x "<<crt_info->height<<+" offset by "<<crt_info->x<<" x "<<crt_info->y<<"."sv;
|
||||||
|
|
||||||
|
width = crt_info -> width;
|
||||||
|
height = crt_info -> height;
|
||||||
|
displayOffsetX = crt_info -> x;
|
||||||
|
displayOffsetY = crt_info -> y;
|
||||||
|
|
||||||
|
XRRFreeCrtcInfo(crt_info);
|
||||||
|
}
|
||||||
|
XRRFreeOutputInfo(out_info);
|
||||||
|
}
|
||||||
|
XRRFreeScreenResources(screenr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
width = xattr.width;
|
||||||
|
height = xattr.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastWidth = xattr.width;
|
||||||
|
lastHeight = xattr.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
void refresh() {
|
/**
|
||||||
XGetWindowAttributes(xdisplay.get(), xwindow, &xattr);
|
* Called when the display attributes should change.
|
||||||
|
*/
|
||||||
|
void refresh()
|
||||||
|
{
|
||||||
|
XGetWindowAttributes(xdisplay.get(), xwindow, &xattr); //Update xattr's
|
||||||
}
|
}
|
||||||
|
|
||||||
capture_e snapshot(img_t *img_out_base, std::chrono::milliseconds timeout, bool cursor) override {
|
capture_e snapshot(img_t *img_out_base, std::chrono::milliseconds timeout, bool cursor) override {
|
||||||
refresh();
|
refresh();
|
||||||
|
|
||||||
if(width != xattr.width || height != xattr.height) {
|
//The whole X server changed, so we gotta reinit everything
|
||||||
|
if (xattr.width != lastWidth || xattr.height != lastHeight) {
|
||||||
|
BOOST_LOG(warning)<< "X dimensions changed in non-SHM mode, request reinit"sv;
|
||||||
return capture_e::reinit;
|
return capture_e::reinit;
|
||||||
}
|
}
|
||||||
|
XImage *img { XGetImage(xdisplay.get(), xwindow, displayOffsetX, displayOffsetY, width,height, AllPlanes, ZPixmap) };
|
||||||
|
|
||||||
XImage *img { XGetImage(
|
auto img_out = (x11_img_t*) img_out_base;
|
||||||
xdisplay.get(),
|
|
||||||
xwindow,
|
|
||||||
0, 0,
|
|
||||||
xattr.width, xattr.height,
|
|
||||||
AllPlanes, ZPixmap)
|
|
||||||
};
|
|
||||||
|
|
||||||
auto img_out = (x11_img_t*)img_out_base;
|
|
||||||
img_out->width = img->width;
|
img_out->width = img->width;
|
||||||
img_out->height = img->height;
|
img_out->height = img->height;
|
||||||
img_out->data = (uint8_t*)img->data;
|
img_out->data = (uint8_t*) img->data;
|
||||||
img_out->row_pitch = img->bytes_per_line;
|
img_out->row_pitch = img->bytes_per_line;
|
||||||
img_out->pixel_pitch = img->bits_per_pixel / 8;
|
img_out->pixel_pitch = img->bits_per_pixel / 8;
|
||||||
img_out->img.reset(img);
|
img_out->img.reset(img);
|
||||||
|
|
||||||
if(cursor) {
|
if (cursor) {
|
||||||
blend_cursor(xdisplay.get(), *img_out_base);
|
blend_cursor(xdisplay.get(), *img_out_base,displayOffsetX,displayOffsetY);
|
||||||
}
|
}
|
||||||
|
|
||||||
return capture_e::ok;
|
return capture_e::ok;
|
||||||
@@ -192,13 +267,9 @@ struct x11_attr_t : public display_t {
|
|||||||
snapshot(img, 0s, true);
|
snapshot(img, 0s, true);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
xdisplay_t xdisplay;
|
|
||||||
Window xwindow;
|
|
||||||
XWindowAttributes xattr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct shm_attr_t : public x11_attr_t {
|
struct shm_attr_t: public x11_attr_t {
|
||||||
xdisplay_t shm_xdisplay; // Prevent race condition with x11_attr_t::xdisplay
|
xdisplay_t shm_xdisplay; // Prevent race condition with x11_attr_t::xdisplay
|
||||||
xcb_connect_t xcb;
|
xcb_connect_t xcb;
|
||||||
xcb_screen_t *display;
|
xcb_screen_t *display;
|
||||||
@@ -209,54 +280,50 @@ struct shm_attr_t : public x11_attr_t {
|
|||||||
shm_data_t data;
|
shm_data_t data;
|
||||||
|
|
||||||
util::TaskPool::task_id_t refresh_task_id;
|
util::TaskPool::task_id_t refresh_task_id;
|
||||||
|
|
||||||
void delayed_refresh() {
|
void delayed_refresh() {
|
||||||
refresh();
|
refresh();
|
||||||
|
|
||||||
refresh_task_id = task_pool.pushDelayed(&shm_attr_t::delayed_refresh, 2s, this).task_id;
|
refresh_task_id = task_pool.pushDelayed(&shm_attr_t::delayed_refresh,2s, this).task_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
shm_attr_t() : x11_attr_t(), shm_xdisplay {XOpenDisplay(nullptr) } {
|
shm_attr_t() : x11_attr_t(), shm_xdisplay { XOpenDisplay(nullptr) } {
|
||||||
refresh_task_id = task_pool.pushDelayed(&shm_attr_t::delayed_refresh, 2s, this).task_id;
|
refresh_task_id = task_pool.pushDelayed(&shm_attr_t::delayed_refresh,2s, this).task_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
~shm_attr_t() override {
|
~shm_attr_t() override {
|
||||||
while(!task_pool.cancel(refresh_task_id));
|
while (!task_pool.cancel(refresh_task_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
capture_e snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor) override {
|
capture_e snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor) override {
|
||||||
if(width != xattr.width || height != xattr.height) {
|
//The whole X server changed, so we gotta reinit everything
|
||||||
|
if (xattr.width != lastWidth || xattr.height != lastHeight) {
|
||||||
|
BOOST_LOG(warning)<< "X dimensions changed in SHM mode, request reinit"sv;
|
||||||
return capture_e::reinit;
|
return capture_e::reinit;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
auto img_cookie = xcb_shm_get_image_unchecked(xcb.get(), display->root,displayOffsetX, displayOffsetY, width, height, ~0, XCB_IMAGE_FORMAT_Z_PIXMAP, seg, 0);
|
||||||
|
|
||||||
auto img_cookie = xcb_shm_get_image_unchecked(
|
xcb_img_t img_reply { xcb_shm_get_image_reply(xcb.get(), img_cookie,nullptr) };
|
||||||
xcb.get(),
|
if (!img_reply) {
|
||||||
display->root,
|
BOOST_LOG(error)
|
||||||
0, 0,
|
<< "Could not get image reply"sv;
|
||||||
width, height,
|
return capture_e::reinit;
|
||||||
~0,
|
}
|
||||||
XCB_IMAGE_FORMAT_Z_PIXMAP,
|
|
||||||
seg,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
xcb_img_t img_reply { xcb_shm_get_image_reply(xcb.get(), img_cookie, nullptr) };
|
std::copy_n((std::uint8_t*) data.data, frame_size(), img->data);
|
||||||
if(!img_reply) {
|
|
||||||
BOOST_LOG(error) << "Could not get image reply"sv;
|
if (cursor) {
|
||||||
return capture_e::reinit;
|
blend_cursor(shm_xdisplay.get(), *img,displayOffsetX,displayOffsetY);
|
||||||
|
}
|
||||||
|
|
||||||
|
return capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::copy_n((std::uint8_t*)data.data, frame_size(), img->data);
|
|
||||||
|
|
||||||
if(cursor) {
|
|
||||||
blend_cursor(shm_xdisplay.get(), *img);
|
|
||||||
}
|
|
||||||
|
|
||||||
return capture_e::ok;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<img_t> alloc_img() override {
|
std::shared_ptr<img_t> alloc_img() override {
|
||||||
auto img = std::make_shared<shm_img_t>();
|
auto img = std::make_shared<shm_img_t>();
|
||||||
img->width = width;
|
img->width = width;
|
||||||
img->height = height;
|
img->height = height;
|
||||||
img->pixel_pitch = 4;
|
img->pixel_pitch = 4;
|
||||||
img->row_pitch = img->pixel_pitch * width;
|
img->row_pitch = img->pixel_pitch * width;
|
||||||
@@ -272,12 +339,15 @@ struct shm_attr_t : public x11_attr_t {
|
|||||||
int init() {
|
int init() {
|
||||||
shm_xdisplay.reset(XOpenDisplay(nullptr));
|
shm_xdisplay.reset(XOpenDisplay(nullptr));
|
||||||
xcb.reset(xcb_connect(nullptr, nullptr));
|
xcb.reset(xcb_connect(nullptr, nullptr));
|
||||||
if(xcb_connection_has_error(xcb.get())) {
|
if (xcb_connection_has_error(xcb.get()))
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!xcb_get_extension_data(xcb.get(), &xcb_shm_id)->present) {
|
if (!xcb_get_extension_data(xcb.get(), &xcb_shm_id)->present)
|
||||||
BOOST_LOG(error) << "Missing SHM extension"sv;
|
{
|
||||||
|
BOOST_LOG(error)
|
||||||
|
<< "Missing SHM extension"sv;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -287,22 +357,29 @@ struct shm_attr_t : public x11_attr_t {
|
|||||||
seg = xcb_generate_id(xcb.get());
|
seg = xcb_generate_id(xcb.get());
|
||||||
|
|
||||||
shm_id.id = shmget(IPC_PRIVATE, frame_size(), IPC_CREAT | 0777);
|
shm_id.id = shmget(IPC_PRIVATE, frame_size(), IPC_CREAT | 0777);
|
||||||
if(shm_id.id == -1) {
|
if (shm_id.id == -1)
|
||||||
BOOST_LOG(error) << "shmget failed"sv;
|
{
|
||||||
|
BOOST_LOG(error)
|
||||||
|
<< "shmget failed"sv;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb_shm_attach(xcb.get(), seg, shm_id.id, false);
|
xcb_shm_attach(xcb.get(), seg, shm_id.id, false);
|
||||||
data.data = shmat(shm_id.id, nullptr, 0);
|
data.data = shmat(shm_id.id, nullptr, 0);
|
||||||
|
|
||||||
if ((uintptr_t)data.data == -1) {
|
if ((uintptr_t) data.data == -1)
|
||||||
BOOST_LOG(error) << "shmat failed"sv;
|
{
|
||||||
|
BOOST_LOG(error)
|
||||||
|
<< "shmat failed"sv;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
width = display->width_in_pixels;
|
/*
|
||||||
height = display->height_in_pixels;
|
* Commented out resetting of the sizes when intializing X in SHM mode. It might be wrong. Expect issues. This is the default mode, so poisoning those variables is not desired
|
||||||
|
*/
|
||||||
|
// width = display->width_in_pixels;
|
||||||
|
// height = display->height_in_pixels;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -312,18 +389,22 @@ struct shm_attr_t : public x11_attr_t {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mic_attr_t : public mic_t {
|
struct mic_attr_t: public mic_t {
|
||||||
pa_sample_spec ss;
|
pa_sample_spec ss;
|
||||||
util::safe_ptr<pa_simple, pa_simple_free> mic;
|
util::safe_ptr<pa_simple, pa_simple_free> mic;
|
||||||
|
|
||||||
explicit mic_attr_t(pa_sample_format format, std::uint32_t sample_rate, std::uint8_t channels) : ss { format, sample_rate, channels }, mic {} {}
|
explicit mic_attr_t(pa_sample_format format, std::uint32_t sample_rate,
|
||||||
|
std::uint8_t channels) : ss { format, sample_rate, channels }, mic { } { }
|
||||||
|
|
||||||
capture_e sample(std::vector<std::int16_t> &sample_buf) override {
|
capture_e sample(std::vector<std::int16_t> &sample_buf) override {
|
||||||
auto sample_size = sample_buf.size();
|
auto sample_size = sample_buf.size();
|
||||||
|
|
||||||
auto buf = sample_buf.data();
|
auto buf = sample_buf.data();
|
||||||
int status;
|
int status;
|
||||||
if(pa_simple_read(mic.get(), buf, sample_size * 2, &status)) {
|
if (pa_simple_read(mic.get(), buf, sample_size * 2, &status))
|
||||||
BOOST_LOG(error) << "pa_simple_read() failed: "sv << pa_strerror(status);
|
{
|
||||||
|
BOOST_LOG(error)
|
||||||
|
<< "pa_simple_read() failed: "sv << pa_strerror(status);
|
||||||
|
|
||||||
return capture_e::error;
|
return capture_e::error;
|
||||||
}
|
}
|
||||||
@@ -335,7 +416,7 @@ struct mic_attr_t : public mic_t {
|
|||||||
std::shared_ptr<display_t> shm_display() {
|
std::shared_ptr<display_t> shm_display() {
|
||||||
auto shm = std::make_shared<shm_attr_t>();
|
auto shm = std::make_shared<shm_attr_t>();
|
||||||
|
|
||||||
if(shm->init()) {
|
if (shm->init()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,14 +424,15 @@ std::shared_ptr<display_t> shm_display() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<display_t> display(platf::dev_type_e hwdevice_type) {
|
std::shared_ptr<display_t> display(platf::dev_type_e hwdevice_type) {
|
||||||
if(hwdevice_type != platf::dev_type_e::none) {
|
if (hwdevice_type != platf::dev_type_e::none) {
|
||||||
|
BOOST_LOG(error)<< "Could not initialize display with the given hw device type."sv;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto shm_disp = shm_display();
|
auto shm_disp = shm_display(); //Attempt to use shared memory X11 to avoid copying the frame
|
||||||
|
|
||||||
if(!shm_disp) {
|
if (!shm_disp) {
|
||||||
return std::make_shared<x11_attr_t>();
|
return std::make_shared<x11_attr_t>(); //Fallback to standard way if else
|
||||||
}
|
}
|
||||||
|
|
||||||
return shm_disp;
|
return shm_disp;
|
||||||
@@ -362,15 +444,16 @@ std::unique_ptr<mic_t> microphone(std::uint32_t sample_rate) {
|
|||||||
int status;
|
int status;
|
||||||
|
|
||||||
const char *audio_sink = "@DEFAULT_MONITOR@";
|
const char *audio_sink = "@DEFAULT_MONITOR@";
|
||||||
if(!config::audio.sink.empty()) {
|
if (!config::audio.sink.empty()) {
|
||||||
audio_sink = config::audio.sink.c_str();
|
audio_sink = config::audio.sink.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
mic->mic.reset(
|
mic->mic.reset(
|
||||||
pa_simple_new(nullptr, "sunshine", pa_stream_direction_t::PA_STREAM_RECORD, audio_sink, "sunshine-record", &mic->ss, nullptr, nullptr, &status)
|
pa_simple_new(nullptr, "sunshine",
|
||||||
);
|
pa_stream_direction_t::PA_STREAM_RECORD, audio_sink,
|
||||||
|
"sunshine-record", &mic->ss, nullptr, nullptr, &status));
|
||||||
|
|
||||||
if(!mic->mic) {
|
if (!mic->mic) {
|
||||||
auto err_str = pa_strerror(status);
|
auto err_str = pa_strerror(status);
|
||||||
BOOST_LOG(error) << "pa_simple_new() failed: "sv << err_str;
|
BOOST_LOG(error) << "pa_simple_new() failed: "sv << err_str;
|
||||||
|
|
||||||
@@ -393,12 +476,14 @@ std::string from_sockaddr(const sockaddr *const ip_addr) {
|
|||||||
char data[INET6_ADDRSTRLEN];
|
char data[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
auto family = ip_addr->sa_family;
|
auto family = ip_addr->sa_family;
|
||||||
if(family == AF_INET6) {
|
if (family == AF_INET6) {
|
||||||
inet_ntop(AF_INET6, &((sockaddr_in6*)ip_addr)->sin6_addr, data, INET6_ADDRSTRLEN);
|
inet_ntop(AF_INET6, &((sockaddr_in6*) ip_addr)->sin6_addr, data,
|
||||||
|
INET6_ADDRSTRLEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(family == AF_INET) {
|
if (family == AF_INET) {
|
||||||
inet_ntop(AF_INET, &((sockaddr_in*)ip_addr)->sin_addr, data, INET_ADDRSTRLEN);
|
inet_ntop(AF_INET, &((sockaddr_in*) ip_addr)->sin_addr, data,
|
||||||
|
INET_ADDRSTRLEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::string { data };
|
return std::string { data };
|
||||||
@@ -409,32 +494,36 @@ std::pair<std::uint16_t, std::string> from_sockaddr_ex(const sockaddr *const ip_
|
|||||||
|
|
||||||
auto family = ip_addr->sa_family;
|
auto family = ip_addr->sa_family;
|
||||||
std::uint16_t port;
|
std::uint16_t port;
|
||||||
if(family == AF_INET6) {
|
if (family == AF_INET6) {
|
||||||
inet_ntop(AF_INET6, &((sockaddr_in6*)ip_addr)->sin6_addr, data, INET6_ADDRSTRLEN);
|
inet_ntop(AF_INET6, &((sockaddr_in6*) ip_addr)->sin6_addr, data,
|
||||||
port = ((sockaddr_in6*)ip_addr)->sin6_port;
|
INET6_ADDRSTRLEN);
|
||||||
|
port = ((sockaddr_in6*) ip_addr)->sin6_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(family == AF_INET) {
|
if (family == AF_INET) {
|
||||||
inet_ntop(AF_INET, &((sockaddr_in*)ip_addr)->sin_addr, data, INET_ADDRSTRLEN);
|
inet_ntop(AF_INET, &((sockaddr_in*) ip_addr)->sin_addr, data,
|
||||||
port = ((sockaddr_in*)ip_addr)->sin_port;
|
INET_ADDRSTRLEN);
|
||||||
|
port = ((sockaddr_in*) ip_addr)->sin_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { port, std::string { data } };
|
return
|
||||||
|
{ port, std::string {data}};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_mac_address(const std::string_view &address) {
|
std::string get_mac_address(const std::string_view &address) {
|
||||||
auto ifaddrs = get_ifaddrs();
|
auto ifaddrs = get_ifaddrs();
|
||||||
for(auto pos = ifaddrs.get(); pos != nullptr; pos = pos->ifa_next) {
|
for (auto pos = ifaddrs.get(); pos != nullptr; pos = pos->ifa_next) {
|
||||||
if(pos->ifa_addr && address == from_sockaddr(pos->ifa_addr)) {
|
if (pos->ifa_addr && address == from_sockaddr(pos->ifa_addr)) {
|
||||||
std::ifstream mac_file("/sys/class/net/"s + pos->ifa_name + "/address");
|
std::ifstream mac_file("/sys/class/net/"s + pos->ifa_name + "/address");
|
||||||
if(mac_file.good()) {
|
if (mac_file.good()) {
|
||||||
std::string mac_address;
|
std::string mac_address;
|
||||||
std::getline(mac_file, mac_address);
|
std::getline(mac_file, mac_address);
|
||||||
return mac_address;
|
return mac_address;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BOOST_LOG(warning) << "Unable to find MAC address for "sv << address;
|
BOOST_LOG(warning)
|
||||||
|
<< "Unable to find MAC address for "sv << address;
|
||||||
return "00:00:00:00:00:00"s;
|
return "00:00:00:00:00:00"s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ int display_base_t::init() {
|
|||||||
FreeLibrary(user32);
|
FreeLibrary(user32);
|
||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
|
|
||||||
dxgi::factory1_t::pointer factory_p {};
|
dxgi::factory1_t::pointer factory_p {};
|
||||||
dxgi::adapter_t::pointer adapter_p {};
|
dxgi::adapter_t::pointer adapter_p {};
|
||||||
dxgi::output_t::pointer output_p {};
|
dxgi::output_t::pointer output_p {};
|
||||||
@@ -150,8 +151,6 @@ int display_base_t::init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
D3D_FEATURE_LEVEL featureLevels[] {
|
D3D_FEATURE_LEVEL featureLevels[] {
|
||||||
D3D_FEATURE_LEVEL_12_1,
|
|
||||||
D3D_FEATURE_LEVEL_12_0,
|
|
||||||
D3D_FEATURE_LEVEL_11_1,
|
D3D_FEATURE_LEVEL_11_1,
|
||||||
D3D_FEATURE_LEVEL_11_0,
|
D3D_FEATURE_LEVEL_11_0,
|
||||||
D3D_FEATURE_LEVEL_10_1,
|
D3D_FEATURE_LEVEL_10_1,
|
||||||
@@ -164,7 +163,6 @@ int display_base_t::init() {
|
|||||||
status = adapter->QueryInterface(IID_IDXGIAdapter, (void**)&adapter_p);
|
status = adapter->QueryInterface(IID_IDXGIAdapter, (void**)&adapter_p);
|
||||||
if(FAILED(status)) {
|
if(FAILED(status)) {
|
||||||
BOOST_LOG(error) << "Failed to query IDXGIAdapter interface"sv;
|
BOOST_LOG(error) << "Failed to query IDXGIAdapter interface"sv;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ util::buffer_t<std::uint8_t> make_cursor_image(util::buffer_t<std::uint8_t> &&im
|
|||||||
|
|
||||||
class hwdevice_t : public platf::hwdevice_t {
|
class hwdevice_t : public platf::hwdevice_t {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
hwdevice_t(std::vector<hwdevice_t*> *hwdevices_p) : hwdevices_p { hwdevices_p } {}
|
hwdevice_t(std::vector<hwdevice_t*> *hwdevices_p) : hwdevices_p { hwdevices_p } {}
|
||||||
hwdevice_t() = delete;
|
hwdevice_t() = delete;
|
||||||
|
|
||||||
@@ -168,8 +169,8 @@ public:
|
|||||||
auto &processor_in = it->second;
|
auto &processor_in = it->second;
|
||||||
|
|
||||||
D3D11_VIDEO_PROCESSOR_STREAM stream[] {
|
D3D11_VIDEO_PROCESSOR_STREAM stream[] {
|
||||||
{ TRUE, 0, 0, 0, 0, nullptr, processor_in.get(), nullptr },
|
{ TRUE, 0, 0, 0, 0, nullptr, processor_in.get() },
|
||||||
{ TRUE, 0, 0, 0, 0, nullptr, cursor_in.get(), nullptr }
|
{ TRUE, 0, 0, 0, 0, nullptr, cursor_in.get() }
|
||||||
};
|
};
|
||||||
|
|
||||||
auto status = ctx->VideoProcessorBlt(processor.get(), processor_out.get(), 0, cursor_visible ? 2 : 1, stream);
|
auto status = ctx->VideoProcessorBlt(processor.get(), processor_out.get(), 0, cursor_visible ? 2 : 1, stream);
|
||||||
@@ -233,6 +234,12 @@ public:
|
|||||||
}
|
}
|
||||||
processor_e.reset(vp_e_p);
|
processor_e.reset(vp_e_p);
|
||||||
|
|
||||||
|
D3D11_VIDEO_PROCESSOR_CAPS proc_caps;
|
||||||
|
processor_e->GetVideoProcessorCaps(&proc_caps);
|
||||||
|
if(!(proc_caps.FeatureCaps & D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_ALPHA_STREAM)) {
|
||||||
|
BOOST_LOG(warning) << "VideoProcessorSetStreamAlpha() not supported, hardware accelerated mouse cannot be added to the video stream"sv;
|
||||||
|
}
|
||||||
|
|
||||||
video::processor_t::pointer processor_p;
|
video::processor_t::pointer processor_p;
|
||||||
status = device->CreateVideoProcessor(processor_e.get(), 0, &processor_p);
|
status = device->CreateVideoProcessor(processor_e.get(), 0, &processor_p);
|
||||||
if(FAILED(status)) {
|
if(FAILED(status)) {
|
||||||
@@ -241,6 +248,9 @@ public:
|
|||||||
}
|
}
|
||||||
processor.reset(processor_p);
|
processor.reset(processor_p);
|
||||||
|
|
||||||
|
// Tell video processor alpha values need to be enabled
|
||||||
|
ctx->VideoProcessorSetStreamAlpha(processor.get(), 1, TRUE, 1.0f);
|
||||||
|
|
||||||
D3D11_TEXTURE2D_DESC t {};
|
D3D11_TEXTURE2D_DESC t {};
|
||||||
t.Width = out_width;
|
t.Width = out_width;
|
||||||
t.Height = out_height;
|
t.Height = out_height;
|
||||||
@@ -275,9 +285,6 @@ public:
|
|||||||
}
|
}
|
||||||
processor_out.reset(processor_out_p);
|
processor_out.reset(processor_out_p);
|
||||||
|
|
||||||
// Tell video processor alpha values need to be enabled
|
|
||||||
ctx->VideoProcessorSetStreamAlpha(processor.get(), 1, TRUE, 1.0f);
|
|
||||||
|
|
||||||
device_p->AddRef();
|
device_p->AddRef();
|
||||||
data = device_p;
|
data = device_p;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -373,7 +380,7 @@ capture_e display_vram_t::snapshot(platf::img_t *img_base, std::chrono::millisec
|
|||||||
dxgi::texture2d_t::pointer tex_p {};
|
dxgi::texture2d_t::pointer tex_p {};
|
||||||
auto status = device->CreateTexture2D(&t, &data, &tex_p);
|
auto status = device->CreateTexture2D(&t, &data, &tex_p);
|
||||||
if(FAILED(status)) {
|
if(FAILED(status)) {
|
||||||
BOOST_LOG(error) << "Failed to create dummy texture [0x"sv << util::hex(status).to_string_view() << ']';
|
BOOST_LOG(error) << "Failed to create mouse texture [0x"sv << util::hex(status).to_string_view() << ']';
|
||||||
return capture_e::error;
|
return capture_e::error;
|
||||||
}
|
}
|
||||||
texture2d_t texture { tex_p };
|
texture2d_t texture { tex_p };
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ using namespace std::literals;
|
|||||||
|
|
||||||
using adapteraddrs_t = util::c_ptr<IP_ADAPTER_ADDRESSES>;
|
using adapteraddrs_t = util::c_ptr<IP_ADAPTER_ADDRESSES>;
|
||||||
|
|
||||||
|
volatile HDESK _lastKnownInputDesktop = NULL;
|
||||||
|
HDESK pairInputDesktop();
|
||||||
|
|
||||||
class vigem_t {
|
class vigem_t {
|
||||||
public:
|
public:
|
||||||
using client_t = util::safe_ptr<_VIGEM_CLIENT_T, vigem_free>;
|
using client_t = util::safe_ptr<_VIGEM_CLIENT_T, vigem_free>;
|
||||||
@@ -171,15 +174,21 @@ void move_mouse(input_t &input, int deltaX, int deltaY) {
|
|||||||
mi.dwFlags = MOUSEEVENTF_MOVE;
|
mi.dwFlags = MOUSEEVENTF_MOVE;
|
||||||
mi.dx = deltaX;
|
mi.dx = deltaX;
|
||||||
mi.dy = deltaY;
|
mi.dy = deltaY;
|
||||||
|
|
||||||
|
retry:
|
||||||
auto send = SendInput(1, &i, sizeof(INPUT));
|
auto send = SendInput(1, &i, sizeof(INPUT));
|
||||||
if(send != 1) {
|
if(send != 1) {
|
||||||
|
auto hDesk = pairInputDesktop();
|
||||||
|
if (_lastKnownInputDesktop != hDesk) {
|
||||||
|
_lastKnownInputDesktop = hDesk;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
BOOST_LOG(warning) << "Couldn't send mouse movement input"sv;
|
BOOST_LOG(warning) << "Couldn't send mouse movement input"sv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void button_mouse(input_t &input, int button, bool release) {
|
void button_mouse(input_t &input, int button, bool release) {
|
||||||
constexpr SHORT KEY_STATE_DOWN = 0x8000;
|
constexpr auto KEY_STATE_DOWN = (SHORT)0x8000;
|
||||||
|
|
||||||
INPUT i {};
|
INPUT i {};
|
||||||
|
|
||||||
@@ -218,8 +227,14 @@ void button_mouse(input_t &input, int button, bool release) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retry:
|
||||||
auto send = SendInput(1, &i, sizeof(INPUT));
|
auto send = SendInput(1, &i, sizeof(INPUT));
|
||||||
if(send != 1) {
|
if(send != 1) {
|
||||||
|
auto hDesk = pairInputDesktop();
|
||||||
|
if (_lastKnownInputDesktop != hDesk) {
|
||||||
|
_lastKnownInputDesktop = hDesk;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
BOOST_LOG(warning) << "Couldn't send mouse button input"sv;
|
BOOST_LOG(warning) << "Couldn't send mouse button input"sv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -233,9 +248,15 @@ void scroll(input_t &input, int distance) {
|
|||||||
mi.dwFlags = MOUSEEVENTF_WHEEL;
|
mi.dwFlags = MOUSEEVENTF_WHEEL;
|
||||||
mi.mouseData = distance;
|
mi.mouseData = distance;
|
||||||
|
|
||||||
|
retry:
|
||||||
auto send = SendInput(1, &i, sizeof(INPUT));
|
auto send = SendInput(1, &i, sizeof(INPUT));
|
||||||
if(send != 1) {
|
if(send != 1) {
|
||||||
BOOST_LOG(warning) << "Couldn't send moue movement input"sv;
|
auto hDesk = pairInputDesktop();
|
||||||
|
if (_lastKnownInputDesktop != hDesk) {
|
||||||
|
_lastKnownInputDesktop = hDesk;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
BOOST_LOG(warning) << "Couldn't send mouse scroll input"sv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,9 +303,15 @@ void keyboard(input_t &input, uint16_t modcode, bool release) {
|
|||||||
ki.dwFlags |= KEYEVENTF_KEYUP;
|
ki.dwFlags |= KEYEVENTF_KEYUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retry:
|
||||||
auto send = SendInput(1, &i, sizeof(INPUT));
|
auto send = SendInput(1, &i, sizeof(INPUT));
|
||||||
if(send != 1) {
|
if(send != 1) {
|
||||||
BOOST_LOG(warning) << "Couldn't send moue movement input"sv;
|
auto hDesk = pairInputDesktop();
|
||||||
|
if (_lastKnownInputDesktop != hDesk) {
|
||||||
|
_lastKnownInputDesktop = hDesk;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
BOOST_LOG(warning) << "Couldn't send keyboard input"sv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,6 +354,24 @@ int thread_priority() {
|
|||||||
return SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST) ? 0 : 1;
|
return SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST) ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HDESK pairInputDesktop() {
|
||||||
|
auto hDesk = OpenInputDesktop(DF_ALLOWOTHERACCOUNTHOOK, FALSE, GENERIC_ALL);
|
||||||
|
if (NULL == hDesk) {
|
||||||
|
auto err = GetLastError();
|
||||||
|
BOOST_LOG(error) << "Failed to OpenInputDesktop [0x"sv << util::hex(err).to_string_view() << ']';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BOOST_LOG(info) << std::endl << "Opened desktop [0x"sv << util::hex(hDesk).to_string_view() << ']';
|
||||||
|
if (!SetThreadDesktop(hDesk) ) {
|
||||||
|
auto err = GetLastError();
|
||||||
|
BOOST_LOG(error) << "Failed to SetThreadDesktop [0x"sv << util::hex(err).to_string_view() << ']';
|
||||||
|
}
|
||||||
|
CloseDesktop(hDesk);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hDesk;
|
||||||
|
}
|
||||||
|
|
||||||
void freeInput(void *p) {
|
void freeInput(void *p) {
|
||||||
auto vigem = (vigem_t*)p;
|
auto vigem = (vigem_t*)p;
|
||||||
|
|
||||||
|
|||||||
+21
-3
@@ -373,9 +373,11 @@ static encoder_t software {
|
|||||||
static std::vector<encoder_t> encoders {
|
static std::vector<encoder_t> encoders {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
nvenc,
|
nvenc,
|
||||||
|
#endif
|
||||||
|
software,
|
||||||
|
#ifdef _WIN32
|
||||||
amdvce,
|
amdvce,
|
||||||
#endif
|
#endif
|
||||||
software
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void reset_display(std::shared_ptr<platf::display_t> &disp, AVHWDeviceType type) {
|
void reset_display(std::shared_ptr<platf::display_t> &disp, AVHWDeviceType type) {
|
||||||
@@ -467,7 +469,14 @@ void captureThread(
|
|||||||
std::this_thread::sleep_for(100ms);
|
std::this_thread::sleep_for(100ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
reset_display(disp, encoder.dev_type);
|
while(capture_ctx_queue->running()) {
|
||||||
|
reset_display(disp, encoder.dev_type);
|
||||||
|
|
||||||
|
if(disp) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(200ms);
|
||||||
|
}
|
||||||
if(!disp) {
|
if(!disp) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -844,7 +853,16 @@ encode_e encode_run_sync(std::vector<std::unique_ptr<sync_session_ctx_t>> &synce
|
|||||||
const auto &encoder = encoders.front();
|
const auto &encoder = encoders.front();
|
||||||
|
|
||||||
std::shared_ptr<platf::display_t> disp;
|
std::shared_ptr<platf::display_t> disp;
|
||||||
reset_display(disp, encoder.dev_type);
|
|
||||||
|
while(encode_session_ctx_queue.running()) {
|
||||||
|
reset_display(disp, encoder.dev_type);
|
||||||
|
if(disp) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(200ms);
|
||||||
|
}
|
||||||
|
|
||||||
if(!disp) {
|
if(!disp) {
|
||||||
return encode_e::error;
|
return encode_e::error;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user