mirror of
https://github.com/LizardByte/Sunshine.git
synced 2026-10-23 03:28:06 +09:00
refactor: clarify C++ declarations across 13 Sonar rules (#5934)
This commit is contained in:
1 parent
2e4d4f5ac0
commit
a36b9f8a9c
44 files changed
+342
-162
No files matched your search
+1
-1
@@ -237,7 +237,7 @@ namespace audio {
|
||||
auto samples = std::make_shared<sample_queue_t::element_type>(30);
|
||||
std::jthread thread {encodeThread, samples, config, channel_data};
|
||||
|
||||
auto fg = util::fail_guard([&]() {
|
||||
auto fg = util::fail_guard([&samples, &thread, &shutdown_event]() {
|
||||
samples->stop();
|
||||
thread.join();
|
||||
|
||||
|
||||
+6
-2
@@ -224,7 +224,9 @@ namespace config {
|
||||
bool config_revert_on_disconnect; ///< Specify whether to revert display configuration on client disconnect.
|
||||
mode_remapping_t mode_remapping; ///< Display mode remapping rules grouped by automatic selection mode.
|
||||
workarounds_t wa; ///< Display-device compatibility workarounds.
|
||||
} dd; ///< Display-device integration settings.
|
||||
};
|
||||
|
||||
dd_t dd; ///< Display-device integration settings.
|
||||
|
||||
int max_bitrate; ///< Maximum bitrate ceiling in kbps for bitrate requested from the client.
|
||||
double minimum_fps_target; ///< Lowest framerate that will be used when streaming. Range 0-1000, 0 = half of client's requested framerate.
|
||||
@@ -387,7 +389,9 @@ namespace config {
|
||||
std::string name; ///< Executable name from the command line.
|
||||
int argc; ///< Number of command-line arguments.
|
||||
char **argv; ///< Command-line argument vector.
|
||||
} cmd; ///< Command line used to launch the application.
|
||||
};
|
||||
|
||||
cmd_t cmd; ///< Command line used to launch the application.
|
||||
|
||||
std::uint16_t port; ///< TCP port used by Sunshine services.
|
||||
std::string address_family; ///< Address family requested for listening sockets.
|
||||
|
||||
+1
-1
@@ -947,7 +947,7 @@ namespace input {
|
||||
* when the last mouse coordinates were absolute
|
||||
*/
|
||||
if (button == BUTTON_LEFT && release && !input->mouse_left_button_timeout) {
|
||||
auto f = [=]() {
|
||||
auto f = [input, release]() {
|
||||
if (auto left_released = mouse_press[BUTTON_LEFT]; left_released) {
|
||||
// Already released left button
|
||||
return;
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ namespace logging {
|
||||
log_type = "Tests: "sv;
|
||||
break;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
|
||||
+2
-2
@@ -179,13 +179,13 @@ namespace logging {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Collect a metric sample and write it to the periodic log when due.
|
||||
* @brief Collect a metric sample and report it with this logger's configured message and units when due.
|
||||
*
|
||||
* @param value Numeric sample to include in the next periodic aggregate.
|
||||
*/
|
||||
void collect_and_log(const T &value) {
|
||||
if (enabled) {
|
||||
auto print_info = [&](const T &min_value, const T &max_value, double avg_value) {
|
||||
auto print_info = [this](const T &min_value, const T &max_value, double avg_value) {
|
||||
auto f = stat_trackers::two_digits_after_decimal();
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
BOOST_LOG(severity.get()) << message << " (min/max/avg): " << f % min_value << units << "/" << f % max_value << units << "/" << f % avg_value << units;
|
||||
|
||||
+5
-5
@@ -63,29 +63,29 @@ namespace net {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a Boost address family to Sunshine network enum value.
|
||||
* @brief Classify an address using the configured loopback and LAN ranges without modifying them.
|
||||
*/
|
||||
net_e from_address(const std::string_view &view) {
|
||||
if (auto addr = normalize_address(ip::make_address(view)); addr.is_v6()) {
|
||||
for (auto &range : pc_ips_v6) {
|
||||
for (const auto &range : pc_ips_v6) {
|
||||
if (range.hosts().find(addr.to_v6()) != range.hosts().end()) {
|
||||
return PC;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &range : lan_ips_v6) {
|
||||
for (const auto &range : lan_ips_v6) {
|
||||
if (range.hosts().find(addr.to_v6()) != range.hosts().end()) {
|
||||
return LAN;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (auto &range : pc_ips_v4) {
|
||||
for (const auto &range : pc_ips_v4) {
|
||||
if (range.hosts().find(addr.to_v4()) != range.hosts().end()) {
|
||||
return PC;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &range : lan_ips_v4) {
|
||||
for (const auto &range : lan_ips_v4) {
|
||||
if (range.hosts().find(addr.to_v4()) != range.hosts().end()) {
|
||||
return LAN;
|
||||
}
|
||||
|
||||
@@ -188,9 +188,7 @@ namespace NVENC_NAMESPACE {
|
||||
device_type(device_type) {
|
||||
}
|
||||
|
||||
nvenc_base::~nvenc_base() {
|
||||
// Use destroy_encoder() instead
|
||||
}
|
||||
nvenc_base::~nvenc_base() = default;
|
||||
|
||||
int nvenc_base::get_encoder_cap(const GUID &encode_guid, NV_ENC_CAPS cap) const {
|
||||
NV_ENC_CAPS_PARAM param = {.version = NV_ENC_CAPS_PARAM_VER};
|
||||
|
||||
@@ -44,6 +44,9 @@ namespace NVENC_NAMESPACE {
|
||||
* @param device_type Underlying device type used by derived class.
|
||||
*/
|
||||
explicit nvenc_base(NV_ENC_DEVICE_TYPE device_type);
|
||||
/**
|
||||
* @brief Destroy the encoder wrapper; callers release the encoder session with destroy_encoder().
|
||||
*/
|
||||
~nvenc_base() override;
|
||||
|
||||
nvenc_base(const nvenc_base &) = delete;
|
||||
|
||||
@@ -178,7 +178,7 @@ namespace NVENC_NAMESPACE {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto unmap = [&]() -> bool {
|
||||
auto unmap = [&]() {
|
||||
if (cuda_failed(cuda_functions.cuGraphicsUnmapResources(1, &cuda_d3d_input_texture, 0))) {
|
||||
BOOST_LOG(error) << "NvEnc: cuGraphicsUnmapResources() failed: error " << last_cuda_error;
|
||||
return false;
|
||||
|
||||
+8
-6
@@ -172,7 +172,9 @@ namespace nvhttp {
|
||||
struct conf_intern_t {
|
||||
std::string servercert; ///< Server certificate PEM string.
|
||||
std::string pkey; ///< Private key PEM string or path.
|
||||
} conf_intern; ///< TLS credential paths loaded from Sunshine's runtime configuration.
|
||||
};
|
||||
|
||||
conf_intern_t conf_intern; ///< TLS credential paths loaded from Sunshine's runtime configuration.
|
||||
|
||||
/**
|
||||
* @brief Certificate entry associated with a client name and UUID.
|
||||
@@ -491,7 +493,7 @@ namespace nvhttp {
|
||||
std::copy(rikey.cbegin(), rikey.cend(), std::back_inserter(launch_session->gcm_key));
|
||||
|
||||
launch_session->host_audio = host_audio;
|
||||
std::stringstream mode = std::stringstream(get_arg(args, "mode", "0x0x0"));
|
||||
auto mode = std::stringstream(get_arg(args, "mode", "0x0x0"));
|
||||
// Split mode by the char "x", to populate width/height/fps
|
||||
int x = 0;
|
||||
std::string segment;
|
||||
@@ -1082,7 +1084,7 @@ namespace nvhttp {
|
||||
|
||||
pt::ptree tree;
|
||||
|
||||
auto fg = util::fail_guard([&]() {
|
||||
auto fg = util::fail_guard([&tree, &response]() {
|
||||
std::ostringstream data;
|
||||
|
||||
pt::write_xml(data, tree);
|
||||
@@ -1339,7 +1341,7 @@ namespace nvhttp {
|
||||
|
||||
pt::ptree tree;
|
||||
|
||||
auto g = util::fail_guard([&]() {
|
||||
auto g = util::fail_guard([&tree, &response]() {
|
||||
std::ostringstream data;
|
||||
|
||||
pt::write_xml(data, tree);
|
||||
@@ -1588,7 +1590,7 @@ namespace nvhttp {
|
||||
print_req<SunshineHTTPS>(request);
|
||||
|
||||
pt::ptree tree;
|
||||
auto g = util::fail_guard([&]() {
|
||||
auto g = util::fail_guard([&tree, &response]() {
|
||||
std::ostringstream data;
|
||||
|
||||
pt::write_xml(data, tree);
|
||||
@@ -1716,7 +1718,7 @@ namespace nvhttp {
|
||||
|
||||
https_server.on_verify_failed = [](resp_https_t resp, req_https_t req) {
|
||||
pt::ptree tree;
|
||||
auto g = util::fail_guard([&]() {
|
||||
auto g = util::fail_guard([&tree, &resp]() {
|
||||
std::ostringstream data;
|
||||
|
||||
pt::write_xml(data, tree);
|
||||
|
||||
@@ -1050,11 +1050,11 @@ namespace platf {
|
||||
boost::asio::ip::address &source_address; ///< Local source IP address for outgoing packets.
|
||||
|
||||
/**
|
||||
* @brief Returns a payload buffer descriptor for the given payload offset.
|
||||
* @brief Locate a payload region without changing the batch descriptor or its buffers.
|
||||
* @param offset The offset in the total payload data (bytes).
|
||||
* @return Buffer descriptor describing the region at the given offset.
|
||||
*/
|
||||
buffer_descriptor_t buffer_for_payload_offset(ptrdiff_t offset) {
|
||||
buffer_descriptor_t buffer_for_payload_offset(ptrdiff_t offset) const {
|
||||
for (const auto &desc : payload_buffers) {
|
||||
if (offset < desc.size) {
|
||||
return {
|
||||
@@ -1070,12 +1070,12 @@ namespace platf {
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Send multiple fixed-size UDP payload blocks using the platform backend.
|
||||
* @brief Send fixed-size UDP payload blocks without modifying the batch descriptor.
|
||||
*
|
||||
* @param send_info Socket addresses, buffers, and sizes for the send operation.
|
||||
* @return True when all requested packet blocks are submitted to the socket.
|
||||
*/
|
||||
bool send_batch(batched_send_info_t &send_info);
|
||||
bool send_batch(const batched_send_info_t &send_info);
|
||||
|
||||
/**
|
||||
* @brief Destination address and payload data for one UDP send.
|
||||
|
||||
@@ -299,7 +299,7 @@ namespace platf {
|
||||
* @param userdata Caller-provided pointer passed through the callback.
|
||||
*/
|
||||
void ctx_state_cb(ctx_t::pointer ctx, void *userdata) {
|
||||
auto &f = *(std::function<void(ctx_t::pointer)> *) userdata;
|
||||
const auto &f = *(std::function<void(ctx_t::pointer)> *) userdata;
|
||||
|
||||
f(ctx);
|
||||
}
|
||||
|
||||
@@ -698,7 +698,12 @@ namespace cuda {
|
||||
static PNVFBCCREATEINSTANCE createInstance {};
|
||||
static NVFBC_API_FUNCTION_LIST func {.dwVersion = NVFBC_VERSION};
|
||||
|
||||
static constexpr inline NVFBC_BOOL nv_bool(bool b) {
|
||||
/**
|
||||
* @brief Convert a C++ boolean to the corresponding NvFBC flag.
|
||||
* @param b Boolean state to convert.
|
||||
* @return NVFBC_TRUE when b is true, otherwise NVFBC_FALSE.
|
||||
*/
|
||||
static constexpr NVFBC_BOOL nv_bool(bool b) {
|
||||
return b ? NVFBC_TRUE : NVFBC_FALSE;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,11 +41,20 @@ namespace cuda {
|
||||
int init();
|
||||
} // namespace cuda
|
||||
|
||||
typedef struct cudaArray *cudaArray_t;
|
||||
/**
|
||||
* @brief Opaque CUDA array handle shared by host and CUDA compiler declarations.
|
||||
*/
|
||||
using cudaArray_t = struct cudaArray *;
|
||||
|
||||
#if !defined(__CUDACC__)
|
||||
typedef struct CUstream_st *cudaStream_t;
|
||||
typedef unsigned long long cudaTextureObject_t;
|
||||
/**
|
||||
* @brief Opaque CUDA stream handle for host compilation.
|
||||
*/
|
||||
using cudaStream_t = struct CUstream_st *;
|
||||
/**
|
||||
* @brief CUDA texture object identifier for host compilation.
|
||||
*/
|
||||
using cudaTextureObject_t = unsigned long long;
|
||||
#else /* defined(__CUDACC__) */
|
||||
typedef __location__(device_builtin) struct CUstream_st *cudaStream_t;
|
||||
typedef __location__(device_builtin) unsigned long long cudaTextureObject_t;
|
||||
@@ -90,10 +99,15 @@ namespace cuda {
|
||||
|
||||
cudaArray_t array;
|
||||
|
||||
struct texture {
|
||||
/**
|
||||
* @brief CUDA texture objects for point and linear sampling of the same image.
|
||||
*/
|
||||
struct texture_t {
|
||||
cudaTextureObject_t point;
|
||||
cudaTextureObject_t linear;
|
||||
} texture;
|
||||
};
|
||||
|
||||
texture_t texture; ///< Point and linear sampling textures for the CUDA array.
|
||||
};
|
||||
|
||||
class sws_t {
|
||||
|
||||
@@ -1342,7 +1342,7 @@ namespace egl {
|
||||
}
|
||||
|
||||
int sws_t::blank(gl::frame_buf_t &fb, int offsetX_, int offsetY_, int width, int height, bool is_yuv444) {
|
||||
auto f = [&]() {
|
||||
auto f = [this, &offsetX_, &offsetY_, &width, &height]() {
|
||||
std::swap(offsetX_, this->offsetX);
|
||||
std::swap(offsetY_, this->offsetY);
|
||||
std::swap(width, this->out_width);
|
||||
|
||||
@@ -1367,7 +1367,7 @@ namespace platf {
|
||||
*
|
||||
* @return True when the active display mode is HDR.
|
||||
*/
|
||||
bool is_hdr() {
|
||||
bool is_hdr() override {
|
||||
if (!hdr_metadata_blob_id || *hdr_metadata_blob_id == 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -1419,7 +1419,7 @@ namespace platf {
|
||||
* @param metadata Output structure populated with HDR metadata.
|
||||
* @return True when HDR metadata was written to the output structure.
|
||||
*/
|
||||
bool get_hdr_metadata(SS_HDR_METADATA &metadata) {
|
||||
bool get_hdr_metadata(SS_HDR_METADATA &metadata) override {
|
||||
// This performs all the metadata validation
|
||||
if (!is_hdr()) {
|
||||
return false;
|
||||
@@ -2080,7 +2080,7 @@ namespace platf {
|
||||
* @param cursor Whether the cursor should be included in the captured image.
|
||||
* @return Final capture status reported to the streaming pipeline.
|
||||
*/
|
||||
capture_e capture(const push_captured_image_cb_t &push_captured_image_cb, const pull_free_image_cb_t &pull_free_image_cb, bool *cursor) {
|
||||
capture_e capture(const push_captured_image_cb_t &push_captured_image_cb, const pull_free_image_cb_t &pull_free_image_cb, bool *cursor) override {
|
||||
using enum platf::capture_e;
|
||||
|
||||
auto next_frame = std::chrono::steady_clock::now();
|
||||
@@ -2429,11 +2429,11 @@ namespace platf {
|
||||
BOOST_LOG(debug) << "Resolution: "sv << monitor_descriptor.viewport.width << 'x' << monitor_descriptor.viewport.height;
|
||||
BOOST_LOG(debug) << "Offset: "sv << monitor_descriptor.viewport.offset_x << 'x' << monitor_descriptor.viewport.offset_y;
|
||||
|
||||
kms::env_width = std::max(kms::env_width, (int) (monitor_descriptor.viewport.offset_x + monitor_descriptor.viewport.width));
|
||||
kms::env_height = std::max(kms::env_height, (int) (monitor_descriptor.viewport.offset_y + monitor_descriptor.viewport.height));
|
||||
kms::env_width = std::max(kms::env_width, monitor_descriptor.viewport.offset_x + monitor_descriptor.viewport.width);
|
||||
kms::env_height = std::max(kms::env_height, monitor_descriptor.viewport.offset_y + monitor_descriptor.viewport.height);
|
||||
|
||||
kms::env_logical_height = std::max(kms::env_logical_height, (int) (monitor_descriptor.viewport.offset_y + monitor_descriptor.viewport.logical_height));
|
||||
kms::env_logical_width = std::max(kms::env_logical_width, (int) (monitor_descriptor.viewport.offset_x + monitor_descriptor.viewport.logical_width));
|
||||
kms::env_logical_height = std::max(kms::env_logical_height, monitor_descriptor.viewport.offset_y + monitor_descriptor.viewport.logical_height);
|
||||
kms::env_logical_width = std::max(kms::env_logical_width, monitor_descriptor.viewport.offset_x + monitor_descriptor.viewport.logical_width);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -625,7 +625,7 @@ namespace platf {
|
||||
executable[len] = '\0';
|
||||
|
||||
// ASIO doesn't use O_CLOEXEC, so we have to close all fds ourselves
|
||||
int openmax = (int) sysconf(_SC_OPEN_MAX);
|
||||
auto openmax = (int) sysconf(_SC_OPEN_MAX);
|
||||
for (int fd = STDERR_FILENO + 1; fd < openmax; fd++) {
|
||||
close(fd);
|
||||
}
|
||||
@@ -756,7 +756,7 @@ namespace platf {
|
||||
/**
|
||||
* @brief Send multiple fixed-size UDP payload blocks using the platform backend.
|
||||
*/
|
||||
bool send_batch(batched_send_info_t &send_info) {
|
||||
bool send_batch(const batched_send_info_t &send_info) {
|
||||
auto sockfd = (int) send_info.native_socket;
|
||||
struct msghdr msg = {};
|
||||
|
||||
@@ -1059,7 +1059,7 @@ namespace platf {
|
||||
* @brief Enables QoS on the given socket for traffic to the specified destination.
|
||||
*/
|
||||
std::unique_ptr<deinit_t> enable_socket_qos(uintptr_t native_socket, boost::asio::ip::address &address, uint16_t port, qos_data_type_e data_type, bool dscp_tagging) {
|
||||
int sockfd = (int) native_socket;
|
||||
auto sockfd = (int) native_socket;
|
||||
std::vector<std::tuple<int, int, int>> reset_options;
|
||||
|
||||
if (dscp_tagging) {
|
||||
|
||||
@@ -477,7 +477,7 @@ namespace platf {
|
||||
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 pixel_p = (int *) &pixel;
|
||||
|
||||
auto colors_in = (uint8_t *) pixels_begin;
|
||||
|
||||
@@ -720,8 +720,8 @@ namespace platf {
|
||||
// TODO: stop cheating and give black image
|
||||
if (!img) {
|
||||
return -1;
|
||||
};
|
||||
auto pull_dummy_img_callback = [&img](std::shared_ptr<platf::img_t> &img_out) -> bool {
|
||||
}
|
||||
auto pull_dummy_img_callback = [&img](std::shared_ptr<platf::img_t> &img_out) {
|
||||
img_out = img->shared_from_this();
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -654,7 +654,7 @@ namespace platf {
|
||||
return saddr_v6;
|
||||
}
|
||||
|
||||
bool send_batch(batched_send_info_t &send_info) {
|
||||
bool send_batch(const batched_send_info_t &send_info) {
|
||||
// Fall back to unbatched send calls
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -441,8 +441,7 @@ namespace platf::audio {
|
||||
*/
|
||||
class audio_notification_t: public ::IMMNotificationClient {
|
||||
public:
|
||||
audio_notification_t() {
|
||||
}
|
||||
audio_notification_t() = default;
|
||||
|
||||
// IUnknown implementation (unused by IMMDeviceEnumerator)
|
||||
/**
|
||||
@@ -450,7 +449,7 @@ namespace platf::audio {
|
||||
*
|
||||
* @return Static reference count because the callback lifetime is externally owned.
|
||||
*/
|
||||
ULONG STDMETHODCALLTYPE AddRef() {
|
||||
ULONG STDMETHODCALLTYPE AddRef() override {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -459,18 +458,18 @@ namespace platf::audio {
|
||||
*
|
||||
* @return Reference count or status returned after releasing the object.
|
||||
*/
|
||||
ULONG STDMETHODCALLTYPE Release() {
|
||||
ULONG STDMETHODCALLTYPE Release() override {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the supported COM interface for the notification callback.
|
||||
* @brief Implement IUnknown's interface query for the endpoint notification callback.
|
||||
*
|
||||
* @param riid COM interface identifier requested by QueryInterface.
|
||||
* @param ppvInterface Output pointer receiving the requested interface.
|
||||
* @return S_OK when the interface is supported; E_NOINTERFACE otherwise.
|
||||
*/
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface) { // NOSONAR(cpp:S5008): IUnknown::QueryInterface requires a void double pointer in the COM ABI.
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface) override { // NOSONAR(cpp:S5008): IUnknown::QueryInterface requires a void double pointer in the COM ABI.
|
||||
if (IID_IUnknown == riid) {
|
||||
AddRef();
|
||||
*ppvInterface = (IUnknown *) this;
|
||||
@@ -494,7 +493,7 @@ namespace platf::audio {
|
||||
* @param pwstrDeviceId Windows endpoint ID for the new default device.
|
||||
* @return S_OK after recording the render-device change notification.
|
||||
*/
|
||||
HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId) {
|
||||
HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId) override {
|
||||
if (flow == eRender) {
|
||||
default_render_device_changed_flag.store(true);
|
||||
}
|
||||
@@ -507,7 +506,7 @@ namespace platf::audio {
|
||||
* @param pwstrDeviceId Windows endpoint ID for the added device.
|
||||
* @return S_OK because Sunshine does not act on this notification.
|
||||
*/
|
||||
HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId) {
|
||||
HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId) override {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -517,7 +516,7 @@ namespace platf::audio {
|
||||
* @param pwstrDeviceId Windows endpoint ID for the removed device.
|
||||
* @return S_OK because Sunshine does not act on this notification.
|
||||
*/
|
||||
HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId) {
|
||||
HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId) override {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -531,7 +530,7 @@ namespace platf::audio {
|
||||
HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(
|
||||
LPCWSTR pwstrDeviceId,
|
||||
DWORD dwNewState
|
||||
) {
|
||||
) override {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -545,7 +544,7 @@ namespace platf::audio {
|
||||
HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(
|
||||
LPCWSTR pwstrDeviceId,
|
||||
const PROPERTYKEY key
|
||||
) {
|
||||
) override {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -751,12 +750,16 @@ namespace platf::audio {
|
||||
struct sample_aligned_t {
|
||||
std::uint32_t uninitialized;
|
||||
float *samples;
|
||||
} sample_aligned;
|
||||
};
|
||||
|
||||
sample_aligned_t sample_aligned;
|
||||
|
||||
// number of samples / number of channels
|
||||
struct block_aligned_t {
|
||||
std::uint32_t audio_sample_size;
|
||||
} block_aligned;
|
||||
};
|
||||
|
||||
block_aligned_t block_aligned;
|
||||
|
||||
// Check if the default audio device has changed
|
||||
if (endpt_notification.check_default_render_device_changed()) {
|
||||
@@ -1448,8 +1451,7 @@ namespace platf::audio {
|
||||
/**
|
||||
* @brief Destroy the Windows audio control.
|
||||
*/
|
||||
~audio_control_t() override {
|
||||
}
|
||||
~audio_control_t() override = default;
|
||||
|
||||
policy_t policy; ///< Windows policy configuration interface used to switch default audio devices.
|
||||
audio::device_enum_t device_enum; ///< Device enumerator used to query and watch audio endpoints.
|
||||
|
||||
@@ -452,14 +452,14 @@ namespace platf::dxgi {
|
||||
*
|
||||
* @return True when the active display mode is HDR.
|
||||
*/
|
||||
virtual bool is_hdr() override;
|
||||
bool is_hdr() override;
|
||||
/**
|
||||
* @brief Read HDR metadata for the active display mode.
|
||||
*
|
||||
* @param metadata Output structure populated with HDR metadata.
|
||||
* @return True when HDR metadata was written to `metadata`.
|
||||
*/
|
||||
virtual bool get_hdr_metadata(SS_HDR_METADATA &metadata) override;
|
||||
bool get_hdr_metadata(SS_HDR_METADATA &metadata) override;
|
||||
|
||||
/**
|
||||
* @brief Convert a DXGI format enum to a diagnostic string.
|
||||
|
||||
@@ -647,7 +647,7 @@ namespace platf::dxgi {
|
||||
|
||||
HMODULE gdi32 = GetModuleHandleA("GDI32");
|
||||
if (gdi32) {
|
||||
auto check_hags = [&](const LUID &adapter_luid) -> bool {
|
||||
auto check_hags = [&](const LUID &adapter_luid) {
|
||||
auto d3dkmt_open_adapter = (PD3DKMTOpenAdapterFromLuid) GetProcAddress(gdi32, "D3DKMTOpenAdapterFromLuid");
|
||||
auto d3dkmt_query_adapter_info = (PD3DKMTQueryAdapterInfo) GetProcAddress(gdi32, "D3DKMTQueryAdapterInfo");
|
||||
auto d3dkmt_close_adapter = (PD3DKMTCloseAdapter) GetProcAddress(gdi32, "D3DKMTCloseAdapter");
|
||||
|
||||
@@ -603,7 +603,7 @@ namespace platf::dxgi {
|
||||
frame_texture->AddRef();
|
||||
output_texture.reset(frame_texture);
|
||||
|
||||
HRESULT status = S_OK;
|
||||
auto status = S_OK;
|
||||
|
||||
#ifndef DOXYGEN
|
||||
#define create_vertex_shader_helper(x, y) \
|
||||
@@ -785,7 +785,7 @@ namespace platf::dxgi {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto create_rtv = [&](auto &rt, DXGI_FORMAT rt_format) -> bool {
|
||||
auto create_rtv = [&](auto &rt, DXGI_FORMAT rt_format) {
|
||||
D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = {};
|
||||
rtv_desc.Format = rt_format;
|
||||
rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
|
||||
@@ -1520,7 +1520,7 @@ namespace platf::dxgi {
|
||||
}
|
||||
}
|
||||
|
||||
auto create_surface = [&](texture2d_t &surface) -> bool {
|
||||
auto create_surface = [&](texture2d_t &surface) {
|
||||
// Try to reuse the old surface if it hasn't been destroyed yet.
|
||||
if (old_surface_delayed_destruction) {
|
||||
surface.reset(old_surface_delayed_destruction.release());
|
||||
|
||||
@@ -632,7 +632,7 @@ namespace platf {
|
||||
|
||||
if (file) {
|
||||
// If a file was provided, get its handle and use it as the standard output and error for the new process
|
||||
HANDLE log_file_handle = (HANDLE) _get_osfhandle(_fileno(file));
|
||||
auto log_file_handle = (HANDLE) _get_osfhandle(_fileno(file));
|
||||
|
||||
// Populate std handles if the caller gave us a log file to use
|
||||
startup_info.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
|
||||
@@ -1045,7 +1045,7 @@ namespace platf {
|
||||
sunshine_wenv[path_var_name].assign(start_dir + L";" + old_path_val);
|
||||
|
||||
// Restore the old PATH value for our process when we're done here
|
||||
auto restore_path = util::fail_guard([&]() {
|
||||
auto restore_path = util::fail_guard([&old_path_val, &sunshine_wenv, &path_var_name]() {
|
||||
if (old_path_val.empty()) {
|
||||
sunshine_wenv[path_var_name].clear();
|
||||
} else {
|
||||
@@ -1505,7 +1505,7 @@ namespace platf {
|
||||
|
||||
// Use UDP segmentation offload if it is supported by the OS. If the NIC is capable, this will use
|
||||
// hardware acceleration to reduce CPU usage. Support for USO was introduced in Windows 10 20H1.
|
||||
bool send_batch(batched_send_info_t &send_info) {
|
||||
bool send_batch(const batched_send_info_t &send_info) {
|
||||
WSAMSG msg;
|
||||
|
||||
// Convert the target address into a SOCKADDR
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace nvprefs {
|
||||
* @param p LocalAlloc-compatible pointer to release.
|
||||
*/
|
||||
template<class T>
|
||||
void operator()(T *p) {
|
||||
void operator()(T *p) const {
|
||||
LocalFree(p);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace nvprefs {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto make_undo_and_commit = [&]() -> bool {
|
||||
auto make_undo_and_commit = [&]() {
|
||||
// Create and lock undo file if it hasn't been done yet
|
||||
if (!pimpl->undo_file) {
|
||||
// Prepare Sunshine folder in ProgramData if it doesn't exist
|
||||
@@ -193,7 +193,7 @@ namespace nvprefs {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nvprefs_interface::owning_undo_file() {
|
||||
bool nvprefs_interface::owning_undo_file() const {
|
||||
return pimpl->undo_file.has_value();
|
||||
}
|
||||
|
||||
|
||||
@@ -53,9 +53,9 @@ namespace nvprefs {
|
||||
/**
|
||||
* @brief Check whether this interface owns the active undo file.
|
||||
*
|
||||
* @return True when the NVIDIA preferences operation succeeds.
|
||||
* @return True when this interface owns the undo file; querying does not load NVIDIA APIs.
|
||||
*/
|
||||
bool owning_undo_file();
|
||||
bool owning_undo_file() const;
|
||||
|
||||
/**
|
||||
* @brief Restore NVIDIA global profile settings from saved undo data.
|
||||
|
||||
+1
-1
@@ -230,7 +230,7 @@ namespace proc {
|
||||
|
||||
std::error_code ec;
|
||||
// Executed when returning from function
|
||||
auto fg = util::fail_guard([&]() {
|
||||
auto fg = util::fail_guard([this]() {
|
||||
terminate();
|
||||
});
|
||||
|
||||
|
||||
+1
-53
@@ -51,58 +51,6 @@ namespace rtsp_stream {
|
||||
delete msg;
|
||||
}
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
/**
|
||||
* @brief Encrypted RTSP message header used by GameStream.
|
||||
*/
|
||||
struct encrypted_rtsp_header_t {
|
||||
// We set the MSB in encrypted RTSP messages to allow format-agnostic
|
||||
// parsing code to be able to tell encrypted from plaintext messages.
|
||||
static constexpr std::uint32_t ENCRYPTED_MESSAGE_TYPE_BIT = 0x80000000; ///< Protocol or platform constant for encrypted message type bit.
|
||||
|
||||
/**
|
||||
* @brief Return a pointer to the protocol payload following the packet header.
|
||||
*
|
||||
* @return Parsed or serialized payload data.
|
||||
*/
|
||||
uint8_t *payload() {
|
||||
return (uint8_t *) (this + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decode the RTSP interleaved-frame payload length.
|
||||
*
|
||||
* @return Payload byte count with the encrypted-message flag masked out.
|
||||
*/
|
||||
std::uint32_t payload_length() {
|
||||
return util::endian::big<std::uint32_t>(typeAndLength) & ~ENCRYPTED_MESSAGE_TYPE_BIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check whether encrypted.
|
||||
*
|
||||
* @return True when the RTSP connection is using TLS.
|
||||
*/
|
||||
bool is_encrypted() {
|
||||
return !!(util::endian::big<std::uint32_t>(typeAndLength) & ENCRYPTED_MESSAGE_TYPE_BIT);
|
||||
}
|
||||
|
||||
// This field is the length of the payload + ENCRYPTED_MESSAGE_TYPE_BIT in big-endian
|
||||
std::uint32_t typeAndLength; ///< Type and length.
|
||||
|
||||
// This field is the number used to initialize the bottom 4 bytes of the AES IV in big-endian
|
||||
std::uint32_t sequenceNumber; ///< Sequence number.
|
||||
|
||||
// This field is the AES GCM authentication tag
|
||||
std::array<std::uint8_t, 16> tag; ///< Authentication tag appended to the encrypted payload.
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
static_assert(sizeof(encrypted_rtsp_header_t) == 24);
|
||||
static_assert(offsetof(encrypted_rtsp_header_t, tag) == 8);
|
||||
|
||||
class rtsp_server_t;
|
||||
|
||||
/**
|
||||
@@ -806,7 +754,7 @@ namespace rtsp_stream {
|
||||
auto [payload, original_payload_length] = std::make_pair(resp->payload, resp->payloadLength);
|
||||
|
||||
// Restore response message for proper destruction
|
||||
auto lg = util::fail_guard([&]() {
|
||||
auto lg = util::fail_guard([&resp, &payload, &original_payload_length]() {
|
||||
resp->payload = payload;
|
||||
resp->payloadLength = original_payload_length;
|
||||
});
|
||||
|
||||
+55
@@ -5,7 +5,10 @@
|
||||
#pragma once
|
||||
|
||||
// standard includes
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
// local includes
|
||||
#include "crypto.h"
|
||||
@@ -14,6 +17,58 @@
|
||||
namespace rtsp_stream {
|
||||
constexpr auto RTSP_SETUP_PORT = 21; ///< GameStream base-port offset used for the RTSP setup listener.
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
/**
|
||||
* @brief Encrypted RTSP message header used by GameStream.
|
||||
*/
|
||||
struct encrypted_rtsp_header_t {
|
||||
// We set the MSB in encrypted RTSP messages to allow format-agnostic
|
||||
// parsing code to be able to tell encrypted from plaintext messages.
|
||||
static constexpr std::uint32_t ENCRYPTED_MESSAGE_TYPE_BIT = 0x80000000; ///< Protocol or platform constant for encrypted message type bit.
|
||||
|
||||
/**
|
||||
* @brief Return a pointer to the protocol payload following the packet header.
|
||||
*
|
||||
* @return Parsed or serialized payload data.
|
||||
*/
|
||||
uint8_t *payload() {
|
||||
return (uint8_t *) (this + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decode the RTSP interleaved-frame payload length.
|
||||
*
|
||||
* @return Payload byte count with the encrypted-message flag masked out.
|
||||
*/
|
||||
std::uint32_t payload_length() const {
|
||||
return util::endian::big<std::uint32_t>(typeAndLength) & ~ENCRYPTED_MESSAGE_TYPE_BIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inspect the encrypted-message flag without modifying the wire header.
|
||||
*
|
||||
* @return True when the encrypted-message flag is set.
|
||||
*/
|
||||
bool is_encrypted() const {
|
||||
return !!(util::endian::big<std::uint32_t>(typeAndLength) & ENCRYPTED_MESSAGE_TYPE_BIT);
|
||||
}
|
||||
|
||||
// This field is the length of the payload + ENCRYPTED_MESSAGE_TYPE_BIT in big-endian
|
||||
std::uint32_t typeAndLength; ///< Type and length.
|
||||
|
||||
// This field is the number used to initialize the bottom 4 bytes of the AES IV in big-endian
|
||||
std::uint32_t sequenceNumber; ///< Sequence number.
|
||||
|
||||
// This field is the AES GCM authentication tag
|
||||
std::array<std::uint8_t, 16> tag; ///< Authentication tag appended to the encrypted payload.
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
static_assert(sizeof(encrypted_rtsp_header_t) == 24);
|
||||
static_assert(offsetof(encrypted_rtsp_header_t, tag) == 8);
|
||||
|
||||
/**
|
||||
* @brief RTSP launch session state shared with stream setup.
|
||||
*/
|
||||
|
||||
+2
-2
@@ -1189,7 +1189,7 @@ namespace stream {
|
||||
});
|
||||
|
||||
server->map(packetTypes[IDX_LOSS_STATS], [&](session_t *session, const std::string_view &payload) {
|
||||
int32_t *stats = (int32_t *) payload.data();
|
||||
auto stats = (int32_t *) payload.data();
|
||||
auto count = stats[0];
|
||||
std::chrono::milliseconds t {stats[1]};
|
||||
|
||||
@@ -1479,7 +1479,7 @@ namespace stream {
|
||||
|
||||
auto recv_func_init = [&](udp::socket &sock, int buf_elem, std::map<av_session_id_t, message_queue_t> &peer_to_session) {
|
||||
recv_func[buf_elem] = [&, buf_elem](const boost::system::error_code &ec, size_t bytes) {
|
||||
auto fg = util::fail_guard([&]() {
|
||||
auto fg = util::fail_guard([&sock, &buf, &peer, &recv_func, &buf_elem]() {
|
||||
sock.async_receive_from(asio::buffer(buf[buf_elem]), peer, 0, recv_func[buf_elem]);
|
||||
});
|
||||
|
||||
|
||||
+4
-1
@@ -28,7 +28,10 @@ namespace task_pool_util {
|
||||
public:
|
||||
// _unique_base_type _this_ptr;
|
||||
|
||||
inline virtual ~_ImplBase() = default;
|
||||
/**
|
||||
* @brief Destroy a queued callable through its polymorphic base.
|
||||
*/
|
||||
virtual ~_ImplBase() = default;
|
||||
|
||||
/**
|
||||
* @brief Execute the queued task body.
|
||||
|
||||
+3
-3
@@ -162,11 +162,11 @@ namespace safe {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inspect the next queued value without popping it.
|
||||
* @brief Inspect whether this event has a value without modifying or consuming it.
|
||||
*
|
||||
* @return True when a value is available to inspect.
|
||||
*/
|
||||
bool peek() {
|
||||
bool peek() const {
|
||||
return _continue && (bool) _status;
|
||||
}
|
||||
|
||||
@@ -859,7 +859,7 @@ namespace safe {
|
||||
std::lock_guard lg {mutex};
|
||||
|
||||
for (auto it = std::begin(id_to_post); it != std::end(id_to_post); ++it) {
|
||||
auto &weak = it->second;
|
||||
const auto &weak = it->second;
|
||||
|
||||
if (weak.expired()) {
|
||||
id_to_post.erase(it);
|
||||
|
||||
+3
-3
@@ -632,7 +632,7 @@ namespace util {
|
||||
T from_hex(const std::string_view &hex, bool rev = false) {
|
||||
std::array<std::byte, sizeof(T)> buf;
|
||||
|
||||
auto is_convertable = [](char ch) -> bool {
|
||||
auto is_convertable = [](char ch) {
|
||||
if (isdigit(ch)) {
|
||||
return true;
|
||||
}
|
||||
@@ -687,7 +687,7 @@ namespace util {
|
||||
inline std::string from_hex_vec(const std::string &hex, bool rev = false) {
|
||||
std::string buf;
|
||||
|
||||
auto is_convertable = [](char ch) -> bool {
|
||||
auto is_convertable = [](char ch) {
|
||||
if (isdigit(ch)) {
|
||||
return true;
|
||||
}
|
||||
@@ -1643,7 +1643,7 @@ namespace util {
|
||||
*
|
||||
* @param p Pointer to release.
|
||||
*/
|
||||
void operator()(pointer p) {
|
||||
void operator()(pointer p) const {
|
||||
function(p);
|
||||
}
|
||||
};
|
||||
|
||||
+19
-18
@@ -1552,6 +1552,7 @@ namespace video {
|
||||
|
||||
/**
|
||||
* @brief Run the shared display capture thread for asynchronous encoding.
|
||||
* @details Capture callbacks share this thread's session queues and reusable image pool.
|
||||
*
|
||||
* @param capture_ctx_queue Capture context queue.
|
||||
* @param display_wp Weak pointer holder for the active display.
|
||||
@@ -1566,7 +1567,7 @@ namespace video {
|
||||
) {
|
||||
std::vector<capture_ctx_t> capture_ctxs;
|
||||
|
||||
auto fg = util::fail_guard([&]() {
|
||||
auto fg = util::fail_guard([&capture_ctx_queue, &capture_ctxs]() {
|
||||
capture_ctx_queue->stop();
|
||||
|
||||
// Stop all sessions listening to this thread
|
||||
@@ -1603,7 +1604,7 @@ namespace video {
|
||||
|
||||
std::vector<std::optional<std::chrono::steady_clock::time_point>> imgs_used_timestamps;
|
||||
const std::chrono::seconds trim_timeot = 3s;
|
||||
auto trim_imgs = [&]() {
|
||||
auto trim_imgs = [&imgs, &imgs_used_timestamps, &trim_timeot]() {
|
||||
// count allocated and used within current pool
|
||||
size_t allocated_count = 0;
|
||||
size_t used_count = 0;
|
||||
@@ -1651,7 +1652,7 @@ namespace video {
|
||||
}
|
||||
};
|
||||
|
||||
auto pull_free_image_callback = [&](std::shared_ptr<platf::img_t> &img_out) -> bool {
|
||||
auto pull_free_image_callback = [&capture_ctx_queue, &imgs, &disp, &trim_imgs](std::shared_ptr<platf::img_t> &img_out) {
|
||||
img_out.reset();
|
||||
while (capture_ctx_queue->running()) {
|
||||
// pick first allocated but unused
|
||||
@@ -1702,7 +1703,7 @@ namespace video {
|
||||
while (capture_ctx_queue->running()) {
|
||||
bool artificial_reinit = false;
|
||||
|
||||
auto push_captured_image_callback = [&](std::shared_ptr<platf::img_t> &&img, bool frame_captured) -> bool {
|
||||
auto push_captured_image_callback = [&capture_ctxs, &capture_ctx_queue, &switch_display_event, &artificial_reinit](std::shared_ptr<platf::img_t> &&img, bool frame_captured) {
|
||||
KITTY_WHILE_LOOP(auto capture_ctx = std::begin(capture_ctxs), capture_ctx != std::end(capture_ctxs), {
|
||||
if (!capture_ctx->images->running()) {
|
||||
capture_ctx = capture_ctxs.erase(capture_ctx);
|
||||
@@ -2164,29 +2165,29 @@ namespace video {
|
||||
auto handle_option = [&options, &config](const encoder_t::option_t &option) {
|
||||
std::visit(
|
||||
util::overloaded {
|
||||
[&](int v) {
|
||||
[&options, &option](int v) {
|
||||
av_dict_set_int(&options, option.name.c_str(), v, 0);
|
||||
},
|
||||
[&](int *v) {
|
||||
[&options, &option](int *v) {
|
||||
av_dict_set_int(&options, option.name.c_str(), *v, 0);
|
||||
},
|
||||
[&](std::optional<int> *v) {
|
||||
[&options, &option](std::optional<int> *v) {
|
||||
if (*v) {
|
||||
av_dict_set_int(&options, option.name.c_str(), **v, 0);
|
||||
}
|
||||
},
|
||||
[&](const std::function<int()> &v) {
|
||||
[&options, &option](const std::function<int()> &v) {
|
||||
av_dict_set_int(&options, option.name.c_str(), v(), 0);
|
||||
},
|
||||
[&](const std::string &v) {
|
||||
[&options, &option](const std::string &v) {
|
||||
av_dict_set(&options, option.name.c_str(), v.c_str(), 0);
|
||||
},
|
||||
[&](std::string *v) {
|
||||
[&options, &option](std::string *v) {
|
||||
if (!v->empty()) {
|
||||
av_dict_set(&options, option.name.c_str(), v->c_str(), 0);
|
||||
}
|
||||
},
|
||||
[&](const std::function<const std::string(const config_t &cfg)> &v) {
|
||||
[&options, &option, &config](const std::function<const std::string(const config_t &cfg)> &v) {
|
||||
av_dict_set(&options, option.name.c_str(), v(config).c_str(), 0);
|
||||
}
|
||||
},
|
||||
@@ -2644,7 +2645,7 @@ namespace video {
|
||||
ctx.touch_port_events->raise(make_port(disp, ctx.config));
|
||||
|
||||
// Update client with our current HDR display state
|
||||
hdr_info_t hdr_info = std::make_unique<hdr_info_raw_t>(false);
|
||||
auto hdr_info = std::make_unique<hdr_info_raw_t>(false);
|
||||
if (colorspace_is_hdr(encode_device->colorspace)) {
|
||||
if (disp->get_hdr_metadata(hdr_info->metadata)) {
|
||||
hdr_info->enabled = true;
|
||||
@@ -2737,7 +2738,7 @@ namespace video {
|
||||
|
||||
auto ec = platf::capture_e::ok;
|
||||
while (encode_session_ctx_queue.running()) {
|
||||
auto push_captured_image_callback = [&](std::shared_ptr<platf::img_t> &&captured_image, bool frame_captured) -> bool {
|
||||
auto push_captured_image_callback = [&](std::shared_ptr<platf::img_t> &&captured_image, bool frame_captured) {
|
||||
while (encode_session_ctx_queue.peek()) {
|
||||
auto encode_session_ctx = encode_session_ctx_queue.pop();
|
||||
if (!encode_session_ctx) {
|
||||
@@ -2810,7 +2811,7 @@ namespace video {
|
||||
return true;
|
||||
};
|
||||
|
||||
auto pull_free_image_callback = [&img](std::shared_ptr<platf::img_t> &img_out) -> bool {
|
||||
auto pull_free_image_callback = [&img](std::shared_ptr<platf::img_t> &img_out) {
|
||||
img_out = img;
|
||||
img_out->frame_timestamp.reset();
|
||||
return true;
|
||||
@@ -2839,10 +2840,10 @@ namespace video {
|
||||
std::vector<std::unique_ptr<sync_session_ctx_t>> synced_session_ctxs;
|
||||
|
||||
auto &ctx = ref->encode_session_ctx_queue;
|
||||
auto lg = util::fail_guard([&]() {
|
||||
auto lg = util::fail_guard([&ctx, &synced_session_ctxs]() {
|
||||
ctx.stop();
|
||||
|
||||
for (auto &session_ctx : synced_session_ctxs) {
|
||||
for (const auto &session_ctx : synced_session_ctxs) {
|
||||
session_ctx->shutdown_event->raise(true);
|
||||
session_ctx->join_event->raise(true);
|
||||
}
|
||||
@@ -2877,7 +2878,7 @@ namespace video {
|
||||
auto shutdown_event = mail->event<bool>(mail::shutdown);
|
||||
|
||||
auto images = std::make_shared<img_event_t::element_type>();
|
||||
auto lg = util::fail_guard([&]() {
|
||||
auto lg = util::fail_guard([&images, &shutdown_event]() {
|
||||
images->stop();
|
||||
shutdown_event->raise(true);
|
||||
});
|
||||
@@ -2929,7 +2930,7 @@ namespace video {
|
||||
touch_port_event->raise(make_port(display.get(), config));
|
||||
|
||||
// Update client with our current HDR display state
|
||||
hdr_info_t hdr_info = std::make_unique<hdr_info_raw_t>(false);
|
||||
auto hdr_info = std::make_unique<hdr_info_raw_t>(false);
|
||||
if (colorspace_is_hdr(encode_device->colorspace)) {
|
||||
if (display->get_hdr_metadata(hdr_info->metadata)) {
|
||||
hdr_info->enabled = true;
|
||||
|
||||
@@ -157,7 +157,7 @@ namespace video {
|
||||
*/
|
||||
const color_t *color_vectors_from_colorspace(const sunshine_colorspace_t &colorspace, bool unorm_output) {
|
||||
using enum colorspace_e;
|
||||
constexpr auto generate_color_vectors = [](const sunshine_colorspace_t &colorspace, bool unorm_output) -> color_t {
|
||||
constexpr auto generate_color_vectors = [](const sunshine_colorspace_t &colorspace, bool unorm_output) {
|
||||
// "Table 4 – Interpretation of matrix coefficients (MatrixCoefficients) value" section of ITU-T H.273
|
||||
double Kr;
|
||||
double Kb;
|
||||
|
||||
@@ -43,6 +43,34 @@ TEST(SocketAddressTest, UnsupportedAddressFamiliesProduceEmptyAddressesAndZeroPo
|
||||
EXPECT_EQ(platf::from_sockaddr_ex(&address), (std::pair<std::uint16_t, std::string> {0, {}}));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Const batch descriptors locate payload boundaries and reject offsets past all buffers.
|
||||
*/
|
||||
TEST(BatchedSendInfoTest, ConstLookupPreservesBuffersAndFindsEveryBoundary) {
|
||||
const std::string_view first = "abc";
|
||||
const std::string_view second = "defg";
|
||||
std::vector<platf::buffer_descriptor_t> buffers {{nullptr, 0}, {first.data(), first.size()}, {second.data(), second.size()}};
|
||||
auto address = boost::asio::ip::address_v4::loopback();
|
||||
boost::asio::ip::address endpoint = address;
|
||||
const platf::batched_send_info_t batch {nullptr, 0, buffers, 1, 0, 7, 0, endpoint, 0, endpoint};
|
||||
|
||||
EXPECT_EQ(batch.buffer_for_payload_offset(0).buffer, first.data());
|
||||
EXPECT_EQ(batch.buffer_for_payload_offset(0).size, first.size());
|
||||
EXPECT_EQ(batch.buffer_for_payload_offset(2).buffer, first.data() + 2);
|
||||
EXPECT_EQ(batch.buffer_for_payload_offset(2).size, 1);
|
||||
EXPECT_EQ(batch.buffer_for_payload_offset(3).buffer, second.data());
|
||||
EXPECT_EQ(batch.buffer_for_payload_offset(3).size, second.size());
|
||||
EXPECT_EQ(batch.buffer_for_payload_offset(6).buffer, second.data() + 3);
|
||||
EXPECT_EQ(batch.buffer_for_payload_offset(6).size, 1);
|
||||
for (const auto offset : {7, 8}) {
|
||||
EXPECT_EQ(batch.buffer_for_payload_offset(offset).buffer, nullptr);
|
||||
EXPECT_EQ(batch.buffer_for_payload_offset(offset).size, 0);
|
||||
}
|
||||
EXPECT_EQ(buffers.size(), 3);
|
||||
EXPECT_EQ(buffers[1].buffer, first.data());
|
||||
EXPECT_EQ(buffers[1].size, first.size());
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(__linux__) || defined(__FreeBSD__)
|
||||
/**
|
||||
* @brief Exercise source-address control messages on bound UDP sockets with optional headers.
|
||||
@@ -64,7 +92,7 @@ TEST_P(UdpSourceAddressTest, SendsTheExpectedDatagramFromTheRequestedAddress) {
|
||||
const std::string_view headers = "headerheader";
|
||||
const std::string_view payloads = "payloadpayload";
|
||||
std::vector<platf::buffer_descriptor_t> buffers {{payloads.data(), payloads.size()}};
|
||||
platf::batched_send_info_t batch_info {
|
||||
const platf::batched_send_info_t batch_info {
|
||||
with_header ? headers.data() : nullptr,
|
||||
with_header ? header.size() : 0,
|
||||
buffers,
|
||||
|
||||
@@ -89,7 +89,7 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
);
|
||||
|
||||
TEST_P(AudioTest, TestEncode) {
|
||||
std::jthread timer([&] {
|
||||
std::jthread timer([this] {
|
||||
// Terminate the audio capture after 100 ms
|
||||
std::this_thread::sleep_for(100ms);
|
||||
const auto shutdown_event = m_mail->event<bool>(mail::shutdown);
|
||||
@@ -97,7 +97,7 @@ TEST_P(AudioTest, TestEncode) {
|
||||
shutdown_event->raise(true);
|
||||
audio_packets->stop();
|
||||
});
|
||||
std::jthread capture([&] {
|
||||
std::jthread capture([this] {
|
||||
const auto packets = m_mail->queue<packet_t>(mail::audio_packets);
|
||||
const auto shutdown_event = m_mail->event<bool>(mail::shutdown);
|
||||
while (const auto packet = packets->pop()) {
|
||||
|
||||
@@ -141,6 +141,22 @@ TEST_F(LogRotationTest, FindsSubstringsAtBoundariesAndWithCaseFolding) {
|
||||
|
||||
struct LogLevelsTest: BaseTest, testing::WithParamInterface<decltype(log_levels)::value_type> {};
|
||||
|
||||
/**
|
||||
* @brief Periodic logger callbacks preserve their owner's message and numeric formatting.
|
||||
*/
|
||||
TEST(PeriodicLoggerTest, ReportsIntegralAndFloatingSamplesWithConfiguredUnits) {
|
||||
logging::min_max_avg_periodic_logger<int> integral {info, "Integral capture", "ms", std::chrono::seconds {-1}};
|
||||
logging::min_max_avg_periodic_logger<double> floating {info, "Floating capture", "s", std::chrono::seconds {-1}};
|
||||
|
||||
integral.collect_and_log(3);
|
||||
floating.collect_and_log(1.25);
|
||||
integral.collect_and_log(7);
|
||||
floating.collect_and_log(2.5);
|
||||
|
||||
EXPECT_TRUE(log_checker::line_contains(log_file, "Integral capture (min/max/avg): 3ms/3ms/3.00ms"));
|
||||
EXPECT_TRUE(log_checker::line_contains(log_file, "Floating capture (min/max/avg): 1.25s/1.25s/1.25s"));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Logging,
|
||||
LogLevelsTest,
|
||||
|
||||
@@ -21,6 +21,17 @@ TEST(NetworkClassificationTest, DeducedNetworkListsPreserveAddressScopes) {
|
||||
EXPECT_EQ(net::from_address("2001:4860:4860::8888"), net::WAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Loopback and documentation addresses retain their classification when mapped to IPv6.
|
||||
*/
|
||||
TEST(NetworkClassificationTest, ClassifiesMappedIpv4AddressesWithoutChangingSubsequentLookups) {
|
||||
for (const auto *address : {"127.0.0.1", "192.0.2.1", "198.51.100.2", "203.0.113.3"}) {
|
||||
const auto expected = net::from_address(address);
|
||||
EXPECT_EQ(net::from_address(std::string {"::ffff:"} + address), expected);
|
||||
EXPECT_EQ(net::from_address(address), expected);
|
||||
}
|
||||
}
|
||||
|
||||
struct MdnsInstanceNameTest: BaseTest, testing::WithParamInterface<std::tuple<std::string, std::string>> {};
|
||||
|
||||
TEST_P(MdnsInstanceNameTest, Run) {
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <src/video.h>
|
||||
#ifdef _WIN32
|
||||
#include <src/platform/windows/nvprefs/nvprefs_common.h>
|
||||
#include <src/platform/windows/nvprefs/nvprefs_interface.h>
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
@@ -163,6 +164,28 @@ TEST(ResourceOwnershipTest, FileResetClosesUnderlyingDescriptor) {
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
/**
|
||||
* @brief Const NVIDIA preference inspection does not claim ownership before the interface is loaded.
|
||||
*/
|
||||
TEST(ResourceOwnershipTest, ConstNvPrefsInterfaceStartsWithoutAnUndoFile) {
|
||||
const nvprefs::nvprefs_interface preferences;
|
||||
EXPECT_FALSE(preferences.owning_undo_file());
|
||||
EXPECT_FALSE(preferences.owning_undo_file());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A const LocalAlloc deleter releases a movable allocation and accepts null pointers.
|
||||
*/
|
||||
TEST(ResourceOwnershipTest, ConstLocalAllocDeleterReleasesTheAllocation) {
|
||||
const auto allocation = LocalAlloc(LMEM_MOVEABLE, 16);
|
||||
ASSERT_NE(allocation, nullptr);
|
||||
ASSERT_NE(LocalFlags(allocation), LMEM_INVALID_HANDLE);
|
||||
const nvprefs::safe_hlocal_deleter destroy;
|
||||
destroy(allocation);
|
||||
EXPECT_EQ(LocalFlags(allocation), LMEM_INVALID_HANDLE);
|
||||
destroy(static_cast<void *>(nullptr));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Moving an NVPrefs handle transfers responsibility for closing it.
|
||||
*/
|
||||
|
||||
@@ -20,6 +20,22 @@ extern "C" {
|
||||
// local includes
|
||||
#include <src/rtsp.h>
|
||||
|
||||
/**
|
||||
* @brief Const RTSP wire headers decode network-order lengths independently of encryption flags.
|
||||
*/
|
||||
TEST(RtspHeaderTest, ConstAccessorsPreserveTheSerializedHeader) {
|
||||
using rtsp_stream::encrypted_rtsp_header_t;
|
||||
for (const auto length : {0U, 1U, 0x7fffffffU}) {
|
||||
for (const bool encrypted : {false, true}) {
|
||||
const auto flags = encrypted ? encrypted_rtsp_header_t::ENCRYPTED_MESSAGE_TYPE_BIT : 0U;
|
||||
const encrypted_rtsp_header_t header {util::endian::big(length | flags), 0, {}};
|
||||
EXPECT_EQ(header.payload_length(), length);
|
||||
EXPECT_EQ(header.is_encrypted(), encrypted);
|
||||
EXPECT_EQ(header.typeAndLength, util::endian::big(length | flags));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace rtsp_stream {
|
||||
class rtsp_server_t;
|
||||
|
||||
|
||||
@@ -15,6 +15,44 @@
|
||||
|
||||
static_assert(!std::is_convertible_v<std::uint32_t, safe::queue_t<int>>);
|
||||
|
||||
/**
|
||||
* @brief Const event inspection observes state transitions without consuming the pending value.
|
||||
*/
|
||||
TEST(ThreadSafeEvent, ConstPeekPreservesPendingValuesAcrossStateChanges) {
|
||||
safe::event_t<int> event;
|
||||
const auto &view = event;
|
||||
EXPECT_FALSE(view.peek());
|
||||
event.raise(42);
|
||||
EXPECT_TRUE(view.peek());
|
||||
EXPECT_TRUE(view.peek());
|
||||
EXPECT_EQ(event.try_pop(), 42);
|
||||
EXPECT_FALSE(view.peek());
|
||||
event.raise(7);
|
||||
event.stop();
|
||||
EXPECT_FALSE(view.peek());
|
||||
event.reset();
|
||||
EXPECT_FALSE(view.peek());
|
||||
event.raise(9);
|
||||
EXPECT_TRUE(view.peek());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Mail cleanup removes an expired post while preserving an active post's owner.
|
||||
*/
|
||||
TEST(ThreadSafeMail, CleanupPreservesLivePostsAndRemovesExpiredPosts) {
|
||||
safe::mail_raw_t mailbox;
|
||||
const auto live = std::make_shared<int>(7);
|
||||
mailbox.id_to_post.try_emplace("live", live);
|
||||
mailbox.id_to_post.try_emplace("expired", std::weak_ptr<void> {});
|
||||
|
||||
mailbox.cleanup();
|
||||
|
||||
EXPECT_EQ(mailbox.id_to_post.size(), 1);
|
||||
EXPECT_EQ(mailbox.id_to_post.at("live").lock(), live);
|
||||
mailbox.cleanup();
|
||||
EXPECT_EQ(mailbox.id_to_post.size(), 1);
|
||||
}
|
||||
|
||||
TEST(ThreadSafeQueue, RejectsNewestItemAtCapacity) {
|
||||
safe::queue_t<int> queue {1, safe::queue_t<int>::overflow_policy_e::reject};
|
||||
|
||||
|
||||
@@ -21,6 +21,19 @@
|
||||
// local includes
|
||||
#include <src/utility.h>
|
||||
|
||||
/**
|
||||
* @brief A const resource deleter invokes its release function exactly once per call.
|
||||
*/
|
||||
TEST(UtilityDestroyTest, ConstDeleterInvokesTheConfiguredReleaseFunction) {
|
||||
const util::Destroy<int *, void, +[](int *value) {
|
||||
++*value;
|
||||
}>
|
||||
destroy;
|
||||
int releases = 0;
|
||||
destroy(&releases);
|
||||
EXPECT_EQ(releases, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Simulate the opposite byte order for a byte-array fixture.
|
||||
*/
|
||||
|
||||
Reference in new issue
Block a user