From f500f0f29636d42352fc6c114136d8538b49aea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Lepin?= Date: Mon, 17 Oct 2016 01:14:33 +0200 Subject: [PATCH] So tired I can't write a decent commit message --- CMakeLists.txt | 1 + Utils.cpp | 63 +++++++++++++++++++++++++++++++++----------- Utils.h | 4 +++ WSEvents.cpp | 47 ++++++++++++++++++++------------- WSEvents.h | 3 +++ WSRequestHandler.cpp | 54 +++++++++++++++++++++++++++++++++++-- WSRequestHandler.h | 8 +++--- 7 files changed, 142 insertions(+), 38 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 752019af..1f9050ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,7 @@ set(obs-websocket_SOURCES Utils.cpp) set(obs-websocket_HEADERS + obs-websocket.h WSServer.h WSRequestHandler.h WSEvents.h diff --git a/Utils.cpp b/Utils.cpp index 4658125d..d545231a 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -1,30 +1,63 @@ #include "Utils.h" -obs_data_array_t* Utils::GetSceneItems(obs_source_t *source) { - obs_data_array *items = obs_data_array_create(); - obs_scene *scene = obs_scene_from_source(source); +bool enum_scene_items(obs_scene_t *scene, obs_sceneitem_t *currentItem, void *param) { + obs_data_array_t *data = static_cast(param); + obs_data_array_push_back(data, Utils::GetSceneItemData(currentItem)); + return true; +} - /*obs_scene_item *currentItem = scene->first_item; - while (currentItem != NULL) { - obs_data_array_push_back(items, GetSceneItemData(currentItem)); - currentItem = currentItem->next; - }*/ +obs_data_array_t* Utils::GetSceneItems(obs_source_t *source) { + obs_data_array_t *items = obs_data_array_create(); + obs_scene_t *scene = obs_scene_from_source(source); + + obs_scene_enum_items(scene, enum_scene_items, items); return items; } -obs_data_t* Utils::GetSceneItemData(obs_scene_item *item) { +obs_data_t* Utils::GetSceneItemData(obs_sceneitem_t *item) { if (!item) { return NULL; } + vec2 pos; + obs_sceneitem_get_pos(item, &pos); + + vec2 bounds; + obs_sceneitem_get_bounds(item, &bounds); + obs_data_t *data = obs_data_create(); - /*obs_data_set_string(data, "name", obs_source_get_name(item->source)); - obs_data_set_double(data, "x", item->pos.x); - obs_data_set_double(data, "y", item->pos.y); - obs_data_set_double(data, "cx", item->bounds.x); - obs_data_set_double(data, "cy", item->bounds.y); - obs_data_set_bool(data, "render", item->visible);*/ + obs_data_set_string(data, "name", obs_source_get_name(obs_sceneitem_get_source(item))); + obs_data_set_string(data, "type", obs_source_get_id(obs_sceneitem_get_source(item))); + obs_data_set_double(data, "volume", obs_source_get_volume(obs_sceneitem_get_source(item))); + obs_data_set_double(data, "x", pos.x); + obs_data_set_double(data, "y", pos.y); + obs_data_set_double(data, "cx", bounds.x); + obs_data_set_double(data, "cy", bounds.y); + obs_data_set_bool(data, "render", obs_sceneitem_visible(item)); return data; +} + +obs_data_array_t* Utils::GetScenes() { + obs_frontend_source_list sceneList = {}; + obs_frontend_get_scenes(&sceneList); + + obs_data_array_t* scenes = obs_data_array_create(); + for (size_t i = 0; i < (&sceneList)->sources.num; i++) { + obs_source_t* scene = (&sceneList)->sources.array[i]; + obs_data_array_push_back(scenes, GetSceneData(scene)); + } + + obs_frontend_source_list_free(&sceneList); + + return scenes; +} + +obs_data_t* Utils::GetSceneData(obs_source *source) { + obs_data_t* sceneData = obs_data_create(); + obs_data_set_string(sceneData, "name", obs_source_get_name(source)); + obs_data_set_array(sceneData, "sources", GetSceneItems(source)); + + return sceneData; } \ No newline at end of file diff --git a/Utils.h b/Utils.h index 27ac7ae8..7c340f13 100644 --- a/Utils.h +++ b/Utils.h @@ -2,12 +2,16 @@ #define UTILS_H #include +#include class Utils { public: static obs_data_array_t* GetSceneItems(obs_source_t* source); static obs_data_t* GetSceneItemData(obs_scene_item *item); + + static obs_data_array_t* GetScenes(); + static obs_data_t* GetSceneData(obs_source *source); }; #endif // UTILS_H \ No newline at end of file diff --git a/WSEvents.cpp b/WSEvents.cpp index 3fab24a9..f43dc2ab 100644 --- a/WSEvents.cpp +++ b/WSEvents.cpp @@ -5,7 +5,7 @@ WSEvents::WSEvents(WSServer *server) { obs_frontend_add_event_callback(WSEvents::FrontendEventHandler, this); QTimer *statusTimer = new QTimer(); - connect(statusTimer, SIGNAL(timeout()), this, SLOT(StreamStatus)); + connect(statusTimer, SIGNAL(timeout()), this, SLOT(StreamStatus())); statusTimer->start(1000); } @@ -17,9 +17,14 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void *private { WSEvents *owner = static_cast(private_data); + // TODO : implement SourceChanged, SourceOrderChanged and RepopulateSources + if (event == OBS_FRONTEND_EVENT_SCENE_CHANGED) { owner->OnSceneChange(); } + else if (event == OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED) { + owner->OnSceneListChange(); + } else if (event == OBS_FRONTEND_EVENT_STREAMING_STARTING) { owner->OnStreamStarting(); } @@ -44,6 +49,9 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void *private else if (event == OBS_FRONTEND_EVENT_RECORDING_STOPPED) { owner->OnRecordingStopped(); } + else if (event == OBS_FRONTEND_EVENT_EXIT) { + owner->OnExit(); + } } void WSEvents::broadcastUpdate(const char *updateType, obs_data_t *additionalFields = NULL) { @@ -77,6 +85,10 @@ void WSEvents::OnSceneChange() { obs_source_release(source); } +void WSEvents::OnSceneListChange() { + broadcastUpdate("ScenesChanged"); +} + void WSEvents::OnStreamStarting() { // Implements an existing update type from bilhamil's OBS Remote obs_data_t *data = obs_data_create(); @@ -130,22 +142,21 @@ void WSEvents::OnRecordingStopped() { broadcastUpdate("RecordingStopped"); } -// TODO : Add a timer to trigger StreamStatus -void WSEvents::StreamStatus() { - blog(LOG_INFO, "top StreamStatus"); +void WSEvents::OnExit() { + // New update type specific to OBS Studio + broadcastUpdate("Exiting"); +} +void WSEvents::StreamStatus() { bool streamingActive = obs_frontend_streaming_active(); bool recordingActive = obs_frontend_recording_active(); obs_output_t *streamOutput = obs_frontend_get_streaming_output(); - if (!streamOutput) { - blog(LOG_INFO, "not this time. no stream output running."); + if (!streamOutput || !streamingActive || !recordingActive) { return; } - uint64_t bytesPerSec = 0; - uint64_t bytesSent = obs_output_get_total_bytes(streamOutput); uint64_t bytesSentTime = os_gettime_ns(); @@ -160,22 +171,22 @@ void WSEvents::StreamStatus() { double timePassed = double(bytesSentTime - _lastBytesSentTime) / 1000000000.0; uint64_t bitsPerSec = bitsBetween / timePassed; - bytesPerSec = bitsPerSec / 8; + uint64_t bytesPerSec = bitsPerSec / 8; - uint64_t totalStreamTime = (os_gettime_ns() - _streamStartTime); // TODO : convert to seconds - - uint64_t droppedFrames = obs_output_get_frames_dropped(streamOutput); - uint64_t totalFrames = obs_output_get_total_frames(streamOutput); + _lastBytesSent = bytesSent; + _lastBytesSentTime = bytesSentTime; + + uint64_t totalStreamTime = (os_gettime_ns() - _streamStartTime) / 1000000000; obs_data_t *data = obs_data_create(); obs_data_set_bool(data, "streaming", streamingActive); - obs_data_set_bool(data, "recording", recordingActive); // New in OBS Studio + obs_data_set_bool(data, "recording", recordingActive); obs_data_set_bool(data, "preview-only", false); // Retrocompat with OBSRemote - obs_data_set_int(data, "bytes-per-sec", bytesPerSec); - obs_data_set_double(data, "strain", 0.0); // TODO + obs_data_set_int(data, "bytes-per-sec", bytesPerSec); // BUG : Computation seems buggy + obs_data_set_double(data, "strain", 0.0); // dafuq is strain obs_data_set_int(data, "total-stream-time", totalStreamTime); - obs_data_set_int(data, "num-total-frames", totalFrames); - obs_data_set_int(data, "num-dropped-frames", droppedFrames); + obs_data_set_int(data, "num-total-frames", obs_output_get_total_frames(streamOutput)); + obs_data_set_int(data, "num-dropped-frames", obs_output_get_frames_dropped(streamOutput)); obs_data_set_double(data, "fps", obs_get_active_fps()); broadcastUpdate("StreamStatus", data); diff --git a/WSEvents.h b/WSEvents.h index d843877d..18192c5c 100644 --- a/WSEvents.h +++ b/WSEvents.h @@ -27,6 +27,7 @@ class WSEvents : public QObject void broadcastUpdate(const char *updateType, obs_data_t *additionalFields); void OnSceneChange(); + void OnSceneListChange(); void OnStreamStarting(); void OnStreamStarted(); @@ -37,6 +38,8 @@ class WSEvents : public QObject void OnRecordingStarted(); void OnRecordingStopping(); void OnRecordingStopped(); + + void OnExit(); }; #endif // WSEVENTS_H \ No newline at end of file diff --git a/WSRequestHandler.cpp b/WSRequestHandler.cpp index 0a353ce2..aa05d0c4 100644 --- a/WSRequestHandler.cpp +++ b/WSRequestHandler.cpp @@ -1,11 +1,17 @@ #include "WSRequestHandler.h" +#include "obs-websocket.h" +#include "Utils.h" WSRequestHandler::WSRequestHandler(QWebSocket *client) { _client = client; + messageMap["GetVersion"] = WSRequestHandler::HandleGetVersion; + messageMap["GetAuthRequired"] = WSRequestHandler::HandleGetAuthRequired; + messageMap["Authenticate"] = WSRequestHandler::HandleAuthenticate; + messageMap["SetCurrentScene"] = WSRequestHandler::HandleSetCurrentScene; messageMap["GetCurrentScene"] = WSRequestHandler::HandleGetCurrentScene; - messageMap["GetSceneList"] = WSRequestHandler::ErrNotImplemented; + messageMap["GetSceneList"] = WSRequestHandler::HandleGetSceneList; messageMap["SetSourceOrder"] = WSRequestHandler::ErrNotImplemented; messageMap["SetSourceRender"] = WSRequestHandler::ErrNotImplemented; messageMap["SetSceneItemPositionAndSize"] = WSRequestHandler::ErrNotImplemented; @@ -69,6 +75,41 @@ void WSRequestHandler::SendErrorResponse(const char *errorMessage) { obs_data_release(response); } +void WSRequestHandler::HandleGetVersion(WSRequestHandler *owner) { + obs_data_t *data = obs_data_create(); + obs_data_set_double(data, "version", OBS_WEBSOCKET_VERSION); + + owner->SendOKResponse(data); + + obs_data_release(data); +} + +void WSRequestHandler::HandleGetAuthRequired(WSRequestHandler *owner) { + bool authRequired = false; // Auth isn't implemented yet + + obs_data_t *data = obs_data_create(); + obs_data_set_bool(data, "authRequired", authRequired); + if (authRequired) { + // Just here for protocol doc + obs_data_set_string(data, "challenge", ""); + obs_data_set_string(data, "salt", ""); + } + + owner->SendOKResponse(data); + + obs_data_release(data); +} + +void WSRequestHandler::HandleAuthenticate(WSRequestHandler *owner) { + const char *auth = obs_data_get_string(owner->_requestData, "auth"); + if (!auth) { + owner->SendErrorResponse("auth not specified!"); + return; + } + + owner->SendOKResponse(); +} + void WSRequestHandler::HandleSetCurrentScene(WSRequestHandler *owner) { const char *sceneName = obs_data_get_string(owner->_requestData, "scene-name"); obs_source_t *source = obs_get_source_by_name(sceneName); @@ -78,7 +119,6 @@ void WSRequestHandler::HandleSetCurrentScene(WSRequestHandler *owner) { owner->SendOKResponse(); } else { - blog(LOG_ERROR, "[obs-websockets] requested scene '%s' doesn't exist !", sceneName); owner->SendErrorResponse("requested scene does not exist"); } @@ -98,6 +138,16 @@ void WSRequestHandler::HandleGetCurrentScene(WSRequestHandler *owner) { obs_source_release(source); } +void WSRequestHandler::HandleGetSceneList(WSRequestHandler *owner) { + obs_data_t *data = obs_data_create(); + obs_data_set_string(data, "current-scene", obs_source_get_name(obs_frontend_get_current_scene())); + obs_data_set_array(data, "scenes", Utils::GetScenes()); + + owner->SendOKResponse(data); + + obs_data_release(data); +} + void WSRequestHandler::HandleGetStreamingStatus(WSRequestHandler *owner) { obs_data_t *data = obs_data_create(); obs_data_set_bool(data, "streaming", obs_frontend_streaming_active()); diff --git a/WSRequestHandler.h b/WSRequestHandler.h index c7785c72..5207837f 100644 --- a/WSRequestHandler.h +++ b/WSRequestHandler.h @@ -4,8 +4,6 @@ #include #include #include -#include "Utils.h" -#include "WSServer.h" class WSRequestHandler { @@ -24,10 +22,14 @@ class WSRequestHandler void SendOKResponse(obs_data_t *additionalFields = NULL); void SendErrorResponse(const char *errorMessage); - static void ErrNotImplemented(WSRequestHandler *owner); + + static void HandleGetVersion(WSRequestHandler *owner); + static void HandleGetAuthRequired(WSRequestHandler *owner); + static void HandleAuthenticate(WSRequestHandler *owner); static void HandleSetCurrentScene(WSRequestHandler *owner); static void HandleGetCurrentScene(WSRequestHandler *owner); + static void HandleGetSceneList(WSRequestHandler *owner); static void HandleGetStreamingStatus(WSRequestHandler *owner); static void HandleStartStopStreaming(WSRequestHandler *owner); static void HandleStartStopRecording(WSRequestHandler *owner);