Skip to content

Commit

Permalink
separated audio and video settings
Browse files Browse the repository at this point in the history
  • Loading branch information
mariotaku committed Oct 5, 2023
1 parent 7f353c2 commit 480e4c1
Show file tree
Hide file tree
Showing 13 changed files with 409 additions and 280 deletions.
1 change: 1 addition & 0 deletions src/app/lvgl/font/material_icons_regular_symbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@
#define MAT_SYMBOL_TUNE "\xee\x90\xa9"
#define MAT_SYMBOL_TV "\xee\x8c\xb3"
#define MAT_SYMBOL_VIDEO_SETTINGS "\xee\xa9\xb5"
#define MAT_SYMBOL_VOLUME_UP "\xee\x81\x90"
#define MAT_SYMBOL_WARNING "\xee\x80\x82"
2 changes: 1 addition & 1 deletion src/app/res/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ endif ()

add_custom_target(moonlight-res VERBATIM
COMMAND ${NPM_COMMAND} run gulp iconfont -- --output "${CMAKE_CURRENT_SOURCE_DIR}/gen" --input "${CMAKE_CURRENT_SOURCE_DIR}/iconfonts/*.ttf"
COMMAND ${NPM_COMMAND} run gulp symlist -- --output "${CMAKE_SOURCE_DIR}/app/lvgl/font" --input "${CMAKE_CURRENT_SOURCE_DIR}/iconfonts/*.ttf"
COMMAND ${NPM_COMMAND} run gulp symlist -- --output "${CMAKE_SOURCE_DIR}/src/app/lvgl/font" --input "${CMAKE_CURRENT_SOURCE_DIR}/iconfonts/*.ttf"
COMMAND ${NPM_COMMAND} run gulp binaries -- --output "${CMAKE_CURRENT_SOURCE_DIR}/gen" --input "${CMAKE_CURRENT_SOURCE_DIR}/img/*"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tools)
310 changes: 158 additions & 152 deletions src/app/res/gen/material_icons_regular_ttf.h

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/app/res/iconfonts/MaterialIcons-Regular.list
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ tune
arrow_drop_down
check
play_arrow
push_pin
push_pin
volume_up
11 changes: 2 additions & 9 deletions src/app/ui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,7 @@ target_sources(moonlight-lib PRIVATE
streaming/streaming.view.c
streaming/streaming.controller.c
streaming/hints.c
settings/settings.controller.c
settings/settings.view.c
settings/panes/basic.pane.c
settings/panes/host.pane.c
settings/panes/input.pane.c
settings/panes/decoder.pane.c
settings/panes/about.pane.c
settings/panes/pref_obj.c
help/help.dialog.c
common/progress_dialog.c
)
)
add_subdirectory(settings)
2 changes: 2 additions & 0 deletions src/app/ui/settings/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target_sources(moonlight-lib PRIVATE settings.view.c settings.controller.c)
add_subdirectory(panes)
2 changes: 2 additions & 0 deletions src/app/ui/settings/panes/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target_sources(moonlight-lib PRIVATE basic.pane.c about.pane.c audio.pane.c host.pane.c input.pane.c video.pane.c
av_pane.c pref_obj.c)
121 changes: 121 additions & 0 deletions src/app/ui/settings/panes/audio.pane.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#include "app.h"

#include "pref_obj.h"
#include "av_pane.h"

#include "ui/settings/settings.controller.h"

#include "util/i18n.h"
#include "ss4s.h"
#include "ss4s_modules.h"

typedef struct audio_pane_t {
lv_fragment_t base;
settings_controller_t *parent;

lv_obj_t *conflict_hint;

pref_dropdown_string_entry_t *adec_entries;
int adec_entries_len;

pref_dropdown_int_entry_t surround_entries[3];
int surround_entries_len;
} audio_pane_t;

static lv_obj_t *create_obj(lv_fragment_t *self, lv_obj_t *container);

static void obj_created(lv_fragment_t *self, lv_obj_t *obj);

static void pane_ctor(lv_fragment_t *self, void *args);

static void pane_dtor(lv_fragment_t *self);

static void module_changed_cb(lv_event_t *e);

const lv_fragment_class_t settings_pane_audio_cls = {
.constructor_cb = pane_ctor,
.destructor_cb = pane_dtor,
.create_obj_cb = create_obj,
.obj_created_cb = obj_created,
.instance_size = sizeof(audio_pane_t),
};

static void pane_ctor(lv_fragment_t *self, void *args) {
audio_pane_t *pane = (audio_pane_t *) self;
pane->parent = args;
SS4S_AudioCapabilities audio_cap = pane->parent->app->ss4s.audio_cap;
array_list_t modules = pane->parent->app->ss4s.modules;
pane->adec_entries = calloc(modules.size + 1, sizeof(pref_dropdown_string_entry_t));

set_decoder_entry(&pane->adec_entries[pane->adec_entries_len++], locstr("Auto"), "auto", true);
for (int module_idx = 0; module_idx < modules.size; module_idx++) {
const SS4S_ModuleInfo *info = array_list_get(&modules, module_idx);
const char *group = SS4S_ModuleInfoGetGroup(info);
if (info->has_audio && !contains_decoder_group(pane->adec_entries, pane->adec_entries_len, group)) {
set_decoder_entry(&pane->adec_entries[pane->adec_entries_len++], info->name, group, false);
}
}
unsigned int supported_ch = audio_cap.maxChannels;
if (supported_ch == 0) {
supported_ch = 2;
}
for (int i = 0; i < audio_config_len; i++) {
audio_config_entry_t config = audio_configs[i];
if (supported_ch < CHANNEL_COUNT_FROM_AUDIO_CONFIGURATION(config.configuration)) {
continue;
}
struct pref_dropdown_int_entry_t *entry = &pane->surround_entries[pane->surround_entries_len];
entry->name = locstr(config.name);
entry->value = config.configuration;
entry->fallback = config.configuration == AUDIO_CONFIGURATION_STEREO;
pane->surround_entries_len++;
}
}

static void pane_dtor(lv_fragment_t *self) {
audio_pane_t *pane = (audio_pane_t *) self;
free(pane->adec_entries);
}

static lv_obj_t *create_obj(lv_fragment_t *self, lv_obj_t *container) {
audio_pane_t *controller = (audio_pane_t *) self;
app_t *app = controller->parent->app;
lv_obj_t *view = pref_pane_container(container);
lv_obj_set_layout(view, LV_LAYOUT_FLEX);
lv_obj_set_flex_flow(view, LV_FLEX_FLOW_COLUMN);
lv_obj_set_flex_align(view, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START);

lv_obj_t *audio_label = pref_title_label(view, locstr("Audio backend"));
lv_label_set_text_fmt(audio_label, locstr("Audio backend - using %s"),
SS4S_ModuleInfoGetName(app->ss4s.selection.audio_module));
lv_obj_t *adec_dropdown = pref_dropdown_string(view, controller->adec_entries, controller->adec_entries_len,
&app_configuration->audio_backend);
lv_obj_set_width(adec_dropdown, LV_PCT(100));

lv_obj_t *conflict_hint = pref_desc_label(view, NULL, false);
controller->conflict_hint = conflict_hint;

pref_header(view, "Audio Settings");

pref_title_label(view, locstr("Sound Channels (Experimental)"));

lv_obj_t *ch_dropdown = pref_dropdown_int(view, controller->surround_entries, controller->surround_entries_len,
&app_configuration->stream.audioConfiguration);
lv_obj_set_width(ch_dropdown, LV_PCT(100));

lv_obj_add_event_cb(adec_dropdown, module_changed_cb, LV_EVENT_VALUE_CHANGED, controller);

return view;
}

static void obj_created(lv_fragment_t *self, lv_obj_t *obj) {
audio_pane_t *fragment = (audio_pane_t *) self;
update_conflict_hint(fragment->parent->app, fragment->conflict_hint);
}

static void module_changed_cb(lv_event_t *e) {
audio_pane_t *fragment = (audio_pane_t *) lv_event_get_user_data(e);
settings_controller_t *parent = fragment->parent;
parent->needs_restart = true;
update_conflict_hint(parent->app, fragment->conflict_hint);
}
67 changes: 67 additions & 0 deletions src/app/ui/settings/panes/av_pane.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2023 Ningyuan Li <https://github.com/mariotaku>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

#include "av_pane.h"

#include <stdbool.h>

static bool module_is_auto(const char *value);

void update_conflict_hint(app_t *app, lv_obj_t *hint) {
SS4S_ModulePreferences preferences = {
.video_module = app_configuration->decoder,
.audio_module = app_configuration->audio_backend,
};
if (module_is_auto(preferences.video_module) || module_is_auto(preferences.audio_module)) {
lv_obj_add_flag(hint, LV_OBJ_FLAG_HIDDEN);
return;
}
SS4S_ModuleSelection selection = {
.audio_module = NULL,
.video_module = NULL
};
SS4S_ModulesSelect(&app->ss4s.modules, &preferences, &selection, false);
const SS4S_ModuleInfo *vdec = selection.video_module;
const SS4S_ModuleInfo *adec = selection.audio_module;
if (vdec != NULL && adec != NULL && SS4S_ModuleInfoConflicts(vdec, adec)) {
lv_label_set_text_fmt(hint, "%s is conflicting with %s", adec->name, vdec->name);
lv_obj_clear_flag(hint, LV_OBJ_FLAG_HIDDEN);
} else {
lv_obj_add_flag(hint, LV_OBJ_FLAG_HIDDEN);
}
}

bool contains_decoder_group(const pref_dropdown_string_entry_t *entry, size_t len, const char *group) {
for (int i = 0; i < len; i++) {
if (strcmp(entry[i].value, group) == 0) {
return true;
}
}
return false;
}

void set_decoder_entry(pref_dropdown_string_entry_t *entry, const char *name, const char *group, bool fallback) {
entry->name = name;
entry->value = group;
entry->fallback = fallback;
}


static bool module_is_auto(const char *value) {
return value == NULL || strcmp("auto", value) == 0;
}
29 changes: 29 additions & 0 deletions src/app/ui/settings/panes/av_pane.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2023 Ningyuan Li <https://github.com/mariotaku>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

#pragma once

#include "app.h"
#include "lvgl.h"
#include "pref_obj.h"

void update_conflict_hint(app_t *app, lv_obj_t *hint);

bool contains_decoder_group(const pref_dropdown_string_entry_t *entry, size_t len, const char *group);

void set_decoder_entry(pref_dropdown_string_entry_t *entry, const char *name, const char *group, bool fallback);
Loading

0 comments on commit 480e4c1

Please sign in to comment.