diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini index e9d5dbadd..a05a24314 100644 --- a/UI/data/locale/en-US.ini +++ b/UI/data/locale/en-US.ini @@ -204,6 +204,7 @@ Basic.AutoConfig.StreamPage.Service.ShowAll="Show All..." Basic.AutoConfig.StreamPage.Service.Custom="Custom..." Basic.AutoConfig.StreamPage.Server="Server" Basic.AutoConfig.StreamPage.StreamKey="Stream Key" +Basic.AutoConfig.StreamPage.StreamKey.ToolTip="RIST: enter the encryption passphrase.\nRTMP: enter the key provided by the service.\nSRT: enter the streamid if the service uses one." Basic.AutoConfig.StreamPage.StreamKey.LinkToSite="(Link)" Basic.AutoConfig.StreamPage.EncoderKey="Encoder Key" Basic.AutoConfig.StreamPage.ConnectedAccount="Connected account" @@ -890,6 +891,8 @@ Basic.Settings.Stream.StreamType="Stream Type" Basic.Settings.Stream.Custom.UseAuthentication="Use authentication" Basic.Settings.Stream.Custom.Username="Username" Basic.Settings.Stream.Custom.Password="Password" +Basic.Settings.Stream.Custom.Username.ToolTip="RIST: enter the srp_username.\nRTMP: enter the username.\nSRT: not used." +Basic.Settings.Stream.Custom.Password.ToolTip="RIST: enter the srp_password.\nRTMP: enter the password.\nSRT: enter the encryption passphrase." Basic.Settings.Stream.BandwidthTestMode="Enable Bandwidth Test Mode" Basic.Settings.Stream.TTVAddon="Twitch Chat Add-Ons" Basic.Settings.Stream.TTVAddon.None="None" diff --git a/UI/window-basic-settings-stream.cpp b/UI/window-basic-settings-stream.cpp index bd9e571b1..a3be78a77 100644 --- a/UI/window-basic-settings-stream.cpp +++ b/UI/window-basic-settings-stream.cpp @@ -132,6 +132,29 @@ void OBSBasicSettings::LoadStream1Settings() ui->authUsername->setText(QT_UTF8(username)); ui->authPw->setText(QT_UTF8(password)); ui->useAuth->setChecked(use_auth); + + /* add tooltips for stream key, user, password fields */ + QString file = !App()->IsThemeDark() + ? ":/res/images/help.svg" + : ":/res/images/help_light.svg"; + QString lStr = "%1 "; + + ui->streamKeyLabel->setText( + lStr.arg(ui->streamKeyLabel->text(), file)); + ui->streamKeyLabel->setToolTip( + QTStr("Basic.AutoConfig.StreamPage.StreamKey.ToolTip")); + + ui->authUsernameLabel->setText( + lStr.arg(ui->authUsernameLabel->text(), file)); + ui->authUsernameLabel->setToolTip( + QTStr("Basic.Settings.Stream.Custom.Username.ToolTip")); + + ui->authPwLabel->setText( + lStr.arg(ui->authPwLabel->text(), file)); + ui->authPwLabel->setToolTip( + QTStr("Basic.Settings.Stream.Custom.Password.ToolTip")); } else { int idx = ui->service->findText(service); if (idx == -1) { @@ -305,7 +328,7 @@ void OBSBasicSettings::UpdateKeyLink() if (serviceName == "Dacast") { ui->streamKeyLabel->setText( QTStr("Basic.AutoConfig.StreamPage.EncoderKey")); - } else { + } else if (!IsCustomService()) { ui->streamKeyLabel->setText( QTStr("Basic.AutoConfig.StreamPage.StreamKey")); } diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-mpegts.c b/plugins/obs-ffmpeg/obs-ffmpeg-mpegts.c index 33e65829a..52ed50197 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-mpegts.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-mpegts.c @@ -347,11 +347,50 @@ static inline int connect_mpegts_url(struct ffmpeg_output *stream, bool is_rist) "Can not allocate memory."); goto fail; } + /* For SRT, pass streamid & passphrase; for RIST, pass passphrase, username + * & password. + */ + if (!is_rist) { + SRTContext *context = (SRTContext *)uc->priv_data; + context->streamid = NULL; + if (stream->ff_data.config.key != NULL) { + if (strlen(stream->ff_data.config.key)) + context->streamid = + av_strdup(stream->ff_data.config.key); + } + context->passphrase = NULL; + if (stream->ff_data.config.password != NULL) { + if (strlen(stream->ff_data.config.password)) + context->passphrase = av_strdup( + stream->ff_data.config.password); + } + } else { + RISTContext *context = (RISTContext *)uc->priv_data; + context->secret = NULL; + if (stream->ff_data.config.key != NULL) { + if (strlen(stream->ff_data.config.key)) + context->secret = + bstrdup(stream->ff_data.config.key); + } + context->username = NULL; + if (stream->ff_data.config.username != NULL) { + if (strlen(stream->ff_data.config.username)) + context->username = bstrdup( + stream->ff_data.config.username); + } + context->password = NULL; + if (stream->ff_data.config.password != NULL) { + if (strlen(stream->ff_data.config.password)) + context->password = bstrdup( + stream->ff_data.config.password); + } + } stream->h = uc; if (is_rist) err = librist_open(uc, uc->url); else err = libsrt_open(uc, uc->url); + if (err < 0) goto fail; return 0; @@ -839,13 +878,15 @@ static bool set_config(struct ffmpeg_output *stream) int ret; int code; - /* 1. Get URL from service & set format + mime-type. */ + /* 1. Get URL/username/password from service & set format + mime-type. */ obs_service_t *service; service = obs_output_get_service(stream->output); if (!service) return false; config.url = obs_service_get_url(service); - + config.username = obs_service_get_username(service); + config.password = obs_service_get_password(service); + config.key = obs_service_get_key(service); config.format_name = "mpegts"; config.format_mime_type = "video/M2PT"; diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-output.h b/plugins/obs-ffmpeg/obs-ffmpeg-output.h index 79bc660f5..682eee30a 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-output.h +++ b/plugins/obs-ffmpeg/obs-ffmpeg-output.h @@ -37,6 +37,9 @@ struct ffmpeg_cfg { int width; int height; int frame_size; // audio frame size + const char *username; + const char *password; + const char *key; }; struct ffmpeg_audio_info { diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-rist.h b/plugins/obs-ffmpeg/obs-ffmpeg-rist.h index f3844246b..f6a7bf655 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-rist.h +++ b/plugins/obs-ffmpeg/obs-ffmpeg-rist.h @@ -44,7 +44,8 @@ typedef struct RISTContext { int fifo_shift; bool overrun_nonfatal; char *secret; - + char *username; + char *password; struct rist_logging_settings logging_settings; struct rist_peer_config peer_config; @@ -100,7 +101,12 @@ static int librist_close(URLContext *h) { RISTContext *s = h->priv_data; int ret = 0; - + if (s->secret) + bfree(s->secret); + if (s->username) + bfree(s->username); + if (s->password) + bfree(s->password); s->peer = NULL; if (s->ctx) @@ -150,7 +156,6 @@ static int librist_open(URLContext *h, const char *uri) s->packet_size = 1316; s->log_level = RIST_LOG_INFO; s->encryption = 0; - s->secret = NULL; s->overrun_nonfatal = 0; s->fifo_shift = FF_LIBRIST_FIFO_DEFAULT_SHIFT; s->logging_settings = @@ -219,6 +224,12 @@ static int librist_open(URLContext *h, const char *uri) peer_config->recovery_length_min = s->buffer_size; peer_config->recovery_length_max = s->buffer_size; } + if (s->username && peer_config->srp_username[0] == 0) + av_strlcpy(peer_config->srp_username, s->username, + RIST_MAX_STRING_LONG); + if (s->password && peer_config->srp_password[0] == 0) + av_strlcpy(peer_config->srp_password, s->password, + RIST_MAX_STRING_LONG); ret = rist_peer_create(s->ctx, &s->peer, &s->peer_config); if (ret < 0) { diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-srt.h b/plugins/obs-ffmpeg/obs-ffmpeg-srt.h index 2afbc4360..3cce5d570 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-srt.h +++ b/plugins/obs-ffmpeg/obs-ffmpeg-srt.h @@ -80,12 +80,24 @@ typedef struct SRTContext { static int libsrt_neterrno(URLContext *h) { + SRTContext *s = (SRTContext *)h->priv_data; int os_errno; int err = srt_getlasterror(&os_errno); blog(LOG_ERROR, "[obs-ffmpeg mpegts muxer / libsrt] : %s\n", srt_getlasterror_str()); if (err == SRT_EASYNCRCV || err == SRT_EASYNCSND) return AVERROR(EAGAIN); + if (err = SRT_ECONNREJ) { + int errj = srt_getrejectreason(s->fd); + if (errj == SRT_REJ_BADSECRET) + blog(LOG_ERROR, + "[obs-ffmpeg mpegts muxer / libsrt] : Wrong password"); + else + blog(LOG_ERROR, + "[obs-ffmpeg mpegts muxer / libsrt] : Connection rejected, %s", + srt_rejectreason_str(errj)); + } + return os_errno ? AVERROR(os_errno) : AVERROR_UNKNOWN; } @@ -139,6 +151,20 @@ static int libsrt_network_wait_fd(URLContext *h, int eid, int write) ret = srt_epoll_wait(eid, ready, &len, error, &errlen, POLLING_TIME, 0, 0, 0, 0); } + if (len == 1 && errlen == 1) { + /* Socket reported in wsock AND rsock signifies an error. */ + int reason = srt_getrejectreason(*ready); + + if (reason == SRT_REJ_BADSECRET || reason == SRT_REJ_UNSECURE) { + blog(LOG_ERROR, + "[obs-ffmpeg mpegts muxer / libsrt] : Connection rejected, wrong password"); + return OBS_OUTPUT_INVALID_STREAM; + } else { + blog(LOG_ERROR, + "[obs-ffmpeg mpegts muxer / libsrt] : Connection rejected, %s", + srt_rejectreason_str(reason)); + } + } if (ret < 0) { if (srt_getlasterror(NULL) == SRT_ETIMEOUT) ret = AVERROR(EAGAIN); @@ -574,7 +600,6 @@ static void libsrt_set_defaults(SRTContext *s) s->payload_size = SRT_LIVE_DEFAULT_PAYLOAD_SIZE; s->maxbw = -1; s->pbkeylen = -1; - s->passphrase = NULL; s->mss = -1; s->ffs = -1; s->ipttl = -1; @@ -592,7 +617,6 @@ static void libsrt_set_defaults(SRTContext *s) s->rcvbuf = -1; s->lossmaxttl = -1; s->minversion = -1; - s->streamid = NULL; s->smoother = NULL; s->messageapi = -1; s->transtype = SRTT_LIVE; @@ -814,7 +838,10 @@ static int libsrt_write(URLContext *h, const uint8_t *buf, int size) static int libsrt_close(URLContext *h) { SRTContext *s = (SRTContext *)h->priv_data; - + if (s->streamid) + av_freep(&s->streamid); + if (s->passphrase) + av_freep(&s->passphrase); /* Log stream stats. */ SRT_TRACEBSTATS perf; srt_bstats(s->fd, &perf, 1);