diff --git a/sunshine/main.cpp b/sunshine/main.cpp index 987098f6..59b49024 100644 --- a/sunshine/main.cpp +++ b/sunshine/main.cpp @@ -189,34 +189,45 @@ int main(int argc, char *argv[]) { task_pool.start(1); + util::TaskPool::task_id_t force_shutdown = nullptr; // Create signal handler after logging has been initialized auto shutdown_event = mail::man->event(mail::shutdown); - on_signal(SIGINT, [shutdown_event]() { + on_signal(SIGINT, [&force_shutdown, shutdown_event]() { BOOST_LOG(info) << "Interrupt handler called"sv; - task_pool.pushDelayed([]() { + auto task = []() { BOOST_LOG(fatal) << "10 seconds passed, yet Sunshine's still running: Forcing shutdown"sv; log_flush(); std::abort(); - }, - 10s); + }; + force_shutdown = task_pool.pushDelayed(task, 10s).task_id; + shutdown_event->raise(true); }); - on_signal(SIGTERM, [shutdown_event]() { + on_signal(SIGTERM, [&force_shutdown, shutdown_event]() { BOOST_LOG(info) << "Terminate handler called"sv; - task_pool.pushDelayed([]() { + auto task = []() { BOOST_LOG(fatal) << "10 seconds passed, yet Sunshine's still running: Forcing shutdown"sv; log_flush(); std::abort(); - }, - 10s); + }; + force_shutdown = task_pool.pushDelayed(task, 10s).task_id; shutdown_event->raise(true); }); + auto exit_guard = util::fail_guard([&force_shutdown]() { + task_pool.cancel(force_shutdown); + + std::cout << "Sunshine exited: Press enter to continue"sv << std::endl; + + std::string _; + std::getline(std::cin, _); + }); + proc::refresh(config::stream.file_apps); auto deinit_guard = platf::init(); diff --git a/sunshine/nvhttp.cpp b/sunshine/nvhttp.cpp index 3f8e2895..09362f0c 100644 --- a/sunshine/nvhttp.cpp +++ b/sunshine/nvhttp.cpp @@ -520,6 +520,8 @@ void serverinfo(std::shared_ptr::Response> res tree.put("root.appversion", VERSION); tree.put("root.GfeVersion", GFE_VERSION); tree.put("root.uniqueid", http::unique_id); + tree.put("root.HttpsPort", map_port(PORT_HTTPS)); + tree.put("root.ExternalPort", map_port(PORT_HTTP)); tree.put("root.mac", platf::get_mac_address(request->local_endpoint_address())); tree.put("root.MaxLumaPixelsHEVC", config::video.hevc_mode > 1 ? "1869449984" : "0"); tree.put("root.LocalIP", request->local_endpoint_address()); @@ -673,6 +675,7 @@ void launch(bool &host_audio, resp_https_t response, req_https_t request) { stream::launch_session_raise(make_launch_session(host_audio, args)); tree.put("root..status_code", 200); + tree.put("root.sessionUrl0", "rtspru://"s + request->local_endpoint_address() + ':' + std::to_string(map_port(stream::RTSP_SETUP_PORT))); tree.put("root.gamesession", 1); } @@ -718,6 +721,7 @@ void resume(bool &host_audio, resp_https_t response, req_https_t request) { stream::launch_session_raise(make_launch_session(host_audio, args)); tree.put("root..status_code", 200); + tree.put("root.sessionUrl0", "rtspru://"s + request->local_endpoint_address() + ':' + std::to_string(map_port(stream::RTSP_SETUP_PORT))); tree.put("root.resume", 1); } diff --git a/sunshine/rtsp.cpp b/sunshine/rtsp.cpp index 538811cd..8dc7dde9 100644 --- a/sunshine/rtsp.cpp +++ b/sunshine/rtsp.cpp @@ -328,10 +328,11 @@ void cmd_describe(rtsp_server_t *server, net::peer_t peer, msg_t &&req) { } void cmd_setup(rtsp_server_t *server, net::peer_t peer, msg_t &&req) { - OPTION_ITEM options[2] {}; + OPTION_ITEM options[3] {}; auto &seqn = options[0]; auto &session_option = options[1]; + auto &port_option = options[2]; seqn.option = const_cast("CSeq"); @@ -343,18 +344,36 @@ void cmd_setup(rtsp_server_t *server, net::peer_t peer, msg_t &&req) { auto end = std::find(begin, std::end(target), '/'); std::string_view type { begin, (size_t)std::distance(begin, end) }; + std::uint16_t port; if(type == "audio"sv) { - seqn.next = &session_option; - - session_option.option = const_cast("Session"); - session_option.content = const_cast("DEADBEEFCAFE;timeout = 90"); + port = map_port(stream::AUDIO_STREAM_PORT); } - else if(type != "video"sv && type != "control"sv) { + else if(type == "video"sv) { + port = map_port(stream::VIDEO_STREAM_PORT); + } + else if(type == "control"sv) { + port = map_port(stream::CONTROL_PORT); + } + else { cmd_not_found(server->host(), peer, std::move(req)); return; } + seqn.next = &session_option; + + session_option.option = const_cast("Session"); + session_option.content = const_cast("DEADBEEFCAFE;timeout = 90"); + + session_option.next = &port_option; + + // Moonlight merely requires 'server_port=' + auto port_value = "server_port=" + std::to_string(port); + + port_option.option = const_cast("Transport"); + port_option.content = port_value.data(); + + respond(server->host(), peer, &seqn, 200, "OK", req->sequenceNumber, {}); }