From 4ba1e814b748d57631f6b7afb7eaa63e8435c24e Mon Sep 17 00:00:00 2001 From: dec05eba Date: Wed, 13 Nov 2024 22:18:30 +0100 Subject: Add application audio option --- src/Config.cpp | 9 ++ src/GsrInfo.cpp | 26 ++++++ src/Overlay.cpp | 149 +++++++++++++------------------- src/gui/CheckBox.cpp | 12 +-- src/gui/Label.cpp | 4 + src/gui/LineSeparator.cpp | 45 ++++++++++ src/gui/SettingsPage.cpp | 215 +++++++++++++++++++++++++++++++++++++++------- src/gui/Subsection.cpp | 18 +++- 8 files changed, 352 insertions(+), 126 deletions(-) create mode 100644 src/gui/LineSeparator.cpp (limited to 'src') diff --git a/src/Config.cpp b/src/Config.cpp index 86d7732..3a0b70b 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -57,8 +57,11 @@ namespace gsr { {"streaming.record_options.fps", &config.streaming_config.record_options.fps}, {"streaming.record_options.video_bitrate", &config.streaming_config.record_options.video_bitrate}, {"streaming.record_options.merge_audio_tracks", &config.streaming_config.record_options.merge_audio_tracks}, + {"streaming.record_options.application_audio_invert", &config.streaming_config.record_options.application_audio_invert}, {"streaming.record_options.change_video_resolution", &config.streaming_config.record_options.change_video_resolution}, + {"streaming.record_options.audio_type_view", &config.streaming_config.record_options.audio_type_view}, {"streaming.record_options.audio_track", &config.streaming_config.record_options.audio_tracks}, + {"streaming.record_options.application_audio", &config.streaming_config.record_options.application_audio}, {"streaming.record_options.color_range", &config.streaming_config.record_options.color_range}, {"streaming.record_options.video_quality", &config.streaming_config.record_options.video_quality}, {"streaming.record_options.codec", &config.streaming_config.record_options.video_codec}, @@ -85,8 +88,11 @@ namespace gsr { {"record.record_options.fps", &config.record_config.record_options.fps}, {"record.record_options.video_bitrate", &config.record_config.record_options.video_bitrate}, {"record.record_options.merge_audio_tracks", &config.record_config.record_options.merge_audio_tracks}, + {"record.record_options.application_audio_invert", &config.record_config.record_options.application_audio_invert}, {"record.record_options.change_video_resolution", &config.record_config.record_options.change_video_resolution}, + {"record.record_options.audio_type_view", &config.record_config.record_options.audio_type_view}, {"record.record_options.audio_track", &config.record_config.record_options.audio_tracks}, + {"record.record_options.application_audio", &config.record_config.record_options.application_audio}, {"record.record_options.color_range", &config.record_config.record_options.color_range}, {"record.record_options.video_quality", &config.record_config.record_options.video_quality}, {"record.record_options.codec", &config.record_config.record_options.video_codec}, @@ -112,8 +118,11 @@ namespace gsr { {"replay.record_options.fps", &config.replay_config.record_options.fps}, {"replay.record_options.video_bitrate", &config.replay_config.record_options.video_bitrate}, {"replay.record_options.merge_audio_tracks", &config.replay_config.record_options.merge_audio_tracks}, + {"replay.record_options.application_audio_invert", &config.replay_config.record_options.application_audio_invert}, {"replay.record_options.change_video_resolution", &config.replay_config.record_options.change_video_resolution}, + {"replay.record_options.audio_type_view", &config.replay_config.record_options.audio_type_view}, {"replay.record_options.audio_track", &config.replay_config.record_options.audio_tracks}, + {"replay.record_options.application_audio", &config.replay_config.record_options.application_audio}, {"replay.record_options.color_range", &config.replay_config.record_options.color_range}, {"replay.record_options.video_quality", &config.replay_config.record_options.video_quality}, {"replay.record_options.codec", &config.replay_config.record_options.video_codec}, diff --git a/src/GsrInfo.cpp b/src/GsrInfo.cpp index 916430c..bb410dc 100644 --- a/src/GsrInfo.cpp +++ b/src/GsrInfo.cpp @@ -218,4 +218,30 @@ namespace gsr { return audio_devices; } + + std::vector get_application_audio() { + std::vector application_audio; + + FILE *f = popen("gpu-screen-recorder --list-application-audio", "r"); + if(!f) { + fprintf(stderr, "error: 'gpu-screen-recorder --list-application-audio' failed\n"); + return application_audio; + } + + char output[16384]; + ssize_t bytes_read = fread(output, 1, sizeof(output) - 1, f); + if(bytes_read < 0 || ferror(f)) { + fprintf(stderr, "error: failed to read 'gpu-screen-recorder --list-application-audio' output\n"); + pclose(f); + return application_audio; + } + output[bytes_read] = '\0'; + + string_split_char({output, (size_t)bytes_read}, '\n', [&](std::string_view line) { + application_audio.emplace_back(line); + return true; + }); + + return application_audio; + } } diff --git a/src/Overlay.cpp b/src/Overlay.cpp index 16dcfe4..e6a218c 100644 --- a/src/Overlay.cpp +++ b/src/Overlay.cpp @@ -130,6 +130,15 @@ namespace gsr { && diff_int(geometry.width, monitor->size.x, margin) && diff_int(geometry.height, monitor->size.y, margin); } + static void set_focused_window(Display *dpy, Window window) { + XSetInputFocus(dpy, window, RevertToParent, CurrentTime); + + const Atom net_active_window_atom = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); + XChangeProperty(dpy, DefaultRootWindow(dpy), net_active_window_atom, XA_WINDOW, 32, PropModeReplace, (const unsigned char*)&window, 1); + + XFlush(dpy); + } + #define _NET_WM_STATE_REMOVE 0 #define _NET_WM_STATE_ADD 1 #define _NET_WM_STATE_TOGGLE 2 @@ -370,8 +379,6 @@ namespace gsr { update_compositor_texture(focused_monitor); - audio_devices = get_audio_devices(); - top_bar_text = mgl::Text("GPU Screen Recorder", get_theme().top_bar_font); logo_sprite = mgl::Sprite(&get_theme().logo_texture); @@ -418,7 +425,7 @@ namespace gsr { button->set_item_icon("save", &get_theme().save_texture); button->on_click = [this](const std::string &id) { if(id == "settings") { - auto replay_settings_page = std::make_unique(SettingsPage::Type::REPLAY, gsr_info, audio_devices, config, &page_stack); + auto replay_settings_page = std::make_unique(SettingsPage::Type::REPLAY, gsr_info, config, &page_stack); page_stack.push(std::move(replay_settings_page)); } else if(id == "save") { on_press_save_replay(); @@ -439,7 +446,7 @@ namespace gsr { button->set_item_icon("pause", &get_theme().pause_texture); button->on_click = [this](const std::string &id) { if(id == "settings") { - auto record_settings_page = std::make_unique(SettingsPage::Type::RECORD, gsr_info, audio_devices, config, &page_stack); + auto record_settings_page = std::make_unique(SettingsPage::Type::RECORD, gsr_info, config, &page_stack); page_stack.push(std::move(record_settings_page)); } else if(id == "pause") { toggle_pause(); @@ -458,7 +465,7 @@ namespace gsr { button->set_item_icon("start", &get_theme().play_texture); button->on_click = [this](const std::string &id) { if(id == "settings") { - auto stream_settings_page = std::make_unique(SettingsPage::Type::STREAM, gsr_info, audio_devices, config, &page_stack); + auto stream_settings_page = std::make_unique(SettingsPage::Type::STREAM, gsr_info, config, &page_stack); page_stack.push(std::move(stream_settings_page)); } else if(id == "start") { on_press_start_stream(); @@ -521,7 +528,7 @@ namespace gsr { // TODO: This breaks global hotkeys //XGrabKeyboard(display, window->get_system_handle(), True, GrabModeAsync, GrabModeAsync, CurrentTime); - XSetInputFocus(display, window->get_system_handle(), RevertToPointerRoot, CurrentTime); + set_focused_window(display, window->get_system_handle()); XFlush(display); //window->set_fullscreen(true); @@ -864,6 +871,46 @@ namespace gsr { kill(gpu_screen_recorder_process, SIGUSR1); } + static void add_common_gpu_screen_recorder_args(RecordOptions &record_options, std::vector &args, const std::string &video_bitrate, const char *region, const std::string &audio_devices_merged, const std::string &application_audio_merged) { + if(record_options.video_quality == "custom") { + args.push_back("-bm"); + args.push_back("cbr"); + args.push_back("-q"); + args.push_back(video_bitrate.c_str()); + } else { + args.push_back("-q"); + args.push_back(record_options.video_quality.c_str()); + } + + if(record_options.record_area_option == "focused" || record_options.change_video_resolution) { + args.push_back("-s"); + args.push_back(region); + } + + if(record_options.audio_type_view == "audio_devices") { + if(record_options.merge_audio_tracks) { + args.push_back("-a"); + args.push_back(audio_devices_merged.c_str()); + } else { + for(const std::string &audio_track : record_options.audio_tracks) { + args.push_back("-a"); + args.push_back(audio_track.c_str()); + } + } + } else if(record_options.audio_type_view == "app_audio") { + const char *app_audio_option = record_options.application_audio_invert ? "-aai" : "-aa"; + if(record_options.merge_audio_tracks) { + args.push_back(app_audio_option); + args.push_back(application_audio_merged.c_str()); + } else { + for(const std::string &app_audio : record_options.application_audio) { + args.push_back(app_audio_option); + args.push_back(app_audio.c_str()); + } + } + } + } + void Overlay::on_press_start_replay(bool disable_notification) { switch(recording_status) { case RecordingStatus::NONE: @@ -900,13 +947,12 @@ namespace gsr { return; } - audio_devices = get_audio_devices(); - // TODO: Validate input, fallback to valid values const std::string fps = std::to_string(config.replay_config.record_options.fps); const std::string video_bitrate = std::to_string(config.replay_config.record_options.video_bitrate); const std::string output_directory = config.replay_config.save_directory; - const std::string audio_tracks_merged = merge_audio_tracks(config.replay_config.record_options.audio_tracks); + const std::string audio_devices_merged = merge_audio_tracks(config.replay_config.record_options.audio_tracks); + const std::string application_audio_merged = merge_audio_tracks(config.replay_config.record_options.application_audio); const std::string framerate_mode = config.replay_config.record_options.framerate_mode == "auto" ? "vfr" : config.replay_config.record_options.framerate_mode; const std::string replay_time = std::to_string(config.replay_config.replay_time); const char *video_codec = config.replay_config.record_options.video_codec.c_str(); @@ -937,30 +983,7 @@ namespace gsr { "-o", output_directory.c_str() }; - if(config.replay_config.record_options.video_quality == "custom") { - args.push_back("-bm"); - args.push_back("cbr"); - args.push_back("-q"); - args.push_back(video_bitrate.c_str()); - } else { - args.push_back("-q"); - args.push_back(config.replay_config.record_options.video_quality.c_str()); - } - - if(config.replay_config.record_options.record_area_option == "focused" || config.replay_config.record_options.change_video_resolution) { - args.push_back("-s"); - args.push_back(region); - } - - if(config.replay_config.record_options.merge_audio_tracks) { - args.push_back("-a"); - args.push_back(audio_tracks_merged.c_str()); - } else { - for(const std::string &audio_track : config.replay_config.record_options.audio_tracks) { - args.push_back("-a"); - args.push_back(audio_track.c_str()); - } - } + add_common_gpu_screen_recorder_args(config.replay_config.record_options, args, video_bitrate, region, audio_devices_merged, application_audio_merged); setenv("GSR_SHOW_SAVED_NOTIFICATION", config.replay_config.show_replay_saved_notifications ? "1" : "0", true); const std::string script_to_run_on_save = resources_path + (config.replay_config.save_video_in_game_folder ? "scripts/save-video-in-game-folder.sh" : "scripts/notify-saved-name.sh"); @@ -1025,13 +1048,12 @@ namespace gsr { return; } - audio_devices = get_audio_devices(); - // TODO: Validate input, fallback to valid values const std::string fps = std::to_string(config.record_config.record_options.fps); const std::string video_bitrate = std::to_string(config.record_config.record_options.video_bitrate); const std::string output_file = config.record_config.save_directory + "/Video_" + get_date_str() + "." + container_to_file_extension(config.record_config.container.c_str()); - const std::string audio_tracks_merged = merge_audio_tracks(config.record_config.record_options.audio_tracks); + const std::string audio_devices_merged = merge_audio_tracks(config.record_config.record_options.audio_tracks); + const std::string application_audio_merged = merge_audio_tracks(config.record_config.record_options.application_audio); const std::string framerate_mode = config.record_config.record_options.framerate_mode == "auto" ? "vfr" : config.record_config.record_options.framerate_mode; const char *video_codec = config.record_config.record_options.video_codec.c_str(); const char *encoder = "gpu"; @@ -1060,30 +1082,7 @@ namespace gsr { "-o", output_file.c_str() }; - if(config.record_config.record_options.video_quality == "custom") { - args.push_back("-bm"); - args.push_back("cbr"); - args.push_back("-q"); - args.push_back(video_bitrate.c_str()); - } else { - args.push_back("-q"); - args.push_back(config.record_config.record_options.video_quality.c_str()); - } - - if(config.record_config.record_options.record_area_option == "focused" || config.record_config.record_options.change_video_resolution) { - args.push_back("-s"); - args.push_back(region); - } - - if(config.record_config.record_options.merge_audio_tracks) { - args.push_back("-a"); - args.push_back(audio_tracks_merged.c_str()); - } else { - for(const std::string &audio_track : config.record_config.record_options.audio_tracks) { - args.push_back("-a"); - args.push_back(audio_track.c_str()); - } - } + add_common_gpu_screen_recorder_args(config.record_config.record_options, args, video_bitrate, region, audio_devices_merged, application_audio_merged); setenv("GSR_SHOW_SAVED_NOTIFICATION", config.record_config.show_video_saved_notifications ? "1" : "0", true); const std::string script_to_run_on_save = resources_path + (config.record_config.save_video_in_game_folder ? "scripts/save-video-in-game-folder.sh" : "scripts/notify-saved-name.sh"); @@ -1178,12 +1177,11 @@ namespace gsr { return; } - audio_devices = get_audio_devices(); - // TODO: Validate input, fallback to valid values const std::string fps = std::to_string(config.streaming_config.record_options.fps); const std::string video_bitrate = std::to_string(config.streaming_config.record_options.video_bitrate); - const std::string audio_tracks_merged = merge_audio_tracks(config.streaming_config.record_options.audio_tracks); + const std::string audio_devices_merged = merge_audio_tracks(config.streaming_config.record_options.audio_tracks); + const std::string application_audio_merged = merge_audio_tracks(config.streaming_config.record_options.application_audio); const std::string framerate_mode = config.streaming_config.record_options.framerate_mode == "auto" ? "vfr" : config.streaming_config.record_options.framerate_mode; const char *video_codec = config.streaming_config.record_options.video_codec.c_str(); const char *encoder = "gpu"; @@ -1218,30 +1216,7 @@ namespace gsr { "-o", url.c_str() }; - if(config.streaming_config.record_options.video_quality == "custom") { - args.push_back("-bm"); - args.push_back("cbr"); - args.push_back("-q"); - args.push_back(video_bitrate.c_str()); - } else { - args.push_back("-q"); - args.push_back(config.streaming_config.record_options.video_quality.c_str()); - } - - if(config.streaming_config.record_options.record_area_option == "focused" || config.streaming_config.record_options.change_video_resolution) { - args.push_back("-s"); - args.push_back(region); - } - - if(config.streaming_config.record_options.merge_audio_tracks) { - args.push_back("-a"); - args.push_back(audio_tracks_merged.c_str()); - } else { - for(const std::string &audio_track : config.streaming_config.record_options.audio_tracks) { - args.push_back("-a"); - args.push_back(audio_track.c_str()); - } - } + add_common_gpu_screen_recorder_args(config.streaming_config.record_options, args, video_bitrate, region, audio_devices_merged, application_audio_merged); args.push_back(nullptr); diff --git a/src/gui/CheckBox.cpp b/src/gui/CheckBox.cpp index 9ae3b41..e2f591c 100644 --- a/src/gui/CheckBox.cpp +++ b/src/gui/CheckBox.cpp @@ -10,7 +10,7 @@ namespace gsr { static const float spacing_scale = 0.005f; static const float check_animation_speed = 10.0f; - static mgl::Color color_multiply(mgl::Color color, float multiply) { + static mgl::Color color_multiply_ignore_alpha(mgl::Color color, float multiply) { return mgl::Color(color.r * multiply, color.g * multiply, color.b * multiply, color.a); } @@ -18,12 +18,12 @@ namespace gsr { return source + (destination - source) * interpolation; } - static mgl::Color interpolate_color(mgl::Color source, mgl::Color destination, float interpolation) { + static mgl::Color interpolate_color_ignore_alpha(mgl::Color source, mgl::Color destination, float interpolation) { mgl::Color color; color.r = linear_interpolation(source.r, destination.r, interpolation); color.g = linear_interpolation(source.g, destination.g, interpolation); color.b = linear_interpolation(source.b, destination.b, interpolation); - color.a = linear_interpolation(source.a, destination.a, interpolation); + color.a = source.a; return color; } @@ -61,9 +61,9 @@ namespace gsr { apply_animation(); - const mgl::Color background_color_unchecked(0, 0, 0, 120); - const mgl::Color background_color_checked = color_multiply(get_color_theme().tint_color, 0.6f); - background_sprite.set_color(interpolate_color(background_color_unchecked, background_color_checked, toggle_animation_value)); + const mgl::Color background_color_unchecked = color_multiply_ignore_alpha(mgl::Color(25, 30, 34), 0.6f); + const mgl::Color background_color_checked = color_multiply_ignore_alpha(get_color_theme().tint_color, 0.6f); + background_sprite.set_color(interpolate_color_ignore_alpha(background_color_unchecked, background_color_checked, toggle_animation_value)); background_sprite.set_position(draw_pos.floor()); window.draw(background_sprite); diff --git a/src/gui/Label.cpp b/src/gui/Label.cpp index 22a302f..773c2f9 100644 --- a/src/gui/Label.cpp +++ b/src/gui/Label.cpp @@ -22,6 +22,10 @@ namespace gsr { text.set_string(std::move(str)); } + const std::string& Label::get_text() const { + return text.get_string(); + } + mgl::vec2f Label::get_size() { if(!visible) return {0.0f, 0.0f}; diff --git a/src/gui/LineSeparator.cpp b/src/gui/LineSeparator.cpp new file mode 100644 index 0000000..637c84f --- /dev/null +++ b/src/gui/LineSeparator.cpp @@ -0,0 +1,45 @@ +#include "../../include/gui/LineSeparator.hpp" +#include "../../include/Theme.hpp" + +#include +#include + +namespace gsr { + static const float height_scale = 0.001f; + + static mgl::Color color_add_ignore_alpha(mgl::Color color, mgl::Color add) { + return { + (uint8_t)std::min((int)color.r + (int)add.r, 255), + (uint8_t)std::min((int)color.g + (int)add.g, 255), + (uint8_t)std::min((int)color.b + (int)add.b, 255), + color.a + }; + } + + LineSeparator::LineSeparator(Type type, float width) : type(type), width(width) { + + } + + bool LineSeparator::on_event(mgl::Event&, mgl::Window&, mgl::vec2f) { + return true; + } + + void LineSeparator::draw(mgl::Window &window, mgl::vec2f offset) { + if(!visible) + return; + + const mgl::vec2f draw_pos = (position + offset).floor(); + const mgl::vec2f size = mgl::vec2f(width, std::max(1.0f, height_scale * get_theme().window_height)).floor(); + mgl::Rectangle rectangle(draw_pos, size); + rectangle.set_color(color_add_ignore_alpha(mgl::Color(25, 30, 34), mgl::Color(30, 30, 30))); + window.draw(rectangle); + } + + mgl::vec2f LineSeparator::get_size() { + if(!visible) + return {0.0f, 0.0f}; + + const mgl::vec2f size = mgl::vec2f(width, std::max(1.0f, height_scale * get_theme().window_height)).floor(); + return size; + } +} \ No newline at end of file diff --git a/src/gui/SettingsPage.cpp b/src/gui/SettingsPage.cpp index a08bd52..083fec5 100644 --- a/src/gui/SettingsPage.cpp +++ b/src/gui/SettingsPage.cpp @@ -1,6 +1,7 @@ #include "../../include/gui/SettingsPage.hpp" #include "../../include/gui/GsrPage.hpp" #include "../../include/gui/Label.hpp" +#include "../../include/gui/LineSeparator.hpp" #include "../../include/gui/PageStack.hpp" #include "../../include/gui/FileChooser.hpp" #include "../../include/gui/Subsection.hpp" @@ -13,15 +14,19 @@ #include #include +#include + namespace gsr { - SettingsPage::SettingsPage(Type type, const GsrInfo &gsr_info, std::vector audio_devices, Config &config, PageStack *page_stack) : + SettingsPage::SettingsPage(Type type, const GsrInfo &gsr_info, Config &config, PageStack *page_stack) : StaticPage(mgl::vec2f(get_theme().window_width, get_theme().window_height).floor()), type(type), config(config), - audio_devices(std::move(audio_devices)), page_stack(page_stack), settings_title_text("Settings", get_theme().title_font) { + audio_devices = get_audio_devices(); + application_audio = get_application_audio(); + auto content_page = std::make_unique(); content_page->add_button("Back", "back", get_color_theme().page_bg_color); content_page->on_click = [page_stack](const std::string &id) { @@ -177,7 +182,7 @@ namespace gsr { return std::make_unique("Record area", std::move(ll), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)); } - std::unique_ptr SettingsPage::create_audio_track_selection_checkbox() { + std::unique_ptr SettingsPage::create_audio_device_selection_combobox() { auto audio_device_box = std::make_unique(&get_theme().body_font); for(const auto &audio_device : audio_devices) { audio_device_box->add_item(audio_device.description, audio_device.name); @@ -185,7 +190,7 @@ namespace gsr { return audio_device_box; } - std::unique_ptr