Skip to content

Commit

Permalink
Merge pull request obsproject#35 from amazon-contributing/ruwen/custo…
Browse files Browse the repository at this point in the history
…m-config

Add support for custom go live configs
  • Loading branch information
palana committed Aug 17, 2023
2 parents c5be740 + 1d2746d commit 64257bc
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 70 deletions.
2 changes: 2 additions & 0 deletions plugins/simulcast/data/locale/en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ Settings.StreamKey="Stream Key"
Settings.MenuName="Twitch Settings"
Settings.WindowTitle="Twitch Settings"
Settings.EnableTelemetry="Allow runtime telemetry collection (Does not apply to Go Live Config request)"
Settings.UseTwitchConfig="Use Twitch Go Live Config (disable to enter custom config below)"
Settings.CustomConfig="Custom config (JSON or URL)"
VisibilityPrompt.Title="Show Twitch Dock"
VisibilityPrompt.Text="Streaming using the newest Twitch features requires using the Start Stream button on the Twitch dock.\n\nShow Dock now?"
VisibilityPrompt.RemindOneWeek="Ask me again in 7 days"
196 changes: 126 additions & 70 deletions plugins/simulcast/src/simulcast-dock-widget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,24 @@ handle_stream_start(SimulcastDockWidget *self, QPushButton *streamingButton,
start_time.CStr());
ProfileScope(scope_name);

QString url = GO_LIVE_API_URL;
OBSDataAutoRelease custom_config_data;
if (!self->UseTwitchConfig()) {
const auto &custom_config = self->CustomConfig();
if (custom_config.startsWith("http")) {
url = custom_config;
} else {
custom_config_data = obs_data_create_from_json(
self->CustomConfig().toUtf8().constData());
if (!custom_config_data) {
QMessageBox::critical(self,
"Failed to start stream",
"Invalid custom config");
return;
}
}
}

streamingButton->setText(
obs_frontend_get_locale_string("Basic.Main.Connecting"));
streamingButton->setDisabled(true);
Expand All @@ -65,92 +83,120 @@ handle_stream_start(SimulcastDockWidget *self, QPushButton *streamingButton,
ProfileScope("constructGoLivePostData");
return constructGoLivePost(start_time);
}()};
DownloadGoLiveConfig(self, GO_LIVE_API_URL, postData).then(self, [=](OBSDataAutoRelease goLiveConfig) mutable {
auto download_time_elapsed = start_time.MSecsElapsed();

self->Output()
.StartStreaming(self->StreamKey(), goLiveConfig)
.then(self,
[=, goLiveConfig =
OBSData{goLiveConfig}](bool started) {
if (!started) {
streamingButton->setText(
obs_frontend_get_locale_string(
"Basic.Main.StartStreaming"));
streamingButton->setDisabled(
false);

DownloadGoLiveConfig(self, url, postData)
.then(self, [=, use_custom_config = !self->UseTwitchConfig(),
custom_config_data = OBSData{custom_config_data}](
OBSDataAutoRelease goLiveConfig) mutable {
auto download_time_elapsed = start_time.MSecsElapsed();

if (!goLiveConfig && !custom_config_data) {
streamingButton->setText(
obs_frontend_get_locale_string(
"Basic.Main.StartStreaming"));
streamingButton->setDisabled(false);
QMessageBox::critical(
self, "Failed to start stream",
use_custom_config
? "Custom config URL returned invalid config, check log for details"
: "API returned invalid config; try again later");
return;
}

auto config_used = custom_config_data
? custom_config_data
: OBSData{goLiveConfig};

self->Output()
.StartStreaming(self->StreamKey(), config_used)
.then(self,
[=](bool started) {
if (!started) {
streamingButton->setText(
obs_frontend_get_locale_string(
"Basic.Main.StartStreaming"));
streamingButton
->setDisabled(
false);

auto start_streaming_returned =
start_time
.MSecsElapsed();
auto event = MakeEvent_ivs_obs_stream_start_failed(
postData,
config_used,
start_time,
download_time_elapsed,
start_streaming_returned);
berryessa->submit(
"ivs_obs_stream_start_failed",
event);
return;
}

auto start_streaming_returned =
start_time.MSecsElapsed();
auto event = MakeEvent_ivs_obs_stream_start_failed(
postData, goLiveConfig,
start_time,
download_time_elapsed,
start_streaming_returned);
berryessa->submit(
"ivs_obs_stream_start_failed",
event);
return;
}

auto start_streaming_returned =
start_time.MSecsElapsed();

auto event =
MakeEvent_ivs_obs_stream_start(
postData, goLiveConfig,
auto event = MakeEvent_ivs_obs_stream_start(
postData, config_used,
start_time,
download_time_elapsed,
start_streaming_returned,
self->Output()
.ConnectTimeMs());
const char *configId =
obs_data_get_string(event,
"config_id");
if (configId) {
// put the config_id on all events until the stream ends

if (!use_custom_config) {
const char *configId =
obs_data_get_string(
event,
"config_id");
if (configId) {
// put the config_id on all events until the stream ends
berryessa->setAlwaysString(
"config_id",
configId);
}
}

berryessa->setAlwaysString(
"config_id", configId);
}
berryessa->setAlwaysString(
"stream_attempt_start_time",
start_time.CStr());
"stream_attempt_start_time",
start_time.CStr());

berryessa->submit("ivs_obs_stream_start",
event);
berryessa->submit(
"ivs_obs_stream_start",
event);

if (!telemetry_enabled)
return;
if (!telemetry_enabled)
return;

berryessaEveryMinute->reset(
new BerryessaEveryMinute(
berryessaEveryMinute->reset(new BerryessaEveryMinute(
self, berryessa,
self->Output()
.VideoEncoders()));
})
.onFailed(self, [=,
goLiveConfig = OBSData{goLiveConfig}](
const QString &error) {
streamingButton->setText(
obs_frontend_get_locale_string(
"Basic.Main.StartStreaming"));
streamingButton->setDisabled(false);

auto start_streaming_returned =
start_time.MSecsElapsed();
auto event =
MakeEvent_ivs_obs_stream_start_failed(
postData, goLiveConfig,
start_time,
download_time_elapsed,
start_streaming_returned);
berryessa->submit("ivs_obs_stream_start_failed",
event);

QMessageBox::critical(
self, "Failed to start stream", error);
});
});
})
.onFailed(self, [=](const QString &error) {
streamingButton->setText(
obs_frontend_get_locale_string(
"Basic.Main.StartStreaming"));
streamingButton->setDisabled(false);

auto start_streaming_returned =
start_time.MSecsElapsed();
auto event =
MakeEvent_ivs_obs_stream_start_failed(
postData, config_used,
start_time,
download_time_elapsed,
start_streaming_returned);
berryessa->submit(
"ivs_obs_stream_start_failed",
event);

QMessageBox::critical(
self, "Failed to start stream",
error);
});
});
}

static void SetupSignalsAndSlots(
Expand Down Expand Up @@ -263,10 +309,12 @@ static OBSDataAutoRelease load_or_create_obj(obs_data_t *data, const char *name)
#define JSON_CONFIG_FILE module_config_path("config.json")
#define DATA_KEY_SETTINGS_WINDOW_GEOMETRY "settings_window_geometry"
#define DATA_KEY_MAKE_DOCK_VISIBLE_PROMPT "make_dock_visible_prompt"
#define DATA_KEY_CUSTOM_CONFIG "custom_config"
#define DATA_KEY_DEVICE_ID "device_id"
#define DATA_KEY_PROFILES "profiles"
#define DATA_KEY_STREAM_KEY "stream_key"
#define DATA_KEY_TELEMETRY_ENABLED "telemetry"
#define DATA_KEY_USE_TWITCH_CONFIG "use_twitch_config"

static void write_config(obs_data_t *config)
{
Expand All @@ -285,6 +333,10 @@ void SimulcastDockWidget::SaveConfig()
stream_key_.toUtf8().constData());
obs_data_set_bool(profile_, DATA_KEY_TELEMETRY_ENABLED,
telemetry_enabled_);
obs_data_set_bool(profile_, DATA_KEY_USE_TWITCH_CONFIG,
use_twitch_config_);
obs_data_set_string(profile_, DATA_KEY_CUSTOM_CONFIG,
custom_config_.toUtf8().constData());
obs_data_set_string(config_, DATA_KEY_SETTINGS_WINDOW_GEOMETRY,
settings_window_geometry_.toBase64().constData());
if (make_dock_visible_prompt_.has_value()) {
Expand Down Expand Up @@ -313,11 +365,15 @@ void SimulcastDockWidget::LoadConfig()
profile_ = load_or_create_obj(profiles_, profile_name_->array);

obs_data_set_default_bool(profile_, DATA_KEY_TELEMETRY_ENABLED, true);
obs_data_set_default_bool(profile_, DATA_KEY_USE_TWITCH_CONFIG, true);

// Set modified config values here
stream_key_ = obs_data_get_string(profile_, DATA_KEY_STREAM_KEY);
telemetry_enabled_ =
obs_data_get_bool(profile_, DATA_KEY_TELEMETRY_ENABLED);
use_twitch_config_ =
obs_data_get_bool(profile_, DATA_KEY_USE_TWITCH_CONFIG);
custom_config_ = obs_data_get_string(profile_, DATA_KEY_CUSTOM_CONFIG);
settings_window_geometry_ = QByteArray::fromBase64(obs_data_get_string(
config_, DATA_KEY_SETTINGS_WINDOW_GEOMETRY));
if (obs_data_has_user_value(config_,
Expand Down
4 changes: 4 additions & 0 deletions plugins/simulcast/src/simulcast-dock-widget.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class SimulcastDockWidget : public QWidget {

QString &StreamKey() { return stream_key_; }
bool &TelemetryEanbled() { return telemetry_enabled_; }
bool &UseTwitchConfig() { return use_twitch_config_; }
QString &CustomConfig() { return custom_config_; }
QByteArray &SettingsWindowGeometry()
{
return settings_window_geometry_;
Expand All @@ -52,6 +54,8 @@ class SimulcastDockWidget : public QWidget {
// Add config vars here
QString stream_key_;
bool telemetry_enabled_;
bool use_twitch_config_;
QString custom_config_;
QByteArray settings_window_geometry_;
std::optional<QDateTime> make_dock_visible_prompt_;
// Add config vars above
Expand Down
23 changes: 23 additions & 0 deletions plugins/simulcast/src/simulcast-settings-window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <QLabel>
#include <QLineEdit>
#include <QMainWindow>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QSpacerItem>
#include <QVBoxLayout>
Expand Down Expand Up @@ -64,6 +65,12 @@ SimulcastSettingsWindow::SimulcastSettingsWindow(SimulcastDockWidget *dock,
telemetry_checkbox_ =
new QCheckBox(obs_module_text("Settings.EnableTelemetry"));

use_twitch_config_ =
new QCheckBox(obs_module_text("Settings.UseTwitchConfig"));
custom_config_ = new QPlainTextEdit;
auto custom_config_label =
new QLabel(obs_module_text("Settings.CustomConfig"));

// Allow button box to move to bottom of window, even when the window is resized
auto stretch_spacer = new QSpacerItem(1, 1, QSizePolicy::Minimum,
QSizePolicy::MinimumExpanding);
Expand All @@ -79,6 +86,8 @@ SimulcastSettingsWindow::SimulcastSettingsWindow(SimulcastDockWidget *dock,
form_layout->addRow(obs_module_text("Settings.StreamKey"),
stream_key_edit_layout);
form_layout->addRow("", telemetry_checkbox_);
form_layout->addRow("", use_twitch_config_);
form_layout->addRow(custom_config_label, custom_config_);
form_layout->addItem(stretch_spacer);
form_layout->addRow(button_box_);

Expand All @@ -104,6 +113,16 @@ SimulcastSettingsWindow::SimulcastSettingsWindow(SimulcastDockWidget *dock,
});
connect(telemetry_checkbox_, &QCheckBox::stateChanged,
[=](int /*state*/) { SetApplyEnabled(true); });
connect(use_twitch_config_, &QCheckBox::stateChanged,
[=](int /*state*/) {
SetApplyEnabled(true);
custom_config_->setEnabled(
!use_twitch_config_->isChecked());
custom_config_label->setEnabled(
!use_twitch_config_->isChecked());
});
connect(custom_config_, &QPlainTextEdit::textChanged,
[=] { SetApplyEnabled(true); });
connect(button_box_, &QDialogButtonBox::clicked,
[=](QAbstractButton *button) { this->ButtonPressed(button); });

Expand Down Expand Up @@ -138,6 +157,8 @@ void SimulcastSettingsWindow::ButtonPressed(QAbstractButton *button)
// Handle individual settings here
dock_->StreamKey() = stream_key_edit_->text();
dock_->TelemetryEanbled() = telemetry_checkbox_->isChecked();
dock_->UseTwitchConfig() = use_twitch_config_->isChecked();
dock_->CustomConfig() = custom_config_->toPlainText();
dock_->SettingsWindowGeometry() = saveGeometry();
// Handle individual settings above

Expand Down Expand Up @@ -170,6 +191,8 @@ void SimulcastSettingsWindow::ResetSettings()
{
stream_key_edit_->setText(dock_->StreamKey());
telemetry_checkbox_->setChecked(dock_->TelemetryEanbled());
use_twitch_config_->setChecked(dock_->UseTwitchConfig());
custom_config_->setPlainText(dock_->CustomConfig());

SetApplyEnabled(false);
}
4 changes: 4 additions & 0 deletions plugins/simulcast/src/simulcast-settings-window.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class QAbstractButton;
class QCheckBox;
class QDialogButtonBox;
class QLineEdit;
class QPlainTextEdit;
class QPushButton;

class SimulcastSettingsWindow : public QDialog {
Expand All @@ -30,4 +31,7 @@ class SimulcastSettingsWindow : public QDialog {
QDialogButtonBox *button_box_;

QCheckBox *telemetry_checkbox_;

QCheckBox *use_twitch_config_;
QPlainTextEdit *custom_config_;
};

0 comments on commit 64257bc

Please sign in to comment.