mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-09-20 13:08:50 +02:00
21f1c155ef
The stream output signals are now put inside of a vector.
618 lines
16 KiB
C++
618 lines
16 KiB
C++
#include <QPainter>
|
|
#include <QPixmap>
|
|
#include "obs-app.hpp"
|
|
#include "window-basic-main.hpp"
|
|
#include "window-basic-status-bar.hpp"
|
|
#include "window-basic-main-outputs.hpp"
|
|
#include "qt-wrappers.hpp"
|
|
#include "platform.hpp"
|
|
|
|
#include "ui_StatusBarWidget.h"
|
|
|
|
static constexpr int bitrateUpdateSeconds = 2;
|
|
static constexpr int congestionUpdateSeconds = 4;
|
|
static constexpr float excellentThreshold = 0.0f;
|
|
static constexpr float goodThreshold = 0.3333f;
|
|
static constexpr float mediocreThreshold = 0.6667f;
|
|
static constexpr float badThreshold = 1.0f;
|
|
|
|
StatusBarWidget::StatusBarWidget(QWidget *parent)
|
|
: QWidget(parent),
|
|
ui(new Ui::StatusBarWidget)
|
|
{
|
|
ui->setupUi(this);
|
|
}
|
|
|
|
StatusBarWidget::~StatusBarWidget() {}
|
|
|
|
OBSBasicStatusBar::OBSBasicStatusBar(QWidget *parent)
|
|
: QStatusBar(parent),
|
|
excellentPixmap(QIcon(":/res/images/network-excellent.svg")
|
|
.pixmap(QSize(16, 16))),
|
|
goodPixmap(
|
|
QIcon(":/res/images/network-good.svg").pixmap(QSize(16, 16))),
|
|
mediocrePixmap(QIcon(":/res/images/network-mediocre.svg")
|
|
.pixmap(QSize(16, 16))),
|
|
badPixmap(
|
|
QIcon(":/res/images/network-bad.svg").pixmap(QSize(16, 16))),
|
|
recordingActivePixmap(QIcon(":/res/images/recording-active.svg")
|
|
.pixmap(QSize(16, 16))),
|
|
recordingPausePixmap(QIcon(":/res/images/recording-pause.svg")
|
|
.pixmap(QSize(16, 16))),
|
|
streamingActivePixmap(QIcon(":/res/images/streaming-active.svg")
|
|
.pixmap(QSize(16, 16)))
|
|
{
|
|
congestionArray.reserve(congestionUpdateSeconds);
|
|
|
|
statusWidget = new StatusBarWidget(this);
|
|
statusWidget->ui->delayInfo->setText("");
|
|
statusWidget->ui->droppedFrames->setText(
|
|
QTStr("DroppedFrames").arg("0", "0.0"));
|
|
statusWidget->ui->statusIcon->setPixmap(inactivePixmap);
|
|
statusWidget->ui->streamIcon->setPixmap(streamingInactivePixmap);
|
|
statusWidget->ui->streamTime->setDisabled(true);
|
|
statusWidget->ui->recordIcon->setPixmap(recordingInactivePixmap);
|
|
statusWidget->ui->recordTime->setDisabled(true);
|
|
statusWidget->ui->delayFrame->hide();
|
|
statusWidget->ui->issuesFrame->hide();
|
|
statusWidget->ui->kbps->hide();
|
|
|
|
addPermanentWidget(statusWidget, 1);
|
|
setMinimumHeight(statusWidget->height());
|
|
|
|
UpdateIcons();
|
|
connect(App(), &OBSApp::StyleChanged, this,
|
|
&OBSBasicStatusBar::UpdateIcons);
|
|
|
|
messageTimer = new QTimer(this);
|
|
messageTimer->setSingleShot(true);
|
|
connect(messageTimer, &QTimer::timeout, this,
|
|
&OBSBasicStatusBar::clearMessage);
|
|
|
|
clearMessage();
|
|
}
|
|
|
|
void OBSBasicStatusBar::Activate()
|
|
{
|
|
if (!active) {
|
|
refreshTimer = new QTimer(this);
|
|
connect(refreshTimer, &QTimer::timeout, this,
|
|
&OBSBasicStatusBar::UpdateStatusBar);
|
|
|
|
int skipped = video_output_get_skipped_frames(obs_get_video());
|
|
int total = video_output_get_total_frames(obs_get_video());
|
|
|
|
totalStreamSeconds = 0;
|
|
totalRecordSeconds = 0;
|
|
lastSkippedFrameCount = 0;
|
|
startSkippedFrameCount = skipped;
|
|
startTotalFrameCount = total;
|
|
|
|
refreshTimer->start(1000);
|
|
active = true;
|
|
|
|
if (streamOutput) {
|
|
statusWidget->ui->statusIcon->setPixmap(inactivePixmap);
|
|
}
|
|
}
|
|
|
|
if (streamOutput) {
|
|
statusWidget->ui->streamIcon->setPixmap(streamingActivePixmap);
|
|
statusWidget->ui->streamTime->setDisabled(false);
|
|
statusWidget->ui->issuesFrame->show();
|
|
statusWidget->ui->kbps->show();
|
|
firstCongestionUpdate = true;
|
|
}
|
|
|
|
if (recordOutput) {
|
|
statusWidget->ui->recordIcon->setPixmap(recordingActivePixmap);
|
|
statusWidget->ui->recordTime->setDisabled(false);
|
|
}
|
|
}
|
|
|
|
void OBSBasicStatusBar::Deactivate()
|
|
{
|
|
OBSBasic *main = qobject_cast<OBSBasic *>(parent());
|
|
if (!main)
|
|
return;
|
|
|
|
if (!streamOutput) {
|
|
statusWidget->ui->streamTime->setText(QString("00:00:00"));
|
|
statusWidget->ui->streamTime->setDisabled(true);
|
|
statusWidget->ui->streamIcon->setPixmap(
|
|
streamingInactivePixmap);
|
|
statusWidget->ui->statusIcon->setPixmap(inactivePixmap);
|
|
statusWidget->ui->delayFrame->hide();
|
|
statusWidget->ui->issuesFrame->hide();
|
|
statusWidget->ui->kbps->hide();
|
|
totalStreamSeconds = 0;
|
|
congestionArray.clear();
|
|
disconnected = false;
|
|
firstCongestionUpdate = false;
|
|
}
|
|
|
|
if (!recordOutput) {
|
|
statusWidget->ui->recordTime->setText(QString("00:00:00"));
|
|
statusWidget->ui->recordTime->setDisabled(true);
|
|
statusWidget->ui->recordIcon->setPixmap(
|
|
recordingInactivePixmap);
|
|
totalRecordSeconds = 0;
|
|
}
|
|
|
|
if (main->outputHandler && !main->outputHandler->Active()) {
|
|
delete refreshTimer;
|
|
|
|
statusWidget->ui->delayInfo->setText("");
|
|
statusWidget->ui->droppedFrames->setText(
|
|
QTStr("DroppedFrames").arg("0", "0.0"));
|
|
statusWidget->ui->kbps->setText("0 kbps");
|
|
|
|
delaySecTotal = 0;
|
|
delaySecStarting = 0;
|
|
delaySecStopping = 0;
|
|
reconnectTimeout = 0;
|
|
active = false;
|
|
overloadedNotify = true;
|
|
|
|
statusWidget->ui->statusIcon->setPixmap(inactivePixmap);
|
|
}
|
|
}
|
|
|
|
void OBSBasicStatusBar::UpdateDelayMsg()
|
|
{
|
|
QString msg;
|
|
|
|
if (delaySecTotal) {
|
|
if (delaySecStarting && !delaySecStopping) {
|
|
msg = QTStr("Basic.StatusBar.DelayStartingIn");
|
|
msg = msg.arg(QString::number(delaySecStarting));
|
|
|
|
} else if (!delaySecStarting && delaySecStopping) {
|
|
msg = QTStr("Basic.StatusBar.DelayStoppingIn");
|
|
msg = msg.arg(QString::number(delaySecStopping));
|
|
|
|
} else if (delaySecStarting && delaySecStopping) {
|
|
msg = QTStr("Basic.StatusBar.DelayStartingStoppingIn");
|
|
msg = msg.arg(QString::number(delaySecStopping),
|
|
QString::number(delaySecStarting));
|
|
} else {
|
|
msg = QTStr("Basic.StatusBar.Delay");
|
|
msg = msg.arg(QString::number(delaySecTotal));
|
|
}
|
|
|
|
if (!statusWidget->ui->delayFrame->isVisible())
|
|
statusWidget->ui->delayFrame->show();
|
|
|
|
statusWidget->ui->delayInfo->setText(msg);
|
|
}
|
|
}
|
|
|
|
void OBSBasicStatusBar::UpdateBandwidth()
|
|
{
|
|
if (!streamOutput)
|
|
return;
|
|
|
|
if (++seconds < bitrateUpdateSeconds)
|
|
return;
|
|
|
|
uint64_t bytesSent = obs_output_get_total_bytes(streamOutput);
|
|
uint64_t bytesSentTime = os_gettime_ns();
|
|
|
|
if (bytesSent < lastBytesSent)
|
|
bytesSent = 0;
|
|
if (bytesSent == 0)
|
|
lastBytesSent = 0;
|
|
|
|
uint64_t bitsBetween = (bytesSent - lastBytesSent) * 8;
|
|
|
|
double timePassed =
|
|
double(bytesSentTime - lastBytesSentTime) / 1000000000.0;
|
|
|
|
double kbitsPerSec = double(bitsBetween) / timePassed / 1000.0;
|
|
|
|
QString text;
|
|
text += QString::number(kbitsPerSec, 'f', 0) + QString(" kbps");
|
|
|
|
statusWidget->ui->kbps->setText(text);
|
|
statusWidget->ui->kbps->setMinimumWidth(
|
|
statusWidget->ui->kbps->width());
|
|
|
|
if (!statusWidget->ui->kbps->isVisible())
|
|
statusWidget->ui->kbps->show();
|
|
|
|
lastBytesSent = bytesSent;
|
|
lastBytesSentTime = bytesSentTime;
|
|
seconds = 0;
|
|
}
|
|
|
|
void OBSBasicStatusBar::UpdateCPUUsage()
|
|
{
|
|
OBSBasic *main = qobject_cast<OBSBasic *>(parent());
|
|
if (!main)
|
|
return;
|
|
|
|
QString text;
|
|
text += QString("CPU: ") +
|
|
QString::number(main->GetCPUUsage(), 'f', 1) + QString("%");
|
|
|
|
statusWidget->ui->cpuUsage->setText(text);
|
|
statusWidget->ui->cpuUsage->setMinimumWidth(
|
|
statusWidget->ui->cpuUsage->width());
|
|
|
|
UpdateCurrentFPS();
|
|
}
|
|
|
|
void OBSBasicStatusBar::UpdateCurrentFPS()
|
|
{
|
|
struct obs_video_info ovi;
|
|
obs_get_video_info(&ovi);
|
|
float targetFPS = (float)ovi.fps_num / (float)ovi.fps_den;
|
|
|
|
QString text = QString::asprintf("%.2f / %.2f FPS",
|
|
obs_get_active_fps(), targetFPS);
|
|
|
|
statusWidget->ui->fpsCurrent->setText(text);
|
|
statusWidget->ui->fpsCurrent->setMinimumWidth(
|
|
statusWidget->ui->fpsCurrent->width());
|
|
}
|
|
|
|
void OBSBasicStatusBar::UpdateStreamTime()
|
|
{
|
|
totalStreamSeconds++;
|
|
|
|
int seconds = totalStreamSeconds % 60;
|
|
int totalMinutes = totalStreamSeconds / 60;
|
|
int minutes = totalMinutes % 60;
|
|
int hours = totalMinutes / 60;
|
|
|
|
QString text =
|
|
QString::asprintf("%02d:%02d:%02d", hours, minutes, seconds);
|
|
statusWidget->ui->streamTime->setText(text);
|
|
if (streamOutput && !statusWidget->ui->streamTime->isEnabled())
|
|
statusWidget->ui->streamTime->setDisabled(false);
|
|
|
|
if (reconnectTimeout > 0) {
|
|
QString msg = QTStr("Basic.StatusBar.Reconnecting")
|
|
.arg(QString::number(retries),
|
|
QString::number(reconnectTimeout));
|
|
showMessage(msg);
|
|
disconnected = true;
|
|
statusWidget->ui->statusIcon->setPixmap(disconnectedPixmap);
|
|
congestionArray.clear();
|
|
reconnectTimeout--;
|
|
|
|
} else if (retries > 0) {
|
|
QString msg = QTStr("Basic.StatusBar.AttemptingReconnect");
|
|
showMessage(msg.arg(QString::number(retries)));
|
|
}
|
|
|
|
if (delaySecStopping > 0 || delaySecStarting > 0) {
|
|
if (delaySecStopping > 0)
|
|
--delaySecStopping;
|
|
if (delaySecStarting > 0)
|
|
--delaySecStarting;
|
|
UpdateDelayMsg();
|
|
}
|
|
}
|
|
|
|
extern volatile bool recording_paused;
|
|
|
|
void OBSBasicStatusBar::UpdateRecordTime()
|
|
{
|
|
bool paused = os_atomic_load_bool(&recording_paused);
|
|
|
|
if (!paused) {
|
|
totalRecordSeconds++;
|
|
|
|
int seconds = totalRecordSeconds % 60;
|
|
int totalMinutes = totalRecordSeconds / 60;
|
|
int minutes = totalMinutes % 60;
|
|
int hours = totalMinutes / 60;
|
|
|
|
QString text = QString::asprintf("%02d:%02d:%02d", hours,
|
|
minutes, seconds);
|
|
|
|
statusWidget->ui->recordTime->setText(text);
|
|
if (recordOutput && !statusWidget->ui->recordTime->isEnabled())
|
|
statusWidget->ui->recordTime->setDisabled(false);
|
|
} else {
|
|
statusWidget->ui->recordIcon->setPixmap(
|
|
streamPauseIconToggle ? recordingPauseInactivePixmap
|
|
: recordingPausePixmap);
|
|
|
|
streamPauseIconToggle = !streamPauseIconToggle;
|
|
}
|
|
}
|
|
|
|
void OBSBasicStatusBar::UpdateDroppedFrames()
|
|
{
|
|
if (!streamOutput)
|
|
return;
|
|
|
|
int totalDropped = obs_output_get_frames_dropped(streamOutput);
|
|
int totalFrames = obs_output_get_total_frames(streamOutput);
|
|
double percent = (double)totalDropped / (double)totalFrames * 100.0;
|
|
|
|
if (!totalFrames)
|
|
return;
|
|
|
|
QString text = QTStr("DroppedFrames");
|
|
text = text.arg(QString::number(totalDropped),
|
|
QString::number(percent, 'f', 1));
|
|
statusWidget->ui->droppedFrames->setText(text);
|
|
|
|
if (!statusWidget->ui->issuesFrame->isVisible())
|
|
statusWidget->ui->issuesFrame->show();
|
|
|
|
/* ----------------------------------- *
|
|
* calculate congestion color */
|
|
|
|
float congestion = obs_output_get_congestion(streamOutput);
|
|
float avgCongestion = (congestion + lastCongestion) * 0.5f;
|
|
if (avgCongestion < congestion)
|
|
avgCongestion = congestion;
|
|
if (avgCongestion > 1.0f)
|
|
avgCongestion = 1.0f;
|
|
|
|
lastCongestion = congestion;
|
|
|
|
if (disconnected)
|
|
return;
|
|
|
|
bool update = firstCongestionUpdate;
|
|
float congestionOverTime = avgCongestion;
|
|
|
|
if (congestionArray.size() >= congestionUpdateSeconds) {
|
|
congestionOverTime = accumulate(congestionArray.begin(),
|
|
congestionArray.end(), 0.0f) /
|
|
(float)congestionArray.size();
|
|
congestionArray.clear();
|
|
update = true;
|
|
} else {
|
|
congestionArray.emplace_back(avgCongestion);
|
|
}
|
|
|
|
if (update) {
|
|
if (congestionOverTime <= excellentThreshold + EPSILON)
|
|
statusWidget->ui->statusIcon->setPixmap(
|
|
excellentPixmap);
|
|
else if (congestionOverTime <= goodThreshold)
|
|
statusWidget->ui->statusIcon->setPixmap(goodPixmap);
|
|
else if (congestionOverTime <= mediocreThreshold)
|
|
statusWidget->ui->statusIcon->setPixmap(mediocrePixmap);
|
|
else if (congestionOverTime <= badThreshold)
|
|
statusWidget->ui->statusIcon->setPixmap(badPixmap);
|
|
|
|
firstCongestionUpdate = false;
|
|
}
|
|
}
|
|
|
|
void OBSBasicStatusBar::OBSOutputReconnect(void *data, calldata_t *params)
|
|
{
|
|
OBSBasicStatusBar *statusBar =
|
|
reinterpret_cast<OBSBasicStatusBar *>(data);
|
|
|
|
int seconds = (int)calldata_int(params, "timeout_sec");
|
|
QMetaObject::invokeMethod(statusBar, "Reconnect", Q_ARG(int, seconds));
|
|
}
|
|
|
|
void OBSBasicStatusBar::OBSOutputReconnectSuccess(void *data, calldata_t *)
|
|
{
|
|
OBSBasicStatusBar *statusBar =
|
|
reinterpret_cast<OBSBasicStatusBar *>(data);
|
|
|
|
QMetaObject::invokeMethod(statusBar, "ReconnectSuccess");
|
|
}
|
|
|
|
void OBSBasicStatusBar::Reconnect(int seconds)
|
|
{
|
|
OBSBasic *main = qobject_cast<OBSBasic *>(parent());
|
|
|
|
if (!retries)
|
|
main->SysTrayNotify(
|
|
QTStr("Basic.SystemTray.Message.Reconnecting"),
|
|
QSystemTrayIcon::Warning);
|
|
|
|
reconnectTimeout = seconds;
|
|
|
|
if (streamOutput) {
|
|
delaySecTotal = obs_output_get_active_delay(streamOutput);
|
|
UpdateDelayMsg();
|
|
|
|
retries++;
|
|
}
|
|
}
|
|
|
|
void OBSBasicStatusBar::ReconnectClear()
|
|
{
|
|
retries = 0;
|
|
reconnectTimeout = 0;
|
|
seconds = -1;
|
|
lastBytesSent = 0;
|
|
lastBytesSentTime = os_gettime_ns();
|
|
delaySecTotal = 0;
|
|
UpdateDelayMsg();
|
|
}
|
|
|
|
void OBSBasicStatusBar::ReconnectSuccess()
|
|
{
|
|
OBSBasic *main = qobject_cast<OBSBasic *>(parent());
|
|
|
|
QString msg = QTStr("Basic.StatusBar.ReconnectSuccessful");
|
|
showMessage(msg, 4000);
|
|
main->SysTrayNotify(msg, QSystemTrayIcon::Information);
|
|
ReconnectClear();
|
|
|
|
if (streamOutput) {
|
|
delaySecTotal = obs_output_get_active_delay(streamOutput);
|
|
UpdateDelayMsg();
|
|
disconnected = false;
|
|
firstCongestionUpdate = true;
|
|
}
|
|
}
|
|
|
|
void OBSBasicStatusBar::UpdateStatusBar()
|
|
{
|
|
OBSBasic *main = qobject_cast<OBSBasic *>(parent());
|
|
|
|
UpdateBandwidth();
|
|
|
|
if (streamOutput)
|
|
UpdateStreamTime();
|
|
|
|
if (recordOutput)
|
|
UpdateRecordTime();
|
|
|
|
UpdateDroppedFrames();
|
|
|
|
int skipped = video_output_get_skipped_frames(obs_get_video());
|
|
int total = video_output_get_total_frames(obs_get_video());
|
|
|
|
skipped -= startSkippedFrameCount;
|
|
total -= startTotalFrameCount;
|
|
|
|
int diff = skipped - lastSkippedFrameCount;
|
|
double percentage = double(skipped) / double(total) * 100.0;
|
|
|
|
if (diff > 10 && percentage >= 0.1f) {
|
|
showMessage(QTStr("HighResourceUsage"), 4000);
|
|
if (!main->isVisible() && overloadedNotify) {
|
|
main->SysTrayNotify(QTStr("HighResourceUsage"),
|
|
QSystemTrayIcon::Warning);
|
|
overloadedNotify = false;
|
|
}
|
|
}
|
|
|
|
lastSkippedFrameCount = skipped;
|
|
}
|
|
|
|
void OBSBasicStatusBar::StreamDelayStarting(int sec)
|
|
{
|
|
OBSBasic *main = qobject_cast<OBSBasic *>(parent());
|
|
if (!main || !main->outputHandler)
|
|
return;
|
|
|
|
streamOutput = main->outputHandler->streamOutput;
|
|
|
|
delaySecTotal = delaySecStarting = sec;
|
|
UpdateDelayMsg();
|
|
Activate();
|
|
}
|
|
|
|
void OBSBasicStatusBar::StreamDelayStopping(int sec)
|
|
{
|
|
delaySecTotal = delaySecStopping = sec;
|
|
UpdateDelayMsg();
|
|
}
|
|
|
|
void OBSBasicStatusBar::StreamStarted(obs_output_t *output)
|
|
{
|
|
streamOutput = output;
|
|
|
|
streamSigs.emplace_back(obs_output_get_signal_handler(streamOutput),
|
|
"reconnect", OBSOutputReconnect, this);
|
|
streamSigs.emplace_back(obs_output_get_signal_handler(streamOutput),
|
|
"reconnect_success", OBSOutputReconnectSuccess,
|
|
this);
|
|
|
|
retries = 0;
|
|
lastBytesSent = 0;
|
|
lastBytesSentTime = os_gettime_ns();
|
|
Activate();
|
|
}
|
|
|
|
void OBSBasicStatusBar::StreamStopped()
|
|
{
|
|
if (streamOutput) {
|
|
streamSigs.clear();
|
|
|
|
ReconnectClear();
|
|
streamOutput = nullptr;
|
|
clearMessage();
|
|
Deactivate();
|
|
}
|
|
}
|
|
|
|
void OBSBasicStatusBar::RecordingStarted(obs_output_t *output)
|
|
{
|
|
recordOutput = output;
|
|
Activate();
|
|
}
|
|
|
|
void OBSBasicStatusBar::RecordingStopped()
|
|
{
|
|
recordOutput = nullptr;
|
|
Deactivate();
|
|
}
|
|
|
|
void OBSBasicStatusBar::RecordingPaused()
|
|
{
|
|
QString text = statusWidget->ui->recordTime->text() +
|
|
QStringLiteral(" (PAUSED)");
|
|
statusWidget->ui->recordTime->setText(text);
|
|
|
|
if (recordOutput) {
|
|
statusWidget->ui->recordIcon->setPixmap(recordingPausePixmap);
|
|
streamPauseIconToggle = true;
|
|
}
|
|
}
|
|
|
|
void OBSBasicStatusBar::RecordingUnpaused()
|
|
{
|
|
if (recordOutput) {
|
|
statusWidget->ui->recordIcon->setPixmap(recordingActivePixmap);
|
|
}
|
|
}
|
|
|
|
static QPixmap GetPixmap(const QString &filename)
|
|
{
|
|
QString path = obs_frontend_is_theme_dark() ? "theme:Dark/"
|
|
: ":/res/images/";
|
|
return QIcon(path + filename).pixmap(QSize(16, 16));
|
|
}
|
|
|
|
void OBSBasicStatusBar::UpdateIcons()
|
|
{
|
|
disconnectedPixmap = GetPixmap("network-disconnected.svg");
|
|
inactivePixmap = GetPixmap("network-inactive.svg");
|
|
|
|
streamingInactivePixmap = GetPixmap("streaming-inactive.svg");
|
|
|
|
recordingInactivePixmap = GetPixmap("recording-inactive.svg");
|
|
recordingPauseInactivePixmap =
|
|
GetPixmap("recording-pause-inactive.svg");
|
|
|
|
bool streaming = obs_frontend_streaming_active();
|
|
|
|
if (!streaming) {
|
|
statusWidget->ui->streamIcon->setPixmap(
|
|
streamingInactivePixmap);
|
|
statusWidget->ui->statusIcon->setPixmap(inactivePixmap);
|
|
} else {
|
|
if (disconnected)
|
|
statusWidget->ui->statusIcon->setPixmap(
|
|
disconnectedPixmap);
|
|
}
|
|
|
|
bool recording = obs_frontend_recording_active();
|
|
|
|
if (!recording)
|
|
statusWidget->ui->recordIcon->setPixmap(
|
|
recordingInactivePixmap);
|
|
}
|
|
|
|
void OBSBasicStatusBar::showMessage(const QString &message, int timeout)
|
|
{
|
|
messageTimer->stop();
|
|
|
|
statusWidget->ui->message->setText(message);
|
|
|
|
if (timeout)
|
|
messageTimer->start(timeout);
|
|
}
|
|
|
|
void OBSBasicStatusBar::clearMessage()
|
|
{
|
|
statusWidget->ui->message->setText("");
|
|
}
|