mirror of
https://github.com/Palakis/obs-websocket.git
synced 2024-08-30 18:12:16 +00:00
Fixes #34
This commit is contained in:
parent
4141983ccd
commit
d1c19382a1
90
PROTOCOL.md
90
PROTOCOL.md
@ -11,8 +11,12 @@ The protocol in general is based on the OBS Remote protocol created by Bill Hami
|
||||
- [Event Types](#event-types)
|
||||
- ["SwitchScenes"](#switchscenes)
|
||||
- ["ScenesChanged"](#sceneschanged)
|
||||
- ["SceneCollectionChanged"](#scenecollectionchanged)
|
||||
- ["SceneCollectionListChanged"](#scenecollectionlistchanged)
|
||||
- ["SwitchTransition"](#switchtransition)
|
||||
- ["TransitionListChanged"](#transitionlistchanged)
|
||||
- ["ProfileChanged"](#profilechanged)
|
||||
- ["ProfileListChanged"](#profilelistchanged)
|
||||
- ["StreamStarting"](#streamstarting)
|
||||
- ["StreamStarted"](#streamstarted)
|
||||
- ["StreamStopping"](#streamstopping)
|
||||
@ -45,6 +49,12 @@ The protocol in general is based on the OBS Remote protocol created by Bill Hami
|
||||
- ["ToggleMute"](#togglemute)
|
||||
- ["SetSceneItemPosition"](#setsceneitemposition)
|
||||
- ["SetSceneItemTransform"](#setsceneitemtransform)
|
||||
- ["SetCurrentSceneCollection"](#setcurrentscenecollection)
|
||||
- ["GetCurrentSceneCollection"](#getcurrentscenecollection)
|
||||
- ["ListSceneCollections"](#listscenecollections)
|
||||
- ["SetCurrentProfile"](#setcurrentprofile)
|
||||
- ["GetCurrentProfile"](#getcurrentprofile)
|
||||
- ["ListProfiles"](#listprofiles)
|
||||
* [Authentication](#authentication)
|
||||
|
||||
## Events
|
||||
@ -67,6 +77,16 @@ The scene list has been modified (Scenes have been added, removed, or renamed).
|
||||
|
||||
---
|
||||
|
||||
#### "SceneCollectionChanged"
|
||||
Triggered when switching to another scene collection or when renaming the current scene collection.
|
||||
|
||||
---
|
||||
|
||||
#### "SceneCollectionListChanged"
|
||||
Triggered when a scene collection is created, added, renamed or removed.
|
||||
|
||||
---
|
||||
|
||||
#### "SwitchTransition"
|
||||
The active transition has been changed.
|
||||
- **transition-name** (string) : The name of the active transition.
|
||||
@ -78,6 +98,16 @@ The list of available transitions has been modified (Transitions have been added
|
||||
|
||||
---
|
||||
|
||||
#### "ProfileChanged"
|
||||
Triggered when switching to another profile or when renaming the current profile.
|
||||
|
||||
---
|
||||
|
||||
#### "ProfileListChanged"
|
||||
Triggered when a profile is created, added, renamed or removed.
|
||||
|
||||
---
|
||||
|
||||
#### "StreamStarting"
|
||||
A request to start streaming has been issued.
|
||||
- **preview-only** (bool) : Always false.
|
||||
@ -390,6 +420,66 @@ __Response__ : OK if specified item exists, error otherwise.
|
||||
|
||||
---
|
||||
|
||||
#### "SetCurrentSceneCollection"
|
||||
Change the current scene collection.
|
||||
|
||||
__Request fields__ :
|
||||
- **"sc-name"** (string) : name of the desired scene collection
|
||||
|
||||
__Response__ : OK if scene collection exists, error otherwise.
|
||||
|
||||
---
|
||||
|
||||
#### "GetCurrentSceneCollection"
|
||||
Get the name of the current scene collection.
|
||||
|
||||
__Request fields__ : none
|
||||
|
||||
__Response__ : OK with these additional fields :
|
||||
- **"sc-name"** (string) : name of the current scene collection
|
||||
|
||||
---
|
||||
|
||||
#### "ListSceneCollections"
|
||||
Get a list of available scene collections.
|
||||
|
||||
__Request fields__ : none
|
||||
|
||||
__Response__ : OK with these additional fields :
|
||||
- **"scene-collections"** (array of objects) : names of available scene collections
|
||||
|
||||
---
|
||||
|
||||
#### "SetCurrentProfile"
|
||||
Change the current profile.
|
||||
|
||||
__Request fields__ :
|
||||
- **"profile-name"** (string) : name of the desired profile
|
||||
|
||||
__Response__ : OK if profile exists, error otherwise.
|
||||
|
||||
---
|
||||
|
||||
#### "GetCurrentProfile"
|
||||
Get the name of the current profile.
|
||||
|
||||
__Request fields__ : none
|
||||
|
||||
__Response__ : OK with these additional fields :
|
||||
- **"profile-name"** (string) : name of the current profile
|
||||
|
||||
---
|
||||
|
||||
#### "ListProfiles"
|
||||
Get a list of available profiles.
|
||||
|
||||
__Request fields__ : none
|
||||
|
||||
__Response__ : OK with the additional fields :
|
||||
- **"profiles"** (array of objects) : names of available profiles
|
||||
|
||||
---
|
||||
|
||||
### Authentication
|
||||
A call to `GetAuthRequired` gives the client two elements :
|
||||
- A challenge : a random string that will be used to generate the auth response
|
||||
|
43
Utils.cpp
43
Utils.cpp
@ -18,6 +18,31 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
#include "Utils.h"
|
||||
#include <obs-frontend-api.h>
|
||||
#include "obs-websocket.h"
|
||||
|
||||
obs_data_array_t* string_list_to_array(char** strings, char* key)
|
||||
{
|
||||
if (!strings)
|
||||
return obs_data_array_create();
|
||||
|
||||
obs_data_array_t *list = obs_data_array_create();
|
||||
|
||||
char* value = "";
|
||||
for (int i = 0; value != nullptr; i++)
|
||||
{
|
||||
value = strings[i];
|
||||
|
||||
obs_data_t *item = obs_data_create();
|
||||
obs_data_set_string(item, key, value);
|
||||
|
||||
if (value)
|
||||
obs_data_array_push_back(list, item);
|
||||
|
||||
obs_data_release(item);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
obs_data_array_t* Utils::GetSceneItems(obs_source_t *source) {
|
||||
obs_data_array_t *items = obs_data_array_create();
|
||||
@ -152,6 +177,24 @@ obs_data_t* Utils::GetSceneData(obs_source *source) {
|
||||
return sceneData;
|
||||
}
|
||||
|
||||
obs_data_array_t* Utils::GetSceneCollections()
|
||||
{
|
||||
char** scene_collections = obs_frontend_get_scene_collections();
|
||||
obs_data_array_t *list = string_list_to_array(scene_collections, "sc-name");
|
||||
|
||||
bfree(scene_collections);
|
||||
return list;
|
||||
}
|
||||
|
||||
obs_data_array_t* Utils::GetProfiles()
|
||||
{
|
||||
char** profiles = obs_frontend_get_profiles();
|
||||
obs_data_array_t *list = string_list_to_array(profiles, "profile-name");
|
||||
|
||||
bfree(profiles);
|
||||
return list;
|
||||
}
|
||||
|
||||
const char* Utils::OBSVersionString() {
|
||||
uint32_t version = obs_get_version();
|
||||
|
||||
|
3
Utils.h
3
Utils.h
@ -33,6 +33,9 @@ class Utils
|
||||
static obs_data_array_t* GetScenes();
|
||||
static obs_data_t* GetSceneData(obs_source *source);
|
||||
|
||||
static obs_data_array_t* GetSceneCollections();
|
||||
static obs_data_array_t* GetProfiles();
|
||||
|
||||
static const char* OBSVersionString();
|
||||
};
|
||||
|
||||
|
133
WSEvents.cpp
133
WSEvents.cpp
@ -22,7 +22,8 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
#include "WSEvents.h"
|
||||
|
||||
WSEvents::WSEvents(WSServer *srv) {
|
||||
WSEvents::WSEvents(WSServer *srv)
|
||||
{
|
||||
_srv = srv;
|
||||
obs_frontend_add_event_callback(WSEvents::FrontendEventHandler, this);
|
||||
|
||||
@ -34,7 +35,8 @@ WSEvents::WSEvents(WSServer *srv) {
|
||||
_rec_starttime = 0;
|
||||
}
|
||||
|
||||
WSEvents::~WSEvents() {
|
||||
WSEvents::~WSEvents()
|
||||
{
|
||||
obs_frontend_remove_event_callback(WSEvents::FrontendEventHandler, this);
|
||||
}
|
||||
|
||||
@ -47,49 +49,78 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void *private
|
||||
|
||||
// TODO : implement SourceChanged, SourceOrderChanged and RepopulateSources
|
||||
|
||||
if (event == OBS_FRONTEND_EVENT_SCENE_CHANGED) {
|
||||
if (event == OBS_FRONTEND_EVENT_SCENE_CHANGED)
|
||||
{
|
||||
owner->OnSceneChange();
|
||||
}
|
||||
else if (event == OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED) {
|
||||
else if (event == OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED)
|
||||
{
|
||||
owner->OnSceneListChange();
|
||||
}
|
||||
else if (event == OBS_FRONTEND_EVENT_TRANSITION_CHANGED) {
|
||||
else if (event == OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED)
|
||||
{
|
||||
owner->OnSceneCollectionChange();
|
||||
}
|
||||
else if (event == OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED)
|
||||
{
|
||||
owner->OnSceneCollectionListChange();
|
||||
}
|
||||
else if (event == OBS_FRONTEND_EVENT_TRANSITION_CHANGED)
|
||||
{
|
||||
owner->OnTransitionChange();
|
||||
}
|
||||
else if (event == OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED) {
|
||||
else if (event == OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED)
|
||||
{
|
||||
owner->OnTransitionListChange();
|
||||
}
|
||||
else if (event == OBS_FRONTEND_EVENT_STREAMING_STARTING) {
|
||||
else if (event == OBS_FRONTEND_EVENT_PROFILE_CHANGED)
|
||||
{
|
||||
owner->OnProfileChange();
|
||||
}
|
||||
else if (event == OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED)
|
||||
{
|
||||
owner->OnProfileListChange();
|
||||
}
|
||||
else if (event == OBS_FRONTEND_EVENT_STREAMING_STARTING)
|
||||
{
|
||||
owner->OnStreamStarting();
|
||||
}
|
||||
else if (event == OBS_FRONTEND_EVENT_STREAMING_STARTED) {
|
||||
else if (event == OBS_FRONTEND_EVENT_STREAMING_STARTED)
|
||||
{
|
||||
owner->OnStreamStarted();
|
||||
}
|
||||
else if (event == OBS_FRONTEND_EVENT_STREAMING_STOPPING) {
|
||||
else if (event == OBS_FRONTEND_EVENT_STREAMING_STOPPING)
|
||||
{
|
||||
owner->OnStreamStopping();
|
||||
}
|
||||
else if (event == OBS_FRONTEND_EVENT_STREAMING_STOPPED) {
|
||||
else if (event == OBS_FRONTEND_EVENT_STREAMING_STOPPED)
|
||||
{
|
||||
owner->OnStreamStopped();
|
||||
}
|
||||
else if (event == OBS_FRONTEND_EVENT_RECORDING_STARTING) {
|
||||
else if (event == OBS_FRONTEND_EVENT_RECORDING_STARTING)
|
||||
{
|
||||
owner->OnRecordingStarting();
|
||||
}
|
||||
else if (event == OBS_FRONTEND_EVENT_RECORDING_STARTED) {
|
||||
else if (event == OBS_FRONTEND_EVENT_RECORDING_STARTED)
|
||||
{
|
||||
owner->OnRecordingStarted();
|
||||
}
|
||||
else if (event == OBS_FRONTEND_EVENT_RECORDING_STOPPING) {
|
||||
else if (event == OBS_FRONTEND_EVENT_RECORDING_STOPPING)
|
||||
{
|
||||
owner->OnRecordingStopping();
|
||||
}
|
||||
else if (event == OBS_FRONTEND_EVENT_RECORDING_STOPPED) {
|
||||
else if (event == OBS_FRONTEND_EVENT_RECORDING_STOPPED)
|
||||
{
|
||||
owner->OnRecordingStopped();
|
||||
}
|
||||
else if (event == OBS_FRONTEND_EVENT_EXIT) {
|
||||
obs_frontend_save();
|
||||
else if (event == OBS_FRONTEND_EVENT_EXIT)
|
||||
{
|
||||
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_set_string(update, "update-type", updateType);
|
||||
@ -102,19 +133,22 @@ void WSEvents::broadcastUpdate(const char *updateType, obs_data_t *additionalFie
|
||||
obs_data_release(update);
|
||||
}
|
||||
|
||||
void WSEvents::OnSceneChange() {
|
||||
void WSEvents::OnSceneChange()
|
||||
{
|
||||
// Implements an existing update type from bilhamil's OBS Remote
|
||||
|
||||
// Default behavior : get the new scene from the running transition
|
||||
obs_source_t *transition = obs_frontend_get_current_transition();
|
||||
obs_source_t *new_scene = obs_transition_get_source(transition, OBS_TRANSITION_SOURCE_B);
|
||||
if (!new_scene) {
|
||||
if (!new_scene)
|
||||
{
|
||||
obs_source_release(transition);
|
||||
return;
|
||||
}
|
||||
|
||||
const char *scene_name = obs_source_get_name(new_scene);
|
||||
if (!scene_name) {
|
||||
if (!scene_name)
|
||||
{
|
||||
// Fallback behaviour : get the new scene straight from the API
|
||||
obs_source_release(new_scene);
|
||||
new_scene = obs_frontend_get_current_scene();
|
||||
@ -134,11 +168,23 @@ void WSEvents::OnSceneChange() {
|
||||
obs_source_release(transition);
|
||||
}
|
||||
|
||||
void WSEvents::OnSceneListChange() {
|
||||
void WSEvents::OnSceneListChange()
|
||||
{
|
||||
broadcastUpdate("ScenesChanged");
|
||||
}
|
||||
|
||||
void WSEvents::OnTransitionChange() {
|
||||
void WSEvents::OnSceneCollectionChange()
|
||||
{
|
||||
broadcastUpdate("SceneCollectionChanged");
|
||||
}
|
||||
|
||||
void WSEvents::OnSceneCollectionListChange()
|
||||
{
|
||||
broadcastUpdate("SceneCollectionListChanged");
|
||||
}
|
||||
|
||||
void WSEvents::OnTransitionChange()
|
||||
{
|
||||
obs_source_t *transition = obs_frontend_get_current_transition();
|
||||
const char *transition_name = obs_source_get_name(transition);
|
||||
|
||||
@ -151,11 +197,23 @@ void WSEvents::OnTransitionChange() {
|
||||
obs_source_release(transition);
|
||||
}
|
||||
|
||||
void WSEvents::OnTransitionListChange() {
|
||||
void WSEvents::OnTransitionListChange()
|
||||
{
|
||||
broadcastUpdate("TransitionListChanged");
|
||||
}
|
||||
|
||||
void WSEvents::OnStreamStarting() {
|
||||
void WSEvents::OnProfileChange()
|
||||
{
|
||||
broadcastUpdate("ProfileChanged");
|
||||
}
|
||||
|
||||
void WSEvents::OnProfileListChange()
|
||||
{
|
||||
broadcastUpdate("ProfileListChanged");
|
||||
}
|
||||
|
||||
void WSEvents::OnStreamStarting()
|
||||
{
|
||||
// Implements an existing update type from bilhamil's OBS Remote
|
||||
obs_data_t *data = obs_data_create();
|
||||
obs_data_set_bool(data, "preview-only", false);
|
||||
@ -165,14 +223,16 @@ void WSEvents::OnStreamStarting() {
|
||||
obs_data_release(data);
|
||||
}
|
||||
|
||||
void WSEvents::OnStreamStarted() {
|
||||
void WSEvents::OnStreamStarted()
|
||||
{
|
||||
// New update type specific to OBS Studio
|
||||
_stream_starttime = os_gettime_ns();
|
||||
_lastBytesSent = 0;
|
||||
broadcastUpdate("StreamStarted");
|
||||
}
|
||||
|
||||
void WSEvents::OnStreamStopping() {
|
||||
void WSEvents::OnStreamStopping()
|
||||
{
|
||||
// Implements an existing update type from bilhamil's OBS Remote
|
||||
obs_data_t *data = obs_data_create();
|
||||
obs_data_set_bool(data, "preview-only", false);
|
||||
@ -182,40 +242,47 @@ void WSEvents::OnStreamStopping() {
|
||||
obs_data_release(data);
|
||||
}
|
||||
|
||||
void WSEvents::OnStreamStopped() {
|
||||
void WSEvents::OnStreamStopped()
|
||||
{
|
||||
// New update type specific to OBS Studio
|
||||
_stream_starttime = 0;
|
||||
broadcastUpdate("StreamStopped");
|
||||
}
|
||||
|
||||
void WSEvents::OnRecordingStarting() {
|
||||
void WSEvents::OnRecordingStarting()
|
||||
{
|
||||
// New update type specific to OBS Studio
|
||||
broadcastUpdate("RecordingStarting");
|
||||
}
|
||||
|
||||
void WSEvents::OnRecordingStarted() {
|
||||
void WSEvents::OnRecordingStarted()
|
||||
{
|
||||
// New update type specific to OBS Studio
|
||||
_rec_starttime = os_gettime_ns();
|
||||
broadcastUpdate("RecordingStarted");
|
||||
}
|
||||
|
||||
void WSEvents::OnRecordingStopping() {
|
||||
void WSEvents::OnRecordingStopping()
|
||||
{
|
||||
// New update type specific to OBS Studio
|
||||
broadcastUpdate("RecordingStopping");
|
||||
}
|
||||
|
||||
void WSEvents::OnRecordingStopped() {
|
||||
void WSEvents::OnRecordingStopped()
|
||||
{
|
||||
// New update type specific to OBS Studio
|
||||
_rec_starttime = 0;
|
||||
broadcastUpdate("RecordingStopped");
|
||||
}
|
||||
|
||||
void WSEvents::OnExit() {
|
||||
void WSEvents::OnExit()
|
||||
{
|
||||
// New update type specific to OBS Studio
|
||||
broadcastUpdate("Exiting");
|
||||
}
|
||||
|
||||
void WSEvents::StreamStatus() {
|
||||
void WSEvents::StreamStatus()
|
||||
{
|
||||
bool streaming_active = obs_frontend_streaming_active();
|
||||
bool recording_active = obs_frontend_recording_active();
|
||||
|
||||
|
@ -46,10 +46,15 @@ class WSEvents : public QObject
|
||||
|
||||
void OnSceneChange();
|
||||
void OnSceneListChange();
|
||||
void OnSceneCollectionChange();
|
||||
void OnSceneCollectionListChange();
|
||||
|
||||
void OnTransitionChange();
|
||||
void OnTransitionListChange();
|
||||
|
||||
void OnProfileChange();
|
||||
void OnProfileListChange();
|
||||
|
||||
void OnStreamStarting();
|
||||
void OnStreamStarted();
|
||||
void OnStreamStopping();
|
||||
|
@ -564,7 +564,15 @@ void WSRequestHandler::HandleGetCurrentSceneCollection(WSRequestHandler *owner)
|
||||
|
||||
void WSRequestHandler::HandleListSceneCollections(WSRequestHandler *owner)
|
||||
{
|
||||
// TODO
|
||||
obs_data_array_t *scene_collections = Utils::GetSceneCollections();
|
||||
|
||||
obs_data_t *response = obs_data_create();
|
||||
obs_data_set_array(response, "scene-collections", scene_collections);
|
||||
|
||||
owner->SendOKResponse(response);
|
||||
|
||||
obs_data_release(response);
|
||||
obs_data_array_release(scene_collections);
|
||||
}
|
||||
|
||||
void WSRequestHandler::HandleSetCurrentProfile(WSRequestHandler *owner)
|
||||
@ -595,7 +603,15 @@ void WSRequestHandler::HandleGetCurrentProfile(WSRequestHandler *owner)
|
||||
|
||||
void WSRequestHandler::HandleListProfiles(WSRequestHandler *owner)
|
||||
{
|
||||
// TODO
|
||||
obs_data_array_t *profiles = Utils::GetProfiles();
|
||||
|
||||
obs_data_t *response = obs_data_create();
|
||||
obs_data_set_array(response, "profiles", profiles);
|
||||
|
||||
owner->SendOKResponse(response);
|
||||
|
||||
obs_data_release(response);
|
||||
obs_data_array_release(profiles);
|
||||
}
|
||||
|
||||
void WSRequestHandler::ErrNotImplemented(WSRequestHandler *owner)
|
||||
|
Loading…
x
Reference in New Issue
Block a user