diff --git a/docs/source/about/usage.rst b/docs/source/about/usage.rst index f24ba011..f6c574f1 100644 --- a/docs/source/about/usage.rst +++ b/docs/source/about/usage.rst @@ -241,8 +241,7 @@ Application List - ``undo`` - Run after the application has terminated - - This should not fail considering it is supposed to undo the ``do`` commands - - If it fails, Sunshine is terminated + - Failures of ``undo`` commands are ignored - ``working-dir`` - The working directory to use. If not specified, Sunshine will use the application directory. diff --git a/src/platform/common.h b/src/platform/common.h index e01a9595..6f4af7e9 100644 --- a/src/platform/common.h +++ b/src/platform/common.h @@ -11,6 +11,7 @@ #include #include +#include "src/main.h" #include "src/thread_safe.h" #include "src/utility.h" @@ -197,7 +198,7 @@ struct hwdevice_t { * implementations must take ownership of 'frame' */ virtual int set_frame(AVFrame *frame) { - std::abort(); // ^ This function must never be called + BOOST_LOG(error) << "Illegal call to hwdevice_t::set_frame(). Did you forget to override it?"; return -1; }; diff --git a/src/platform/linux/audio.cpp b/src/platform/linux/audio.cpp index 531e348a..7973a384 100644 --- a/src/platform/linux/audio.cpp +++ b/src/platform/linux/audio.cpp @@ -89,9 +89,7 @@ std::unique_ptr microphone(const std::uint8_t *mapping, int channels, std if(!mic->mic) { auto err_str = pa_strerror(status); BOOST_LOG(error) << "pa_simple_new() failed: "sv << err_str; - - log_flush(); - std::abort(); + return nullptr; } return mic; @@ -232,10 +230,8 @@ public: auto status = pa_mainloop_run(loop, &retval); if(status < 0) { - BOOST_LOG(fatal) << "Couldn't run pulseaudio main loop"sv; - - log_flush(); - std::abort(); + BOOST_LOG(error) << "Couldn't run pulseaudio main loop"sv; + return; } }, loop.get() diff --git a/src/platform/linux/input.cpp b/src/platform/linux/input.cpp index 35e10f51..23acb33e 100644 --- a/src/platform/linux/input.cpp +++ b/src/platform/linux/input.cpp @@ -902,6 +902,9 @@ void broadcastRumble(safe::queue_t &rumble_queue_queue) { void abs_mouse(input_t &input, const touch_port_t &touch_port, float x, float y) { auto touchscreen = ((input_raw_t *)input.get())->touch_input.get(); + if(!touchscreen) { + return; + } auto scaled_x = (int)std::lround((x + touch_port.offset_x) * ((float)target_touch_port.width / (float)touch_port.width)); auto scaled_y = (int)std::lround((y + touch_port.offset_y) * ((float)target_touch_port.height / (float)touch_port.height)); @@ -916,6 +919,9 @@ void abs_mouse(input_t &input, const touch_port_t &touch_port, float x, float y) void move_mouse(input_t &input, int deltaX, int deltaY) { auto mouse = ((input_raw_t *)input.get())->mouse_input.get(); + if(!mouse) { + return; + } if(deltaX) { libevdev_uinput_write_event(mouse, EV_REL, REL_X, deltaX); @@ -954,6 +960,10 @@ void button_mouse(input_t &input, int button, bool release) { } auto mouse = ((input_raw_t *)input.get())->mouse_input.get(); + if(!mouse) { + return; + } + libevdev_uinput_write_event(mouse, EV_MSC, MSC_SCAN, scan); libevdev_uinput_write_event(mouse, EV_KEY, btn_type, release ? 0 : 1); libevdev_uinput_write_event(mouse, EV_SYN, SYN_REPORT, 0); @@ -963,6 +973,10 @@ void scroll(input_t &input, int high_res_distance) { int distance = high_res_distance / 120; auto mouse = ((input_raw_t *)input.get())->mouse_input.get(); + if(!mouse) { + return; + } + libevdev_uinput_write_event(mouse, EV_REL, REL_WHEEL, distance); libevdev_uinput_write_event(mouse, EV_REL, REL_WHEEL_HI_RES, high_res_distance); libevdev_uinput_write_event(mouse, EV_SYN, SYN_REPORT, 0); @@ -978,6 +992,9 @@ static keycode_t keysym(std::uint16_t modcode) { void keyboard(input_t &input, uint16_t modcode, bool release) { auto keyboard = ((input_raw_t *)input.get())->keyboard_input.get(); + if(!keyboard) { + return; + } auto keycode = keysym(modcode); if(keycode.keycode == UNKNOWN) { @@ -1255,10 +1272,13 @@ input_t input() { gp.mouse_dev = mouse(); gp.gamepad_dev = x360(); - // If we do not have a keyboard, gamepad or mouse, no input is possible and we should abort - if(gp.create_mouse() || gp.create_touchscreen() || gp.create_keyboard()) { - log_flush(); - std::abort(); + gp.create_mouse(); + gp.create_touchscreen(); + gp.create_keyboard(); + + // If we do not have a keyboard, touchscreen, or mouse, no input is possible + if(!gp.mouse_input && !gp.touch_input && !gp.keyboard_input) { + BOOST_LOG(error) << "Unable to create any input devices! Are you a member of the 'input' group?"sv; } return result; diff --git a/src/platform/linux/kmsgrab.cpp b/src/platform/linux/kmsgrab.cpp index 04763026..8a756716 100644 --- a/src/platform/linux/kmsgrab.cpp +++ b/src/platform/linux/kmsgrab.cpp @@ -251,11 +251,18 @@ public: fb_t fb(plane_t::pointer plane) { cap_sys_admin admin; - auto fb = drmModeGetFB2(fd.el, plane->fb_id); + + auto fb2 = drmModeGetFB2(fd.el, plane->fb_id); + if(fb2) { + return std::make_unique(fb2); + } + + auto fb = drmModeGetFB(fd.el, plane->fb_id); if(fb) { return std::make_unique(fb); } - return std::make_unique(drmModeGetFB(fd.el, plane->fb_id)); + + return nullptr; } crtc_t crtc(std::uint32_t id) { diff --git a/src/platform/windows/input.cpp b/src/platform/windows/input.cpp index dddaf376..8c7384e1 100644 --- a/src/platform/windows/input.cpp +++ b/src/platform/windows/input.cpp @@ -495,10 +495,7 @@ void gamepad(input_t &input, int nr, const gamepad_state_t &gamepad_state) { } if(!VIGEM_SUCCESS(status)) { - BOOST_LOG(fatal) << "Couldn't send gamepad input to ViGEm ["sv << util::hex(status).to_string_view() << ']'; - - log_flush(); - std::abort(); + BOOST_LOG(warning) << "Couldn't send gamepad input to ViGEm ["sv << util::hex(status).to_string_view() << ']'; } } diff --git a/src/platform/windows/publish.cpp b/src/platform/windows/publish.cpp index 92673e1d..d59c55c5 100644 --- a/src/platform/windows/publish.cpp +++ b/src/platform/windows/publish.cpp @@ -25,8 +25,9 @@ using namespace std::literals; #define SV(quote) __SV(quote) extern "C" { +constexpr auto DNS_REQUEST_PENDING = 9506L; + #ifndef __MINGW32__ -constexpr auto DNS_REQUEST_PENDING = 9506L; constexpr auto DNS_QUERY_REQUEST_VERSION1 = 0x1; constexpr auto DNS_QUERY_RESULTS_VERSION1 = 0x1; #endif @@ -88,26 +89,17 @@ _FN(_DnsServiceRegister, DWORD, (_In_ PDNS_SERVICE_REGISTER_REQUEST pRequest, _I namespace platf::publish { VOID WINAPI register_cb(DWORD status, PVOID pQueryContext, PDNS_SERVICE_INSTANCE pInstance) { - auto alarm = (safe::alarm_t::element_type *)pQueryContext; - - auto fg = util::fail_guard([&]() { - if(pInstance) { - _DnsServiceFreeInstance(pInstance); - } - }); + auto alarm = (safe::alarm_t::element_type *)pQueryContext; if(status) { print_status("register_cb()"sv, status); - alarm->ring(-1); - - return; } - alarm->ring(0); + alarm->ring(pInstance); } -static int service(bool enable) { - auto alarm = safe::make_alarm(); +static int service(bool enable, PDNS_SERVICE_INSTANCE &existing_instance) { + auto alarm = safe::make_alarm(); std::wstring_convert, wchar_t> converter; @@ -124,38 +116,66 @@ static int service(bool enable) { DNS_SERVICE_REGISTER_REQUEST req {}; req.Version = DNS_QUERY_REQUEST_VERSION1; req.pQueryContext = alarm.get(); - req.pServiceInstance = &instance; + req.pServiceInstance = enable ? &instance : existing_instance; req.pRegisterCompletionCallback = register_cb; DNS_STATUS status {}; if(enable) { status = _DnsServiceRegister(&req, nullptr); + if(status != DNS_REQUEST_PENDING) { + print_status("DnsServiceRegister()"sv, status); + return -1; + } } else { status = _DnsServiceDeRegister(&req, nullptr); + if(status != DNS_REQUEST_PENDING) { + print_status("DnsServiceDeRegister()"sv, status); + return -1; + } } alarm->wait(); - status = *alarm->status(); - if(status) { - BOOST_LOG(error) << "No mDNS service"sv; - return -1; + auto registered_instance = alarm->status(); + if(enable) { + // Store this instance for later deregistration + existing_instance = registered_instance; + } + else if(registered_instance) { + // Deregistration was successful + _DnsServiceFreeInstance(registered_instance); + existing_instance = nullptr; } - return 0; + return registered_instance ? 0 : -1; } -class deinit_t : public ::platf::deinit_t { +class mdns_registration_t : public ::platf::deinit_t { public: - ~deinit_t() override { - if(service(false)) { - std::abort(); + mdns_registration_t() : existing_instance(nullptr) { + if(service(true, existing_instance)) { + BOOST_LOG(error) << "Unable to register Sunshine mDNS service"sv; + return; } - BOOST_LOG(info) << "Unregistered Sunshine Gamestream service"sv; + BOOST_LOG(info) << "Registered Sunshine mDNS service"sv; } + + ~mdns_registration_t() override { + if(existing_instance) { + if(service(false, existing_instance)) { + BOOST_LOG(error) << "Unable to unregister Sunshine mDNS service"sv; + return; + } + + BOOST_LOG(info) << "Unregistered Sunshine mDNS service"sv; + } + } + +private: + PDNS_SERVICE_INSTANCE existing_instance; }; int load_funcs(HMODULE handle) { @@ -184,12 +204,6 @@ std::unique_ptr<::platf::deinit_t> start() { return nullptr; } - if(service(true)) { - return nullptr; - } - - BOOST_LOG(info) << "Registered Sunshine Gamestream service"sv; - - return std::make_unique(); + return std::make_unique(); } } // namespace platf::publish diff --git a/src/process.cpp b/src/process.cpp index 44be2e83..05dabe19 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -195,12 +195,6 @@ void proc_t::terminate() { _process_handle = bp::group(); _app_id = -1; - if(ec) { - BOOST_LOG(fatal) << "System: "sv << ec.message(); - log_flush(); - std::abort(); - } - for(; _undo_it != _undo_begin; --_undo_it) { auto &cmd = (_undo_it - 1)->undo_cmd; @@ -213,15 +207,11 @@ void proc_t::terminate() { auto ret = exe_with_full_privs(cmd, _env, _pipe, ec); if(ec) { - BOOST_LOG(fatal) << "System: "sv << ec.message(); - log_flush(); - std::abort(); + BOOST_LOG(warning) << "System: "sv << ec.message(); } if(ret != 0) { - BOOST_LOG(fatal) << "Return code ["sv << ret << ']'; - log_flush(); - std::abort(); + BOOST_LOG(warning) << "Return code ["sv << ret << ']'; } } diff --git a/src/stream.cpp b/src/stream.cpp index 4d530998..d263cff4 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -877,10 +877,8 @@ void recvThread(broadcast_ctx_t &ctx) { } if(ec || !bytes) { - BOOST_LOG(fatal) << "Couldn't receive data from udp socket: "sv << ec.message(); - - log_flush(); - std::abort(); + BOOST_LOG(error) << "Couldn't receive data from udp socket: "sv << ec.message(); + return; } auto it = peer_to_session.find(peer.address());