diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c2145c0..520d4254 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,7 @@ set(obs-websocket_SOURCES src/Utils.cpp src/rpc/RpcRequest.cpp src/rpc/RpcResponse.cpp + src/rpc/RpcEvent.cpp src/protocol/OBSRemoteProtocol.cpp src/forms/settings-dialog.cpp) @@ -61,6 +62,7 @@ set(obs-websocket_HEADERS src/Utils.h src/rpc/RpcRequest.h src/rpc/RpcResponse.h + src/rpc/RpcEvent.h src/protocol/OBSRemoteProtocol.h src/forms/settings-dialog.h) @@ -180,8 +182,8 @@ if(UNIX AND NOT APPLE) install(TARGETS obs-websocket LIBRARY DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/obs-plugins") # Dirty fix for Ubuntu - install(TARGETS obs-websocket - LIBRARY DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/${UNAME_MACHINE}-linux-gnu/obs-plugins") + install(TARGETS obs-websocket + LIBRARY DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/${UNAME_MACHINE}-linux-gnu/obs-plugins") install(FILES ${locale_files} DESTINATION "${CMAKE_INSTALL_PREFIX}/share/obs/obs-plugins/obs-websocket/locale") diff --git a/src/Utils.cpp b/src/Utils.cpp index 243faf35..02b55e1d 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -16,6 +16,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see */ +#include #include #include #include @@ -822,3 +823,17 @@ void Utils::PauseRecording(bool pause) pauseRecording(pause); } + +QString Utils::nsToTimestamp(uint64_t ns) +{ + uint64_t ms = ns / 1000000ULL; + uint64_t secs = ms / 1000ULL; + uint64_t minutes = secs / 60ULL; + + uint64_t hoursPart = minutes / 60ULL; + uint64_t minutesPart = minutes % 60ULL; + uint64_t secsPart = secs % 60ULL; + uint64_t msPart = ms % 1000ULL; + + return QString::asprintf("%02" PRIu64 ":%02" PRIu64 ":%02" PRIu64 ".%03" PRIu64, hoursPart, minutesPart, secsPart, msPart); +} diff --git a/src/Utils.h b/src/Utils.h index 89f01acc..bdd5da20 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -86,4 +86,6 @@ class Utils { static bool RecordingPauseSupported(); static bool RecordingPaused(); static void PauseRecording(bool pause); + + static QString nsToTimestamp(uint64_t ns); }; diff --git a/src/WSEvents.cpp b/src/WSEvents.cpp index 4e978cc4..143309e8 100644 --- a/src/WSEvents.cpp +++ b/src/WSEvents.cpp @@ -23,27 +23,15 @@ #include -#include "Config.h" -#include "Utils.h" #include "WSEvents.h" #include "obs-websocket.h" +#include "Config.h" +#include "Utils.h" +#include "rpc/RpcEvent.h" #define STATUS_INTERVAL 2000 -QString nsToTimestamp(uint64_t ns) { - uint64_t ms = ns / 1000000ULL; - uint64_t secs = ms / 1000ULL; - uint64_t minutes = secs / 60ULL; - - uint64_t hoursPart = minutes / 60ULL; - uint64_t minutesPart = minutes % 60ULL; - uint64_t secsPart = secs % 60ULL; - uint64_t msPart = ms % 1000ULL; - - return QString::asprintf("%02" PRIu64 ":%02" PRIu64 ":%02" PRIu64 ".%03" PRIu64, hoursPart, minutesPart, secsPart, msPart); -} - const char* sourceTypeToString(obs_source_type type) { switch (type) { case OBS_SOURCE_TYPE_INPUT: @@ -252,28 +240,11 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void* private void WSEvents::broadcastUpdate(const char* updateType, obs_data_t* additionalFields = nullptr) { - OBSDataAutoRelease update = obs_data_create(); - obs_data_set_string(update, "update-type", updateType); + uint64_t streamTime = getStreamingTime(); + uint64_t recordingTime = getStreamingTime(); + RpcEvent event(QString(updateType), streamTime, recordingTime, additionalFields); - if (obs_frontend_streaming_active()) { - QString streamingTimecode = getStreamingTimecode(); - obs_data_set_string(update, "stream-timecode", streamingTimecode.toUtf8().constData()); - } - - if (obs_frontend_recording_active()) { - QString recordingTimecode = getRecordingTimecode(); - obs_data_set_string(update, "rec-timecode", recordingTimecode.toUtf8().constData()); - } - - if (additionalFields) - obs_data_apply(update, additionalFields); - - QString json = obs_data_get_json(update); - _srv->broadcast(json.toStdString()); - - if (GetConfig()->DebugEnabled) { - blog(LOG_INFO, "Update << '%s'", json.toUtf8().constData()); - } + _srv->broadcast(event); } void WSEvents::connectSourceSignals(obs_source_t* source) { @@ -410,11 +381,11 @@ uint64_t WSEvents::getRecordingTime() { } QString WSEvents::getStreamingTimecode() { - return nsToTimestamp(getStreamingTime()); + return Utils::nsToTimestamp(getStreamingTime()); } QString WSEvents::getRecordingTimecode() { - return nsToTimestamp(getRecordingTime()); + return Utils::nsToTimestamp(getRecordingTime()); } /** diff --git a/src/WSServer.cpp b/src/WSServer.cpp index 69c25ec7..c9f09362 100644 --- a/src/WSServer.cpp +++ b/src/WSServer.cpp @@ -125,8 +125,15 @@ void WSServer::stop() blog(LOG_INFO, "server stopped successfully"); } -void WSServer::broadcast(std::string message) +void WSServer::broadcast(const RpcEvent& event) { + OBSRemoteProtocol protocol; + std::string message = protocol.encodeEvent(event); + + if (GetConfig()->DebugEnabled) { + blog(LOG_INFO, "Update << '%s'", message.c_str()); + } + QMutexLocker locker(&_clMutex); for (connection_hdl hdl : _connections) { if (GetConfig()->AuthRequired) { diff --git a/src/WSServer.h b/src/WSServer.h index 76e978e3..723f51af 100644 --- a/src/WSServer.h +++ b/src/WSServer.h @@ -30,8 +30,8 @@ with this program. If not, see #include #include "ConnectionProperties.h" - #include "WSRequestHandler.h" +#include "rpc/RpcEvent.h" using websocketpp::connection_hdl; @@ -46,7 +46,7 @@ public: virtual ~WSServer(); void start(quint16 port); void stop(); - void broadcast(std::string message); + void broadcast(const RpcEvent& event); QThreadPool* threadPool() { return &_threadPool; } diff --git a/src/protocol/OBSRemoteProtocol.cpp b/src/protocol/OBSRemoteProtocol.cpp index f0adb7c1..002f0f54 100644 --- a/src/protocol/OBSRemoteProtocol.cpp +++ b/src/protocol/OBSRemoteProtocol.cpp @@ -16,8 +16,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see */ +#include + #include "OBSRemoteProtocol.h" #include "../WSRequestHandler.h" +#include "../rpc/RpcEvent.h" +#include "../Utils.h" std::string OBSRemoteProtocol::processMessage(WSRequestHandler& requestHandler, std::string message) { @@ -56,7 +60,33 @@ std::string OBSRemoteProtocol::processMessage(WSRequestHandler& requestHandler, return std::string(); } -std::string OBSRemoteProtocol::buildResponse(QString messageId, QString status, obs_data_t* fields) { +std::string OBSRemoteProtocol::encodeEvent(const RpcEvent& event) +{ + OBSDataAutoRelease eventData = obs_data_create(); + + OBSData additionalFields = event.fields(); + if (additionalFields) { + obs_data_apply(eventData, additionalFields); + } + + QString updateType = event.updateType(); + obs_data_set_string(eventData, "update-type", updateType.toUtf8().constData()); + + if (obs_frontend_streaming_active()) { + QString streamingTimecode = Utils::nsToTimestamp(event.streamTime()); + obs_data_set_string(eventData, "stream-timecode", streamingTimecode.toUtf8().constData()); + } + + if (obs_frontend_recording_active()) { + QString recordingTimecode = Utils::nsToTimestamp(event.recordingTime()); + obs_data_set_string(eventData, "rec-timecode", recordingTimecode.toUtf8().constData()); + } + + return std::string(obs_data_get_json(eventData)); +} + +std::string OBSRemoteProtocol::buildResponse(QString messageId, QString status, obs_data_t* fields) +{ OBSDataAutoRelease response = obs_data_create(); if (!messageId.isNull()) { obs_data_set_string(response, "message-id", messageId.toUtf8().constData()); @@ -71,11 +101,13 @@ std::string OBSRemoteProtocol::buildResponse(QString messageId, QString status, return responseString; } -std::string OBSRemoteProtocol::successResponse(QString messageId, obs_data_t* fields) { +std::string OBSRemoteProtocol::successResponse(QString messageId, obs_data_t* fields) +{ return buildResponse(messageId, "ok", fields); } -std::string OBSRemoteProtocol::errorResponse(QString messageId, QString errorMessage, obs_data_t* additionalFields) { +std::string OBSRemoteProtocol::errorResponse(QString messageId, QString errorMessage, obs_data_t* additionalFields) +{ OBSDataAutoRelease fields = obs_data_create(); if (additionalFields) { obs_data_apply(fields, additionalFields); diff --git a/src/protocol/OBSRemoteProtocol.h b/src/protocol/OBSRemoteProtocol.h index 6df77fac..03d8aa7d 100644 --- a/src/protocol/OBSRemoteProtocol.h +++ b/src/protocol/OBSRemoteProtocol.h @@ -23,11 +23,13 @@ with this program. If not, see #include class WSRequestHandler; +class RpcEvent; class OBSRemoteProtocol { public: std::string processMessage(WSRequestHandler& requestHandler, std::string message); + std::string encodeEvent(const RpcEvent& event); private: std::string buildResponse(QString messageId, QString status, obs_data_t* fields = nullptr); diff --git a/src/rpc/RpcEvent.cpp b/src/rpc/RpcEvent.cpp new file mode 100644 index 00000000..488aaaf2 --- /dev/null +++ b/src/rpc/RpcEvent.cpp @@ -0,0 +1,47 @@ +/* +obs-websocket +Copyright (C) 2016-2020 Stéphane Lepin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see +*/ + +#include "RpcEvent.h" + +RpcEvent::RpcEvent(const QString& updateType, uint64_t streamTime, uint64_t recordingTime, obs_data_t* fields) : + _updateType(updateType), + _streamTime(streamTime), + _recordingTime(recordingTime), + _fields(fields) +{ +} + +const QString& RpcEvent::updateType() const +{ + return _updateType; +} + +const uint64_t RpcEvent::streamTime() const +{ + return _streamTime; +} + +const uint64_t RpcEvent::recordingTime() const +{ + return _recordingTime; +} + +const OBSData RpcEvent::fields() const +{ + return OBSData(_fields); +} \ No newline at end of file diff --git a/src/rpc/RpcEvent.h b/src/rpc/RpcEvent.h new file mode 100644 index 00000000..b1deee67 --- /dev/null +++ b/src/rpc/RpcEvent.h @@ -0,0 +1,45 @@ +/* +obs-websocket +Copyright (C) 2016-2020 Stéphane Lepin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see +*/ + +#pragma once + +#include +#include + +#include "../obs-websocket.h" + +class RpcEvent +{ +public: + explicit RpcEvent( + const QString& updateType, + uint64_t streamTime, uint64_t recordingTime, + obs_data_t* fields = nullptr + ); + + const QString& updateType() const; + const uint64_t streamTime() const; + const uint64_t recordingTime() const; + const OBSData fields() const; + +private: + QString _updateType; + uint64_t _streamTime; + uint64_t _recordingTime; + OBSDataAutoRelease _fields; +};