From f0bbbbe4a9d6b0314dc98ed27b63e96045a6e8cf Mon Sep 17 00:00:00 2001 From: dec05eba Date: Tue, 25 Feb 2025 17:33:21 +0100 Subject: Replay on startup: wait until audio devices are available before turning replay on --- src/Config.cpp | 14 +++++++ src/GsrInfo.cpp | 2 +- src/Overlay.cpp | 83 ++++++++++++++++++++++++++++---------- src/Process.cpp | 20 ++++----- src/gui/ScreenshotSettingsPage.cpp | 6 ++- 5 files changed, 91 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/Config.cpp b/src/Config.cpp index ebdc0ca..734f827 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -45,6 +46,19 @@ namespace gsr { } } + ReplayStartupMode replay_startup_string_to_type(const char *startup_mode_str) { + if(strcmp(startup_mode_str, "dont_turn_on_automatically") == 0) + return ReplayStartupMode::DONT_TURN_ON_AUTOMATICALLY; + else if(strcmp(startup_mode_str, "turn_on_at_system_startup") == 0) + return ReplayStartupMode::TURN_ON_AT_SYSTEM_STARTUP; + else if(strcmp(startup_mode_str, "turn_on_at_fullscreen") == 0) + return ReplayStartupMode::TURN_ON_AT_FULLSCREEN; + else if(strcmp(startup_mode_str, "turn_on_at_power_supply_connected") == 0) + return ReplayStartupMode::TURN_ON_AT_POWER_SUPPLY_CONNECTED; + else + return ReplayStartupMode::DONT_TURN_ON_AUTOMATICALLY; + } + bool ConfigHotkey::operator==(const ConfigHotkey &other) const { return key == other.key && modifiers == other.modifiers; } diff --git a/src/GsrInfo.cpp b/src/GsrInfo.cpp index c9373ae..5126d13 100644 --- a/src/GsrInfo.cpp +++ b/src/GsrInfo.cpp @@ -258,7 +258,7 @@ namespace gsr { std::string stdout_str; const char *args[] = { "gpu-screen-recorder", "--list-audio-devices", nullptr }; - if(exec_program_get_stdout(args, stdout_str) != 0) { + if(exec_program_get_stdout(args, stdout_str, false) != 0) { fprintf(stderr, "error: 'gpu-screen-recorder --list-audio-devices' failed\n"); return audio_devices; } diff --git a/src/Overlay.cpp b/src/Overlay.cpp index 22d8a7f..35bb78f 100644 --- a/src/Overlay.cpp +++ b/src/Overlay.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -41,7 +42,7 @@ extern "C" { namespace gsr { static const mgl::Color bg_color(0, 0, 0, 100); static const double force_window_on_top_timeout_seconds = 1.0; - static const double replay_status_update_check_timeout_seconds = 1.0; + static const double replay_status_update_check_timeout_seconds = 1.5; static const double replay_saving_notification_timeout_seconds = 0.5; static mgl::Texture texture_from_ximage(XImage *img) { @@ -436,9 +437,7 @@ namespace gsr { init_color_theme(config, this->gsr_info); power_supply_online_filepath = get_power_supply_online_filepath(); - - if(config.replay_config.turn_on_replay_automatically_mode == "turn_on_at_system_startup") - on_press_start_replay(true); + replay_startup_mode = replay_startup_string_to_type(config.replay_config.turn_on_replay_automatically_mode.c_str()); if(config.main_config.hotkeys_enable_option == "enable_hotkeys") global_hotkeys = register_linux_hotkeys(this, GlobalHotkeysLinux::GrabType::ALL); @@ -1070,6 +1069,7 @@ namespace gsr { if(id == "settings") { auto replay_settings_page = std::make_unique(SettingsPage::Type::REPLAY, &gsr_info, config, &page_stack); replay_settings_page->on_config_changed = [this]() { + replay_startup_mode = replay_startup_string_to_type(config.replay_config.turn_on_replay_automatically_mode.c_str()); if(recording_status == RecordingStatus::REPLAY) show_notification("Replay settings have been modified.\nYou may need to restart replay to apply the changes.", 5.0, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::REPLAY); }; @@ -1656,6 +1656,33 @@ namespace gsr { gpu_screen_recorder_screenshot_process = -1; } + static bool starts_with(std::string_view str, const char *substr) { + size_t len = strlen(substr); + return str.size() >= len && memcmp(str.data(), substr, len) == 0; + } + + static bool are_all_audio_tracks_available_to_capture(const std::vector &audio_tracks) { + const auto audio_devices = get_audio_devices(); + for(const std::string &audio_track : audio_tracks) { + std::string_view audio_track_name(audio_track.c_str()); + const bool is_app_audio = starts_with(audio_track_name, "app:"); + if(is_app_audio) + continue; + + if(starts_with(audio_track_name, "device:")) + audio_track_name.remove_prefix(7); + + auto it = std::find_if(audio_devices.begin(), audio_devices.end(), [&](const auto &audio_device) { + return audio_device.name == audio_track_name; + }); + if(it == audio_devices.end()) { + //fprintf(stderr, "Audio not ready\n"); + return false; + } + } + return true; + } + void Overlay::replay_status_update_status() { if(replay_status_update_clock.get_elapsed_time_seconds() < replay_status_update_check_timeout_seconds) return; @@ -1663,10 +1690,11 @@ namespace gsr { replay_status_update_clock.restart(); update_focused_fullscreen_status(); update_power_supply_status(); + update_system_startup_status(); } void Overlay::update_focused_fullscreen_status() { - if(config.replay_config.turn_on_replay_automatically_mode != "turn_on_at_fullscreen") + if(replay_startup_mode != ReplayStartupMode::TURN_ON_AT_FULLSCREEN) return; mgl_context *context = mgl_get_context(); @@ -1679,28 +1707,40 @@ namespace gsr { const bool prev_focused_window_is_fullscreen = focused_window_is_fullscreen; focused_window_is_fullscreen = focused_window != 0 && window_is_fullscreen(display, focused_window); if(focused_window_is_fullscreen != prev_focused_window_is_fullscreen) { - if(recording_status == RecordingStatus::NONE && focused_window_is_fullscreen) - on_press_start_replay(false); - else if(recording_status == RecordingStatus::REPLAY && !focused_window_is_fullscreen) + if(recording_status == RecordingStatus::NONE && focused_window_is_fullscreen) { + if(are_all_audio_tracks_available_to_capture(config.replay_config.record_options.audio_tracks)) + on_press_start_replay(false); + } else if(recording_status == RecordingStatus::REPLAY && !focused_window_is_fullscreen) { on_press_start_replay(true); + } } } // TODO: Instead of checking power supply status periodically listen to power supply event void Overlay::update_power_supply_status() { - if(config.replay_config.turn_on_replay_automatically_mode != "turn_on_at_power_supply_connected") + if(replay_startup_mode != ReplayStartupMode::TURN_ON_AT_POWER_SUPPLY_CONNECTED) return; const bool prev_power_supply_status = power_supply_connected; power_supply_connected = power_supply_online_filepath.empty() || power_supply_is_connected(power_supply_online_filepath.c_str()); if(power_supply_connected != prev_power_supply_status) { - if(recording_status == RecordingStatus::NONE && power_supply_connected) - on_press_start_replay(false); - else if(recording_status == RecordingStatus::REPLAY && !power_supply_connected) + if(recording_status == RecordingStatus::NONE && power_supply_connected) { + if(are_all_audio_tracks_available_to_capture(config.replay_config.record_options.audio_tracks)) + on_press_start_replay(false); + } else if(recording_status == RecordingStatus::REPLAY && !power_supply_connected) { on_press_start_replay(false); + } } } + void Overlay::update_system_startup_status() { + if(replay_startup_mode != ReplayStartupMode::TURN_ON_AT_SYSTEM_STARTUP || recording_status != RecordingStatus::NONE || !try_replay_startup) + return; + + if(are_all_audio_tracks_available_to_capture(config.replay_config.record_options.audio_tracks)) + on_press_start_replay(true); + } + void Overlay::on_stop_recording(int exit_code) { if(exit_code == 0) { if(config.record_config.save_video_in_game_folder) { @@ -1816,11 +1856,6 @@ namespace gsr { return container; } - static bool starts_with(std::string_view str, const char *substr) { - size_t len = strlen(substr); - return str.size() >= len && memcmp(str.data(), substr, len) == 0; - } - static std::vector create_audio_tracks_real_names(const std::vector &audio_tracks, bool application_audio_invert, const GsrInfo &gsr_info) { std::vector result; for(const std::string &audio_track : audio_tracks) { @@ -1906,21 +1941,22 @@ namespace gsr { kill(gpu_screen_recorder_process, SIGUSR1); } - void Overlay::on_press_start_replay(bool disable_notification) { + bool Overlay::on_press_start_replay(bool disable_notification) { switch(recording_status) { case RecordingStatus::NONE: case RecordingStatus::REPLAY: break; case RecordingStatus::RECORD: show_notification("Unable to start replay when recording.\nStop recording before starting replay.", 5.0, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::RECORD); - return; + return false; case RecordingStatus::STREAM: show_notification("Unable to start replay when streaming.\nStop streaming before starting replay.", 5.0, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::STREAM); - return; + return false; } paused = false; replay_save_show_notification = false; + try_replay_startup = false; // window->close(); // usleep(1000 * 50); // 50 milliseconds @@ -1942,14 +1978,15 @@ namespace gsr { // TODO: Show this with a slight delay to make sure it doesn't show up in the video if(!disable_notification && config.replay_config.show_replay_stopped_notifications) show_notification("Replay stopped", 3.0, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::REPLAY); - return; + + return true; } if(!validate_capture_target(gsr_info, config.replay_config.record_options.record_area_option)) { char err_msg[256]; snprintf(err_msg, sizeof(err_msg), "Failed to start replay, capture target \"%s\" is invalid. Please change capture target in settings", config.replay_config.record_options.record_area_option.c_str()); show_notification(err_msg, 3.0, mgl::Color(255, 0, 0, 0), mgl::Color(255, 0, 0, 0), NotificationType::REPLAY); - return; + return false; } // TODO: Validate input, fallback to valid values @@ -2024,6 +2061,8 @@ namespace gsr { // to see when the program has exit. if(!disable_notification && config.replay_config.show_replay_started_notifications) show_notification("Replay has started", 3.0, get_color_theme().tint_color, get_color_theme().tint_color, NotificationType::REPLAY); + + return true; } void Overlay::on_press_start_record() { diff --git a/src/Process.cpp b/src/Process.cpp index c5fcf0f..0a62986 100644 --- a/src/Process.cpp +++ b/src/Process.cpp @@ -40,12 +40,13 @@ namespace gsr { return num_args; } - bool exec_program_daemonized(const char **args) { + bool exec_program_daemonized(const char **args, bool debug) { /* 1 argument */ if(args[0] == nullptr) return false; - debug_print_args(args); + if(debug) + debug_print_args(args); const pid_t pid = vfork(); if(pid == -1) { @@ -72,7 +73,7 @@ namespace gsr { return true; } - pid_t exec_program(const char **args, int *read_fd) { + pid_t exec_program(const char **args, int *read_fd, bool debug) { if(read_fd) *read_fd = -1; @@ -84,7 +85,8 @@ namespace gsr { if(pipe(fds) == -1) return -1; - debug_print_args(args); + if(debug) + debug_print_args(args); const pid_t pid = vfork(); if(pid == -1) { @@ -110,10 +112,10 @@ namespace gsr { } } - int exec_program_get_stdout(const char **args, std::string &result) { + int exec_program_get_stdout(const char **args, std::string &result, bool debug) { result.clear(); int read_fd = -1; - const pid_t process_id = exec_program(args, &read_fd); + const pid_t process_id = exec_program(args, &read_fd, debug); if(process_id == -1) return -1; @@ -152,7 +154,7 @@ namespace gsr { return exit_status; } - int exec_program_on_host_get_stdout(const char **args, std::string &result) { + int exec_program_on_host_get_stdout(const char **args, std::string &result, bool debug) { if(count_num_args(args) > 64 - 3) { fprintf(stderr, "Error: too many arguments when trying to launch \"%s\"\n", args[0]); return -1; @@ -170,9 +172,9 @@ namespace gsr { } modified_args[i] = arg; } - return exec_program_get_stdout(modified_args, result); + return exec_program_get_stdout(modified_args, result, debug); } else { - return exec_program_get_stdout(args, result); + return exec_program_get_stdout(args, result, debug); } } diff --git a/src/gui/ScreenshotSettingsPage.cpp b/src/gui/ScreenshotSettingsPage.cpp index 457ff89..f2f4730 100644 --- a/src/gui/ScreenshotSettingsPage.cpp +++ b/src/gui/ScreenshotSettingsPage.cpp @@ -191,8 +191,10 @@ namespace gsr { std::unique_ptr ScreenshotSettingsPage::create_image_format_box() { auto box = std::make_unique(&get_theme().body_font); - box->add_item("jpg", "jpg"); - box->add_item("png", "png"); + if(gsr_info->supported_image_formats.jpeg) + box->add_item("jpg", "jpg"); + if(gsr_info->supported_image_formats.png) + box->add_item("png", "png"); image_format_box_ptr = box.get(); return box; } -- cgit v1.2.3-70-g09d2