diff --git a/config-dialog.cpp b/config-dialog.cpp index 7b8bce0..ade541f 100644 --- a/config-dialog.cpp +++ b/config-dialog.cpp @@ -191,6 +191,12 @@ OBSBasicSettings::OBSBasicSettings(QMainWindow *parent) : QDialog(parent) version->setOpenExternalLinks(true); version->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); + newVersion = new QLabel; + newVersion->setProperty("themeID", "warning"); + newVersion->setVisible(false); + newVersion->setOpenExternalLinks(true); + newVersion->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); + QPushButton *okButton = new QPushButton(QString::fromUtf8(obs_frontend_get_locale_string("OK"))); connect(okButton, &QPushButton::clicked, [this] { accept(); }); @@ -199,7 +205,7 @@ OBSBasicSettings::OBSBasicSettings(QMainWindow *parent) : QDialog(parent) QHBoxLayout *bottomLayout = new QHBoxLayout; bottomLayout->addWidget(version, 1, Qt::AlignLeft); - //bottomLayout->addWidget(newVersion, 1, Qt::AlignLeft); + bottomLayout->addWidget(newVersion, 1, Qt::AlignLeft); bottomLayout->addWidget(okButton, 0, Qt::AlignRight); bottomLayout->addWidget(cancelButton, 0, Qt::AlignRight); @@ -889,10 +895,21 @@ void OBSBasicSettings::RefreshProperties(obs_properties_t *properties, QFormLayo obs_property_next(&property); } } +static bool obs_encoder_parent_video_loaded = false; +static video_t *(*obs_encoder_parent_video_wrapper)(const obs_encoder_t *encoder) = nullptr; void OBSBasicSettings::LoadOutputStats() { - + if (!obs_encoder_parent_video_loaded) { + void *dl = os_dlopen("obs"); + if (dl) { + auto sym = os_dlsym(dl, "obs_encoder_parent_video"); + if (sym) + obs_encoder_parent_video_wrapper = (video_t * (*)(const obs_encoder_t *encoder)) sym; + os_dlclose(dl); + } + obs_encoder_parent_video_loaded = true; + } std::vector> refs; obs_enum_outputs( [](void *data, obs_output_t *output) { @@ -903,14 +920,10 @@ void OBSBasicSettings::LoadOutputStats() if (!venc) continue; ec++; - video_t *video = obs_output_video(output); - void *dl = os_dlopen("obs"); - if (dl) { - auto sym = (video_t * (*)(const obs_encoder_t *encoder)) - os_dlsym(dl, "obs_encoder_parent_video"); - if (sym) - video = sym(venc); - } + video_t *video = obs_encoder_parent_video_wrapper ? obs_encoder_parent_video_wrapper(venc) + : obs_encoder_video(venc); + if (!video) + video = obs_output_video(output); refs->push_back(std::tuple(video, venc, output)); } if (!ec) { @@ -1011,9 +1024,7 @@ void OBSBasicSettings::LoadOutputStats() stats += obs_output_get_name(output); stats += "("; stats += obs_output_get_id(output); - stats += ")"; - //stats += obs_output_get_display_name(obs_output_get_id(output)); - stats += " "; + stats += ") "; stats += std::to_string(obs_output_get_connect_time_ms(output)); stats += "ms "; //obs_output_get_total_bytes(output); @@ -1038,3 +1049,11 @@ void OBSBasicSettings::LoadOutputStats() } troubleshooterText->setText(QString::fromUtf8(stats)); } + +void OBSBasicSettings::SetNewerVersion(QString newer_version_available) +{ + if (newer_version_available.isEmpty()) + return; + newVersion->setText(QString::fromUtf8(obs_module_text("NewVersion")).arg(newer_version_available)); + newVersion->setVisible(true); +} diff --git a/config-dialog.hpp b/config-dialog.hpp index aeadbcd..61e8782 100644 --- a/config-dialog.hpp +++ b/config-dialog.hpp @@ -11,6 +11,7 @@ #include #include #include +#include class OBSBasicSettings : public QDialog { Q_OBJECT @@ -45,6 +46,7 @@ private: QFormLayout *mainOutputsLayout; QFormLayout *verticalOutputsLayout; + QLabel *newVersion; QTextEdit *troubleshooterText; @@ -64,5 +66,6 @@ public: void LoadSettings(obs_data_t *settings); void LoadOutputStats(); + void SetNewerVersion(QString newer_version_available); public slots: }; diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 86d3c58..655c7ef 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -23,4 +23,5 @@ AudioTrack="Audio Track" Server="Server" Key="Key" Stream="Stream" -MainOutputNotActive="Main output not active!" \ No newline at end of file +MainOutputNotActive="Main output not active!" +NewVersion="New version (%1) available here" diff --git a/multistream.cpp b/multistream.cpp index 6b3154b..94c14bd 100644 --- a/multistream.cpp +++ b/multistream.cpp @@ -12,12 +12,44 @@ #include #include #include +extern "C" { +#include "file-updater.h" +} OBS_DECLARE_MODULE() OBS_MODULE_AUTHOR("Aitum"); OBS_MODULE_USE_DEFAULT_LOCALE("aitum-multistream", "en-US") -static MultistreamDock *multistream_dock; +static MultistreamDock *multistream_dock = nullptr; + +update_info_t *version_update_info = nullptr; + +bool version_info_downloaded(void *param, struct file_download_data *file) +{ + UNUSED_PARAMETER(param); + if (!file || !file->buffer.num) + return true; + auto d = obs_data_create_from_json((const char *)file->buffer.array); + if (!d) + return true; + auto data = obs_data_get_obj(d, "data"); + obs_data_release(d); + if (!data) + return true; + auto version = QString::fromUtf8(obs_data_get_string(data, "version")); + QStringList pieces = version.split("."); + if (pieces.count() > 2) { + auto major = pieces[0].toInt(); + auto minor = pieces[1].toInt(); + auto patch = pieces[2].toInt(); + auto sv = MAKE_SEMANTIC_VERSION(major, minor, patch); + if (sv > MAKE_SEMANTIC_VERSION(PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR, PROJECT_VERSION_PATCH)) { + QMetaObject::invokeMethod(multistream_dock, "NewerVersionAvailable", Q_ARG(QString, version)); + } + } + obs_data_release(data); + return true; +} bool obs_module_load(void) { @@ -28,11 +60,14 @@ bool obs_module_load(void) multistream_dock = new MultistreamDock(main_window); obs_frontend_add_dock_by_id("AitumMultistreamDock", obs_module_text("AitumMultistream"), multistream_dock); + version_update_info = update_info_create_single("[Aitum Multistream]", "OBS", "https://api.aitum.tv/multi", + version_info_downloaded, nullptr); return true; } void obs_module_unload() { + update_info_destroy(version_update_info); if (multistream_dock) { delete multistream_dock; } @@ -133,7 +168,7 @@ MultistreamDock::MultistreamDock(QWidget *parent) : QFrame(parent) auto buttonRow = new QHBoxLayout; buttonRow->setContentsMargins(0, 0, 0, 0); - auto configButton = new QPushButton; + configButton = new QPushButton; configButton->setMinimumHeight(30); configButton->setProperty("themeID", "configIconSmall"); configButton->setFlat(true); @@ -149,6 +184,7 @@ MultistreamDock::MultistreamDock(QWidget *parent) : QFrame(parent) obs_data_apply(settings, current_config); configDialog->LoadSettings(settings); configDialog->LoadOutputStats(); + configDialog->SetNewerVersion(newer_version_available); configDialog->setResult(QDialog::Rejected); if (configDialog->exec() == QDialog::Accepted) { if (current_config) { @@ -479,8 +515,7 @@ bool MultistreamDock::StartOutput(obs_data_t *settings, QPushButton *streamButto std::string audio_encoder_name = "aitum_multi_audio_encoder_"; audio_encoder_name += name; aenc = obs_audio_encoder_create(venc_name, audio_encoder_name.c_str(), s, - obs_data_get_int(settings, "audio_track"), - nullptr); + obs_data_get_int(settings, "audio_track"), nullptr); obs_data_release(s); obs_encoder_set_audio(aenc, obs_get_audio()); } @@ -500,25 +535,29 @@ bool MultistreamDock::StartOutput(obs_data_t *settings, QPushButton *streamButto if (!aenc || !venc) { return false; } - + auto server = obs_data_get_string(settings, "server"); + bool whip = strstr(server, "whip") != nullptr; auto s = obs_data_create(); - obs_data_set_string(s, "server", obs_data_get_string(settings, "server")); - obs_data_set_string(s, "key", obs_data_get_string(settings, "key")); + obs_data_set_string(s, "server", server); + if (whip) { + obs_data_set_string(s, "bearer_token", obs_data_get_string(settings, "key")); + } else { + obs_data_set_string(s, "key", obs_data_get_string(settings, "key")); + } //use_auth //username //password std::string service_name = "aitum_multi_service_"; service_name += name; - auto service = obs_service_create("rtmp_custom", service_name.c_str(), s, nullptr); + auto service = obs_service_create(whip ? "whip_custom" : "rtmp_custom", service_name.c_str(), s, nullptr); obs_data_release(s); const char *type = obs_service_get_preferred_output_type(service); if (!type) { - const char *url = obs_service_get_connect_info(service, OBS_SERVICE_CONNECT_INFO_SERVER_URL); type = "rtmp_output"; - if (url != NULL && strncmp(url, "ftl", 3) == 0) { + if (strncmp(server, "ftl", 3) == 0) { type = "ftl_output"; - } else if (url != NULL && strncmp(url, "rtmp", 4) != 0) { + } else if (strncmp(server, "rtmp", 4) != 0) { type = "ffmpeg_mpegts_muxer"; } } @@ -576,3 +615,9 @@ void MultistreamDock::stream_output_stop(void *data, calldata_t *calldata) //const char *last_error = (const char *)calldata_ptr(calldata, "last_error"); streamButton->setChecked(false); } + +void MultistreamDock::NewerVersionAvailable(QString version) +{ + newer_version_available = version; + configButton->setStyleSheet(QString::fromUtf8("background: rgb(192,128,0);")); +} diff --git a/multistream.hpp b/multistream.hpp index d1af232..747128f 100644 --- a/multistream.hpp +++ b/multistream.hpp @@ -19,6 +19,9 @@ private: QVBoxLayout *mainCanvasLayout = nullptr; QPushButton *mainStreamButton = nullptr; + QPushButton *configButton = nullptr; + + QString newer_version_available; std::map outputs; @@ -37,6 +40,9 @@ private: static void stream_output_stop(void *data, calldata_t *calldata); static void stream_output_start(void *data, calldata_t *calldata); +private slots: + void NewerVersionAvailable(QString version); + public: MultistreamDock(QWidget *parent = nullptr); ~MultistreamDock();