Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add obs-websocket 5.0.0 integration #340

Merged
merged 1 commit into from
Jan 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ set(obs-browser_HEADERS
browser-version.h
deps/json11/json11.hpp
deps/base64/base64.hpp
deps/obs-websocket-api/obs-websocket-api.h
deps/wide-string.hpp
cef-headers.hpp
)
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ Descriptions for these events can be [found here](https://obsproject.com/docs/re
* obsVirtualcamStarted
* obsVirtualcamStopped
* obsExit
* [Any custom event emitted via obs-websocket vendor requests]


### Control OBS
Expand Down Expand Up @@ -346,6 +347,14 @@ window.obsstudio.onActiveChange = function(active) {
};
```

### obs-websocket Vendor
obs-browser includes integration with obs-websocket's Vendor requests. The vendor name to use is `obs-browser`, and available requests are:

- `emit_event` - Takes `event_name` and ?`event_data` parameters. Emits a custom event to all browser sources. To subscribe to events, see [here](#register-for-event-callbacks)
- See [#340](https://github.com/obsproject/obs-browser/pull/340) for example usage.

There are no available vendor events at this time.

## Building

OBS Browser cannot be built standalone. It is built as part of OBS Studio.
Expand Down
3 changes: 3 additions & 0 deletions deps/obs-websocket-api/.clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Language: Cpp
SortIncludes: false
DisableFormat: true
135 changes: 135 additions & 0 deletions deps/obs-websocket-api/obs-websocket-api.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
obs-websocket
Copyright (C) 2016-2021 Stephane Lepin <stephane.lepin@gmail.com>
Copyright (C) 2020-2021 Kyle Manning <tt2468@gmail.com>

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 <https://www.gnu.org/licenses/>
*/

#ifndef _OBS_WEBSOCKET_API_H
#define _OBS_WEBSOCKET_API_H

#include <obs.h>

#define OBS_WEBSOCKET_API_VERSION 1

#ifdef __cplusplus
extern "C" {
#endif

typedef void* obs_websocket_vendor;
typedef void (*obs_websocket_request_callback_function)(obs_data_t*, obs_data_t*, void*);

struct obs_websocket_request_callback {
obs_websocket_request_callback_function callback;
void *priv_data;
};

inline proc_handler_t *ph;

static inline proc_handler_t *obs_websocket_get_ph(void)
{
proc_handler_t *global_ph = obs_get_proc_handler();
assert(global_ph != NULL);

calldata_t cd = {0};
if (!proc_handler_call(global_ph, "obs_websocket_api_get_ph", &cd))
blog(LOG_DEBUG, "Unable to fetch obs-websocket proc handler object. obs-websocket not installed?");
proc_handler_t *ret = (proc_handler_t*)calldata_ptr(&cd, "ph");
calldata_free(&cd);

return ret;
}

static inline bool obs_websocket_run_simple_proc(obs_websocket_vendor vendor, const char *proc_name, calldata_t *cd)
{
if (!ph || !vendor || !proc_name || !strlen(proc_name) || !cd)
return false;

calldata_set_ptr(cd, "vendor", vendor);

proc_handler_call(ph, proc_name, cd);
return calldata_bool(cd, "success");
}

// ALWAYS CALL VIA `obs_module_post_load()` CALLBACK!
// Registers a new "vendor" (Example: obs-ndi)
static inline obs_websocket_vendor obs_websocket_register_vendor(const char *vendor_name)
{
ph = obs_websocket_get_ph();
if (!ph)
return NULL;

calldata_t cd = {0};

calldata_set_string(&cd, "name", vendor_name);

proc_handler_call(ph, "vendor_register", &cd);
obs_websocket_vendor ret = calldata_ptr(&cd, "vendor");
calldata_free(&cd);

return ret;
}

// Registers a new request for a vendor
static inline bool obs_websocket_vendor_register_request(obs_websocket_vendor vendor, const char *request_type, obs_websocket_request_callback_function request_callback, void* priv_data)
{
calldata_t cd = {0};

struct obs_websocket_request_callback cb = {};
cb.callback = request_callback;
cb.priv_data = priv_data;

calldata_set_string(&cd, "type", request_type);
calldata_set_ptr(&cd, "callback", &cb);

bool success = obs_websocket_run_simple_proc(vendor, "vendor_request_register", &cd);
calldata_free(&cd);

return success;
}

// Unregisters an existing vendor request
static inline bool obs_websocket_vendor_unregister_request(obs_websocket_vendor vendor, const char *request_type)
{
calldata_t cd = {0};

calldata_set_string(&cd, "type", request_type);

bool success = obs_websocket_run_simple_proc(vendor, "vendor_request_unregister", &cd);
calldata_free(&cd);

return success;
}

// Does not affect event_data refcount.
// Emits an event under the vendor's name
static inline bool obs_websocket_vendor_emit_event(obs_websocket_vendor vendor, const char *event_name, obs_data_t *event_data)
{
calldata_t cd = {0};

calldata_set_string(&cd, "type", event_name);
calldata_set_ptr(&cd, "data", (void*)event_data);

bool success = obs_websocket_run_simple_proc(vendor, "vendor_event_emit", &cd);
calldata_free(&cd);

return success;
}

#ifdef __cplusplus
}
#endif

#endif
28 changes: 28 additions & 0 deletions obs-browser-plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "browser-config.h"

#include "json11/json11.hpp"
#include "obs-websocket-api/obs-websocket-api.h"
#include "cef-headers.hpp"

#ifdef _WIN32
Expand Down Expand Up @@ -736,6 +737,33 @@ bool obs_module_load(void)
return true;
}

void obs_module_post_load(void)
{
auto vendor = obs_websocket_register_vendor("obs-browser");
if (!vendor)
return;

auto emit_event_request_cb = [](obs_data_t *request_data, obs_data_t *,
void *) {
const char *event_name =
obs_data_get_string(request_data, "event_name");
if (!event_name)
return;

OBSDataAutoRelease event_data =
obs_data_get_obj(request_data, "event_data");
const char *event_data_string =
event_data ? obs_data_get_json(event_data) : "{}";

DispatchJSEvent(event_name, event_data_string, nullptr);
};

if (!obs_websocket_vendor_register_request(
vendor, "emit_event", emit_event_request_cb, nullptr))
blog(LOG_WARNING,
"[obs-browser]: Failed to register obs-websocket request emit_event");
}

void obs_module_unload(void)
{
#ifdef USE_QT_LOOP
Expand Down