Add network tab (#149)

The network tab allows you to open a web-socket or connect to web-socket to synchronize the active scene between two or more instances of OBS.
The functionality is mostly based on https://github.com/Palakis/obs-websocket.

An OBS instance running a server will send its currently active scene to all connected clients on scene change.
By default all scene switches will trigger a message to be sent to all clients, but you also have the option to limit sending these messages only when an automated scene change is triggered by the advanced scene switcher.
This commit is contained in:
WarmUpTill
2021-03-24 20:51:22 +01:00
committed by GitHub
parent b0ef1fee71
commit dfccc4b16d
14 changed files with 1044 additions and 7 deletions

View File

@@ -60,6 +60,7 @@ public:
void setupSceneGroupTab();
void setupTriggerTab();
void setupVideoTab();
void setupNetworkTab();
void setTabOrder();
static bool DisplayMessage(QString msg, bool question = false);
@@ -212,6 +213,18 @@ public slots:
void on_videoDown_clicked();
void on_getScreenshot_clicked();
void on_serverSettings_toggled(bool on);
void on_serverPort_valueChanged(int value);
void on_lockToIPv4_stateChanged(int state);
void on_serverRestart_clicked();
void updateServerStatus();
void on_clientSettings_toggled(bool on);
void on_clientHostname_textChanged(const QString &text);
void on_clientPort_valueChanged(int value);
void on_restrictSend_stateChanged(int state);
void on_clientReconnect_clicked();
void updateClientStatus();
void on_sceneGroupAdd_clicked();
void on_sceneGroupRemove_clicked();
void on_sceneGroupUp_clicked();

View File

@@ -0,0 +1,111 @@
/*
Most of this code is based on https://github.com/Palakis/obs-websocket
*/
#pragma once
#include <set>
#include <QtCore/QObject>
#include <QtCore/QMutex>
#include <QtCore/QSharedPointer>
#include <QtCore/QVariantHash>
#include <QtCore/QThreadPool>
#include <mutex>
#include <condition_variable>
#include <websocketpp/config/asio_no_tls_client.hpp>
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
#include <websocketpp/client.hpp>
using websocketpp::connection_hdl;
typedef websocketpp::server<websocketpp::config::asio> server;
typedef websocketpp::client<websocketpp::config::asio_client> client;
class NetworkConfig {
public:
NetworkConfig();
void Load(obs_data_t *obj);
void Save(obs_data_t *obj);
void SetDefaults(obs_data_t *obj);
std::string GetClientUri();
// Server
bool ServerEnabled;
uint64_t ServerPort;
bool LockToIPv4;
// Client
bool ClientEnabled;
std::string Address;
uint64_t ClientPort;
bool SendAll;
};
class WSServer : public QObject {
Q_OBJECT
public:
explicit WSServer();
virtual ~WSServer();
void start(quint16 port, bool lockToIPv4);
void stop();
void sendMessage(OBSWeakSource scene, OBSWeakSource transition);
QThreadPool *threadPool() { return &_threadPool; }
private:
void onOpen(connection_hdl hdl);
void onMessage(connection_hdl hdl, server::message_ptr message);
void onClose(connection_hdl hdl);
QString getRemoteEndpoint(connection_hdl hdl);
server _server;
quint16 _serverPort;
bool _lockToIPv4;
std::set<connection_hdl, std::owner_less<connection_hdl>> _connections;
QMutex _clMutex;
QThreadPool _threadPool;
};
enum class ServerStatus {
NOT_RUNNING,
STARTING,
RUNNING,
};
class WSClient : public QObject {
Q_OBJECT
public:
explicit WSClient();
virtual ~WSClient();
void connect(std::string uri);
void disconnect();
std::string getFail() { return _failMsg; }
private:
void onOpen(connection_hdl hdl);
void onFail(connection_hdl hdl);
void onMessage(connection_hdl hdl, client::message_ptr message);
void onClose(connection_hdl hdl);
void connectThread();
client _client;
std::string _uri;
connection_hdl _connection;
std::thread _thread;
bool _retry = false;
std::atomic_bool _connected = {false};
std::mutex _waitMtx;
std::condition_variable _cv;
std::string _failMsg;
};
enum class ClientStatus {
DISCONNECTED,
CONNECTING,
CONNECTED,
FAIL,
};

View File

@@ -22,6 +22,7 @@
#include "switch-window.hpp"
#include "switch-sequence.hpp"
#include "switch-video.hpp"
#include "switch-network.hpp"
constexpr auto default_interval = 300;
constexpr auto previous_scene_name = "Previous Scene";
@@ -115,6 +116,12 @@ struct SwitcherData {
std::deque<AudioSwitch> audioSwitches;
AudioSwitchFallback audioFallback;
WSServer server;
ServerStatus serverStatus = ServerStatus::NOT_RUNNING;
WSClient client;
ClientStatus clientStatus = ClientStatus::DISCONNECTED;
NetworkConfig networkConfig;
std::deque<VideoSwitch> videoSwitches;
std::deque<SceneGroup> sceneGroups;
@@ -226,6 +233,7 @@ struct SwitcherData {
void saveSceneGroups(obs_data_t *obj);
void saveSceneTriggers(obs_data_t *obj);
void saveVideoSwitches(obs_data_t *obj);
void saveNetworkSwitches(obs_data_t *obj);
void saveGeneralSettings(obs_data_t *obj);
void saveHotkeys(obs_data_t *obj);
void saveVersion(obs_data_t *obj, std::string currentVersion);
@@ -247,6 +255,7 @@ struct SwitcherData {
void loadSceneGroups(obs_data_t *obj);
void loadSceneTriggers(obs_data_t *obj);
void loadVideoSwitches(obs_data_t *obj);
void loadNetworkSettings(obs_data_t *obj);
void loadGeneralSettings(obs_data_t *obj);
void loadHotkeys(obs_data_t *obj);