mirror of
https://github.com/LizardByte/Sunshine.git
synced 2026-10-23 03:28:06 +09:00
refactor: modernize standard library usage across six Sonar rules (#5930)
This commit is contained in:
1 parent
81a677c1ee
commit
80588defde
37 files changed
+464
-121
No files matched your search
+33
-33
@@ -742,20 +742,20 @@ namespace config {
|
|||||||
}, // qsv
|
}, // qsv
|
||||||
|
|
||||||
{
|
{
|
||||||
(int) amd::usage_h264_e::ultralowlatency, // usage (h264)
|
std::to_underlying(amd::usage_h264_e::ultralowlatency), // usage (h264)
|
||||||
(int) amd::usage_hevc_e::ultralowlatency, // usage (hevc)
|
std::to_underlying(amd::usage_hevc_e::ultralowlatency), // usage (hevc)
|
||||||
(int) amd::usage_av1_e::ultralowlatency, // usage (av1)
|
std::to_underlying(amd::usage_av1_e::ultralowlatency), // usage (av1)
|
||||||
(int) amd::rc_h264_e::vbr_latency, // rate control (h264)
|
std::to_underlying(amd::rc_h264_e::vbr_latency), // rate control (h264)
|
||||||
(int) amd::rc_hevc_e::vbr_latency, // rate control (hevc)
|
std::to_underlying(amd::rc_hevc_e::vbr_latency), // rate control (hevc)
|
||||||
(int) amd::rc_av1_e::vbr_latency, // rate control (av1)
|
std::to_underlying(amd::rc_av1_e::vbr_latency), // rate control (av1)
|
||||||
0, // enforce_hrd
|
0, // enforce_hrd
|
||||||
(int) amd::quality_h264_e::balanced, // quality (h264)
|
std::to_underlying(amd::quality_h264_e::balanced), // quality (h264)
|
||||||
(int) amd::quality_hevc_e::balanced, // quality (hevc)
|
std::to_underlying(amd::quality_hevc_e::balanced), // quality (hevc)
|
||||||
(int) amd::quality_av1_e::balanced, // quality (av1)
|
std::to_underlying(amd::quality_av1_e::balanced), // quality (av1)
|
||||||
0, // preanalysis
|
0, // preanalysis
|
||||||
1, // vbaq
|
1, // vbaq
|
||||||
{}, // max_au_size (disabled by default)
|
{}, // max_au_size (disabled by default)
|
||||||
(int) amd::coder_e::_auto, // coder
|
std::to_underlying(amd::coder_e::_auto), // coder
|
||||||
}, // amd
|
}, // amd
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -1021,8 +1021,8 @@ namespace config {
|
|||||||
/**
|
/**
|
||||||
* @brief Parse Sunshine configuration text into key-value entries.
|
* @brief Parse Sunshine configuration text into key-value entries.
|
||||||
*/
|
*/
|
||||||
std::unordered_map<std::string, std::string> parse_config(const std::string_view &file_content) {
|
config_map_t parse_config(const std::string_view &file_content) {
|
||||||
std::unordered_map<std::string, std::string> vars;
|
config_map_t vars;
|
||||||
|
|
||||||
auto pos = std::begin(file_content);
|
auto pos = std::begin(file_content);
|
||||||
auto end = std::end(file_content);
|
auto end = std::end(file_content);
|
||||||
@@ -1081,7 +1081,7 @@ namespace config {
|
|||||||
* @param name Configuration key to consume.
|
* @param name Configuration key to consume.
|
||||||
* @param destination Destination field updated when the setting exists and parses successfully.
|
* @param destination Destination field updated when the setting exists and parses successfully.
|
||||||
*/
|
*/
|
||||||
void string_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::string &destination) {
|
void string_f(config_map_t &vars, const std::string &name, std::string &destination) {
|
||||||
auto it = vars.find(name);
|
auto it = vars.find(name);
|
||||||
if (it == std::end(vars)) {
|
if (it == std::end(vars)) {
|
||||||
return;
|
return;
|
||||||
@@ -1101,7 +1101,7 @@ namespace config {
|
|||||||
* @param f Converter applied to the raw configuration string.
|
* @param f Converter applied to the raw configuration string.
|
||||||
*/
|
*/
|
||||||
template<typename T, typename F>
|
template<typename T, typename F>
|
||||||
void generic_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, T &destination, F &&f) {
|
void generic_f(config_map_t &vars, const std::string &name, T &destination, F &&f) {
|
||||||
std::string tmp;
|
std::string tmp;
|
||||||
string_f(vars, name, tmp);
|
string_f(vars, name, tmp);
|
||||||
if (!tmp.empty()) {
|
if (!tmp.empty()) {
|
||||||
@@ -1117,7 +1117,7 @@ namespace config {
|
|||||||
* @param destination Destination field updated when the setting exists and parses successfully.
|
* @param destination Destination field updated when the setting exists and parses successfully.
|
||||||
* @param allowed_vals Accepted string values for this setting.
|
* @param allowed_vals Accepted string values for this setting.
|
||||||
*/
|
*/
|
||||||
void string_restricted_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::string &destination, const std::vector<std::string_view> &allowed_vals) {
|
void string_restricted_f(config_map_t &vars, const std::string &name, std::string &destination, const std::vector<std::string_view> &allowed_vals) {
|
||||||
std::string temp;
|
std::string temp;
|
||||||
string_f(vars, name, temp);
|
string_f(vars, name, temp);
|
||||||
|
|
||||||
@@ -1136,7 +1136,7 @@ namespace config {
|
|||||||
* @param name Setting name.
|
* @param name Setting name.
|
||||||
* @param output Parsed string list.
|
* @param output Parsed string list.
|
||||||
*/
|
*/
|
||||||
void string_list_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::vector<std::string> &output) { // NOSONAR(cpp:S6045): transparent hasher not available for unordered_map in this codebase
|
void string_list_f(config_map_t &vars, const std::string &name, std::vector<std::string> &output) {
|
||||||
std::string temp;
|
std::string temp;
|
||||||
string_f(vars, name, temp);
|
string_f(vars, name, temp);
|
||||||
|
|
||||||
@@ -1164,7 +1164,7 @@ namespace config {
|
|||||||
* @param name Configuration key to consume.
|
* @param name Configuration key to consume.
|
||||||
* @param destination Destination field updated when the setting exists and parses successfully.
|
* @param destination Destination field updated when the setting exists and parses successfully.
|
||||||
*/
|
*/
|
||||||
void path_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, fs::path &destination) {
|
void path_f(config_map_t &vars, const std::string &name, fs::path &destination) {
|
||||||
// appdata needs to be retrieved once only
|
// appdata needs to be retrieved once only
|
||||||
static auto appdata = platf::appdata();
|
static auto appdata = platf::appdata();
|
||||||
|
|
||||||
@@ -1195,7 +1195,7 @@ namespace config {
|
|||||||
* @param name Configuration key to consume.
|
* @param name Configuration key to consume.
|
||||||
* @param destination Destination field updated when the setting exists and parses successfully.
|
* @param destination Destination field updated when the setting exists and parses successfully.
|
||||||
*/
|
*/
|
||||||
void path_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::string &destination) {
|
void path_f(config_map_t &vars, const std::string &name, std::string &destination) {
|
||||||
fs::path temp = destination;
|
fs::path temp = destination;
|
||||||
|
|
||||||
path_f(vars, name, temp);
|
path_f(vars, name, temp);
|
||||||
@@ -1227,7 +1227,7 @@ namespace config {
|
|||||||
* @param name Configuration key to consume.
|
* @param name Configuration key to consume.
|
||||||
* @param destination Destination field updated when the setting exists and parses successfully.
|
* @param destination Destination field updated when the setting exists and parses successfully.
|
||||||
*/
|
*/
|
||||||
void int_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, int &destination) {
|
void int_f(config_map_t &vars, const std::string &name, int &destination) {
|
||||||
auto it = vars.find(name);
|
auto it = vars.find(name);
|
||||||
|
|
||||||
if (it == std::end(vars)) {
|
if (it == std::end(vars)) {
|
||||||
@@ -1245,7 +1245,7 @@ namespace config {
|
|||||||
* @param name Configuration key to consume.
|
* @param name Configuration key to consume.
|
||||||
* @param destination Destination field updated when the setting exists and parses successfully.
|
* @param destination Destination field updated when the setting exists and parses successfully.
|
||||||
*/
|
*/
|
||||||
void int_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::optional<int> &destination) {
|
void int_f(config_map_t &vars, const std::string &name, std::optional<int> &destination) {
|
||||||
auto it = vars.find(name);
|
auto it = vars.find(name);
|
||||||
|
|
||||||
if (it == std::end(vars)) {
|
if (it == std::end(vars)) {
|
||||||
@@ -1265,7 +1265,7 @@ namespace config {
|
|||||||
* @param f Converter applied to the raw configuration string.
|
* @param f Converter applied to the raw configuration string.
|
||||||
*/
|
*/
|
||||||
template<class F>
|
template<class F>
|
||||||
void int_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, int &destination, F &&f) {
|
void int_f(config_map_t &vars, const std::string &name, int &destination, F &&f) {
|
||||||
std::string tmp;
|
std::string tmp;
|
||||||
string_f(vars, name, tmp);
|
string_f(vars, name, tmp);
|
||||||
if (!tmp.empty()) {
|
if (!tmp.empty()) {
|
||||||
@@ -1282,7 +1282,7 @@ namespace config {
|
|||||||
* @param f Converter applied to the raw configuration string.
|
* @param f Converter applied to the raw configuration string.
|
||||||
*/
|
*/
|
||||||
template<class F>
|
template<class F>
|
||||||
void int_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::optional<int> &destination, F &&f) {
|
void int_f(config_map_t &vars, const std::string &name, std::optional<int> &destination, F &&f) {
|
||||||
std::string tmp;
|
std::string tmp;
|
||||||
string_f(vars, name, tmp);
|
string_f(vars, name, tmp);
|
||||||
if (!tmp.empty()) {
|
if (!tmp.empty()) {
|
||||||
@@ -1298,7 +1298,7 @@ namespace config {
|
|||||||
* @param destination Destination field updated when the setting exists and parses successfully.
|
* @param destination Destination field updated when the setting exists and parses successfully.
|
||||||
* @param range Inclusive range accepted for the parsed value.
|
* @param range Inclusive range accepted for the parsed value.
|
||||||
*/
|
*/
|
||||||
void int_between_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, int &destination, const std::pair<int, int> &range) {
|
void int_between_f(config_map_t &vars, const std::string &name, int &destination, const std::pair<int, int> &range) {
|
||||||
int temp = destination;
|
int temp = destination;
|
||||||
|
|
||||||
int_f(vars, name, temp);
|
int_f(vars, name, temp);
|
||||||
@@ -1335,7 +1335,7 @@ namespace config {
|
|||||||
* @param name Configuration key to consume.
|
* @param name Configuration key to consume.
|
||||||
* @param destination Destination field updated when the setting exists and parses successfully.
|
* @param destination Destination field updated when the setting exists and parses successfully.
|
||||||
*/
|
*/
|
||||||
void bool_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, bool &destination) {
|
void bool_f(config_map_t &vars, const std::string &name, bool &destination) {
|
||||||
std::string tmp;
|
std::string tmp;
|
||||||
string_f(vars, name, tmp);
|
string_f(vars, name, tmp);
|
||||||
|
|
||||||
@@ -1353,7 +1353,7 @@ namespace config {
|
|||||||
* @param name Configuration key to consume.
|
* @param name Configuration key to consume.
|
||||||
* @param destination Destination field updated when the setting exists and parses successfully.
|
* @param destination Destination field updated when the setting exists and parses successfully.
|
||||||
*/
|
*/
|
||||||
void double_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, double &destination) {
|
void double_f(config_map_t &vars, const std::string &name, double &destination) {
|
||||||
std::string tmp;
|
std::string tmp;
|
||||||
string_f(vars, name, tmp);
|
string_f(vars, name, tmp);
|
||||||
|
|
||||||
@@ -1379,7 +1379,7 @@ namespace config {
|
|||||||
* @param destination Destination field updated when the setting exists and parses successfully.
|
* @param destination Destination field updated when the setting exists and parses successfully.
|
||||||
* @param range Inclusive range accepted for the parsed value.
|
* @param range Inclusive range accepted for the parsed value.
|
||||||
*/
|
*/
|
||||||
void double_between_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, double &destination, const std::pair<double, double> &range) {
|
void double_between_f(config_map_t &vars, const std::string &name, double &destination, const std::pair<double, double> &range) {
|
||||||
double temp = destination;
|
double temp = destination;
|
||||||
|
|
||||||
double_f(vars, name, temp);
|
double_f(vars, name, temp);
|
||||||
@@ -1397,7 +1397,7 @@ namespace config {
|
|||||||
* @param name Configuration key to consume.
|
* @param name Configuration key to consume.
|
||||||
* @param destination Destination field updated when the setting exists and parses successfully.
|
* @param destination Destination field updated when the setting exists and parses successfully.
|
||||||
*/
|
*/
|
||||||
void list_string_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::vector<std::string> &destination) {
|
void list_string_f(config_map_t &vars, const std::string &name, std::vector<std::string> &destination) {
|
||||||
std::string string;
|
std::string string;
|
||||||
string_f(vars, name, string);
|
string_f(vars, name, string);
|
||||||
|
|
||||||
@@ -1443,7 +1443,7 @@ namespace config {
|
|||||||
* @param name Configuration key to consume.
|
* @param name Configuration key to consume.
|
||||||
* @param destination Destination field updated when the setting exists and parses successfully.
|
* @param destination Destination field updated when the setting exists and parses successfully.
|
||||||
*/
|
*/
|
||||||
void list_prep_cmd_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::vector<prep_cmd_t> &destination) {
|
void list_prep_cmd_f(config_map_t &vars, const std::string &name, std::vector<prep_cmd_t> &destination) {
|
||||||
std::string string;
|
std::string string;
|
||||||
string_f(vars, name, string);
|
string_f(vars, name, string);
|
||||||
|
|
||||||
@@ -1476,7 +1476,7 @@ namespace config {
|
|||||||
* @param name Configuration key to consume.
|
* @param name Configuration key to consume.
|
||||||
* @param destination Destination field updated when the setting exists and parses successfully.
|
* @param destination Destination field updated when the setting exists and parses successfully.
|
||||||
*/
|
*/
|
||||||
void list_int_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::vector<int> &destination) {
|
void list_int_f(config_map_t &vars, const std::string &name, std::vector<int> &destination) {
|
||||||
std::vector<std::string> list;
|
std::vector<std::string> list;
|
||||||
list_string_f(vars, name, list);
|
list_string_f(vars, name, list);
|
||||||
|
|
||||||
@@ -1516,7 +1516,7 @@ namespace config {
|
|||||||
* @param name Configuration key to consume.
|
* @param name Configuration key to consume.
|
||||||
* @param destination Destination field updated when the setting exists and parses successfully.
|
* @param destination Destination field updated when the setting exists and parses successfully.
|
||||||
*/
|
*/
|
||||||
void map_int_int_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::unordered_map<int, int> &destination) {
|
void map_int_int_f(config_map_t &vars, const std::string &name, std::unordered_map<int, int> &destination) {
|
||||||
std::vector<int> list;
|
std::vector<int> list;
|
||||||
list_int_f(vars, name, list);
|
list_int_f(vars, name, list);
|
||||||
|
|
||||||
@@ -1589,7 +1589,7 @@ namespace config {
|
|||||||
/**
|
/**
|
||||||
* @brief Log parsed configuration entries and optionally record them as modified.
|
* @brief Log parsed configuration entries and optionally record them as modified.
|
||||||
*/
|
*/
|
||||||
void log_config_settings(const std::unordered_map<std::string, std::string> &vars, bool save) {
|
void log_config_settings(const config_map_t &vars, bool save) {
|
||||||
for (auto &[name, val] : vars) {
|
for (auto &[name, val] : vars) {
|
||||||
bool is_redacted = std::ranges::find(config::redacted_config, name) != config::redacted_config.end();
|
bool is_redacted = std::ranges::find(config::redacted_config, name) != config::redacted_config.end();
|
||||||
|
|
||||||
@@ -1606,7 +1606,7 @@ namespace config {
|
|||||||
*
|
*
|
||||||
* @param vars Parsed configuration entries; consumed keys are erased.
|
* @param vars Parsed configuration entries; consumed keys are erased.
|
||||||
*/
|
*/
|
||||||
void apply_config(std::unordered_map<std::string, std::string> &&vars) {
|
void apply_config(config_map_t &&vars) {
|
||||||
log_config_settings(vars, true);
|
log_config_settings(vars, true);
|
||||||
|
|
||||||
int_f(vars, "qp", video.qp);
|
int_f(vars, "qp", video.qp);
|
||||||
@@ -1973,7 +1973,7 @@ namespace config {
|
|||||||
* @brief Parse serialized text into the corresponding runtime representation.
|
* @brief Parse serialized text into the corresponding runtime representation.
|
||||||
*/
|
*/
|
||||||
int parse(int argc, char *argv[]) {
|
int parse(int argc, char *argv[]) {
|
||||||
std::unordered_map<std::string, std::string> cmd_vars;
|
config_map_t cmd_vars;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
bool shortcut_launch = false;
|
bool shortcut_launch = false;
|
||||||
bool service_admin_launch = false;
|
bool service_admin_launch = false;
|
||||||
|
|||||||
+9
-3
@@ -15,8 +15,14 @@
|
|||||||
|
|
||||||
// local includes
|
// local includes
|
||||||
#include "nvenc/nvenc_config.h"
|
#include "nvenc/nvenc_config.h"
|
||||||
|
#include "string_hash.h"
|
||||||
|
|
||||||
namespace config {
|
namespace config {
|
||||||
|
/**
|
||||||
|
* @brief Owning configuration entries supporting lookup by string view or C string.
|
||||||
|
*/
|
||||||
|
using config_map_t = std::unordered_map<std::string, std::string, util::transparent_string_hash, std::equal_to<>>;
|
||||||
|
|
||||||
namespace nv {
|
namespace nv {
|
||||||
/**
|
/**
|
||||||
* @brief Convert Sunshine's NVENC quality preset number to FFmpeg's stable symbolic name.
|
* @brief Convert Sunshine's NVENC quality preset number to FFmpeg's stable symbolic name.
|
||||||
@@ -39,7 +45,7 @@ namespace config {
|
|||||||
inline constexpr std::string_view GAMEPAD_DRIVER_NONE = "none"; ///< Disable virtual gamepads on Windows and macOS.
|
inline constexpr std::string_view GAMEPAD_DRIVER_NONE = "none"; ///< Disable virtual gamepads on Windows and macOS.
|
||||||
|
|
||||||
// track modified config options
|
// track modified config options
|
||||||
inline std::unordered_map<std::string, std::string> modified_config_settings; ///< Configuration keys changed during the current parse or UI update.
|
inline config_map_t modified_config_settings; ///< Configuration keys changed during the current parse or UI update.
|
||||||
|
|
||||||
// sensitive values that should be redacted from logging
|
// sensitive values that should be redacted from logging
|
||||||
/**
|
/**
|
||||||
@@ -55,7 +61,7 @@ namespace config {
|
|||||||
* @param vars Parsed configuration entries to log.
|
* @param vars Parsed configuration entries to log.
|
||||||
* @param save Whether modified configuration values should be written back to disk.
|
* @param save Whether modified configuration values should be written back to disk.
|
||||||
*/
|
*/
|
||||||
void log_config_settings(const std::unordered_map<std::string, std::string> &vars, bool save);
|
void log_config_settings(const config_map_t &vars, bool save);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Video encoder, capture, and color settings loaded from configuration.
|
* @brief Video encoder, capture, and color settings loaded from configuration.
|
||||||
@@ -427,7 +433,7 @@ namespace config {
|
|||||||
* @param file_content Raw configuration file contents to parse.
|
* @param file_content Raw configuration file contents to parse.
|
||||||
* @return Parsed configuration key-value entries.
|
* @return Parsed configuration key-value entries.
|
||||||
*/
|
*/
|
||||||
std::unordered_map<std::string, std::string> parse_config(const std::string_view &file_content);
|
config_map_t parse_config(const std::string_view &file_content);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Persist a configuration option when the active file does not already define it.
|
* @brief Persist a configuration option when the active file does not already define it.
|
||||||
|
|||||||
+1
-1
@@ -274,7 +274,7 @@ namespace confighttp {
|
|||||||
/**
|
/**
|
||||||
* @brief File-extension to MIME-type mapping used when serving the Web UI.
|
* @brief File-extension to MIME-type mapping used when serving the Web UI.
|
||||||
*/
|
*/
|
||||||
const std::map<std::string, std::string> mime_types = {
|
const std::map<std::string, std::string, std::less<>> mime_types = {
|
||||||
{"css", "text/css"},
|
{"css", "text/css"},
|
||||||
{"gif", "image/gif"},
|
{"gif", "image/gif"},
|
||||||
{"htm", "text/html"},
|
{"htm", "text/html"},
|
||||||
|
|||||||
+1
-1
@@ -2109,7 +2109,7 @@ namespace input {
|
|||||||
// the input to the OS. This avoids potentially lengthy lock contention
|
// the input to the OS. This avoids potentially lengthy lock contention
|
||||||
// in the control stream thread while input is being processed by the OS.
|
// in the control stream thread while input is being processed by the OS.
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lg(input->input_queue_lock);
|
std::scoped_lock lg(input->input_queue_lock);
|
||||||
|
|
||||||
// If all entries have already been processed, nothing to do
|
// If all entries have already been processed, nothing to do
|
||||||
if (input->input_queue.empty()) {
|
if (input->input_queue.empty()) {
|
||||||
|
|||||||
+3
-2
@@ -7,6 +7,7 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
// lib includes
|
// lib includes
|
||||||
#include <boost/core/null_deleter.hpp>
|
#include <boost/core/null_deleter.hpp>
|
||||||
@@ -226,8 +227,8 @@ namespace logging {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setup_libdisplaydevice_logging(int min_log_level) {
|
void setup_libdisplaydevice_logging(int min_log_level) {
|
||||||
constexpr int min_level {static_cast<int>(display_device::Logger::LogLevel::verbose)};
|
constexpr int min_level {std::to_underlying(display_device::Logger::LogLevel::verbose)};
|
||||||
constexpr int max_level {static_cast<int>(display_device::Logger::LogLevel::fatal)};
|
constexpr int max_level {std::to_underlying(display_device::Logger::LogLevel::fatal)};
|
||||||
const auto log_level {static_cast<display_device::Logger::LogLevel>(std::min(std::max(min_level, min_log_level), max_level))};
|
const auto log_level {static_cast<display_device::Logger::LogLevel>(std::min(std::max(min_level, min_log_level), max_level))};
|
||||||
|
|
||||||
display_device::Logger::get().setLogLevel(log_level);
|
display_device::Logger::get().setLogLevel(log_level);
|
||||||
|
|||||||
+3
-2
@@ -123,8 +123,9 @@ namespace logging {
|
|||||||
void setup_av_logging(int min_log_level);
|
void setup_av_logging(int min_log_level);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Setup logging for libdisplaydevice.
|
* @brief Set up libdisplaydevice logging, clamping to its supported enum values.
|
||||||
* @param min_log_level The log level.
|
*
|
||||||
|
* @param min_log_level Numeric minimum severity, clamped from verbose through fatal.
|
||||||
*/
|
*/
|
||||||
void setup_libdisplaydevice_logging(int min_log_level);
|
void setup_libdisplaydevice_logging(int min_log_level);
|
||||||
|
|
||||||
|
|||||||
+8
-8
@@ -18,15 +18,15 @@ namespace ip = boost::asio::ip;
|
|||||||
|
|
||||||
namespace net {
|
namespace net {
|
||||||
/**
|
/**
|
||||||
* @brief Pc ips v4.
|
* @brief IPv4 loopback networks used for local-client classification.
|
||||||
*/
|
*/
|
||||||
std::vector<ip::network_v4> pc_ips_v4 {
|
std::vector pc_ips_v4 {
|
||||||
ip::make_network_v4("127.0.0.0/8"sv),
|
ip::make_network_v4("127.0.0.0/8"sv),
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* @brief Lan ips v4.
|
* @brief IPv4 private and link-local networks used for LAN classification.
|
||||||
*/
|
*/
|
||||||
std::vector<ip::network_v4> lan_ips_v4 {
|
std::vector lan_ips_v4 {
|
||||||
ip::make_network_v4("192.168.0.0/16"sv),
|
ip::make_network_v4("192.168.0.0/16"sv),
|
||||||
ip::make_network_v4("172.16.0.0/12"sv),
|
ip::make_network_v4("172.16.0.0/12"sv),
|
||||||
ip::make_network_v4("10.0.0.0/8"sv),
|
ip::make_network_v4("10.0.0.0/8"sv),
|
||||||
@@ -35,15 +35,15 @@ namespace net {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Pc ips v6.
|
* @brief IPv6 loopback networks used for local-client classification.
|
||||||
*/
|
*/
|
||||||
std::vector<ip::network_v6> pc_ips_v6 {
|
std::vector pc_ips_v6 {
|
||||||
ip::make_network_v6("::1/128"sv),
|
ip::make_network_v6("::1/128"sv),
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* @brief Lan ips v6.
|
* @brief IPv6 private and link-local networks used for LAN classification.
|
||||||
*/
|
*/
|
||||||
std::vector<ip::network_v6> lan_ips_v6 {
|
std::vector lan_ips_v6 {
|
||||||
ip::make_network_v6("fc00::/7"sv),
|
ip::make_network_v6("fc00::/7"sv),
|
||||||
ip::make_network_v6("fe80::/64"sv),
|
ip::make_network_v6("fe80::/64"sv),
|
||||||
};
|
};
|
||||||
|
|||||||
+2
-1
@@ -35,6 +35,7 @@
|
|||||||
#include "platform/common.h"
|
#include "platform/common.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "rtsp.h"
|
#include "rtsp.h"
|
||||||
|
#include "string_hash.h"
|
||||||
#include "system_tray.h"
|
#include "system_tray.h"
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
#include "uuid.h"
|
#include "uuid.h"
|
||||||
@@ -191,7 +192,7 @@ namespace nvhttp {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// uniqueID, session
|
// uniqueID, session
|
||||||
std::unordered_map<std::string, pair_session_t> map_id_sess; ///< Pairing sessions keyed by temporary unique ID.
|
std::unordered_map<std::string, pair_session_t, util::transparent_string_hash, std::equal_to<>> map_id_sess; ///< Pairing sessions keyed by temporary unique ID.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the mutex protecting pairing-session state.
|
* @brief Get the mutex protecting pairing-session state.
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
// lib includes
|
// lib includes
|
||||||
#include <ffnvcodec/dynlink_loader.h>
|
#include <ffnvcodec/dynlink_loader.h>
|
||||||
@@ -363,7 +364,7 @@ namespace cuda {
|
|||||||
BOOST_LOG(debug) << "Found CUDA device with PCI bus ID: "sv << pci_bus_id.data();
|
BOOST_LOG(debug) << "Found CUDA device with PCI bus ID: "sv << pci_bus_id.data();
|
||||||
|
|
||||||
// Linux uses lowercase hexadecimal while CUDA uses uppercase
|
// Linux uses lowercase hexadecimal while CUDA uses uppercase
|
||||||
std::transform(pci_bus_id.begin(), pci_bus_id.end(), pci_bus_id.begin(), [](char c) {
|
std::ranges::transform(pci_bus_id, pci_bus_id.begin(), [](char c) {
|
||||||
return std::tolower(c);
|
return std::tolower(c);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1063,7 +1064,7 @@ namespace cuda {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BOOST_LOG(error) << "Unrecognized capture status ["sv << (int) status << ']';
|
BOOST_LOG(error) << "Unrecognized capture status ["sv << std::to_underlying(status) << ']';
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
// local includes
|
// local includes
|
||||||
#include "graphics.h"
|
#include "graphics.h"
|
||||||
@@ -557,7 +558,7 @@ namespace egl {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (auto ext : extensions) {
|
for (auto ext : extensions) {
|
||||||
if (!std::strstr(extension_st, ext)) {
|
if (!std::string_view {extension_st}.contains(ext)) {
|
||||||
BOOST_LOG(error) << "Missing extension: ["sv << ext << ']';
|
BOOST_LOG(error) << "Missing extension: ["sv << ext << ']';
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
// platform includes
|
// platform includes
|
||||||
#include <drm_fourcc.h>
|
#include <drm_fourcc.h>
|
||||||
@@ -1831,7 +1832,7 @@ namespace platf {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BOOST_LOG(error) << "Unrecognized capture status ["sv << (int) status << ']';
|
BOOST_LOG(error) << "Unrecognized capture status ["sv << std::to_underlying(status) << ']';
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2107,7 +2108,7 @@ namespace platf {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BOOST_LOG(error) << "Unrecognized capture status ["sv << (int) status << ']';
|
BOOST_LOG(error) << "Unrecognized capture status ["sv << std::to_underlying(status) << ']';
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
// platform includes
|
// platform includes
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
@@ -1020,7 +1021,7 @@ namespace platf {
|
|||||||
// We can't track QoS state separately for each destination on this OS,
|
// We can't track QoS state separately for each destination on this OS,
|
||||||
// so we keep a ref count to only disable QoS options when all clients
|
// so we keep a ref count to only disable QoS options when all clients
|
||||||
// are disconnected.
|
// are disconnected.
|
||||||
static std::atomic<int> qos_ref_count = 0;
|
static std::atomic qos_ref_count = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Linux QoS state used to tune socket priority while streaming.
|
* @brief Linux QoS state used to tune socket priority while streaming.
|
||||||
@@ -1086,7 +1087,7 @@ namespace platf {
|
|||||||
dscp = 48;
|
dscp = 48;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BOOST_LOG(error) << "Unknown traffic type: "sv << (int) data_type;
|
BOOST_LOG(error) << "Unknown traffic type: "sv << std::to_underlying(data_type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1081,7 +1081,7 @@ namespace portal {
|
|||||||
dbus_t dbus; ///< DBus connection used for portal screencast requests.
|
dbus_t dbus; ///< DBus connection used for portal screencast requests.
|
||||||
|
|
||||||
// Class variable to store runtime state of maxFramerate negotiation
|
// Class variable to store runtime state of maxFramerate negotiation
|
||||||
static inline std::atomic<bool> negotiate_maxframerate {true}; ///< Whether portal negotiation should request the maximum frame rate.
|
static inline std::atomic negotiate_maxframerate {true}; ///< Whether portal negotiation should request the maximum frame rate.
|
||||||
};
|
};
|
||||||
} // namespace portal
|
} // namespace portal
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#ifdef SUNSHINE_TESTS
|
#ifdef SUNSHINE_TESTS
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
@@ -630,7 +631,7 @@ namespace platf {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BOOST_LOG(error) << "Unrecognized capture status ["sv << (int) status << ']';
|
BOOST_LOG(error) << "Unrecognized capture status ["sv << std::to_underlying(status) << ']';
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -804,7 +805,7 @@ namespace platf {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BOOST_LOG(error) << "Unrecognized capture status ["sv << (int) status << ']';
|
BOOST_LOG(error) << "Unrecognized capture status ["sv << std::to_underlying(status) << ']';
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ namespace {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
static_assert((int) sample_format_e::_size == 5, "Unrecognized sample_format_e");
|
static_assert(std::to_underlying(sample_format_e::_size) == 5, "Unrecognized sample_format_e");
|
||||||
|
|
||||||
waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
waveformat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
||||||
waveformat.Format.nChannels = channel_count;
|
waveformat.Format.nChannels = channel_count;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
// platform includes
|
// platform includes
|
||||||
#include <initguid.h>
|
#include <initguid.h>
|
||||||
@@ -353,7 +354,7 @@ namespace platf::dxgi {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BOOST_LOG(error) << "Unrecognized capture status ["sv << (int) status << ']';
|
BOOST_LOG(error) << "Unrecognized capture status ["sv << std::to_underlying(status) << ']';
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1137,7 +1138,7 @@ namespace platf {
|
|||||||
bool needs_encoder_reenumeration() {
|
bool needs_encoder_reenumeration() {
|
||||||
// Serialize access to the static DXGI factory
|
// Serialize access to the static DXGI factory
|
||||||
static std::mutex reenumeration_state_lock;
|
static std::mutex reenumeration_state_lock;
|
||||||
auto lg = std::lock_guard(reenumeration_state_lock);
|
auto lg = std::scoped_lock(reenumeration_state_lock);
|
||||||
|
|
||||||
// Keep a reference to the DXGI factory, which will keep track of changes internally.
|
// Keep a reference to the DXGI factory, which will keep track of changes internally.
|
||||||
static dxgi::factory1_t factory;
|
static dxgi::factory1_t factory;
|
||||||
|
|||||||
@@ -3,8 +3,10 @@
|
|||||||
* @brief Definitions for handling video ram.
|
* @brief Definitions for handling video ram.
|
||||||
*/
|
*/
|
||||||
// standard includes
|
// standard includes
|
||||||
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
// platform includes
|
// platform includes
|
||||||
#include <d3dcompiler.h>
|
#include <d3dcompiler.h>
|
||||||
@@ -286,7 +288,7 @@ namespace platf::dxgi {
|
|||||||
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR:
|
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR:
|
||||||
{
|
{
|
||||||
util::buffer_t<std::uint8_t> cursor_img = img_data;
|
util::buffer_t<std::uint8_t> cursor_img = img_data;
|
||||||
std::for_each((std::uint32_t *) std::begin(cursor_img), (std::uint32_t *) std::end(cursor_img), [](auto &pixel) {
|
std::ranges::for_each(std::span {(std::uint32_t *) std::begin(cursor_img), (std::uint32_t *) std::end(cursor_img)}, [](auto &pixel) {
|
||||||
auto alpha = (std::uint8_t) ((pixel >> 24) & 0xFF);
|
auto alpha = (std::uint8_t) ((pixel >> 24) & 0xFF);
|
||||||
if (alpha == 0xFF) {
|
if (alpha == 0xFF) {
|
||||||
// Pixels with 0xFF alpha will be XOR-blended as is.
|
// Pixels with 0xFF alpha will be XOR-blended as is.
|
||||||
@@ -360,7 +362,7 @@ namespace platf::dxgi {
|
|||||||
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR:
|
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR:
|
||||||
{
|
{
|
||||||
util::buffer_t<std::uint8_t> cursor_img = img_data;
|
util::buffer_t<std::uint8_t> cursor_img = img_data;
|
||||||
std::for_each((std::uint32_t *) std::begin(cursor_img), (std::uint32_t *) std::end(cursor_img), [](auto &pixel) {
|
std::ranges::for_each(std::span {(std::uint32_t *) std::begin(cursor_img), (std::uint32_t *) std::end(cursor_img)}, [](auto &pixel) {
|
||||||
auto alpha = (std::uint8_t) ((pixel >> 24) & 0xFF);
|
auto alpha = (std::uint8_t) ((pixel >> 24) & 0xFF);
|
||||||
if (alpha == 0xFF) {
|
if (alpha == 0xFF) {
|
||||||
// Pixels with 0xFF alpha will be XOR-blended by make_cursor_xor_image().
|
// Pixels with 0xFF alpha will be XOR-blended by make_cursor_xor_image().
|
||||||
|
|||||||
@@ -10,12 +10,14 @@
|
|||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
// lib includes
|
// lib includes
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <boost/asio/ip/address.hpp>
|
#include <boost/asio/ip/address.hpp>
|
||||||
#include <boost/program_options/parsers.hpp>
|
#include <boost/program_options/parsers.hpp>
|
||||||
|
#include <boost/range/algorithm/find_if.hpp>
|
||||||
|
|
||||||
// local includes required before platform includes
|
// local includes required before platform includes
|
||||||
#include "src/boost_process_compat.h"
|
#include "src/boost_process_compat.h"
|
||||||
@@ -100,7 +102,7 @@ extern "C" {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
std::atomic<bool> used_nt_set_timer_resolution = false;
|
std::atomic used_nt_set_timer_resolution = false;
|
||||||
|
|
||||||
bool nt_set_timer_resolution_max() {
|
bool nt_set_timer_resolution_max() {
|
||||||
ULONG maximum;
|
ULONG maximum;
|
||||||
@@ -375,6 +377,8 @@ namespace platf {
|
|||||||
/**
|
/**
|
||||||
* @brief Merge user environment variables into a Windows environment block.
|
* @brief Merge user environment variables into a Windows environment block.
|
||||||
*
|
*
|
||||||
|
* Existing variable names retain their spelling when matched case-insensitively.
|
||||||
|
*
|
||||||
* @param env Environment variables for the child process.
|
* @param env Environment variables for the child process.
|
||||||
* @param shell_token Shell token.
|
* @param shell_token Shell token.
|
||||||
* @return True when the user environment block was merged into `env`.
|
* @return True when the user environment block was merged into `env`.
|
||||||
@@ -394,7 +398,7 @@ namespace platf {
|
|||||||
std::string env_val = env_tuple.substr(env_tuple.find('=') + 1);
|
std::string env_val = env_tuple.substr(env_tuple.find('=') + 1);
|
||||||
|
|
||||||
// Perform a case-insensitive search to see if this variable name already exists
|
// Perform a case-insensitive search to see if this variable name already exists
|
||||||
if (auto itr = std::find_if(env.begin(), env.end(), [&](const auto &e) {
|
if (auto itr = boost::range::find_if(env, [&env_name](const auto &e) {
|
||||||
return boost::iequals(e.get_name(), env_name);
|
return boost::iequals(e.get_name(), env_name);
|
||||||
});
|
});
|
||||||
itr != env.end()) {
|
itr != env.end()) {
|
||||||
@@ -829,7 +833,7 @@ namespace platf {
|
|||||||
// Overriding these predefined keys affects process-wide state, so serialize all calls
|
// Overriding these predefined keys affects process-wide state, so serialize all calls
|
||||||
// to ensure the handle state is consistent while we perform the command query.
|
// to ensure the handle state is consistent while we perform the command query.
|
||||||
static std::mutex per_user_key_mutex;
|
static std::mutex per_user_key_mutex;
|
||||||
auto lg = std::lock_guard(per_user_key_mutex);
|
auto lg = std::scoped_lock(per_user_key_mutex);
|
||||||
|
|
||||||
// Override HKEY_CLASSES_ROOT and HKEY_CURRENT_USER to ensure we query the correct class info
|
// Override HKEY_CLASSES_ROOT and HKEY_CURRENT_USER to ensure we query the correct class info
|
||||||
if (!override_per_user_predefined_keys(token)) {
|
if (!override_per_user_predefined_keys(token)) {
|
||||||
@@ -1027,7 +1031,7 @@ namespace platf {
|
|||||||
auto sunshine_wenv = boost::this_process::wenvironment();
|
auto sunshine_wenv = boost::this_process::wenvironment();
|
||||||
std::wstring path_var_name {L"PATH"};
|
std::wstring path_var_name {L"PATH"};
|
||||||
std::wstring old_path_val;
|
std::wstring old_path_val;
|
||||||
auto itr = std::find_if(sunshine_wenv.cbegin(), sunshine_wenv.cend(), [&](const auto &e) {
|
auto itr = boost::range::find_if(std::as_const(sunshine_wenv), [&path_var_name](const auto &e) {
|
||||||
return boost::iequals(e.get_name(), path_var_name);
|
return boost::iequals(e.get_name(), path_var_name);
|
||||||
});
|
});
|
||||||
if (itr != sunshine_wenv.cend()) {
|
if (itr != sunshine_wenv.cend()) {
|
||||||
@@ -1144,7 +1148,7 @@ namespace platf {
|
|||||||
win32_priority = THREAD_PRIORITY_HIGHEST;
|
win32_priority = THREAD_PRIORITY_HIGHEST;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BOOST_LOG(error) << "Unknown thread priority: "sv << (int) priority;
|
BOOST_LOG(error) << "Unknown thread priority: "sv << std::to_underlying(priority);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1749,7 +1753,7 @@ namespace platf {
|
|||||||
traffic_type = QOSTrafficTypeAudioVideo;
|
traffic_type = QOSTrafficTypeAudioVideo;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BOOST_LOG(error) << "Unknown traffic type: "sv << (int) data_type;
|
BOOST_LOG(error) << "Unknown traffic type: "sv << std::to_underlying(data_type);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-3
@@ -5,10 +5,12 @@
|
|||||||
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
|
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
|
||||||
|
|
||||||
// standard includes
|
// standard includes
|
||||||
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
// lib includes
|
// lib includes
|
||||||
@@ -18,6 +20,7 @@
|
|||||||
#include <boost/program_options/parsers.hpp>
|
#include <boost/program_options/parsers.hpp>
|
||||||
#include <boost/property_tree/json_parser.hpp>
|
#include <boost/property_tree/json_parser.hpp>
|
||||||
#include <boost/property_tree/ptree.hpp>
|
#include <boost/property_tree/ptree.hpp>
|
||||||
|
#include <boost/range/algorithm/find_if.hpp>
|
||||||
#include <boost/token_functions.hpp>
|
#include <boost/token_functions.hpp>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
@@ -130,7 +133,7 @@ namespace proc {
|
|||||||
BOOST_LOG(debug) << "Parsed target ["sv << parts.at(0) << "] from command ["sv << cmd << ']';
|
BOOST_LOG(debug) << "Parsed target ["sv << parts.at(0) << "] from command ["sv << cmd << ']';
|
||||||
|
|
||||||
// If the target is a URL, don't parse any further here
|
// If the target is a URL, don't parse any further here
|
||||||
if (parts.at(0).find("://") != std::string::npos) {
|
if (parts.at(0).contains("://")) {
|
||||||
return boost::filesystem::path();
|
return boost::filesystem::path();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,7 +498,7 @@ namespace proc {
|
|||||||
// Windows treats environment variable names in a case-insensitive manner,
|
// Windows treats environment variable names in a case-insensitive manner,
|
||||||
// so we look for a case-insensitive match here. This is critical for
|
// so we look for a case-insensitive match here. This is critical for
|
||||||
// correctly appending to PATH on Windows.
|
// correctly appending to PATH on Windows.
|
||||||
auto itr = std::find_if(env.cbegin(), env.cend(), [&](const auto &e) {
|
auto itr = boost::range::find_if(std::as_const(env), [&var_name](const auto &e) {
|
||||||
return boost::iequals(e.get_name(), var_name);
|
return boost::iequals(e.get_name(), var_name);
|
||||||
});
|
});
|
||||||
if (itr != env.cend()) {
|
if (itr != env.cend()) {
|
||||||
@@ -715,7 +718,7 @@ namespace proc {
|
|||||||
this_env[name] = parse_env_val(this_env, val.get_value<std::string>());
|
this_env[name] = parse_env_val(this_env, val.get_value<std::string>());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<std::string> ids;
|
std::set<std::string, std::less<>> ids;
|
||||||
std::vector<proc::ctx_t> apps;
|
std::vector<proc::ctx_t> apps;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (auto &[_, app_node] : apps_node) {
|
for (auto &[_, app_node] : apps_node) {
|
||||||
|
|||||||
+3
-3
@@ -375,7 +375,7 @@ namespace rtsp_stream {
|
|||||||
// If content_length > bytes read, then we need to store current data read,
|
// If content_length > bytes read, then we need to store current data read,
|
||||||
// to be appended by the next read.
|
// to be appended by the next read.
|
||||||
std::string_view content {option->content};
|
std::string_view content {option->content};
|
||||||
auto begin = std::find_if(std::begin(content), std::end(content), [](auto ch) {
|
auto begin = std::ranges::find_if(content, [](auto ch) {
|
||||||
return (bool) std::isdigit(ch);
|
return (bool) std::isdigit(ch);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1019,7 +1019,7 @@ namespace rtsp_stream {
|
|||||||
seqn.content = const_cast<char *>(seqn_str.c_str());
|
seqn.content = const_cast<char *>(seqn_str.c_str());
|
||||||
|
|
||||||
std::string_view target {req->message.request.target};
|
std::string_view target {req->message.request.target};
|
||||||
auto begin = std::find(std::begin(target), std::end(target), '=') + 1;
|
auto begin = std::ranges::find(target, '=') + 1;
|
||||||
auto end = std::find(begin, std::end(target), '/');
|
auto end = std::find(begin, std::end(target), '/');
|
||||||
std::string_view type {begin, (size_t) std::distance(begin, end)};
|
std::string_view type {begin, (size_t) std::distance(begin, end)};
|
||||||
|
|
||||||
@@ -1220,7 +1220,7 @@ namespace rtsp_stream {
|
|||||||
if ("Host"sv == request_option->option) {
|
if ("Host"sv == request_option->option) {
|
||||||
std::string_view content {request_option->content};
|
std::string_view content {request_option->content};
|
||||||
BOOST_LOG(debug) << "Found Host: "sv << content;
|
BOOST_LOG(debug) << "Found Host: "sv << content;
|
||||||
config.audio.flags[audio::config_t::HIGH_QUALITY] = (content.find("0.0.0.0"sv) == std::string::npos);
|
config.audio.flags[audio::config_t::HIGH_QUALITY] = !content.contains("0.0.0.0"sv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (session.surround_params.length() > 3) {
|
} else if (session.surround_params.length() > 3) {
|
||||||
|
|||||||
+3
-3
@@ -367,7 +367,7 @@ namespace stream {
|
|||||||
static inline int encode_audio(bool encrypted, const audio::buffer_t &plaintext, uint8_t *destination, crypto::aes_t &iv, crypto::cipher::cbc_t &cbc) {
|
static inline int encode_audio(bool encrypted, const audio::buffer_t &plaintext, uint8_t *destination, crypto::aes_t &iv, crypto::cipher::cbc_t &cbc) {
|
||||||
// If encryption isn't enabled
|
// If encryption isn't enabled
|
||||||
if (!encrypted) {
|
if (!encrypted) {
|
||||||
std::copy(std::begin(plaintext), std::end(plaintext), destination);
|
std::ranges::copy(plaintext, destination);
|
||||||
return (int) plaintext.size();
|
return (int) plaintext.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1000,7 +1000,7 @@ namespace stream {
|
|||||||
|
|
||||||
std::copy(begin, next, std::back_inserter(replaced));
|
std::copy(begin, next, std::back_inserter(replaced));
|
||||||
if (next != end) {
|
if (next != end) {
|
||||||
std::copy(std::begin(_new), std::end(_new), std::back_inserter(replaced));
|
std::ranges::copy(_new, std::back_inserter(replaced));
|
||||||
std::copy(next + old.size(), end, std::back_inserter(replaced));
|
std::copy(next + old.size(), end, std::back_inserter(replaced));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2116,7 +2116,7 @@ namespace stream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TUPLE_2D_REF(recv_peer, msg, *msg_opt);
|
TUPLE_2D_REF(recv_peer, msg, *msg_opt);
|
||||||
if (msg.find(expected_payload) != std::string::npos) {
|
if (msg.contains(expected_payload)) {
|
||||||
// Match the new PING payload format
|
// Match the new PING payload format
|
||||||
BOOST_LOG(debug) << "Received ping [v2] from "sv << recv_peer.address() << ':' << recv_peer.port() << " ["sv << util::hex_vec(msg) << ']';
|
BOOST_LOG(debug) << "Received ping [v2] from "sv << recv_peer.address() << ':' << recv_peer.port() << " ["sv << util::hex_vec(msg) << ']';
|
||||||
} else if (!(session->config.mlFeatureFlags & ML_FF_SESSION_ID_V1) && msg == "PING"sv) {
|
} else if (!(session->config.mlFeatureFlags & ML_FF_SESSION_ID_V1) && msg == "PING"sv) {
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* @file src/string_hash.h
|
||||||
|
* @brief Transparent hashing for containers with owning string keys.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// standard includes
|
||||||
|
#include <cstddef>
|
||||||
|
#include <functional>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace util {
|
||||||
|
/**
|
||||||
|
* @brief Hash strings, string views, and C strings without temporary allocations.
|
||||||
|
*/
|
||||||
|
struct transparent_string_hash {
|
||||||
|
using is_transparent = void; ///< Enable heterogeneous unordered-container lookup.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Hash all characters in a string-like key, including embedded nulls in views.
|
||||||
|
*
|
||||||
|
* @param value Text to hash.
|
||||||
|
* @return Hash shared by equivalent owning and non-owning string keys.
|
||||||
|
*/
|
||||||
|
std::size_t operator()(std::string_view value) const noexcept {
|
||||||
|
return std::hash<std::string_view> {}(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace util
|
||||||
+3
-3
@@ -29,10 +29,10 @@ namespace sync_util {
|
|||||||
/**
|
/**
|
||||||
* @brief Acquire the underlying lock or keyed mutex.
|
* @brief Acquire the underlying lock or keyed mutex.
|
||||||
*
|
*
|
||||||
* @return Lock guard owning the synchronized object until destruction.
|
* @return Scoped lock owning the synchronized object until destruction.
|
||||||
*/
|
*/
|
||||||
std::lock_guard<mutex_t> lock() {
|
std::scoped_lock<mutex_t> lock() {
|
||||||
return std::lock_guard {_lock};
|
return std::scoped_lock {_lock};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+2
-18
@@ -77,6 +77,7 @@
|
|||||||
#include "platform/common.h"
|
#include "platform/common.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "src/entry_handler.h"
|
#include "src/entry_handler.h"
|
||||||
|
#include "string_hash.h"
|
||||||
#include "system_tray.h"
|
#include "system_tray.h"
|
||||||
#include "thread_safe.h"
|
#include "thread_safe.h"
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -118,23 +119,6 @@ namespace system_tray {
|
|||||||
return worker;
|
return worker;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Hash string-like resource paths without allocating temporary strings.
|
|
||||||
*/
|
|
||||||
struct transparent_string_hash_t {
|
|
||||||
using is_transparent = void; ///< Enable heterogeneous unordered-map lookup.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Hash a string view.
|
|
||||||
*
|
|
||||||
* @param value String view to hash.
|
|
||||||
* @return Hash value for the supplied text.
|
|
||||||
*/
|
|
||||||
std::size_t operator()(const std::string_view value) const noexcept {
|
|
||||||
return std::hash<std::string_view> {}(value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(__APPLE__)
|
#if defined(_WIN32) || defined(__APPLE__)
|
||||||
/**
|
/**
|
||||||
* @brief Access storage for dynamic Virtual HID Broker license menu labels.
|
* @brief Access storage for dynamic Virtual HID Broker license menu labels.
|
||||||
@@ -629,7 +613,7 @@ namespace system_tray {
|
|||||||
|
|
||||||
#if defined(_WIN32) || defined(__APPLE__)
|
#if defined(_WIN32) || defined(__APPLE__)
|
||||||
// Simple cache ensures our string pointers live forever.
|
// Simple cache ensures our string pointers live forever.
|
||||||
static std::unordered_map<std::string, std::string, transparent_string_hash_t, std::equal_to<>> g_cache;
|
static std::unordered_map<std::string, std::string, util::transparent_string_hash, std::equal_to<>> g_cache;
|
||||||
auto search = g_cache.find(std::string_view {relativePath});
|
auto search = g_cache.find(std::string_view {relativePath});
|
||||||
if (search != g_cache.end()) {
|
if (search != g_cache.end()) {
|
||||||
return search->second.c_str();
|
return search->second.c_str();
|
||||||
|
|||||||
+9
-9
@@ -154,7 +154,7 @@ namespace task_pool_util {
|
|||||||
|
|
||||||
auto future = task.get_future();
|
auto future = task.get_future();
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lg(_task_mutex);
|
std::scoped_lock lg(_task_mutex);
|
||||||
_tasks.emplace_back(toRunnable(std::move(task)));
|
_tasks.emplace_back(toRunnable(std::move(task)));
|
||||||
|
|
||||||
return future;
|
return future;
|
||||||
@@ -166,7 +166,7 @@ namespace task_pool_util {
|
|||||||
* @param task Task object to enqueue or execute.
|
* @param task Task object to enqueue or execute.
|
||||||
*/
|
*/
|
||||||
void pushDelayed(std::pair<__time_point, __task> &&task) {
|
void pushDelayed(std::pair<__time_point, __task> &&task) {
|
||||||
std::lock_guard lg(_task_mutex);
|
std::scoped_lock lg(_task_mutex);
|
||||||
|
|
||||||
auto it = _timer_tasks.cbegin();
|
auto it = _timer_tasks.cbegin();
|
||||||
for (; it < _timer_tasks.cend(); ++it) {
|
for (; it < _timer_tasks.cend(); ++it) {
|
||||||
@@ -221,7 +221,7 @@ namespace task_pool_util {
|
|||||||
*/
|
*/
|
||||||
template<class X, class Y>
|
template<class X, class Y>
|
||||||
void delay(task_id_t task_id, std::chrono::duration<X, Y> duration) {
|
void delay(task_id_t task_id, std::chrono::duration<X, Y> duration) {
|
||||||
std::lock_guard<std::mutex> lg(_task_mutex);
|
std::scoped_lock lg(_task_mutex);
|
||||||
|
|
||||||
auto it = _timer_tasks.begin();
|
auto it = _timer_tasks.begin();
|
||||||
for (; it < _timer_tasks.cend(); ++it) {
|
for (; it < _timer_tasks.cend(); ++it) {
|
||||||
@@ -257,7 +257,7 @@ namespace task_pool_util {
|
|||||||
* @return True when the task was found and cancelled.
|
* @return True when the task was found and cancelled.
|
||||||
*/
|
*/
|
||||||
bool cancel(task_id_t task_id) {
|
bool cancel(task_id_t task_id) {
|
||||||
std::lock_guard lg(_task_mutex);
|
std::scoped_lock lg(_task_mutex);
|
||||||
|
|
||||||
auto it = _timer_tasks.begin();
|
auto it = _timer_tasks.begin();
|
||||||
for (; it < _timer_tasks.cend(); ++it) {
|
for (; it < _timer_tasks.cend(); ++it) {
|
||||||
@@ -280,9 +280,9 @@ namespace task_pool_util {
|
|||||||
* @return Removed queue item, or empty result when the queue is stopped or empty.
|
* @return Removed queue item, or empty result when the queue is stopped or empty.
|
||||||
*/
|
*/
|
||||||
std::optional<std::pair<__time_point, __task>> pop(task_id_t task_id) {
|
std::optional<std::pair<__time_point, __task>> pop(task_id_t task_id) {
|
||||||
std::lock_guard lg(_task_mutex);
|
std::scoped_lock lg(_task_mutex);
|
||||||
|
|
||||||
auto pos = std::find_if(std::begin(_timer_tasks), std::end(_timer_tasks), [&task_id](const auto &t) {
|
auto pos = std::ranges::find_if(_timer_tasks, [&task_id](const auto &t) {
|
||||||
return t.second.get() == task_id;
|
return t.second.get() == task_id;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -299,7 +299,7 @@ namespace task_pool_util {
|
|||||||
* @return Removed queue item, or empty result when the queue is stopped or empty.
|
* @return Removed queue item, or empty result when the queue is stopped or empty.
|
||||||
*/
|
*/
|
||||||
std::optional<__task> pop() {
|
std::optional<__task> pop() {
|
||||||
std::lock_guard lg(_task_mutex);
|
std::scoped_lock lg(_task_mutex);
|
||||||
|
|
||||||
if (!_tasks.empty()) {
|
if (!_tasks.empty()) {
|
||||||
__task task = std::move(_tasks.front());
|
__task task = std::move(_tasks.front());
|
||||||
@@ -322,7 +322,7 @@ namespace task_pool_util {
|
|||||||
* @return True when the task was found and cancelled.
|
* @return True when the task was found and cancelled.
|
||||||
*/
|
*/
|
||||||
bool ready() {
|
bool ready() {
|
||||||
std::lock_guard<std::mutex> lg(_task_mutex);
|
std::scoped_lock lg(_task_mutex);
|
||||||
|
|
||||||
return !_tasks.empty() || (!_timer_tasks.empty() && std::get<0>(_timer_tasks.back()) <= std::chrono::steady_clock::now());
|
return !_tasks.empty() || (!_timer_tasks.empty() && std::get<0>(_timer_tasks.back()) <= std::chrono::steady_clock::now());
|
||||||
}
|
}
|
||||||
@@ -333,7 +333,7 @@ namespace task_pool_util {
|
|||||||
* @return Time point for the next queued timer task, or std::nullopt when none exist.
|
* @return Time point for the next queued timer task, or std::nullopt when none exist.
|
||||||
*/
|
*/
|
||||||
std::optional<__time_point> next() {
|
std::optional<__time_point> next() {
|
||||||
std::lock_guard<std::mutex> lg(_task_mutex);
|
std::scoped_lock lg(_task_mutex);
|
||||||
|
|
||||||
if (_timer_tasks.empty()) {
|
if (_timer_tasks.empty()) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
|||||||
+6
-6
@@ -640,7 +640,7 @@ namespace util {
|
|||||||
return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z');
|
return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z');
|
||||||
};
|
};
|
||||||
|
|
||||||
auto buf_size = std::count_if(std::begin(hex), std::end(hex), is_convertable) / 2;
|
auto buf_size = std::ranges::count_if(hex, is_convertable) / 2;
|
||||||
auto padding = sizeof(T) - buf_size;
|
auto padding = sizeof(T) - buf_size;
|
||||||
|
|
||||||
const char *data = hex.data() + hex.size() - 1;
|
const char *data = hex.data() + hex.size() - 1;
|
||||||
@@ -671,7 +671,7 @@ namespace util {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (rev) {
|
if (rev) {
|
||||||
std::reverse(std::begin(buf), std::end(buf));
|
std::ranges::reverse(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::bit_cast<T>(buf);
|
return std::bit_cast<T>(buf);
|
||||||
@@ -695,7 +695,7 @@ namespace util {
|
|||||||
return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z');
|
return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z');
|
||||||
};
|
};
|
||||||
|
|
||||||
auto buf_size = std::count_if(std::begin(hex), std::end(hex), is_convertable) / 2;
|
auto buf_size = std::ranges::count_if(hex, is_convertable) / 2;
|
||||||
buf.resize(buf_size);
|
buf.resize(buf_size);
|
||||||
|
|
||||||
const char *data = hex.data() + hex.size() - 1;
|
const char *data = hex.data() + hex.size() - 1;
|
||||||
@@ -724,7 +724,7 @@ namespace util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rev) {
|
if (rev) {
|
||||||
std::reverse(std::begin(buf), std::end(buf));
|
std::ranges::reverse(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
@@ -1477,14 +1477,14 @@ namespace util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Construct an owning contiguous buffer.
|
* @brief Copy the source buffer's logical range into an independent allocation.
|
||||||
*
|
*
|
||||||
* @param o Source object used for comparison or assignment.
|
* @param o Source object used for comparison or assignment.
|
||||||
*/
|
*/
|
||||||
buffer_t(const buffer_t &o):
|
buffer_t(const buffer_t &o):
|
||||||
_els {o._els},
|
_els {o._els},
|
||||||
_buf(_els) {
|
_buf(_els) {
|
||||||
std::copy(o.begin(), o.end(), begin());
|
std::ranges::copy(o, begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+2
-2
@@ -77,12 +77,12 @@ namespace uuid_util {
|
|||||||
auto last_slice = hex_view.substr(20, 12);
|
auto last_slice = hex_view.substr(20, 12);
|
||||||
|
|
||||||
for (auto &slice : slices) {
|
for (auto &slice : slices) {
|
||||||
std::copy(std::begin(slice), std::end(slice), std::back_inserter(result));
|
std::ranges::copy(slice, std::back_inserter(result));
|
||||||
|
|
||||||
result.push_back('-');
|
result.push_back('-');
|
||||||
}
|
}
|
||||||
|
|
||||||
std::copy(std::begin(last_slice), std::end(last_slice), std::back_inserter(result));
|
std::ranges::copy(last_slice, std::back_inserter(result));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ namespace log_checker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check if a log file contains a line that contains the given substring.
|
* @brief Check whether any log line contains the substring, including an empty substring.
|
||||||
* @param log_file Path to the log file.
|
* @param log_file Path to the log file.
|
||||||
* @param substr The substring to search for.
|
* @param substr The substring to search for.
|
||||||
* @param case_insensitive Whether the search should be case-insensitive.
|
* @param case_insensitive Whether the search should be case-insensitive.
|
||||||
@@ -122,7 +122,7 @@ namespace log_checker {
|
|||||||
// sonarcloud complains about this, but the solution doesn't work for macOS-12
|
// sonarcloud complains about this, but the solution doesn't work for macOS-12
|
||||||
std::transform(line.begin(), line.end(), line.begin(), ::tolower);
|
std::transform(line.begin(), line.end(), line.begin(), ::tolower);
|
||||||
}
|
}
|
||||||
if (line.find(search_str) != std::string::npos) {
|
if (line.contains(search_str)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// standard includes
|
// standard includes
|
||||||
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@@ -87,6 +88,27 @@ TEST(WindowsCursorTest, StopsAtTheLastPixelInAPartialMaskByte) {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(WindowsCursorTest, ProcessesEveryMaskedColorPixelAndPreservesTheInput) {
|
||||||
|
const std::array<std::uint32_t, 3> pixels {0xFF112233, 0x00123456, 0x7F445566};
|
||||||
|
const auto bytes = std::bit_cast<std::array<std::uint8_t, 12>>(pixels);
|
||||||
|
util::buffer_t<std::uint8_t> input {bytes.size()};
|
||||||
|
std::ranges::copy(bytes, input.begin());
|
||||||
|
const DXGI_OUTDUPL_POINTER_SHAPE_INFO shape {
|
||||||
|
.Type = DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR,
|
||||||
|
.Width = 3,
|
||||||
|
.Height = 1,
|
||||||
|
.Pitch = 12,
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto alpha = platf::dxgi::make_cursor_alpha_image(input, shape);
|
||||||
|
const auto xor_image = platf::dxgi::make_cursor_xor_image(input, shape);
|
||||||
|
const std::array<std::uint32_t, 3> expected_alpha {0, 0xFF123456, 0x7F445566};
|
||||||
|
const std::array<std::uint32_t, 3> expected_xor {0xFF112233, 0, 0x7F445566};
|
||||||
|
EXPECT_TRUE((std::ranges::equal(alpha, std::bit_cast<std::array<std::uint8_t, 12>>(expected_alpha))));
|
||||||
|
EXPECT_TRUE((std::ranges::equal(xor_image, std::bit_cast<std::array<std::uint8_t, 12>>(expected_xor))));
|
||||||
|
EXPECT_TRUE(std::ranges::equal(input, bytes));
|
||||||
|
}
|
||||||
|
|
||||||
using platf::dxgi::fp16_transfer_e;
|
using platf::dxgi::fp16_transfer_e;
|
||||||
using platf::dxgi::select_fp16_transfer;
|
using platf::dxgi::select_fp16_transfer;
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,20 @@
|
|||||||
|
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
|
|
||||||
|
TEST(ConfigParsingTest, ParsedEntriesOwnKeysAndSupportStringViewLookup) {
|
||||||
|
std::string input = "encoder = software\nencoder = nvenc\n";
|
||||||
|
const auto entries = config::parse_config(input);
|
||||||
|
input.assign(input.size(), 'x');
|
||||||
|
|
||||||
|
const std::string padded = "__encoder__";
|
||||||
|
const auto key = std::string_view {padded}.substr(2, 7);
|
||||||
|
const auto found = entries.find(key);
|
||||||
|
ASSERT_NE(found, entries.end());
|
||||||
|
EXPECT_EQ(found->second, "software");
|
||||||
|
EXPECT_FALSE(entries.contains("missing"sv));
|
||||||
|
EXPECT_EQ(entries.size(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ConfigDefaultsTest, UsesAutomaticGamepadSelection) {
|
TEST(ConfigDefaultsTest, UsesAutomaticGamepadSelection) {
|
||||||
EXPECT_EQ(config::input.gamepad, "auto");
|
EXPECT_EQ(config::input.gamepad, "auto");
|
||||||
}
|
}
|
||||||
@@ -28,6 +42,19 @@ TEST(ConfigDefaultsTest, TreatsFp16SdrCapturesAsLinear) {
|
|||||||
EXPECT_FALSE(config::video.fp16_sdr_gamma_encoded);
|
EXPECT_FALSE(config::video.fp16_sdr_gamma_encoded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ConfigDefaultsTest, PreservesAmdEncoderNumericDefaults) {
|
||||||
|
EXPECT_EQ(config::video.amd.amd_usage_h264, 1);
|
||||||
|
EXPECT_EQ(config::video.amd.amd_usage_hevc, 1);
|
||||||
|
EXPECT_EQ(config::video.amd.amd_usage_av1, 2);
|
||||||
|
EXPECT_EQ(config::video.amd.amd_rc_h264, 3);
|
||||||
|
EXPECT_EQ(config::video.amd.amd_rc_hevc, 1);
|
||||||
|
EXPECT_EQ(config::video.amd.amd_rc_av1, 1);
|
||||||
|
EXPECT_EQ(config::video.amd.amd_quality_h264, 0);
|
||||||
|
EXPECT_EQ(config::video.amd.amd_quality_hevc, 5);
|
||||||
|
EXPECT_EQ(config::video.amd.amd_quality_av1, 70);
|
||||||
|
EXPECT_EQ(config::video.amd.amd_coder, 0);
|
||||||
|
}
|
||||||
|
|
||||||
using NvencPresetNameParam = std::pair<int, std::string_view>;
|
using NvencPresetNameParam = std::pair<int, std::string_view>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -127,6 +127,18 @@ TEST_F(LogRotationTest, ReportsFilesystemErrors) {
|
|||||||
EXPECT_EQ(read_log_file(log_path), "current");
|
EXPECT_EQ(read_log_file(log_path), "current");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(LogRotationTest, FindsSubstringsAtBoundariesAndWithCaseFolding) {
|
||||||
|
write_log_file(log_path, "prefix middle suffix\nMiXeD\n\n");
|
||||||
|
const auto path = log_path.string();
|
||||||
|
EXPECT_TRUE(log_checker::line_contains(path, "prefix"));
|
||||||
|
EXPECT_TRUE(log_checker::line_contains(path, "middle"));
|
||||||
|
EXPECT_TRUE(log_checker::line_contains(path, "suffix"));
|
||||||
|
EXPECT_TRUE(log_checker::line_contains(path, ""));
|
||||||
|
EXPECT_TRUE(log_checker::line_contains(path, "mixed", true));
|
||||||
|
EXPECT_FALSE(log_checker::line_contains(path, "mixed"));
|
||||||
|
EXPECT_FALSE(log_checker::line_contains(path, "absent"));
|
||||||
|
}
|
||||||
|
|
||||||
struct LogLevelsTest: BaseTest, testing::WithParamInterface<decltype(log_levels)::value_type> {};
|
struct LogLevelsTest: BaseTest, testing::WithParamInterface<decltype(log_levels)::value_type> {};
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
|
|||||||
@@ -9,6 +9,18 @@
|
|||||||
// local includes
|
// local includes
|
||||||
#include <src/network.h>
|
#include <src/network.h>
|
||||||
|
|
||||||
|
TEST(NetworkClassificationTest, DeducedNetworkListsPreserveAddressScopes) {
|
||||||
|
EXPECT_EQ(net::from_address("127.0.0.1"), net::PC);
|
||||||
|
EXPECT_EQ(net::from_address("192.168.1.2"), net::LAN);
|
||||||
|
EXPECT_EQ(net::from_address("100.64.0.1"), net::LAN);
|
||||||
|
EXPECT_EQ(net::from_address("169.254.1.2"), net::LAN);
|
||||||
|
EXPECT_EQ(net::from_address("8.8.8.8"), net::WAN);
|
||||||
|
EXPECT_EQ(net::from_address("::1"), net::PC);
|
||||||
|
EXPECT_EQ(net::from_address("fc00::1"), net::LAN);
|
||||||
|
EXPECT_EQ(net::from_address("fe80::1"), net::LAN);
|
||||||
|
EXPECT_EQ(net::from_address("2001:4860:4860::8888"), net::WAN);
|
||||||
|
}
|
||||||
|
|
||||||
struct MdnsInstanceNameTest: BaseTest, testing::WithParamInterface<std::tuple<std::string, std::string>> {};
|
struct MdnsInstanceNameTest: BaseTest, testing::WithParamInterface<std::tuple<std::string, std::string>> {};
|
||||||
|
|
||||||
TEST_P(MdnsInstanceNameTest, Run) {
|
TEST_P(MdnsInstanceNameTest, Run) {
|
||||||
|
|||||||
@@ -15,9 +15,57 @@
|
|||||||
|
|
||||||
// local includes
|
// local includes
|
||||||
#include <src/process.h>
|
#include <src/process.h>
|
||||||
|
#include <src/utility.h>
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
namespace proc {
|
||||||
|
/**
|
||||||
|
* @brief Resolve a command's working directory, returning an empty path for URLs.
|
||||||
|
*
|
||||||
|
* @param cmd Command line to inspect.
|
||||||
|
* @param env Environment used for executable lookup.
|
||||||
|
* @return Working directory, or an empty path when the command is a URL.
|
||||||
|
*/
|
||||||
|
boost::filesystem::path find_working_directory(const std::string &cmd, boost::process::v1::environment &env);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Expand environment references while preserving Windows variable-name casing.
|
||||||
|
*
|
||||||
|
* @param env Environment whose variables are expanded.
|
||||||
|
* @param val_raw Text containing variable references.
|
||||||
|
* @return Text with environment references expanded.
|
||||||
|
*/
|
||||||
|
std::string parse_env_val(boost::process::v1::native_environment &env, const std::string_view &val_raw);
|
||||||
|
} // namespace proc
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
TEST(ProcessTest, ExpandsEnvironmentNamesWithoutChangingTheirCase) {
|
||||||
|
auto env = boost::this_process::environment();
|
||||||
|
const std::string key = "SUNSHINE_RANGE_SEARCH_REGRESSION";
|
||||||
|
const auto original = env.find(key);
|
||||||
|
const std::optional<std::string> saved = original == env.end() ? std::nullopt : std::optional {original->to_string()};
|
||||||
|
const auto restore = util::fail_guard([&env, &key, &saved]() {
|
||||||
|
if (saved.has_value()) {
|
||||||
|
env[key] = *saved;
|
||||||
|
} else {
|
||||||
|
env[key].clear();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
env[key] = "case-preserved";
|
||||||
|
|
||||||
|
EXPECT_EQ(proc::parse_env_val(env, "before-$(sunshine_range_search_regression)-after"), "before-case-preserved-after");
|
||||||
|
EXPECT_EQ(proc::parse_env_val(env, "$(SUNSHINE_RANGE_SEARCH_REGRESSION)"), "case-preserved");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TEST(ProcessTest, UrlCommandsDoNotResolveAnExecutableWorkingDirectory) {
|
||||||
|
boost::process::v1::environment env;
|
||||||
|
EXPECT_TRUE(proc::find_working_directory("https://example.com", env).empty());
|
||||||
|
EXPECT_TRUE(proc::find_working_directory("steam://run/123", env).empty());
|
||||||
|
EXPECT_TRUE(proc::find_working_directory("custom+scheme://host/path", env).empty());
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ProcessTest, PrepareCommand) {
|
TEST(ProcessTest, PrepareCommand) {
|
||||||
#ifdef SUNSHINE_BUILD_FLATPAK
|
#ifdef SUNSHINE_BUILD_FLATPAK
|
||||||
EXPECT_EQ(proc::prepare_command("steam"), "flatpak-spawn --host steam");
|
EXPECT_EQ(proc::prepare_command("steam"), "flatpak-spawn --host steam");
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* @file tests/unit/test_string_hash.cpp
|
||||||
|
* @brief Regression coverage for heterogeneous owning-string containers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// test includes
|
||||||
|
#include "../tests_common.h"
|
||||||
|
|
||||||
|
// standard includes
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
// local includes
|
||||||
|
#include <src/string_hash.h>
|
||||||
|
|
||||||
|
TEST(TransparentStringHashTest, EquivalentKeyRepresentationsFindTheSameEntry) {
|
||||||
|
const std::string key(128, 'k');
|
||||||
|
const std::string padded = "prefix" + key + "suffix";
|
||||||
|
const auto view = std::string_view {padded}.substr(6, key.size());
|
||||||
|
std::unordered_map<std::string, int, util::transparent_string_hash, std::equal_to<>> entries {{key, 42}};
|
||||||
|
|
||||||
|
EXPECT_EQ(entries.find(key)->second, 42);
|
||||||
|
EXPECT_EQ(entries.find(key.c_str())->second, 42);
|
||||||
|
EXPECT_EQ(entries.find(view)->second, 42);
|
||||||
|
EXPECT_FALSE(entries.contains(std::string_view {padded}));
|
||||||
|
EXPECT_EQ(entries.size(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TransparentStringHashTest, EmptyAndEmbeddedNullKeysRetainTheirLengths) {
|
||||||
|
using namespace std::literals;
|
||||||
|
std::unordered_map<std::string, int, util::transparent_string_hash, std::equal_to<>> entries {
|
||||||
|
{"", 1},
|
||||||
|
{"key\0suffix"s, 2},
|
||||||
|
{"key", 3},
|
||||||
|
};
|
||||||
|
|
||||||
|
EXPECT_EQ(entries.find(""sv)->second, 1);
|
||||||
|
EXPECT_EQ(entries.find("key\0suffix"sv)->second, 2);
|
||||||
|
EXPECT_EQ(entries.find("key")->second, 3);
|
||||||
|
EXPECT_FALSE(entries.contains("key\0other"sv));
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
/**
|
||||||
|
* @file tests/unit/test_sync.cpp
|
||||||
|
* @brief Regression coverage for synchronized-value lock lifetimes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// standard includes
|
||||||
|
#include <array>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <system_error>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
// lib includes
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
// local includes
|
||||||
|
#include <src/sync.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
/**
|
||||||
|
* @brief BasicLockable mutex that detects an unreleased lock without requiring try_lock.
|
||||||
|
*/
|
||||||
|
class basic_mutex {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Acquire the mutex, rejecting recursive locking.
|
||||||
|
*
|
||||||
|
* @throws std::system_error If the mutex is already locked.
|
||||||
|
*/
|
||||||
|
void lock() {
|
||||||
|
if (held_) {
|
||||||
|
throw std::system_error {std::make_error_code(std::errc::resource_deadlock_would_occur)};
|
||||||
|
}
|
||||||
|
held_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Release the mutex.
|
||||||
|
*/
|
||||||
|
void unlock() noexcept {
|
||||||
|
held_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool held_ {false}; ///< Whether a guard currently owns this mutex.
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST(SyncLockTest, RejectsRecursiveLockingAndReleasesTheOriginalGuard) {
|
||||||
|
sync_util::sync_t<int, basic_mutex> value {0};
|
||||||
|
{
|
||||||
|
const auto guard = value.lock();
|
||||||
|
EXPECT_THROW(value.lock(), std::system_error);
|
||||||
|
}
|
||||||
|
EXPECT_NO_THROW(value.lock());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SyncLockTest, SupportsBasicLockableAndReleasesOnException) {
|
||||||
|
sync_util::sync_t<int, basic_mutex> value {0};
|
||||||
|
EXPECT_THROW(
|
||||||
|
[&value]() {
|
||||||
|
const auto guard = value.lock();
|
||||||
|
++*value;
|
||||||
|
throw std::runtime_error {"unwind the guard"};
|
||||||
|
}(),
|
||||||
|
std::runtime_error
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_NO_THROW([&value]() {
|
||||||
|
const auto guard = value.lock();
|
||||||
|
EXPECT_EQ(*value, 1);
|
||||||
|
}());
|
||||||
|
EXPECT_NO_THROW([&value]() {
|
||||||
|
const auto guard = value.lock();
|
||||||
|
EXPECT_EQ(*value, 1);
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SyncLockTest, SerializesConcurrentUpdates) {
|
||||||
|
sync_util::sync_t<int> value {0};
|
||||||
|
{
|
||||||
|
std::array<std::jthread, 4> workers;
|
||||||
|
for (auto &worker : workers) {
|
||||||
|
worker = std::jthread {[&value]() {
|
||||||
|
for (int i = 0; i < 250; ++i) {
|
||||||
|
const auto guard = value.lock();
|
||||||
|
++*value;
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPECT_EQ(*value, 1000);
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* @file tests/unit/test_task_pool.cpp
|
||||||
|
* @brief Regression coverage for delayed task lookup over the complete queue.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// lib includes
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
// local includes
|
||||||
|
#include <src/task_pool.h>
|
||||||
|
|
||||||
|
TEST(TaskPoolTest, FindsRequestedDelayedTaskAndRejectsMissingIdentifiers) {
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
task_pool_util::TaskPool pool;
|
||||||
|
EXPECT_FALSE(pool.pop(nullptr).has_value());
|
||||||
|
|
||||||
|
auto first = pool.pushDelayed([]() {
|
||||||
|
return 11;
|
||||||
|
},
|
||||||
|
1h);
|
||||||
|
auto second = pool.pushDelayed([]() {
|
||||||
|
return 22;
|
||||||
|
},
|
||||||
|
2h);
|
||||||
|
EXPECT_FALSE(pool.pop(nullptr).has_value());
|
||||||
|
|
||||||
|
auto removed = pool.pop(first.task_id);
|
||||||
|
ASSERT_TRUE(removed.has_value());
|
||||||
|
ASSERT_NE(removed->second, nullptr);
|
||||||
|
removed->second->run();
|
||||||
|
EXPECT_EQ(first.future.get(), 11);
|
||||||
|
|
||||||
|
auto other = pool.pop(second.task_id);
|
||||||
|
ASSERT_TRUE(other.has_value());
|
||||||
|
ASSERT_NE(other->second, nullptr);
|
||||||
|
other->second->run();
|
||||||
|
EXPECT_EQ(second.future.get(), 22);
|
||||||
|
}
|
||||||
@@ -267,13 +267,26 @@ TEST(UtilityBufferTests, MoveConstruction) {
|
|||||||
|
|
||||||
TEST(UtilityBufferTests, CopyConstruction) {
|
TEST(UtilityBufferTests, CopyConstruction) {
|
||||||
util::buffer_t buf1(3, 55);
|
util::buffer_t buf1(3, 55);
|
||||||
|
buf1[1] = 66;
|
||||||
|
buf1[2] = 77;
|
||||||
util::buffer_t<int> buf2(buf1);
|
util::buffer_t<int> buf2(buf1);
|
||||||
EXPECT_EQ(buf2.size(), 3U);
|
EXPECT_EQ(buf2.size(), 3U);
|
||||||
EXPECT_EQ(buf2[0], 55);
|
EXPECT_EQ(buf2[0], 55);
|
||||||
|
EXPECT_EQ(buf2[1], 66);
|
||||||
|
EXPECT_EQ(buf2[2], 77);
|
||||||
EXPECT_EQ(buf1.size(), 3U);
|
EXPECT_EQ(buf1.size(), 3U);
|
||||||
EXPECT_EQ(buf1[0], 55);
|
EXPECT_EQ(buf1[0], 55);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(UtilityBufferTests, CopiesAnEmptyLogicalRange) {
|
||||||
|
util::buffer_t buf(3, 42);
|
||||||
|
buf.fake_resize(0);
|
||||||
|
const util::buffer_t<int> copy(buf);
|
||||||
|
EXPECT_EQ(copy.size(), 0U);
|
||||||
|
EXPECT_EQ(copy.begin(), copy.end());
|
||||||
|
EXPECT_EQ(buf[0], 42);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(UtilityBufferTests, SizeConstructionValueInitializesEveryElement) {
|
TEST(UtilityBufferTests, SizeConstructionValueInitializesEveryElement) {
|
||||||
const util::buffer_t<int> buf(4);
|
const util::buffer_t<int> buf(4);
|
||||||
EXPECT_EQ(buf.end() - buf.begin(), 4);
|
EXPECT_EQ(buf.end() - buf.begin(), 4);
|
||||||
|
|||||||
Reference in new issue
Block a user