General: code style refactor

This commit is contained in:
Stéphane L 2017-08-05 03:14:07 +02:00
parent add39cfc5f
commit 586f9076f0
10 changed files with 408 additions and 555 deletions

View File

@ -22,8 +22,6 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#include <util/config-file.h> #include <util/config-file.h>
#include <string> #include <string>
#include "Config.h"
#define SECTION_NAME "WebsocketAPI" #define SECTION_NAME "WebsocketAPI"
#define PARAM_ENABLE "ServerEnabled" #define PARAM_ENABLE "ServerEnabled"
#define PARAM_PORT "ServerPort" #define PARAM_PORT "ServerPort"
@ -32,25 +30,21 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#define PARAM_SECRET "AuthSecret" #define PARAM_SECRET "AuthSecret"
#define PARAM_SALT "AuthSalt" #define PARAM_SALT "AuthSalt"
Config *Config::_instance = new Config(); #include "Config.h"
Config::Config() Config* Config::_instance = new Config();
{
// Default settings
ServerEnabled = true;
ServerPort = 4444;
DebugEnabled = false;
AuthRequired = false;
Secret = "";
Salt = "";
SettingsLoaded = false;
Config::Config() :
ServerEnabled(true),
ServerPort(4444),
DebugEnabled(false),
AuthRequired(false),
Secret(""),
Salt(""),
SettingsLoaded(false) {
// OBS Config defaults // OBS Config defaults
config_t* obs_config = obs_frontend_get_global_config(); config_t* obs_config = obs_frontend_get_global_config();
if (obs_config) if (obs_config) {
{
config_set_default_bool(obs_config, config_set_default_bool(obs_config,
SECTION_NAME, PARAM_ENABLE, ServerEnabled); SECTION_NAME, PARAM_ENABLE, ServerEnabled);
config_set_default_uint(obs_config, config_set_default_uint(obs_config,
@ -70,19 +64,16 @@ Config::Config()
mbedtls_entropy_init(&entropy); mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_init(&rng); mbedtls_ctr_drbg_init(&rng);
mbedtls_ctr_drbg_seed(&rng, mbedtls_entropy_func, &entropy, nullptr, 0); mbedtls_ctr_drbg_seed(&rng, mbedtls_entropy_func, &entropy, nullptr, 0);
//mbedtls_ctr_drbg_set_prediction_resistance(&rng, MBEDTLS_CTR_DRBG_PR_ON);
SessionChallenge = GenerateSalt(); SessionChallenge = GenerateSalt();
} }
Config::~Config() Config::~Config() {
{
mbedtls_ctr_drbg_free(&rng); mbedtls_ctr_drbg_free(&rng);
mbedtls_entropy_free(&entropy); mbedtls_entropy_free(&entropy);
} }
void Config::Load() void Config::Load() {
{
config_t* obs_config = obs_frontend_get_global_config(); config_t* obs_config = obs_frontend_get_global_config();
ServerEnabled = config_get_bool(obs_config, SECTION_NAME, PARAM_ENABLE); ServerEnabled = config_get_bool(obs_config, SECTION_NAME, PARAM_ENABLE);
@ -95,8 +86,7 @@ void Config::Load()
Salt = config_get_string(obs_config, SECTION_NAME, PARAM_SALT); Salt = config_get_string(obs_config, SECTION_NAME, PARAM_SALT);
} }
void Config::Save() void Config::Save() {
{
config_t* obs_config = obs_frontend_get_global_config(); config_t* obs_config = obs_frontend_get_global_config();
config_set_bool(obs_config, SECTION_NAME, PARAM_ENABLE, ServerEnabled); config_set_bool(obs_config, SECTION_NAME, PARAM_ENABLE, ServerEnabled);
@ -111,8 +101,7 @@ void Config::Save()
config_save(obs_config); config_save(obs_config);
} }
const char* Config::GenerateSalt() const char* Config::GenerateSalt() {
{
// Generate 32 random chars // Generate 32 random chars
unsigned char* random_chars = (unsigned char*)bzalloc(32); unsigned char* random_chars = (unsigned char*)bzalloc(32);
mbedtls_ctr_drbg_random(&rng, random_chars, 32); mbedtls_ctr_drbg_random(&rng, random_chars, 32);
@ -128,8 +117,7 @@ const char* Config::GenerateSalt()
return salt; return salt;
} }
const char* Config::GenerateSecret(const char *password, const char *salt) const char* Config::GenerateSecret(const char* password, const char* salt) {
{
// Concatenate the password and the salt // Concatenate the password and the salt
std::string passAndSalt = ""; std::string passAndSalt = "";
passAndSalt += password; passAndSalt += password;
@ -152,17 +140,15 @@ const char* Config::GenerateSecret(const char *password, const char *salt)
return challenge; return challenge;
} }
void Config::SetPassword(const char *password) void Config::SetPassword(const char* password) {
{ const char* new_salt = GenerateSalt();
const char *new_salt = GenerateSalt(); const char* new_challenge = GenerateSecret(password, new_salt);
const char *new_challenge = GenerateSecret(password, new_salt);
this->Salt = new_salt; this->Salt = new_salt;
this->Secret = new_challenge; this->Secret = new_challenge;
} }
bool Config::CheckAuth(const char *response) bool Config::CheckAuth(const char* response) {
{
// Concatenate auth secret with the challenge sent to the user // Concatenate auth secret with the challenge sent to the user
std::string challengeAndResponse = ""; std::string challengeAndResponse = "";
challengeAndResponse += this->Secret; challengeAndResponse += this->Secret;
@ -193,7 +179,6 @@ bool Config::CheckAuth(const char *response)
return authSuccess; return authSuccess;
} }
Config* Config::Current() Config* Config::Current() {
{
return _instance; return _instance;
} }

View File

@ -22,37 +22,36 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#include <mbedtls/entropy.h> #include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h> #include <mbedtls/ctr_drbg.h>
class Config class Config {
{ public:
public: Config();
Config(); ~Config();
~Config(); void Load();
void Load(); void Save();
void Save();
void SetPassword(const char *password); void SetPassword(const char* password);
bool CheckAuth(const char *userChallenge); bool CheckAuth(const char* userChallenge);
const char* GenerateSalt(); const char* GenerateSalt();
static const char* GenerateSecret( static const char* GenerateSecret(
const char *password, const char *salt); const char* password, const char* salt);
bool ServerEnabled; bool ServerEnabled;
uint64_t ServerPort; uint64_t ServerPort;
bool DebugEnabled; bool DebugEnabled;
bool AuthRequired; bool AuthRequired;
const char *Secret; const char* Secret;
const char *Salt; const char* Salt;
const char *SessionChallenge; const char* SessionChallenge;
bool SettingsLoaded; bool SettingsLoaded;
static Config* Current(); static Config* Current();
private: private:
static Config *_instance; static Config* _instance;
mbedtls_entropy_context entropy; mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context rng; mbedtls_ctr_drbg_context rng;
}; };
#endif // CONFIG_H #endif // CONFIG_H

193
Utils.cpp
View File

@ -16,26 +16,25 @@ You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/> with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#include <obs-frontend-api.h>
#include <obs.hpp>
#include <QMainWindow> #include <QMainWindow>
#include <QDir> #include <QDir>
#include <QUrl> #include <QUrl>
#include "Utils.h" #include <obs-frontend-api.h>
#include <obs.hpp>
#include "obs-websocket.h" #include "obs-websocket.h"
#include "Utils.h"
Q_DECLARE_METATYPE(OBSScene); Q_DECLARE_METATYPE(OBSScene);
obs_data_array_t* string_list_to_array(char** strings, char* key) obs_data_array_t* string_list_to_array(char** strings, char* key) {
{
if (!strings) if (!strings)
return obs_data_array_create(); return obs_data_array_create();
obs_data_array_t* list = obs_data_array_create(); obs_data_array_t* list = obs_data_array_create();
char* value = ""; char* value = "";
for (int i = 0; value != nullptr; i++) for (int i = 0; value != nullptr; i++) {
{
value = strings[i]; value = strings[i];
obs_data_t* item = obs_data_create(); obs_data_t* item = obs_data_create();
@ -50,17 +49,18 @@ obs_data_array_t* string_list_to_array(char** strings, char* key)
return list; return list;
} }
obs_data_array_t* Utils::GetSceneItems(obs_source_t* source) obs_data_array_t* Utils::GetSceneItems(obs_source_t* source) {
{
obs_data_array_t* items = obs_data_array_create(); obs_data_array_t* items = obs_data_array_create();
obs_scene_t* scene = obs_scene_from_source(source); obs_scene_t* scene = obs_scene_from_source(source);
if (!scene) if (!scene)
return nullptr; return nullptr;
obs_scene_enum_items(scene, [](obs_scene_t* scene, obs_sceneitem_t* currentItem, void* param) obs_scene_enum_items(scene, [](
{ obs_scene_t* scene,
obs_data_array_t* data = static_cast<obs_data_array_t* >(param); obs_sceneitem_t* currentItem,
void* param) {
obs_data_array_t* data = static_cast<obs_data_array_t*>(param);
obs_data_t* item_data = GetSceneItemData(currentItem); obs_data_t* item_data = GetSceneItemData(currentItem);
obs_data_array_insert(data, 0, item_data); obs_data_array_insert(data, 0, item_data);
@ -72,8 +72,7 @@ obs_data_array_t* Utils::GetSceneItems(obs_source_t* source)
return items; return items;
} }
obs_data_t* Utils::GetSceneItemData(obs_sceneitem_t* item) obs_data_t* Utils::GetSceneItemData(obs_sceneitem_t* item) {
{
if (!item) if (!item)
return nullptr; return nullptr;
@ -105,8 +104,7 @@ obs_data_t* Utils::GetSceneItemData(obs_sceneitem_t* item)
return data; return data;
} }
obs_sceneitem_t* Utils::GetSceneItemFromName(obs_source_t* source, const char* name) obs_sceneitem_t* Utils::GetSceneItemFromName(obs_source_t* source, const char* name) {
{
struct current_search { struct current_search {
const char* query; const char* query;
obs_sceneitem_t* result; obs_sceneitem_t* result;
@ -120,15 +118,16 @@ obs_sceneitem_t* Utils::GetSceneItemFromName(obs_source_t* source, const char* n
if (scene == nullptr) if (scene == nullptr)
return nullptr; return nullptr;
obs_scene_enum_items(scene, [](obs_scene_t* scene, obs_sceneitem_t* currentItem, void* param) obs_scene_enum_items(scene, [](
{ obs_scene_t* scene,
current_search* search = static_cast<current_search* >(param); obs_sceneitem_t* currentItem,
void* param) {
current_search* search = static_cast<current_search*>(param);
const char* currentItemName = const char* currentItemName =
obs_source_get_name(obs_sceneitem_get_source(currentItem)); obs_source_get_name(obs_sceneitem_get_source(currentItem));
if (strcmp(currentItemName, search->query) == 0) if (strcmp(currentItemName, search->query) == 0) {
{
search->result = currentItem; search->result = currentItem;
obs_sceneitem_addref(search->result); obs_sceneitem_addref(search->result);
return false; return false;
@ -140,15 +139,13 @@ obs_sceneitem_t* Utils::GetSceneItemFromName(obs_source_t* source, const char* n
return search.result; return search.result;
} }
obs_source_t* Utils::GetTransitionFromName(const char* search_name) obs_source_t* Utils::GetTransitionFromName(const char* search_name) {
{
obs_source_t* found_transition = NULL; obs_source_t* found_transition = NULL;
obs_frontend_source_list transition_list = {}; obs_frontend_source_list transition_list = {};
obs_frontend_get_transitions(&transition_list); obs_frontend_get_transitions(&transition_list);
for (size_t i = 0; i < transition_list.sources.num; i++) for (size_t i = 0; i < transition_list.sources.num; i++) {
{
obs_source_t* transition = transition_list.sources.array[i]; obs_source_t* transition = transition_list.sources.array[i];
const char* transition_name = obs_source_get_name(transition); const char* transition_name = obs_source_get_name(transition);
@ -165,8 +162,7 @@ obs_source_t* Utils::GetTransitionFromName(const char* search_name)
return found_transition; return found_transition;
} }
obs_source_t* Utils::GetSceneFromNameOrCurrent(const char* scene_name) obs_source_t* Utils::GetSceneFromNameOrCurrent(const char* scene_name) {
{
obs_source_t* scene = nullptr; obs_source_t* scene = nullptr;
if (!scene_name || !strlen(scene_name)) if (!scene_name || !strlen(scene_name))
@ -177,14 +173,12 @@ obs_source_t* Utils::GetSceneFromNameOrCurrent(const char* scene_name)
return scene; return scene;
} }
obs_data_array_t* Utils::GetScenes() obs_data_array_t* Utils::GetScenes() {
{
obs_frontend_source_list sceneList = {}; obs_frontend_source_list sceneList = {};
obs_frontend_get_scenes(&sceneList); obs_frontend_get_scenes(&sceneList);
obs_data_array_t* scenes = obs_data_array_create(); obs_data_array_t* scenes = obs_data_array_create();
for (size_t i = 0; i < sceneList.sources.num; i++) for (size_t i = 0; i < sceneList.sources.num; i++) {
{
obs_source_t* scene = sceneList.sources.array[i]; obs_source_t* scene = sceneList.sources.array[i];
obs_data_t* scene_data = GetSceneData(scene); obs_data_t* scene_data = GetSceneData(scene);
@ -198,8 +192,7 @@ obs_data_array_t* Utils::GetScenes()
return scenes; return scenes;
} }
obs_data_t* Utils::GetSceneData(obs_source* source) obs_data_t* Utils::GetSceneData(obs_source* source) {
{
obs_data_array_t* scene_items = GetSceneItems(source); obs_data_array_t* scene_items = GetSceneItems(source);
obs_data_t* sceneData = obs_data_create(); obs_data_t* sceneData = obs_data_create();
@ -210,8 +203,7 @@ obs_data_t* Utils::GetSceneData(obs_source* source)
return sceneData; return sceneData;
} }
obs_data_array_t* Utils::GetSceneCollections() obs_data_array_t* Utils::GetSceneCollections() {
{
char** scene_collections = obs_frontend_get_scene_collections(); char** scene_collections = obs_frontend_get_scene_collections();
obs_data_array_t* list = string_list_to_array(scene_collections, "sc-name"); obs_data_array_t* list = string_list_to_array(scene_collections, "sc-name");
@ -219,8 +211,7 @@ obs_data_array_t* Utils::GetSceneCollections()
return list; return list;
} }
obs_data_array_t* Utils::GetProfiles() obs_data_array_t* Utils::GetProfiles() {
{
char** profiles = obs_frontend_get_profiles(); char** profiles = obs_frontend_get_profiles();
obs_data_array_t* list = string_list_to_array(profiles, "profile-name"); obs_data_array_t* list = string_list_to_array(profiles, "profile-name");
@ -228,14 +219,12 @@ obs_data_array_t* Utils::GetProfiles()
return list; return list;
} }
QSpinBox* Utils::GetTransitionDurationControl() QSpinBox* Utils::GetTransitionDurationControl() {
{
QMainWindow* window = (QMainWindow*)obs_frontend_get_main_window(); QMainWindow* window = (QMainWindow*)obs_frontend_get_main_window();
return window->findChild<QSpinBox*>("transitionDuration"); return window->findChild<QSpinBox*>("transitionDuration");
} }
int Utils::GetTransitionDuration() int Utils::GetTransitionDuration() {
{
QSpinBox* control = GetTransitionDurationControl(); QSpinBox* control = GetTransitionDurationControl();
if (control) if (control)
return control->value(); return control->value();
@ -243,45 +232,35 @@ int Utils::GetTransitionDuration()
return -1; return -1;
} }
void Utils::SetTransitionDuration(int ms) void Utils::SetTransitionDuration(int ms) {
{
QSpinBox* control = GetTransitionDurationControl(); QSpinBox* control = GetTransitionDurationControl();
if (control && ms >= 0) if (control && ms >= 0)
control->setValue(ms); control->setValue(ms);
} }
bool Utils::SetTransitionByName(const char* transition_name) bool Utils::SetTransitionByName(const char* transition_name) {
{
obs_source_t* transition = GetTransitionFromName(transition_name); obs_source_t* transition = GetTransitionFromName(transition_name);
if (transition) if (transition) {
{
obs_frontend_set_current_transition(transition); obs_frontend_set_current_transition(transition);
obs_source_release(transition); obs_source_release(transition);
return true; return true;
} } else {
else
{
return false; return false;
} }
} }
QPushButton* Utils::GetPreviewModeButtonControl() QPushButton* Utils::GetPreviewModeButtonControl() {
{
QMainWindow* main = (QMainWindow*)obs_frontend_get_main_window(); QMainWindow* main = (QMainWindow*)obs_frontend_get_main_window();
return main->findChild<QPushButton*>("modeSwitch"); return main->findChild<QPushButton*>("modeSwitch");
} }
QListWidget* Utils::GetSceneListControl() QListWidget* Utils::GetSceneListControl() {
{
QMainWindow* main = (QMainWindow*)obs_frontend_get_main_window(); QMainWindow* main = (QMainWindow*)obs_frontend_get_main_window();
return main->findChild<QListWidget*>("scenes"); return main->findChild<QListWidget*>("scenes");
} }
obs_scene_t* Utils::SceneListItemToScene(QListWidgetItem* item) obs_scene_t* Utils::SceneListItemToScene(QListWidgetItem* item) {
{
if (!item) if (!item)
return nullptr; return nullptr;
@ -289,14 +268,12 @@ obs_scene_t* Utils::SceneListItemToScene(QListWidgetItem* item)
return item_data.value<OBSScene>(); return item_data.value<OBSScene>();
} }
QLayout* Utils::GetPreviewLayout() QLayout* Utils::GetPreviewLayout() {
{
QMainWindow* main = (QMainWindow*)obs_frontend_get_main_window(); QMainWindow* main = (QMainWindow*)obs_frontend_get_main_window();
return main->findChild<QLayout*>("previewLayout"); return main->findChild<QLayout*>("previewLayout");
} }
bool Utils::IsPreviewModeActive() bool Utils::IsPreviewModeActive() {
{
QMainWindow* main = (QMainWindow*)obs_frontend_get_main_window(); QMainWindow* main = (QMainWindow*)obs_frontend_get_main_window();
// Clue 1 : "Studio Mode" button is toggled on // Clue 1 : "Studio Mode" button is toggled on
@ -309,29 +286,23 @@ bool Utils::IsPreviewModeActive()
return buttonToggledOn || (previewChildCount >= 2); return buttonToggledOn || (previewChildCount >= 2);
} }
void Utils::EnablePreviewMode() void Utils::EnablePreviewMode() {
{
if (!IsPreviewModeActive()) if (!IsPreviewModeActive())
GetPreviewModeButtonControl()->click(); GetPreviewModeButtonControl()->click();
} }
void Utils::DisablePreviewMode() void Utils::DisablePreviewMode() {
{
if (IsPreviewModeActive()) if (IsPreviewModeActive())
GetPreviewModeButtonControl()->click(); GetPreviewModeButtonControl()->click();
} }
void Utils::TogglePreviewMode() void Utils::TogglePreviewMode() {
{
GetPreviewModeButtonControl()->click(); GetPreviewModeButtonControl()->click();
} }
obs_scene_t* Utils::GetPreviewScene() obs_scene_t* Utils::GetPreviewScene() {
{ if (IsPreviewModeActive()) {
if (IsPreviewModeActive())
{
QListWidget* sceneList = GetSceneListControl(); QListWidget* sceneList = GetSceneListControl();
QList<QListWidgetItem*> selected = sceneList->selectedItems(); QList<QListWidgetItem*> selected = sceneList->selectedItems();
// Qt::UserRole == QtUserRole::OBSRef // Qt::UserRole == QtUserRole::OBSRef
@ -344,21 +315,16 @@ obs_scene_t* Utils::GetPreviewScene()
return nullptr; return nullptr;
} }
bool Utils::SetPreviewScene(const char* name) bool Utils::SetPreviewScene(const char* name) {
{ if (IsPreviewModeActive()) {
if (IsPreviewModeActive())
{
QListWidget* sceneList = GetSceneListControl(); QListWidget* sceneList = GetSceneListControl();
QList<QListWidgetItem*> matchingItems = QList<QListWidgetItem*> matchingItems =
sceneList->findItems(name, Qt::MatchExactly); sceneList->findItems(name, Qt::MatchExactly);
if (matchingItems.count() > 0) if (matchingItems.count() > 0) {
{
sceneList->setCurrentItem(matchingItems.first()); sceneList->setCurrentItem(matchingItems.first());
return true; return true;
} } else {
else
{
return false; return false;
} }
} }
@ -366,8 +332,7 @@ bool Utils::SetPreviewScene(const char* name)
return false; return false;
} }
void Utils::TransitionToProgram() void Utils::TransitionToProgram() {
{
if (!IsPreviewModeActive()) if (!IsPreviewModeActive())
return; return;
@ -405,14 +370,13 @@ const char* Utils::OBSVersionString() {
return result; return result;
} }
QSystemTrayIcon* Utils::GetTrayIcon() QSystemTrayIcon* Utils::GetTrayIcon() {
{
QMainWindow* main = (QMainWindow*)obs_frontend_get_main_window(); QMainWindow* main = (QMainWindow*)obs_frontend_get_main_window();
return main->findChildren<QSystemTrayIcon*>().first(); return main->findChildren<QSystemTrayIcon*>().first();
} }
void Utils::SysTrayNotify(QString &text, QSystemTrayIcon::MessageIcon icon, QString title) void Utils::SysTrayNotify(QString &text,
{ QSystemTrayIcon::MessageIcon icon, QString title) {
if (!QSystemTrayIcon::supportsMessages()) if (!QSystemTrayIcon::supportsMessages())
return; return;
@ -421,45 +385,36 @@ void Utils::SysTrayNotify(QString &text, QSystemTrayIcon::MessageIcon icon, QStr
trayIcon->showMessage(title, text, icon); trayIcon->showMessage(title, text, icon);
} }
QString Utils::FormatIPAddress(QHostAddress &addr) QString Utils::FormatIPAddress(QHostAddress &addr) {
{
if (addr.protocol() == QAbstractSocket::IPv4Protocol) if (addr.protocol() == QAbstractSocket::IPv4Protocol)
QString v4addr = addr.toString().replace("::fff:", ""); QString v4addr = addr.toString().replace("::fff:", "");
return addr.toString(); return addr.toString();
} }
const char* Utils::GetRecordingFolder() const char* Utils::GetRecordingFolder() {
{
config_t* profile = obs_frontend_get_profile_config(); config_t* profile = obs_frontend_get_profile_config();
const char* outputMode = config_get_string(profile, "Output", "Mode"); const char* outputMode = config_get_string(profile, "Output", "Mode");
if (strcmp(outputMode, "Advanced") == 0) if (strcmp(outputMode, "Advanced") == 0) {
{
// Advanced mode // Advanced mode
return config_get_string(profile, "AdvOut", "RecFilePath"); return config_get_string(profile, "AdvOut", "RecFilePath");
} } else {
else
{
// Simple mode // Simple mode
return config_get_string(profile, "SimpleOutput", "FilePath"); return config_get_string(profile, "SimpleOutput", "FilePath");
} }
} }
bool Utils::SetRecordingFolder(const char* path) bool Utils::SetRecordingFolder(const char* path) {
{
if (!QDir(path).exists()) if (!QDir(path).exists())
return false; return false;
config_t* profile = obs_frontend_get_profile_config(); config_t* profile = obs_frontend_get_profile_config();
const char* outputMode = config_get_string(profile, "Output", "Mode"); const char* outputMode = config_get_string(profile, "Output", "Mode");
if (strcmp(outputMode, "Advanced") == 0) if (strcmp(outputMode, "Advanced") == 0) {
{
config_set_string(profile, "AdvOut", "RecFilePath", path); config_set_string(profile, "AdvOut", "RecFilePath", path);
} } else {
else
{
config_set_string(profile, "SimpleOutput", "FilePath", path); config_set_string(profile, "SimpleOutput", "FilePath", path);
} }
@ -467,18 +422,14 @@ bool Utils::SetRecordingFolder(const char* path)
return true; return true;
} }
QString* Utils::ParseDataToQueryString(obs_data_t * data) QString* Utils::ParseDataToQueryString(obs_data_t* data) {
{
QString* query = nullptr; QString* query = nullptr;
if (data) if (data) {
{ obs_data_item_t* item = obs_data_first(data);
obs_data_item_t* item = obs_data_first(data); if (item) {
if (item)
{
query = new QString(); query = new QString();
bool isFirst = true; bool isFirst = true;
do do {
{
if (!obs_data_item_has_user_value(item)) if (!obs_data_item_has_user_value(item))
continue; continue;
@ -489,8 +440,8 @@ QString* Utils::ParseDataToQueryString(obs_data_t * data)
const char* attrName = obs_data_item_get_name(item); const char* attrName = obs_data_item_get_name(item);
query->append(attrName).append("="); query->append(attrName).append("=");
switch (obs_data_item_gettype(item))
{ switch (obs_data_item_gettype(item)) {
case OBS_DATA_BOOLEAN: case OBS_DATA_BOOLEAN:
query->append(obs_data_item_get_bool(item)?"true":"false"); query->append(obs_data_item_get_bool(item)?"true":"false");
break; break;
@ -498,25 +449,27 @@ QString* Utils::ParseDataToQueryString(obs_data_t * data)
switch (obs_data_item_numtype(item)) switch (obs_data_item_numtype(item))
{ {
case OBS_DATA_NUM_DOUBLE: case OBS_DATA_NUM_DOUBLE:
query->append(QString::number(obs_data_item_get_double(item))); query->append(
QString::number(obs_data_item_get_double(item)));
break; break;
case OBS_DATA_NUM_INT: case OBS_DATA_NUM_INT:
query->append(QString::number(obs_data_item_get_int(item))); query->append(
QString::number(obs_data_item_get_int(item)));
break; break;
case OBS_DATA_NUM_INVALID: case OBS_DATA_NUM_INVALID:
break; break;
} }
break; break;
case OBS_DATA_STRING: case OBS_DATA_STRING:
query->append(QUrl::toPercentEncoding(QString(obs_data_item_get_string(item)))); query->append(QUrl::toPercentEncoding(
QString(obs_data_item_get_string(item))));
break; break;
default: default:
//other types are not supported //other types are not supported
break; break;
} }
} while ( obs_data_item_next( &item ) ); } while (obs_data_item_next(&item));
} }
} }
return query; return query;
} }

78
Utils.h
View File

@ -25,59 +25,59 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#include <QListWidget> #include <QListWidget>
#include <QSystemTrayIcon> #include <QSystemTrayIcon>
#include <QHostAddress> #include <QHostAddress>
#include <stdio.h> #include <stdio.h>
#include <obs-module.h> #include <obs-module.h>
#include <util/config-file.h> #include <util/config-file.h>
class Utils class Utils {
{ public:
public: static obs_data_array_t* GetSceneItems(obs_source_t* source);
static obs_data_array_t* GetSceneItems(obs_source_t* source); static obs_data_t* GetSceneItemData(obs_scene_item* item);
static obs_data_t* GetSceneItemData(obs_scene_item* item); static obs_sceneitem_t* GetSceneItemFromName(
static obs_sceneitem_t* GetSceneItemFromName( obs_source_t* source, const char* name);
obs_source_t* source, const char* name); static obs_source_t* GetTransitionFromName(const char* search_name);
static obs_source_t* GetTransitionFromName(const char* search_name); static obs_source_t* GetSceneFromNameOrCurrent(const char* scene_name);
static obs_source_t* GetSceneFromNameOrCurrent(const char* scene_name);
static obs_data_array_t* GetScenes(); static obs_data_array_t* GetScenes();
static obs_data_t* GetSceneData(obs_source* source); static obs_data_t* GetSceneData(obs_source* source);
static obs_data_array_t* GetSceneCollections(); static obs_data_array_t* GetSceneCollections();
static obs_data_array_t* GetProfiles(); static obs_data_array_t* GetProfiles();
static QSpinBox* GetTransitionDurationControl();
static int GetTransitionDuration();
static void SetTransitionDuration(int ms);
static QSpinBox* GetTransitionDurationControl(); static bool SetTransitionByName(const char* transition_name);
static int GetTransitionDuration();
static void SetTransitionDuration(int ms);
static bool SetTransitionByName(const char* transition_name); static QPushButton* GetPreviewModeButtonControl();
static QLayout* GetPreviewLayout();
static QListWidget* GetSceneListControl();
static obs_scene_t* SceneListItemToScene(QListWidgetItem* item);
static QPushButton* GetPreviewModeButtonControl(); static bool IsPreviewModeActive();
static QLayout* GetPreviewLayout(); static void EnablePreviewMode();
static QListWidget* GetSceneListControl(); static void DisablePreviewMode();
static obs_scene_t* SceneListItemToScene(QListWidgetItem* item); static void TogglePreviewMode();
static bool IsPreviewModeActive(); static obs_scene_t* GetPreviewScene();
static void EnablePreviewMode(); static bool SetPreviewScene(const char* name);
static void DisablePreviewMode(); static void TransitionToProgram();
static void TogglePreviewMode();
static obs_scene_t* GetPreviewScene(); static const char* OBSVersionString();
static bool SetPreviewScene(const char* name);
static void TransitionToProgram();
static const char* OBSVersionString(); static QSystemTrayIcon* GetTrayIcon();
static void SysTrayNotify(
QString &text,
QSystemTrayIcon::MessageIcon n,
QString title = QString("obs-websocket"));
static QSystemTrayIcon* GetTrayIcon(); static QString FormatIPAddress(QHostAddress &addr);
static void SysTrayNotify( static const char* GetRecordingFolder();
QString &text, static bool SetRecordingFolder(const char* path);
QSystemTrayIcon::MessageIcon n,
QString title = QString("obs-websocket"));
static QString FormatIPAddress(QHostAddress &addr);
static const char* GetRecordingFolder();
static bool SetRecordingFolder(const char* path);
static QString* ParseDataToQueryString(obs_data_t * data); static QString* ParseDataToQueryString(obs_data_t * data);
}; };
#endif // UTILS_H #endif // UTILS_H

View File

@ -18,29 +18,28 @@ with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#include <util/platform.h> #include <util/platform.h>
#include <QTimer> #include <QTimer>
#include <QPushButton> #include <QPushButton>
#include "Config.h" #include "Config.h"
#include "Utils.h" #include "Utils.h"
#include "WSEvents.h" #include "WSEvents.h"
#include "obs-websocket.h" #include "obs-websocket.h"
bool transition_is_cut(obs_source_t* transition) bool transition_is_cut(obs_source_t* transition) {
{
if (!transition) if (!transition)
return false; return false;
if (obs_source_get_type(transition) == OBS_SOURCE_TYPE_TRANSITION if (obs_source_get_type(transition) == OBS_SOURCE_TYPE_TRANSITION
&& strcmp(obs_source_get_id(transition), "cut_transition") == 0) && strcmp(obs_source_get_id(transition), "cut_transition") == 0) {
{
return true; return true;
} }
return false; return false;
} }
const char* ns_to_timestamp(uint64_t ns) const char* ns_to_timestamp(uint64_t ns) {
{
uint64_t ms = ns / (1000 * 1000); uint64_t ms = ns / (1000 * 1000);
uint64_t secs = ms / 1000; uint64_t secs = ms / 1000;
uint64_t minutes = secs / 60; uint64_t minutes = secs / 60;
@ -59,8 +58,7 @@ const char* ns_to_timestamp(uint64_t ns)
WSEvents* WSEvents::Instance = nullptr; WSEvents* WSEvents::Instance = nullptr;
WSEvents::WSEvents(WSServer* srv) WSEvents::WSEvents(WSServer* srv) {
{
_srv = srv; _srv = srv;
obs_frontend_add_event_callback(WSEvents::FrontendEventHandler, this); obs_frontend_add_event_callback(WSEvents::FrontendEventHandler, this);
@ -92,13 +90,11 @@ WSEvents::WSEvents(WSServer* srv)
_rec_starttime = 0; _rec_starttime = 0;
} }
WSEvents::~WSEvents() WSEvents::~WSEvents() {
{
obs_frontend_remove_event_callback(WSEvents::FrontendEventHandler, this); obs_frontend_remove_event_callback(WSEvents::FrontendEventHandler, this);
} }
void WSEvents::deferredInitOperations() void WSEvents::deferredInitOperations() {
{
obs_source_t* transition = obs_frontend_get_current_transition(); obs_source_t* transition = obs_frontend_get_current_transition();
connectTransitionSignals(transition); connectTransitionSignals(transition);
obs_source_release(transition); obs_source_release(transition);
@ -108,8 +104,7 @@ void WSEvents::deferredInitOperations()
obs_source_release(scene); obs_source_release(scene);
} }
void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void* private_data) void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void* private_data) {
{
WSEvents* owner = static_cast<WSEvents*>(private_data); WSEvents* owner = static_cast<WSEvents*>(private_data);
if (!owner->_srv) if (!owner->_srv)
@ -117,95 +112,76 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void* private
// TODO : implement SourceOrderChanged and RepopulateSources // TODO : implement SourceOrderChanged and RepopulateSources
if (event == OBS_FRONTEND_EVENT_SCENE_CHANGED) if (event == OBS_FRONTEND_EVENT_SCENE_CHANGED) {
{
owner->OnSceneChange(); owner->OnSceneChange();
} }
else if (event == OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED) else if (event == OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED) {
{
owner->OnSceneListChange(); owner->OnSceneListChange();
} }
else if (event == OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED) else if (event == OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED) {
{
owner->OnSceneCollectionChange(); owner->OnSceneCollectionChange();
} }
else if (event == OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED) else if (event == OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED) {
{
owner->OnSceneCollectionListChange(); owner->OnSceneCollectionListChange();
} }
else if (event == OBS_FRONTEND_EVENT_TRANSITION_CHANGED) else if (event == OBS_FRONTEND_EVENT_TRANSITION_CHANGED) {
{
owner->OnTransitionChange(); owner->OnTransitionChange();
} }
else if (event == OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED) else if (event == OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED) {
{
owner->OnTransitionListChange(); owner->OnTransitionListChange();
} }
else if (event == OBS_FRONTEND_EVENT_PROFILE_CHANGED) else if (event == OBS_FRONTEND_EVENT_PROFILE_CHANGED) {
{
owner->OnProfileChange(); owner->OnProfileChange();
} }
else if (event == OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED) else if (event == OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED) {
{
owner->OnProfileListChange(); owner->OnProfileListChange();
} }
else if (event == OBS_FRONTEND_EVENT_STREAMING_STARTING) else if (event == OBS_FRONTEND_EVENT_STREAMING_STARTING) {
{
owner->OnStreamStarting(); owner->OnStreamStarting();
} }
else if (event == OBS_FRONTEND_EVENT_STREAMING_STARTED) else if (event == OBS_FRONTEND_EVENT_STREAMING_STARTED) {
{
owner->_streaming_active = true; owner->_streaming_active = true;
owner->OnStreamStarted(); owner->OnStreamStarted();
} }
else if (event == OBS_FRONTEND_EVENT_STREAMING_STOPPING) else if (event == OBS_FRONTEND_EVENT_STREAMING_STOPPING) {
{
owner->OnStreamStopping(); owner->OnStreamStopping();
} }
else if (event == OBS_FRONTEND_EVENT_STREAMING_STOPPED) else if (event == OBS_FRONTEND_EVENT_STREAMING_STOPPED) {
{
owner->_streaming_active = false; owner->_streaming_active = false;
owner->OnStreamStopped(); owner->OnStreamStopped();
} }
else if (event == OBS_FRONTEND_EVENT_RECORDING_STARTING) else if (event == OBS_FRONTEND_EVENT_RECORDING_STARTING) {
{
owner->OnRecordingStarting(); owner->OnRecordingStarting();
} }
else if (event == OBS_FRONTEND_EVENT_RECORDING_STARTED) else if (event == OBS_FRONTEND_EVENT_RECORDING_STARTED) {
{
owner->_recording_active = true; owner->_recording_active = true;
owner->OnRecordingStarted(); owner->OnRecordingStarted();
} }
else if (event == OBS_FRONTEND_EVENT_RECORDING_STOPPING) else if (event == OBS_FRONTEND_EVENT_RECORDING_STOPPING) {
{
owner->OnRecordingStopping(); owner->OnRecordingStopping();
} }
else if (event == OBS_FRONTEND_EVENT_RECORDING_STOPPED) else if (event == OBS_FRONTEND_EVENT_RECORDING_STOPPED) {
{
owner->_recording_active = false; owner->_recording_active = false;
owner->OnRecordingStopped(); owner->OnRecordingStopped();
} }
else if (event == OBS_FRONTEND_EVENT_EXIT) else if (event == OBS_FRONTEND_EVENT_EXIT) {
{
owner->OnExit(); owner->OnExit();
} }
} }
void WSEvents::broadcastUpdate(const char* updateType, obs_data_t* additionalFields = NULL) void WSEvents::broadcastUpdate(const char* updateType,
{ obs_data_t* additionalFields = NULL) {
obs_data_t* update = obs_data_create(); obs_data_t* update = obs_data_create();
obs_data_set_string(update, "update-type", updateType); obs_data_set_string(update, "update-type", updateType);
const char* ts = nullptr; const char* ts = nullptr;
if (_streaming_active) if (_streaming_active) {
{
ts = ns_to_timestamp(os_gettime_ns() - _stream_starttime); ts = ns_to_timestamp(os_gettime_ns() - _stream_starttime);
obs_data_set_string(update, "stream-timecode", ts); obs_data_set_string(update, "stream-timecode", ts);
bfree((void*)ts); bfree((void*)ts);
} }
if (_recording_active) if (_recording_active) {
{
ts = ns_to_timestamp(os_gettime_ns() - _rec_starttime); ts = ns_to_timestamp(os_gettime_ns() - _rec_starttime);
obs_data_set_string(update, "rec-timecode", ts); obs_data_set_string(update, "rec-timecode", ts);
bfree((void*)ts); bfree((void*)ts);
@ -222,30 +198,23 @@ void WSEvents::broadcastUpdate(const char* updateType, obs_data_t* additionalFie
obs_data_release(update); obs_data_release(update);
} }
void WSEvents::connectTransitionSignals(obs_source_t* transition) void WSEvents::connectTransitionSignals(obs_source_t* transition) {
{ if (transition_handler) {
if (transition_handler)
{
signal_handler_disconnect(transition_handler, signal_handler_disconnect(transition_handler,
"transition_start", OnTransitionBegin, this); "transition_start", OnTransitionBegin, this);
} }
if (!transition_is_cut(transition)) if (!transition_is_cut(transition)) {
{
transition_handler = obs_source_get_signal_handler(transition); transition_handler = obs_source_get_signal_handler(transition);
signal_handler_connect(transition_handler, signal_handler_connect(transition_handler,
"transition_start", OnTransitionBegin, this); "transition_start", OnTransitionBegin, this);
} } else {
else
{
transition_handler = nullptr; transition_handler = nullptr;
} }
} }
void WSEvents::connectSceneSignals(obs_source_t* scene) void WSEvents::connectSceneSignals(obs_source_t* scene) {
{ if (scene_handler) {
if (scene_handler)
{
signal_handler_disconnect(scene_handler, signal_handler_disconnect(scene_handler,
"reorder", OnSceneReordered, this); "reorder", OnSceneReordered, this);
signal_handler_disconnect(scene_handler, signal_handler_disconnect(scene_handler,
@ -268,34 +237,29 @@ void WSEvents::connectSceneSignals(obs_source_t* scene)
"item_visible", OnSceneItemVisibilityChanged, this); "item_visible", OnSceneItemVisibilityChanged, this);
} }
uint64_t WSEvents::GetStreamingTime() uint64_t WSEvents::GetStreamingTime() {
{
if (_streaming_active) if (_streaming_active)
return (os_gettime_ns() - _stream_starttime); return (os_gettime_ns() - _stream_starttime);
else else
return 0; return 0;
} }
const char* WSEvents::GetStreamingTimecode() const char* WSEvents::GetStreamingTimecode() {
{
return ns_to_timestamp(GetStreamingTime()); return ns_to_timestamp(GetStreamingTime());
} }
uint64_t WSEvents::GetRecordingTime() uint64_t WSEvents::GetRecordingTime() {
{
if (_recording_active) if (_recording_active)
return (os_gettime_ns() - _rec_starttime); return (os_gettime_ns() - _rec_starttime);
else else
return 0; return 0;
} }
const char* WSEvents::GetRecordingTimecode() const char* WSEvents::GetRecordingTimecode() {
{
return ns_to_timestamp(GetRecordingTime()); return ns_to_timestamp(GetRecordingTime());
} }
void WSEvents::OnSceneChange() void WSEvents::OnSceneChange() {
{
// Implements an existing update type from bilhamil's OBS Remote // Implements an existing update type from bilhamil's OBS Remote
obs_data_t* data = obs_data_create(); obs_data_t* data = obs_data_create();
@ -314,20 +278,17 @@ void WSEvents::OnSceneChange()
// Dirty fix : OBS blocks signals when swapping scenes in Studio Mode // Dirty fix : OBS blocks signals when swapping scenes in Studio Mode
// after transition end, so SelectedSceneChanged is never called... // after transition end, so SelectedSceneChanged is never called...
if (Utils::IsPreviewModeActive()) if (Utils::IsPreviewModeActive()) {
{
QListWidget* list = Utils::GetSceneListControl(); QListWidget* list = Utils::GetSceneListControl();
SelectedSceneChanged(list->currentItem(), nullptr); SelectedSceneChanged(list->currentItem(), nullptr);
} }
} }
void WSEvents::OnSceneListChange() void WSEvents::OnSceneListChange() {
{
broadcastUpdate("ScenesChanged"); broadcastUpdate("ScenesChanged");
} }
void WSEvents::OnSceneCollectionChange() void WSEvents::OnSceneCollectionChange() {
{
broadcastUpdate("SceneCollectionChanged"); broadcastUpdate("SceneCollectionChanged");
scene_handler = nullptr; scene_handler = nullptr;
@ -340,13 +301,11 @@ void WSEvents::OnSceneCollectionChange()
OnSceneChange(); OnSceneChange();
} }
void WSEvents::OnSceneCollectionListChange() void WSEvents::OnSceneCollectionListChange() {
{
broadcastUpdate("SceneCollectionListChanged"); broadcastUpdate("SceneCollectionListChanged");
} }
void WSEvents::OnTransitionChange() void WSEvents::OnTransitionChange() {
{
obs_source_t* current_transition = obs_frontend_get_current_transition(); obs_source_t* current_transition = obs_frontend_get_current_transition();
connectTransitionSignals(current_transition); connectTransitionSignals(current_transition);
@ -360,23 +319,19 @@ void WSEvents::OnTransitionChange()
obs_source_release(current_transition); obs_source_release(current_transition);
} }
void WSEvents::OnTransitionListChange() void WSEvents::OnTransitionListChange() {
{
broadcastUpdate("TransitionListChanged"); broadcastUpdate("TransitionListChanged");
} }
void WSEvents::OnProfileChange() void WSEvents::OnProfileChange() {
{
broadcastUpdate("ProfileChanged"); broadcastUpdate("ProfileChanged");
} }
void WSEvents::OnProfileListChange() void WSEvents::OnProfileListChange() {
{
broadcastUpdate("ProfileListChanged"); broadcastUpdate("ProfileListChanged");
} }
void WSEvents::OnStreamStarting() void WSEvents::OnStreamStarting() {
{
// Implements an existing update type from bilhamil's OBS Remote // Implements an existing update type from bilhamil's OBS Remote
obs_data_t* data = obs_data_create(); obs_data_t* data = obs_data_create();
obs_data_set_bool(data, "preview-only", false); obs_data_set_bool(data, "preview-only", false);
@ -386,16 +341,14 @@ void WSEvents::OnStreamStarting()
obs_data_release(data); obs_data_release(data);
} }
void WSEvents::OnStreamStarted() void WSEvents::OnStreamStarted() {
{
// New update type specific to OBS Studio // New update type specific to OBS Studio
_stream_starttime = os_gettime_ns(); _stream_starttime = os_gettime_ns();
_lastBytesSent = 0; _lastBytesSent = 0;
broadcastUpdate("StreamStarted"); broadcastUpdate("StreamStarted");
} }
void WSEvents::OnStreamStopping() void WSEvents::OnStreamStopping() {
{
// Implements an existing update type from bilhamil's OBS Remote // Implements an existing update type from bilhamil's OBS Remote
obs_data_t* data = obs_data_create(); obs_data_t* data = obs_data_create();
obs_data_set_bool(data, "preview-only", false); obs_data_set_bool(data, "preview-only", false);
@ -405,57 +358,49 @@ void WSEvents::OnStreamStopping()
obs_data_release(data); obs_data_release(data);
} }
void WSEvents::OnStreamStopped() void WSEvents::OnStreamStopped() {
{
// New update type specific to OBS Studio // New update type specific to OBS Studio
_stream_starttime = 0; _stream_starttime = 0;
broadcastUpdate("StreamStopped"); broadcastUpdate("StreamStopped");
} }
void WSEvents::OnRecordingStarting() void WSEvents::OnRecordingStarting() {
{
// New update type specific to OBS Studio // New update type specific to OBS Studio
broadcastUpdate("RecordingStarting"); broadcastUpdate("RecordingStarting");
} }
void WSEvents::OnRecordingStarted() void WSEvents::OnRecordingStarted() {
{
// New update type specific to OBS Studio // New update type specific to OBS Studio
_rec_starttime = os_gettime_ns(); _rec_starttime = os_gettime_ns();
broadcastUpdate("RecordingStarted"); broadcastUpdate("RecordingStarted");
} }
void WSEvents::OnRecordingStopping() void WSEvents::OnRecordingStopping() {
{
// New update type specific to OBS Studio // New update type specific to OBS Studio
broadcastUpdate("RecordingStopping"); broadcastUpdate("RecordingStopping");
} }
void WSEvents::OnRecordingStopped() void WSEvents::OnRecordingStopped() {
{
// New update type specific to OBS Studio // New update type specific to OBS Studio
_rec_starttime = 0; _rec_starttime = 0;
broadcastUpdate("RecordingStopped"); broadcastUpdate("RecordingStopped");
} }
void WSEvents::OnExit() void WSEvents::OnExit() {
{
// New update type specific to OBS Studio // New update type specific to OBS Studio
broadcastUpdate("Exiting"); broadcastUpdate("Exiting");
} }
void WSEvents::StreamStatus() void WSEvents::StreamStatus() {
{
bool streaming_active = obs_frontend_streaming_active(); bool streaming_active = obs_frontend_streaming_active();
bool recording_active = obs_frontend_recording_active(); bool recording_active = obs_frontend_recording_active();
obs_output_t* stream_output = obs_frontend_get_streaming_output(); obs_output_t* stream_output = obs_frontend_get_streaming_output();
if (!stream_output || !streaming_active) if (!stream_output || !streaming_active) {
{ if (stream_output) {
if (stream_output) obs_output_release(stream_output);
obs_output_release(stream_output); }
return; return;
} }
@ -503,8 +448,7 @@ void WSEvents::StreamStatus()
obs_output_release(stream_output); obs_output_release(stream_output);
} }
void WSEvents::TransitionDurationChanged(int ms) void WSEvents::TransitionDurationChanged(int ms) {
{
obs_data_t* fields = obs_data_create(); obs_data_t* fields = obs_data_create();
obs_data_set_int(fields, "new-duration", ms); obs_data_set_int(fields, "new-duration", ms);
@ -513,8 +457,7 @@ void WSEvents::TransitionDurationChanged(int ms)
obs_data_release(fields); obs_data_release(fields);
} }
void WSEvents::OnTransitionBegin(void* param, calldata_t* data) void WSEvents::OnTransitionBegin(void* param, calldata_t* data) {
{
UNUSED_PARAMETER(data); UNUSED_PARAMETER(data);
WSEvents* instance = static_cast<WSEvents*>(param); WSEvents* instance = static_cast<WSEvents*>(param);
@ -523,8 +466,7 @@ void WSEvents::OnTransitionBegin(void* param, calldata_t* data)
blog(LOG_INFO, "transition begin"); blog(LOG_INFO, "transition begin");
} }
void WSEvents::OnSceneReordered(void* param, calldata_t* data) void WSEvents::OnSceneReordered(void* param, calldata_t* data) {
{
WSEvents* instance = static_cast<WSEvents*>(param); WSEvents* instance = static_cast<WSEvents*>(param);
obs_scene_t* scene = nullptr; obs_scene_t* scene = nullptr;
@ -539,8 +481,7 @@ void WSEvents::OnSceneReordered(void* param, calldata_t* data)
obs_data_release(fields); obs_data_release(fields);
} }
void WSEvents::OnSceneItemAdd(void* param, calldata_t* data) void WSEvents::OnSceneItemAdd(void* param, calldata_t* data) {
{
WSEvents* instance = static_cast<WSEvents*>(param); WSEvents* instance = static_cast<WSEvents*>(param);
obs_scene_t* scene = nullptr; obs_scene_t* scene = nullptr;
@ -563,8 +504,7 @@ void WSEvents::OnSceneItemAdd(void* param, calldata_t* data)
obs_data_release(fields); obs_data_release(fields);
} }
void WSEvents::OnSceneItemDelete(void* param, calldata_t* data) void WSEvents::OnSceneItemDelete(void* param, calldata_t* data) {
{
WSEvents* instance = static_cast<WSEvents*>(param); WSEvents* instance = static_cast<WSEvents*>(param);
obs_scene_t* scene = nullptr; obs_scene_t* scene = nullptr;
@ -587,8 +527,7 @@ void WSEvents::OnSceneItemDelete(void* param, calldata_t* data)
obs_data_release(fields); obs_data_release(fields);
} }
void WSEvents::OnSceneItemVisibilityChanged(void* param, calldata_t* data) void WSEvents::OnSceneItemVisibilityChanged(void* param, calldata_t* data) {
{
WSEvents* instance = static_cast<WSEvents*>(param); WSEvents* instance = static_cast<WSEvents*>(param);
obs_scene_t* scene = nullptr; obs_scene_t* scene = nullptr;
@ -615,10 +554,8 @@ void WSEvents::OnSceneItemVisibilityChanged(void* param, calldata_t* data)
obs_data_release(fields); obs_data_release(fields);
} }
void WSEvents::SelectedSceneChanged(QListWidgetItem* current, QListWidgetItem* prev) void WSEvents::SelectedSceneChanged(QListWidgetItem* current, QListWidgetItem* prev) {
{ if (Utils::IsPreviewModeActive()) {
if (Utils::IsPreviewModeActive())
{
obs_scene_t* scene = Utils::SceneListItemToScene(current); obs_scene_t* scene = Utils::SceneListItemToScene(current);
if (!scene) return; if (!scene) return;
@ -636,8 +573,7 @@ void WSEvents::SelectedSceneChanged(QListWidgetItem* current, QListWidgetItem* p
} }
} }
void WSEvents::ModeSwitchClicked(bool checked) void WSEvents::ModeSwitchClicked(bool checked) {
{
obs_data_t* data = obs_data_create(); obs_data_t* data = obs_data_create();
obs_data_set_bool(data, "new-state", checked); obs_data_set_bool(data, "new-state", checked);

View File

@ -22,80 +22,79 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#include <obs-frontend-api.h> #include <obs-frontend-api.h>
#include <QListWidgetItem> #include <QListWidgetItem>
#include "WSServer.h" #include "WSServer.h"
class WSEvents : public QObject class WSEvents : public QObject {
{ Q_OBJECT
Q_OBJECT public:
explicit WSEvents(WSServer* srv);
~WSEvents();
static void FrontendEventHandler(
enum obs_frontend_event event, void* private_data);
void connectTransitionSignals(obs_source_t* transition);
void connectSceneSignals(obs_source_t* scene);
static WSEvents* Instance;
public: uint64_t GetStreamingTime();
explicit WSEvents(WSServer* srv); const char* GetStreamingTimecode();
~WSEvents(); uint64_t GetRecordingTime();
static void FrontendEventHandler( const char* GetRecordingTimecode();
enum obs_frontend_event event, void* private_data);
void connectTransitionSignals(obs_source_t* transition);
void connectSceneSignals(obs_source_t* scene);
static WSEvents* Instance;
uint64_t GetStreamingTime(); private slots:
const char* GetStreamingTimecode(); void deferredInitOperations();
uint64_t GetRecordingTime(); void StreamStatus();
const char* GetRecordingTimecode(); void TransitionDurationChanged(int ms);
void SelectedSceneChanged(
QListWidgetItem* current, QListWidgetItem* prev);
void ModeSwitchClicked(bool checked);
private Q_SLOTS: private:
void deferredInitOperations(); WSServer* _srv;
void StreamStatus(); signal_handler_t* transition_handler;
void TransitionDurationChanged(int ms); signal_handler_t* scene_handler;
void SelectedSceneChanged(
QListWidgetItem* current, QListWidgetItem* prev);
void ModeSwitchClicked(bool checked);
private: bool _streaming_active;
WSServer* _srv; bool _recording_active;
signal_handler_t* transition_handler;
signal_handler_t* scene_handler;
bool _streaming_active; uint64_t _stream_starttime;
bool _recording_active; uint64_t _rec_starttime;
uint64_t _stream_starttime; uint64_t _lastBytesSent;
uint64_t _rec_starttime; uint64_t _lastBytesSentTime;
uint64_t _lastBytesSent; void broadcastUpdate(const char* updateType,
uint64_t _lastBytesSentTime; obs_data_t* additionalFields);
void broadcastUpdate(const char* updateType, void OnSceneChange();
obs_data_t* additionalFields); void OnSceneListChange();
void OnSceneCollectionChange();
void OnSceneCollectionListChange();
void OnSceneChange(); void OnTransitionChange();
void OnSceneListChange(); void OnTransitionListChange();
void OnSceneCollectionChange();
void OnSceneCollectionListChange();
void OnTransitionChange(); void OnProfileChange();
void OnTransitionListChange(); void OnProfileListChange();
void OnProfileChange(); void OnStreamStarting();
void OnProfileListChange(); void OnStreamStarted();
void OnStreamStopping();
void OnStreamStopped();
void OnStreamStarting(); void OnRecordingStarting();
void OnStreamStarted(); void OnRecordingStarted();
void OnStreamStopping(); void OnRecordingStopping();
void OnStreamStopped(); void OnRecordingStopped();
void OnRecordingStarting(); void OnExit();
void OnRecordingStarted();
void OnRecordingStopping();
void OnRecordingStopped();
void OnExit(); static void OnTransitionBegin(void* param, calldata_t* data);
static void OnTransitionBegin(void* param, calldata_t* data); static void OnSceneReordered(void* param, calldata_t* data);
static void OnSceneItemAdd(void* param, calldata_t* data);
static void OnSceneReordered(void* param, calldata_t* data); static void OnSceneItemDelete(void* param, calldata_t* data);
static void OnSceneItemAdd(void* param, calldata_t* data); static void OnSceneItemVisibilityChanged(void* param, calldata_t* data);
static void OnSceneItemDelete(void* param, calldata_t* data);
static void OnSceneItemVisibilityChanged(void* param, calldata_t* data);
}; };
#endif // WSEVENTS_H #endif // WSEVENTS_H

View File

@ -20,97 +20,96 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#ifndef WSREQUESTHANDLER_H #ifndef WSREQUESTHANDLER_H
#define WSREQUESTHANDLER_H #define WSREQUESTHANDLER_H
#include <QWebSocket>
#include <QWebSocketServer>
#include <obs-frontend-api.h> #include <obs-frontend-api.h>
#include <QtWebSockets/QWebSocket> class WSRequestHandler : public QObject {
#include <QtWebSockets/QWebSocketServer> Q_OBJECT
class WSRequestHandler : public QObject public:
{ explicit WSRequestHandler(QWebSocket* client);
Q_OBJECT ~WSRequestHandler();
void processIncomingMessage(QString textMessage);
bool hasField(const char* name);
public: private:
explicit WSRequestHandler(QWebSocket* client); static obs_service_t* _service;
~WSRequestHandler(); QWebSocket* _client;
void processIncomingMessage(QString textMessage); const char* _messageId;
bool hasField(const char* name); const char* _requestType;
obs_data_t* data;
private: QMap<QString, void(*)(WSRequestHandler*)> messageMap;
static obs_service_t* _service; QSet<QString> authNotRequired;
QWebSocket* _client;
const char* _messageId;
const char* _requestType;
obs_data_t* data;
QMap<QString, void(*)(WSRequestHandler*)> messageMap; void SendOKResponse(obs_data_t* additionalFields = NULL);
QSet<QString> authNotRequired; void SendErrorResponse(const char* errorMessage);
void SendResponse(obs_data_t* response);
void SendOKResponse(obs_data_t* additionalFields = NULL); static void HandleGetVersion(WSRequestHandler* req);
void SendErrorResponse(const char* errorMessage); static void HandleGetAuthRequired(WSRequestHandler* req);
void SendResponse(obs_data_t* response); static void HandleAuthenticate(WSRequestHandler* req);
static void HandleGetVersion(WSRequestHandler* req); static void HandleSetCurrentScene(WSRequestHandler* req);
static void HandleGetAuthRequired(WSRequestHandler* req); static void HandleGetCurrentScene(WSRequestHandler* req);
static void HandleAuthenticate(WSRequestHandler* req); static void HandleGetSceneList(WSRequestHandler* req);
static void HandleSetCurrentScene(WSRequestHandler* req); static void HandleSetSceneItemRender(WSRequestHandler* req);
static void HandleGetCurrentScene(WSRequestHandler* req); static void HandleSetSceneItemPosition(WSRequestHandler* req);
static void HandleGetSceneList(WSRequestHandler* req); static void HandleSetSceneItemTransform(WSRequestHandler* req);
static void HandleSetSceneItemCrop(WSRequestHandler* req);
static void HandleSetSceneItemRender(WSRequestHandler* req); static void HandleGetStreamingStatus(WSRequestHandler* req);
static void HandleSetSceneItemPosition(WSRequestHandler* req); static void HandleStartStopStreaming(WSRequestHandler* req);
static void HandleSetSceneItemTransform(WSRequestHandler* req); static void HandleStartStopRecording(WSRequestHandler* req);
static void HandleSetSceneItemCrop(WSRequestHandler* req); static void HandleStartStreaming(WSRequestHandler* req);
static void HandleStopStreaming(WSRequestHandler* req);
static void HandleStartRecording(WSRequestHandler* req);
static void HandleStopRecording(WSRequestHandler* req);
static void HandleGetStreamingStatus(WSRequestHandler* req); static void HandleSetRecordingFolder(WSRequestHandler* req);
static void HandleStartStopStreaming(WSRequestHandler* req); static void HandleGetRecordingFolder(WSRequestHandler* req);
static void HandleStartStopRecording(WSRequestHandler* req);
static void HandleStartStreaming(WSRequestHandler* req);
static void HandleStopStreaming(WSRequestHandler* req);
static void HandleStartRecording(WSRequestHandler* req);
static void HandleStopRecording(WSRequestHandler* req);
static void HandleSetRecordingFolder(WSRequestHandler* req); static void HandleGetTransitionList(WSRequestHandler* req);
static void HandleGetRecordingFolder(WSRequestHandler* req); static void HandleGetCurrentTransition(WSRequestHandler* req);
static void HandleSetCurrentTransition(WSRequestHandler* req);
static void HandleGetTransitionList(WSRequestHandler* req); static void HandleSetVolume(WSRequestHandler* req);
static void HandleGetCurrentTransition(WSRequestHandler* req); static void HandleGetVolume(WSRequestHandler* req);
static void HandleSetCurrentTransition(WSRequestHandler* req); static void HandleToggleMute(WSRequestHandler* req);
static void HandleSetMute(WSRequestHandler* req);
static void HandleGetMute(WSRequestHandler* req);
static void HandleGetSpecialSources(WSRequestHandler* req);
static void HandleSetVolume(WSRequestHandler* req); static void HandleSetCurrentSceneCollection(WSRequestHandler* req);
static void HandleGetVolume(WSRequestHandler* req); static void HandleGetCurrentSceneCollection(WSRequestHandler* req);
static void HandleToggleMute(WSRequestHandler* req); static void HandleListSceneCollections(WSRequestHandler* req);
static void HandleSetMute(WSRequestHandler* req);
static void HandleGetMute(WSRequestHandler* req);
static void HandleGetSpecialSources(WSRequestHandler* req);
static void HandleSetCurrentSceneCollection(WSRequestHandler* req); static void HandleSetCurrentProfile(WSRequestHandler* req);
static void HandleGetCurrentSceneCollection(WSRequestHandler* req); static void HandleGetCurrentProfile(WSRequestHandler* req);
static void HandleListSceneCollections(WSRequestHandler* req); static void HandleListProfiles(WSRequestHandler* req);
static void HandleSetCurrentProfile(WSRequestHandler* req); static void HandleSetStreamSettings(WSRequestHandler* req);
static void HandleGetCurrentProfile(WSRequestHandler* req); static void HandleGetStreamSettings(WSRequestHandler* req);
static void HandleListProfiles(WSRequestHandler* req); static void HandleSaveStreamSettings(WSRequestHandler* req);
static void HandleSetStreamSettings(WSRequestHandler* req); static void HandleSetTransitionDuration(WSRequestHandler* req);
static void HandleGetStreamSettings(WSRequestHandler* req); static void HandleGetTransitionDuration(WSRequestHandler* req);
static void HandleSaveStreamSettings(WSRequestHandler* req);
static void HandleSetTransitionDuration(WSRequestHandler* req); static void HandleGetStudioModeStatus(WSRequestHandler* req);
static void HandleGetTransitionDuration(WSRequestHandler* req); static void HandleGetPreviewScene(WSRequestHandler* req);
static void HandleSetPreviewScene(WSRequestHandler* req);
static void HandleGetStudioModeStatus(WSRequestHandler* req); static void HandleTransitionToProgram(WSRequestHandler* req);
static void HandleGetPreviewScene(WSRequestHandler* req); static void HandleEnableStudioMode(WSRequestHandler* req);
static void HandleSetPreviewScene(WSRequestHandler* req); static void HandleDisableStudioMode(WSRequestHandler* req);
static void HandleTransitionToProgram(WSRequestHandler* req); static void HandleToggleStudioMode(WSRequestHandler* req);
static void HandleEnableStudioMode(WSRequestHandler* req);
static void HandleDisableStudioMode(WSRequestHandler* req);
static void HandleToggleStudioMode(WSRequestHandler* req);
static void HandleSetTextGDIPlusProperties(WSRequestHandler* req); static void HandleSetTextGDIPlusProperties(WSRequestHandler* req);
static void HandleGetTextGDIPlusProperties(WSRequestHandler* req); static void HandleGetTextGDIPlusProperties(WSRequestHandler* req);
static void HandleSetBrowserSourceProperties(WSRequestHandler* req); static void HandleSetBrowserSourceProperties(WSRequestHandler* req);
static void HandleGetBrowserSourceProperties(WSRequestHandler* req); static void HandleGetBrowserSourceProperties(WSRequestHandler* req);
}; };
#endif // WSPROTOCOL_H #endif // WSPROTOCOL_H

View File

@ -34,26 +34,21 @@ WSServer::WSServer(QObject* parent) :
QObject(parent), QObject(parent),
_wsServer(Q_NULLPTR), _wsServer(Q_NULLPTR),
_clients(), _clients(),
_clMutex(QMutex::Recursive) _clMutex(QMutex::Recursive) {
{
_serverThread = new QThread(); _serverThread = new QThread();
_wsServer = new QWebSocketServer( _wsServer = new QWebSocketServer(
QStringLiteral("obs-websocket"), QStringLiteral("obs-websocket"),
QWebSocketServer::NonSecureMode, QWebSocketServer::NonSecureMode,
_serverThread); _serverThread);
_serverThread->start(); _serverThread->start();
} }
WSServer::~WSServer() WSServer::~WSServer() {
{
Stop(); Stop();
delete _serverThread; delete _serverThread;
} }
void WSServer::Start(quint16 port) void WSServer::Start(quint16 port) {
{
if (port == _wsServer->serverPort()) if (port == _wsServer->serverPort())
return; return;
@ -61,15 +56,13 @@ void WSServer::Start(quint16 port)
Stop(); Stop();
bool serverStarted = _wsServer->listen(QHostAddress::Any, port); bool serverStarted = _wsServer->listen(QHostAddress::Any, port);
if (serverStarted) if (serverStarted) {
{ connect(_wsServer, SIGNAL(newConnection()),
connect(_wsServer, &QWebSocketServer::newConnection, this, SLOT(onNewConnection()));
this, &WSServer::onNewConnection);
} }
} }
void WSServer::Stop() void WSServer::Stop() {
{
_clMutex.lock(); _clMutex.lock();
for(QWebSocket* pClient : _clients) { for(QWebSocket* pClient : _clients) {
pClient->close(); pClient->close();
@ -79,35 +72,34 @@ void WSServer::Stop()
_wsServer->close(); _wsServer->close();
} }
void WSServer::broadcast(QString message) void WSServer::broadcast(QString message) {
{
_clMutex.lock(); _clMutex.lock();
for(QWebSocket* pClient : _clients) { for(QWebSocket* pClient : _clients) {
if (Config::Current()->AuthRequired if (Config::Current()->AuthRequired
&& (pClient->property(PROP_AUTHENTICATED).toBool() == false)) && (pClient->property(PROP_AUTHENTICATED).toBool() == false)) {
{
// Skip this client if unauthenticated // Skip this client if unauthenticated
continue; continue;
} }
pClient->sendTextMessage(message); pClient->sendTextMessage(message);
} }
_clMutex.unlock(); _clMutex.unlock();
} }
void WSServer::onNewConnection() void WSServer::onNewConnection() {
{
QWebSocket* pSocket = _wsServer->nextPendingConnection(); QWebSocket* pSocket = _wsServer->nextPendingConnection();
if (pSocket) {
if (pSocket)
{
connect(pSocket, &QWebSocket::textMessageReceived, connect(pSocket, &QWebSocket::textMessageReceived,
this, &WSServer::textMessageReceived); this, &WSServer::onTextMessageReceived);
connect(pSocket, &QWebSocket::disconnected, connect(pSocket, &QWebSocket::disconnected,
this, &WSServer::socketDisconnected); this, &WSServer::onSocketDisconnected);
pSocket->setProperty(PROP_AUTHENTICATED, false);
connect(pSocket, SIGNAL(textMessageReceived(const QString&)),
this, SLOT(onTextMessageReceived(QString)));
connect(pSocket, SIGNAL(disconnected()),
this, SLOT(onSocketDisconnected()));
pSocket->setProperty(PROP_AUTHENTICATED, false);
_clMutex.lock(); _clMutex.lock();
_clients << pSocket; _clients << pSocket;
@ -129,23 +121,17 @@ void WSServer::onNewConnection()
} }
} }
void WSServer::textMessageReceived(QString message) void WSServer::onTextMessageReceived(QString message) {
{
QWebSocket* pSocket = qobject_cast<QWebSocket*>(sender()); QWebSocket* pSocket = qobject_cast<QWebSocket*>(sender());
if (pSocket) {
if (pSocket)
{
WSRequestHandler handler(pSocket); WSRequestHandler handler(pSocket);
handler.processIncomingMessage(message); handler.processIncomingMessage(message);
} }
} }
void WSServer::socketDisconnected() void WSServer::onSocketDisconnected() {
{
QWebSocket* pSocket = qobject_cast<QWebSocket*>(sender()); QWebSocket* pSocket = qobject_cast<QWebSocket*>(sender());
if (pSocket) {
if (pSocket)
{
pSocket->setProperty(PROP_AUTHENTICATED, false); pSocket->setProperty(PROP_AUTHENTICATED, false);
_clMutex.lock(); _clMutex.lock();

View File

@ -19,37 +19,35 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#ifndef WSSERVER_H #ifndef WSSERVER_H
#define WSSERVER_H #define WSSERVER_H
#include <QtCore/QObject> #include <QObject>
#include <QtCore/QList> #include <QList>
#include <QtCore/QMutex> #include <QMutex>
#include "WSRequestHandler.h"
QT_FORWARD_DECLARE_CLASS(QWebSocketServer) QT_FORWARD_DECLARE_CLASS(QWebSocketServer)
QT_FORWARD_DECLARE_CLASS(QWebSocket) QT_FORWARD_DECLARE_CLASS(QWebSocket)
#include "WSRequestHandler.h" class WSServer : public QObject {
Q_OBJECT
public:
explicit WSServer(QObject* parent = Q_NULLPTR);
virtual ~WSServer();
void Start(quint16 port);
void Stop();
void broadcast(QString message);
static WSServer* Instance;
class WSServer : public QObject private slots:
{ void onNewConnection();
Q_OBJECT void onTextMessageReceived(QString message);
void onSocketDisconnected();
public: private:
explicit WSServer(QObject* parent = Q_NULLPTR); QWebSocketServer* _wsServer;
virtual ~WSServer(); QList<QWebSocket*> _clients;
void Start(quint16 port); QMutex _clMutex;
void Stop(); QThread* _serverThread;
void broadcast(QString message);
static WSServer* Instance;
private Q_SLOTS:
void onNewConnection();
void textMessageReceived(QString message);
void socketDisconnected();
private:
QWebSocketServer* _wsServer;
QList<QWebSocket*> _clients;
QMutex _clMutex;
QThread* _serverThread;
}; };
#endif // WSSERVER_H #endif // WSSERVER_H

View File

@ -31,10 +31,9 @@ with this program. If not, see <https://www.gnu.org/licenses/>
OBS_DECLARE_MODULE() OBS_DECLARE_MODULE()
OBS_MODULE_USE_DEFAULT_LOCALE("obs-websocket", "en-US") OBS_MODULE_USE_DEFAULT_LOCALE("obs-websocket", "en-US")
SettingsDialog *settings_dialog; SettingsDialog* settings_dialog;
bool obs_module_load(void) bool obs_module_load(void) {
{
blog(LOG_INFO, "you can haz websockets (version %s)", OBS_WEBSOCKET_VERSION); blog(LOG_INFO, "you can haz websockets (version %s)", OBS_WEBSOCKET_VERSION);
// Core setup // Core setup
@ -48,7 +47,7 @@ bool obs_module_load(void)
WSServer::Instance->Start(config->ServerPort); WSServer::Instance->Start(config->ServerPort);
// UI setup // UI setup
QAction *menu_action = (QAction*)obs_frontend_add_tools_menu_qaction( QAction* menu_action = (QAction*)obs_frontend_add_tools_menu_qaction(
obs_module_text("OBSWebsocket.Menu.SettingsItem")); obs_module_text("OBSWebsocket.Menu.SettingsItem"));
obs_frontend_push_ui_translation(obs_module_get_string); obs_frontend_push_ui_translation(obs_module_get_string);
@ -67,8 +66,7 @@ bool obs_module_load(void)
return true; return true;
} }
void obs_module_unload() void obs_module_unload() {
{
blog(LOG_INFO, "goodbye!"); blog(LOG_INFO, "goodbye!");
} }