diff --git a/src/core/src/platforms/linux/virtual-display/wayland-display.cpp b/src/core/src/platforms/linux/virtual-display/wayland-display.cpp index 71fda463..14edf73f 100644 --- a/src/core/src/platforms/linux/virtual-display/wayland-display.cpp +++ b/src/core/src/platforms/linux/virtual-display/wayland-display.cpp @@ -90,6 +90,7 @@ GstBuffer *get_frame(WaylandState &w_state) { static void destroy(WaylandState *w_state) { logs::log(logs::trace, "~WaylandState"); display_finish(w_state->display); + delete (w_state); } bool add_input_device(WaylandState &w_state, const std::string &device_path) { diff --git a/src/moonlight-server/gst-plugin/gstrtpmoonlightpay_audio.cpp b/src/moonlight-server/gst-plugin/gstrtpmoonlightpay_audio.cpp index 37ccae91..92a64f25 100644 --- a/src/moonlight-server/gst-plugin/gstrtpmoonlightpay_audio.cpp +++ b/src/moonlight-server/gst-plugin/gstrtpmoonlightpay_audio.cpp @@ -208,6 +208,12 @@ void gst_rtp_moonlight_pay_audio_dispose(GObject *object) { GST_DEBUG_OBJECT(rtpmoonlightpay_audio, "dispose"); + // free rtpmoonlightpay_audio->packets_buffer matrix + for (int i = 0; i < AUDIO_TOTAL_SHARDS; i++) { + delete[] rtpmoonlightpay_audio->packets_buffer[i]; + } + delete[] rtpmoonlightpay_audio->packets_buffer; + G_OBJECT_CLASS(gst_rtp_moonlight_pay_audio_parent_class)->dispose(object); } diff --git a/src/moonlight-server/state/config.hpp b/src/moonlight-server/state/config.hpp index 1281c514..531fdea6 100644 --- a/src/moonlight-server/state/config.hpp +++ b/src/moonlight-server/state/config.hpp @@ -29,7 +29,7 @@ void unpair(const Config &cfg, const PairedClient &client); * Returns the first PairedClient with the given client_cert */ inline std::optional get_client_via_ssl(const Config &cfg, x509::x509_ptr client_cert) { - auto paired_clients = cfg.paired_clients.load(); + auto paired_clients = cfg.paired_clients->load(); auto search_result = std::find_if(paired_clients->begin(), paired_clients->end(), [&client_cert](const PairedClient &pair_client) { auto paired_cert = x509::cert_from_string(pair_client.client_cert); diff --git a/src/moonlight-server/state/configTOML.cpp b/src/moonlight-server/state/configTOML.cpp index 5c71f508..cdd0a14b 100644 --- a/src/moonlight-server/state/configTOML.cpp +++ b/src/moonlight-server/state/configTOML.cpp @@ -148,27 +148,24 @@ static bool is_available(const GPU_VENDOR &gpu_vendor, const GstEncoder &setting settings.check_elements.begin(), settings.check_elements.end(), [settings, gpu_vendor](const auto &el_name) { - // Can we instantiate the plugin? - if (auto el = gst_element_factory_make(el_name.c_str(), nullptr)) { + // Is the selected GPU vendor compatible with the encoder? + // (Particularly useful when using multiple GPUs, e.g. nvcodec might be available but user + // wants to encode using the Intel GPU) + auto encoder_vendor = encoder_type(settings); + if (encoder_vendor == NVIDIA && gpu_vendor != GPU_VENDOR::NVIDIA) { + logs::log(logs::debug, "Skipping NVIDIA encoder, not a NVIDIA GPU ({})", (int)gpu_vendor); + } else if (encoder_vendor == VAAPI && (gpu_vendor != GPU_VENDOR::INTEL && gpu_vendor != GPU_VENDOR::AMD)) { + logs::log(logs::debug, "Skipping VAAPI encoder, not an Intel or AMD GPU ({})", (int)gpu_vendor); + } else if (encoder_vendor == QUICKSYNC && gpu_vendor != GPU_VENDOR::INTEL) { + logs::log(logs::debug, "Skipping QUICKSYNC encoder, not an Intel GPU ({})", (int)gpu_vendor); + } + // Can Gstreamer instantiate the element? This will only work if all the drivers are in place + else if (auto el = gst_element_factory_make(el_name.c_str(), nullptr)) { gst_object_unref(el); - // Is the selected GPU vendor compatible with the encoder? - // (Particularly useful when using multiple GPUs, e.g. nvcodec might be available but user - // wants to encode using the Intel GPU) - auto encoder_vendor = encoder_type(settings); - if (encoder_vendor == NVIDIA && gpu_vendor != GPU_VENDOR::NVIDIA) { - logs::log(logs::debug, "Skipping NVIDIA encoder, not a NVIDIA GPU ({})", (int)gpu_vendor); - return false; - } else if (encoder_vendor == VAAPI && (gpu_vendor != GPU_VENDOR::INTEL && gpu_vendor != GPU_VENDOR::AMD)) { - logs::log(logs::debug, "Skipping VAAPI encoder, not an Intel or AMD GPU ({})", (int)gpu_vendor); - return false; - } else if (encoder_vendor == QUICKSYNC && gpu_vendor != GPU_VENDOR::INTEL) { - logs::log(logs::debug, "Skipping QUICKSYNC encoder, not an Intel GPU ({})", (int)gpu_vendor); - return false; - } return true; - } else { - return false; } + + return false; }); } return false; @@ -340,19 +337,19 @@ Config load_or_default(const std::string &source, const std::shared_ptr>(); // - auto clients_atom = new immer::atom(paired_clients); + auto clients_atom = std::make_shared>(paired_clients); return Config{.uuid = uuid, .hostname = hostname, .config_source = source, .support_hevc = hevc_encoder.has_value(), .support_av1 = av1_encoder.has_value() && encoder_type(*av1_encoder) != SOFTWARE, - .paired_clients = *clients_atom, + .paired_clients = clients_atom, .apps = apps}; } void pair(const Config &cfg, const PairedClient &client) { // Update CFG - cfg.paired_clients.update( + cfg.paired_clients->update( [&client](const state::PairedClientList &paired_clients) { return paired_clients.push_back(client); }); // Update TOML @@ -364,7 +361,7 @@ void pair(const Config &cfg, const PairedClient &client) { void unpair(const Config &cfg, const PairedClient &client) { // Update CFG - cfg.paired_clients.update([&client](const state::PairedClientList &paired_clients) { + cfg.paired_clients->update([&client](const state::PairedClientList &paired_clients) { return paired_clients // | ranges::views::filter([&client](auto paired_client) { // return paired_client->client_cert != client.client_cert; // diff --git a/src/moonlight-server/state/data-structures.hpp b/src/moonlight-server/state/data-structures.hpp index 0617d492..0dfa21a8 100644 --- a/src/moonlight-server/state/data-structures.hpp +++ b/src/moonlight-server/state/data-structures.hpp @@ -127,7 +127,7 @@ struct Config { * Mutable, paired_clients will be loaded up on startup * but can be added at runtime */ - immer::atom &paired_clients; + std::shared_ptr> paired_clients; /** * List of available Apps diff --git a/tests/testGSTPlugin.cpp b/tests/testGSTPlugin.cpp index 1a3d9264..935534b8 100644 --- a/tests/testGSTPlugin.cpp +++ b/tests/testGSTPlugin.cpp @@ -1,8 +1,8 @@ #include -#include -#include #include #include +#include +#include using Catch::Matchers::Equals; @@ -291,7 +291,7 @@ TEST_CASE_METHOD(GStreamerTestsFixture, "Create RTP VIDEO packets", "[GSTPlugin] auto flatten_packets = gst_buffer_list_unfold(rtp_packets); auto packets_content = gst_buffer_copy_content(flatten_packets); - std::vector packets_ptr(total_shards); + std::vector packets_ptr(total_shards); for (int shard_idx = 0; shard_idx < total_shards; shard_idx++) { packets_ptr[shard_idx] = &packets_content.front() + (shard_idx * rtp_packet_size); } @@ -300,7 +300,8 @@ TEST_CASE_METHOD(GStreamerTestsFixture, "Create RTP VIDEO packets", "[GSTPlugin] std::vector marks = {0, 0, 0, 0}; auto rs = moonlight::fec::create(data_shards, parity_shards); - auto result = moonlight::fec::decode(rs.get(), &packets_ptr.front(), &marks.front(), total_shards, rtp_packet_size); + auto result = + moonlight::fec::decode(rs.get(), &packets_ptr.front(), &marks.front(), total_shards, rtp_packet_size); REQUIRE(result == 0); REQUIRE_THAT(packets_content, Equals(gst_buffer_copy_content(flatten_packets))); @@ -312,7 +313,8 @@ TEST_CASE_METHOD(GStreamerTestsFixture, "Create RTP VIDEO packets", "[GSTPlugin] std::vector marks = {1, 0, 0, 0}; auto rs = moonlight::fec::create(data_shards, parity_shards); - auto result = moonlight::fec::decode(rs.get(), &packets_ptr.front(), &marks.front(), total_shards, rtp_packet_size); + auto result = + moonlight::fec::decode(rs.get(), &packets_ptr.front(), &marks.front(), total_shards, rtp_packet_size); REQUIRE(result == 0); @@ -345,7 +347,9 @@ TEST_CASE_METHOD(GStreamerTestsFixture, "Create RTP VIDEO packets", "[GSTPlugin] * AUDIO */ TEST_CASE_METHOD(GStreamerTestsFixture, "Audio RTP packet creation", "[GSTPlugin]") { - auto rtpmoonlightpay = (gst_rtp_moonlight_pay_audio *)g_object_new(gst_TYPE_rtp_moonlight_pay_audio, nullptr); + auto rtpmoonlightpay = std::shared_ptr( + (gst_rtp_moonlight_pay_audio *)g_object_new(gst_TYPE_rtp_moonlight_pay_audio, nullptr), + g_object_unref); rtpmoonlightpay->encrypt = true; rtpmoonlightpay->aes_key = "0123456789012345"; @@ -353,7 +357,7 @@ TEST_CASE_METHOD(GStreamerTestsFixture, "Audio RTP packet creation", "[GSTPlugin auto payload_str = "TUNZ TUNZ TUMP TUMP!"s; auto payload = gst_buffer_new_and_fill(payload_str.size(), payload_str.c_str()); - auto rtp_packets = audio::split_into_rtp(rtpmoonlightpay, payload); + auto rtp_packets = audio::split_into_rtp(rtpmoonlightpay.get(), payload); REQUIRE(gst_buffer_list_length(rtp_packets) == 1); REQUIRE(rtpmoonlightpay->cur_seq_number == 1); @@ -377,7 +381,7 @@ TEST_CASE_METHOD(GStreamerTestsFixture, "Audio RTP packet creation", "[GSTPlugin REQUIRE_THAT(decrypted, Equals(payload_str)); } - rtp_packets = audio::split_into_rtp(rtpmoonlightpay, payload); + rtp_packets = audio::split_into_rtp(rtpmoonlightpay.get(), payload); REQUIRE(gst_buffer_list_length(rtp_packets) == 1); REQUIRE(rtpmoonlightpay->cur_seq_number == 2); auto second_pkt = gst_buffer_list_get(rtp_packets, 0); @@ -400,7 +404,7 @@ TEST_CASE_METHOD(GStreamerTestsFixture, "Audio RTP packet creation", "[GSTPlugin REQUIRE_THAT(decrypted, Equals(payload_str)); } - rtp_packets = audio::split_into_rtp(rtpmoonlightpay, payload); + rtp_packets = audio::split_into_rtp(rtpmoonlightpay.get(), payload); REQUIRE(gst_buffer_list_length(rtp_packets) == 1); REQUIRE(rtpmoonlightpay->cur_seq_number == 3); auto third_pkt = gst_buffer_list_get(rtp_packets, 0); @@ -426,7 +430,7 @@ TEST_CASE_METHOD(GStreamerTestsFixture, "Audio RTP packet creation", "[GSTPlugin /* When the 4th packet arrives, we'll also FEC encode all the previous and return * the data packet + 2 more FEC packets */ - rtp_packets = audio::split_into_rtp(rtpmoonlightpay, payload); + rtp_packets = audio::split_into_rtp(rtpmoonlightpay.get(), payload); REQUIRE(gst_buffer_list_length(rtp_packets) == 3); // One data packet + 2 FEC packets REQUIRE(rtpmoonlightpay->cur_seq_number == 4); @@ -478,7 +482,7 @@ TEST_CASE_METHOD(GStreamerTestsFixture, "Audio RTP packet creation", "[GSTPlugin SECTION("Missing one packet should still lead to successful reconstruct") { auto original_pkt = gst_buffer_copy_content(first_pkt, sizeof(audio::AudioRTPHeaders)); auto missing_pkt = std::vector(packet_size); - rtpmoonlightpay->packets_buffer[0] = &missing_pkt[0]; + std::copy(missing_pkt.begin(), missing_pkt.end(), rtpmoonlightpay->packets_buffer[0]); std::vector marks = {1, 0, 0, 0, 0, 0}; auto result = moonlight::fec::decode(rtpmoonlightpay->rs.get(), @@ -488,10 +492,9 @@ TEST_CASE_METHOD(GStreamerTestsFixture, "Audio RTP packet creation", "[GSTPlugin packet_size); REQUIRE(result == 0); - REQUIRE_THAT(std::string(missing_pkt.begin() + sizeof(audio::AudioRTPHeaders), missing_pkt.end()), + REQUIRE_THAT(std::string(rtpmoonlightpay->packets_buffer[0] + sizeof(audio::AudioRTPHeaders), + rtpmoonlightpay->packets_buffer[0] + packet_size), Equals(std::string(original_pkt.begin(), original_pkt.end()))); } - - g_object_unref(rtpmoonlightpay); } } diff --git a/tests/testMoonlight.cpp b/tests/testMoonlight.cpp index 5eb0d439..af8f6dfc 100644 --- a/tests/testMoonlight.cpp +++ b/tests/testMoonlight.cpp @@ -55,18 +55,18 @@ TEST_CASE("LocalState load TOML", "[LocalState]") { } SECTION("Paired Clients") { - REQUIRE_THAT(state.paired_clients.load().get(), Catch::Matchers::SizeIs(1)); - REQUIRE_THAT(state.paired_clients.load().get()[0]->client_cert, Equals("A VERY VALID CERTIFICATE")); - REQUIRE(state.paired_clients.load().get()[0]->run_uid == 1234); - REQUIRE(state.paired_clients.load().get()[0]->run_gid == 5678); - REQUIRE_THAT(state.paired_clients.load().get()[0]->app_state_folder, Equals("some/folder")); + REQUIRE_THAT(state.paired_clients->load().get(), Catch::Matchers::SizeIs(1)); + REQUIRE_THAT(state.paired_clients->load().get()[0]->client_cert, Equals("A VERY VALID CERTIFICATE")); + REQUIRE(state.paired_clients->load().get()[0]->run_uid == 1234); + REQUIRE(state.paired_clients->load().get()[0]->run_gid == 5678); + REQUIRE_THAT(state.paired_clients->load().get()[0]->app_state_folder, Equals("some/folder")); } } TEST_CASE("LocalState pairing information", "[LocalState]") { auto event_bus = std::make_shared(); - auto clients_atom = new immer::atom(); - auto cfg = state::Config{.config_source = "config.test.toml", .paired_clients = *clients_atom}; + auto clients_atom = std::make_shared>(); + auto cfg = state::Config{.config_source = "config.test.toml", .paired_clients = clients_atom}; auto a_client_cert = "-----BEGIN CERTIFICATE-----\n" "MIICvzCCAaegAwIBAgIBADANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDDBhOVklE\n" "SUEgR2FtZVN0cmVhbSBDbGllbnQwHhcNMjEwNzEwMDgzNjE3WhcNNDEwNzA1MDgz\n" @@ -112,15 +112,15 @@ TEST_CASE("LocalState pairing information", "[LocalState]") { REQUIRE(state::get_client_via_ssl(cfg, another_cert).has_value() == false); state::pair(cfg, {another_cert}); REQUIRE(state::get_client_via_ssl(cfg, another_cert).has_value() == true); - REQUIRE_THAT(cfg.paired_clients.load().get(), Catch::Matchers::SizeIs(2)); + REQUIRE_THAT(cfg.paired_clients->load().get(), Catch::Matchers::SizeIs(2)); state::unpair(cfg, {a_client_cert}); REQUIRE(state::get_client_via_ssl(cfg, a_client_cert).has_value() == false); REQUIRE(state::get_client_via_ssl(cfg, another_cert).has_value() == true); - REQUIRE_THAT(cfg.paired_clients.load().get(), Catch::Matchers::SizeIs(1)); + REQUIRE_THAT(cfg.paired_clients->load().get(), Catch::Matchers::SizeIs(1)); state::unpair(cfg, {another_cert}); - REQUIRE_THAT(cfg.paired_clients.load().get(), Catch::Matchers::SizeIs(0)); + REQUIRE_THAT(cfg.paired_clients->load().get(), Catch::Matchers::SizeIs(0)); } } @@ -353,7 +353,7 @@ TEST_CASE("launch", "[MoonlightProtocol]") { TEST_CASE("Multiple users", "[HTTP]") { auto event_bus = std::make_shared(); - auto paired_clients = immer::atom(); + auto paired_clients = std::shared_ptr>(); auto app_state = state::AppState{ .config = state::Config{.paired_clients = paired_clients}, .host = {},