diff --git a/SerialPrograms/Source/CommonFramework/AudioPipeline/Backends/AudioDeviceInfo.cpp b/SerialPrograms/Source/CommonFramework/AudioPipeline/Backends/AudioDeviceInfo.cpp index 5b8146d359..d9bb087bfb 100644 --- a/SerialPrograms/Source/CommonFramework/AudioPipeline/Backends/AudioDeviceInfo.cpp +++ b/SerialPrograms/Source/CommonFramework/AudioPipeline/Backends/AudioDeviceInfo.cpp @@ -12,6 +12,7 @@ #include "CommonFramework/AudioPipeline/AudioInputChoice.h" #include "CommonFramework/AudioPipeline/Backends/NativeAudioFormats.h" #include "CommonFramework/Logging/Logger.h" +#include "CommonFramework/Options/DeviceDropdownAliases.h" #include "AudioDeviceInfo.h" namespace PokemonAutomation{ @@ -192,7 +193,16 @@ AudioDeviceInfo::AudioDeviceInfo(const std::string& device_name){ AudioDeviceInfo::operator bool() const{ return m_body && !m_body->device_name.empty(); } -const std::string& AudioDeviceInfo::display_name() const{ +std::string AudioDeviceInfo::display_name() const{ + if (!*this){ + return std::string(); + } + if (auto alias = device_dropdown_name(DeviceAliasType::AUDIO, m_body->device_name)){ + return *alias; + } + return m_body->display_name; +} +const std::string& AudioDeviceInfo::original_name() const{ return m_body->display_name; } const std::string& AudioDeviceInfo::device_name() const{ diff --git a/SerialPrograms/Source/CommonFramework/AudioPipeline/Backends/AudioDeviceInfo.h b/SerialPrograms/Source/CommonFramework/AudioPipeline/Backends/AudioDeviceInfo.h index 3865b43b71..7d6ef0bf92 100644 --- a/SerialPrograms/Source/CommonFramework/AudioPipeline/Backends/AudioDeviceInfo.h +++ b/SerialPrograms/Source/CommonFramework/AudioPipeline/Backends/AudioDeviceInfo.h @@ -27,7 +27,8 @@ class AudioDeviceInfo{ explicit operator bool() const; - const std::string& display_name() const; + std::string display_name() const; + const std::string& original_name() const; const std::string& device_name() const; // The device-driven format list (see input_choices()). Populated for diff --git a/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp index a47e919dfa..df38989010 100644 --- a/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp +++ b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp @@ -32,6 +32,7 @@ #include "Controllers/ControllerSettings.h" //#include "CommonFramework/Environment/Environment.h" #include "Integrations/DiscordSettingsOption.h" +#include "CommonFramework/Options/DeviceDropdownAliases.h" #include "GlobalSettingsPanel.h" // #include @@ -126,6 +127,7 @@ GlobalSettings::GlobalSettings() LockMode::UNLOCK_WHILE_RUNNING, KeyboardLayout::QWERTY ) + , DEVICE_ALIASES(CONSTRUCT_TOKEN) , STREAM_HISTORY(CONSTRUCT_TOKEN) , SLEEP_SUPPRESS(CONSTRUCT_TOKEN) , m_discord_settings( @@ -205,6 +207,7 @@ GlobalSettings::GlobalSettings() PA_ADD_OPTION(LOG_WINDOW_STARTUP); PA_ADD_OPTION(KEYBOARD_CONTROLS_LAYOUT); + PA_ADD_OPTION(DEVICE_ALIASES); PA_ADD_OPTION(STREAM_HISTORY); #ifdef PA_ENABLE_SLEEP_SUPPRESS @@ -349,6 +352,7 @@ GlobalSettings_Descriptor::Wrapper& GlobalSettings_Descriptor::instance(){ GlobalSettingsPanel::GlobalSettingsPanel() : settings(GlobalSettings::instance()) { + settings.DEVICE_ALIASES->add_connected_devices(); PA_ADD_OPTION(settings); } diff --git a/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.h b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.h index 6983e04de6..29ef1fff03 100644 --- a/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.h +++ b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.h @@ -31,6 +31,7 @@ class ResolutionOption; class KeyboardLayoutOption; class StreamHistoryOption; class SleepSuppressOptions; +class DeviceAliasOptions; namespace Integration{ class DiscordSettingsOption; } @@ -94,6 +95,8 @@ class GlobalSettings : public BatchOption, private ConfigOption::Listener, priva Pimpl KEYBOARD_CONTROLS_LAYOUT; + Pimpl DEVICE_ALIASES; + Pimpl STREAM_HISTORY; Pimpl SLEEP_SUPPRESS; diff --git a/SerialPrograms/Source/CommonFramework/Options/DeviceDropdownAliases.cpp b/SerialPrograms/Source/CommonFramework/Options/DeviceDropdownAliases.cpp new file mode 100644 index 0000000000..81e0842d1e --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Options/DeviceDropdownAliases.cpp @@ -0,0 +1,134 @@ +/* Device Dropdown Aliases + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "Common/Cpp/Json/JsonValue.h" +#include "CommonFramework/GlobalSettingsPanel.h" +#include "CommonFramework/AudioPipeline/Backends/AudioDeviceInfo.h" +#include "CommonFramework/VideoPipeline/Backends/CameraImplementations.h" +#include "DeviceDropdownAliases.h" + +namespace PokemonAutomation{ +namespace{ + +const EnumDropdownDatabase& categories(){ + static const EnumDropdownDatabase database{ + {DeviceAliasType::VIDEO, "Video", "Video"}, + {DeviceAliasType::AUDIO, "Audio", "Audio"}, + }; + return database; +} + +} + +DeviceAliasRow::DeviceAliasRow(EditableTableOption& parent) + : EditableTableRow(parent) + , category(categories(), LockMode::UNLOCK_WHILE_RUNNING, DeviceAliasType::VIDEO) + , device_id(false, LockMode::UNLOCK_WHILE_RUNNING, "", "Device ID") + , device_name(false, LockMode::READ_ONLY, "", "") + , alias(false, LockMode::UNLOCK_WHILE_RUNNING, "", "Use original name") +{ + PA_ADD_OPTION(category); + PA_ADD_OPTION(device_id); + PA_ADD_OPTION(device_name); + PA_ADD_OPTION(alias); +} + +std::unique_ptr DeviceAliasRow::clone() const{ + auto row = std::make_unique(parent()); + row->category.set(category); + row->device_id.set(device_id); + row->device_name.set(device_name); + row->alias.set(alias); + return row; +} + +DeviceDropdownAliases::DeviceDropdownAliases() + : EditableTableOption_t( + "Device Aliases:
" + "Choose names for cameras and audio devices. " + "Connected devices are added when Global Settings opens.
" + "An empty alias uses the original name.", + LockMode::UNLOCK_WHILE_RUNNING, + true, + 10 + ) +{} + +std::vector DeviceDropdownAliases::make_header() const{ + return {"Type", "Device ID", "Original Name", "Alias"}; +} + +std::optional DeviceDropdownAliases::lookup(DeviceAliasType category, const std::string& device_id) const{ + std::optional result; + EditableTableOption::run_on_all_rows([&](const DeviceAliasRow& row){ + if (row.category != category || std::string(row.device_id) != device_id){ + return false; + } + std::string alias = row.alias; + if (!alias.empty()){ + result = std::move(alias); + } + return true; + }); + return result; +} + +void DeviceDropdownAliases::add_device(DeviceAliasType category, const std::string& id, const std::string& name){ + bool found = false; + run_on_all_rows([&](DeviceAliasRow& row){ + if (row.category != category || std::string(row.device_id) != id){ + return false; + } + row.device_name.set(name); + found = true; + return true; + }); + if (!found){ + auto row = std::make_unique(*this); + row->category.set(category); + row->device_id.set(id); + row->device_name.set(name); + append_row(std::move(row)); + } +} + +void DeviceDropdownAliases::add_connected_devices(){ + for (const CameraInfo& info : get_all_cameras()){ + add_device(DeviceAliasType::VIDEO, info.device_name(), get_camera_name(info)); + } + for (const AudioDeviceInfo& info : AudioDeviceInfo::all_input_devices()){ + add_device(DeviceAliasType::AUDIO, info.device_name(), info.original_name()); + } + for (const AudioDeviceInfo& info : AudioDeviceInfo::all_output_devices()){ + add_device(DeviceAliasType::AUDIO, info.device_name(), info.original_name()); + } +} + +DeviceAliasOptions::DeviceAliasOptions() + : BatchOption(LockMode::UNLOCK_WHILE_RUNNING, false) +{ + PA_ADD_OPTION(m_aliases); +} + +JsonValue DeviceAliasOptions::to_json() const{ + return m_aliases.to_json(); +} +void DeviceAliasOptions::load_json(const JsonValue& json){ + m_aliases.load_json(json); +} + +void DeviceAliasOptions::add_connected_devices(){ + m_aliases.add_connected_devices(); +} +std::optional DeviceAliasOptions::lookup(DeviceAliasType category, const std::string& device_id) const{ + return m_aliases.lookup(category, device_id); +} + +std::optional device_dropdown_name(DeviceAliasType category, const std::string& device_id){ + return GlobalSettings::instance().DEVICE_ALIASES->lookup(category, device_id); +} + +} diff --git a/SerialPrograms/Source/CommonFramework/Options/DeviceDropdownAliases.h b/SerialPrograms/Source/CommonFramework/Options/DeviceDropdownAliases.h new file mode 100644 index 0000000000..b2daa88ab9 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/Options/DeviceDropdownAliases.h @@ -0,0 +1,70 @@ +/* Device Dropdown Aliases + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_DeviceDropdownAliases_H +#define PokemonAutomation_DeviceDropdownAliases_H + +#include +#include +#include "Common/Cpp/Options/EditableTableOption.h" +#include "Common/Cpp/Options/EnumDropdownOption.h" +#include "Common/Cpp/Options/BatchOption.h" +#include "Common/Cpp/Options/StringOption.h" + +namespace PokemonAutomation{ + +enum class DeviceAliasType{ + VIDEO, + AUDIO, +}; + +class DeviceAliasRow : public EditableTableRow{ +public: + DeviceAliasRow(EditableTableOption& parent); + virtual std::unique_ptr clone() const override; + + EnumDropdownCell category; + StringCell device_id; + StringCell device_name; + StringCell alias; +}; + +class DeviceDropdownAliases : public EditableTableOption_t{ +public: + DeviceDropdownAliases(); + + virtual std::vector make_header() const override; + void add_connected_devices(); + std::optional lookup(DeviceAliasType category, const std::string& device_id) const; + +private: + void add_device(DeviceAliasType category, const std::string& id, const std::string& name); +}; + +class DeviceAliasOptions : public BatchOption{ +public: + DeviceAliasOptions(); + + virtual JsonValue to_json() const override; + virtual void load_json(const JsonValue& json) override; + + void add_connected_devices(); + std::optional lookup(DeviceAliasType category, const std::string& device_id) const; + +private: + DeviceDropdownAliases m_aliases; +}; + +// Presentation only: never use this result for device selection or serialization. +// Returns std::nullopt when no non-empty alias is configured. +// Configured in Global Settings. Device IDs remain unchanged. +std::optional device_dropdown_name( + DeviceAliasType category, + const std::string& device_id +); + +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/VideoPipeline/CameraInfo.cpp b/SerialPrograms/Source/CommonFramework/VideoPipeline/CameraInfo.cpp new file mode 100644 index 0000000000..8962bdbf3f --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/VideoPipeline/CameraInfo.cpp @@ -0,0 +1,23 @@ +/* Camera Info + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "CommonFramework/Options/DeviceDropdownAliases.h" +#include "Backends/CameraImplementations.h" +#include "CameraInfo.h" + +namespace PokemonAutomation{ + +std::string CameraInfo::display_name() const{ + if (!*this){ + return std::string(); + } + if (auto alias = device_dropdown_name(DeviceAliasType::VIDEO, m_device_name)){ + return *alias; + } + return get_camera_name(*this); +} + +} diff --git a/SerialPrograms/Source/CommonFramework/VideoPipeline/CameraInfo.h b/SerialPrograms/Source/CommonFramework/VideoPipeline/CameraInfo.h index 9e2fa92b49..b8127d27be 100644 --- a/SerialPrograms/Source/CommonFramework/VideoPipeline/CameraInfo.h +++ b/SerialPrograms/Source/CommonFramework/VideoPipeline/CameraInfo.h @@ -24,6 +24,8 @@ class CameraInfo{ explicit operator bool() const{ return !m_device_name.empty(); } const std::string& device_name() const{ return m_device_name; } + std::string display_name() const; + bool operator==(const CameraInfo& info) const{ return m_device_name == info.m_device_name; } diff --git a/SerialPrograms/Source/CommonFramework/VideoPipeline/Sources/VideoSource_Camera.cpp b/SerialPrograms/Source/CommonFramework/VideoPipeline/Sources/VideoSource_Camera.cpp index a7750ba6f0..be409b05b6 100644 --- a/SerialPrograms/Source/CommonFramework/VideoPipeline/Sources/VideoSource_Camera.cpp +++ b/SerialPrograms/Source/CommonFramework/VideoPipeline/Sources/VideoSource_Camera.cpp @@ -23,7 +23,7 @@ bool VideoSourceDescriptor_Camera::operator==(const VideoSourceDescriptor& x) co return m_info == static_cast(x).m_info; } std::string VideoSourceDescriptor_Camera::display_name() const{ - return get_camera_name(m_info); + return m_info.display_name(); } JsonValue VideoSourceDescriptor_Camera::to_json() const{ diff --git a/SerialPrograms/cmake/SourceFiles.cmake b/SerialPrograms/cmake/SourceFiles.cmake index 5c5468e44d..35418bfb08 100644 --- a/SerialPrograms/cmake/SourceFiles.cmake +++ b/SerialPrograms/cmake/SourceFiles.cmake @@ -634,6 +634,8 @@ file(GLOB LIBRARY_SOURCES Source/CommonFramework/Notifications/SenderNotificationTable.h Source/CommonFramework/Options/BoxOption.cpp Source/CommonFramework/Options/BoxOption.h + Source/CommonFramework/Options/DeviceDropdownAliases.cpp + Source/CommonFramework/Options/DeviceDropdownAliases.h Source/CommonFramework/Options/Environment/OnnxOptions.h Source/CommonFramework/Options/Environment/SleepSuppressOption.cpp Source/CommonFramework/Options/Environment/SleepSuppressOption.h @@ -745,6 +747,7 @@ file(GLOB LIBRARY_SOURCES Source/CommonFramework/VideoPipeline/Backends/SnapshotManager.h Source/CommonFramework/VideoPipeline/Backends/VideoFrameQt.cpp Source/CommonFramework/VideoPipeline/Backends/VideoFrameQt.h + Source/CommonFramework/VideoPipeline/CameraInfo.cpp Source/CommonFramework/VideoPipeline/CameraInfo.h Source/CommonFramework/VideoPipeline/Stats/CpuUtilizationStats.cpp Source/CommonFramework/VideoPipeline/Stats/CpuUtilizationStats.h