Skip to content

Commit

Permalink
Added scene switcher, added main thread execution loop, added screens…
Browse files Browse the repository at this point in the history
…hot trigger, fixed issue where message was being deleted before child classes could parse it, fixed issue where quantizer would add unnecessary bytes if the current value was already fine
  • Loading branch information
benaclejames committed Aug 11, 2022
1 parent 7c6bd9e commit b955415
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 22 deletions.
111 changes: 104 additions & 7 deletions obsc.cpp
Original file line number Diff line number Diff line change
@@ -1,41 +1,80 @@
#include <obs-module.h>
#include <obs-frontend-api.h>
#include <thread>
#include <functional>
#include <queue>
#include <mutex>

#include "stored.h"
#include "socket_helper.h"
#include "osc_message.h"


OBS_DECLARE_MODULE()

typedef std::function<void(void)> task_t;
std::queue<task_t> tasks;
std::mutex tasks_mutex;

socket_helper* sockets;
stored stored;
stored stored_data;

void update_osc()
{
osc_message* currentMessage = new osc_bool_message((char*)"/recording", stored.get_recording_active());
// Are we recording?
osc_message* currentMessage = new osc_bool_message((char*)"/avatar/parameters/OBSRecordToggle", stored_data.get_recording_active());
sockets->send(currentMessage->message, currentMessage->writerIndex);

// Are we streaming?
currentMessage = new osc_bool_message((char*)"/avatar/parameters/OBSStreamToggle", stored_data.get_streaming_active());
sockets->send(currentMessage->message, currentMessage->writerIndex);

currentMessage = new osc_bool_message((char*)"/streaming", stored.get_streaming_active());
// Is replay buffer currently recording?
currentMessage = new osc_bool_message((char*)"/avatar/parameters/OBSReplayBufferToggle", stored_data.get_replay_buffer_active());
sockets->send(currentMessage->message, currentMessage->writerIndex);

currentMessage = new osc_int_message((char*)"/replaybuffer", stored.get_replay_buffer_save_count());
// How many times has the replay buffer been saved?
currentMessage = new osc_int_message((char*)"/avatar/parameters/OBSReplayBufferSaveCount", stored_data.get_replay_buffer_save_count());
sockets->send(currentMessage->message, currentMessage->writerIndex);

// What index is the scene currently at?
float sceneIndex = stored_data.get_scene_index() / 100.0f;
currentMessage = new osc_float_message((char*)"/avatar/parameters/OBSSceneSwitchSelector", sceneIndex);
sockets->send(currentMessage->message, currentMessage->writerIndex);
}

void handle_scene_switch(int newSceneIndex) {
if (stored_data.get_scene_index() == newSceneIndex)
return;

if (stored_data.sceneList.sources.array != nullptr && stored_data.sceneList.sources.num > newSceneIndex) {
obs_source_t *source = stored_data.sceneList.sources.array[newSceneIndex];
if (source != nullptr)
obs_frontend_set_current_scene(source);
}
else { // We're out of range, relay this info back to the client
float sceneIndex = stored_data.get_scene_index() / 100.0f;
osc_message* currentMessage = new osc_float_message((char*)"/avatar/parameters/OBSSceneSwitchSelector", sceneIndex);
sockets->send(currentMessage->message, currentMessage->writerIndex);
}
}

void frontend_cb(enum obs_frontend_event event, void *priv_data)
{
blog(LOG_INFO, "frontend_cb: %d", event);
switch (event)
{
case OBS_FRONTEND_EVENT_RECORDING_STARTED:
case OBS_FRONTEND_EVENT_RECORDING_STOPPED:
case OBS_FRONTEND_EVENT_STREAMING_STARTED:
case OBS_FRONTEND_EVENT_STREAMING_STOPPED:
case OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTED:
case OBS_FRONTEND_EVENT_REPLAY_BUFFER_STOPPED:
case OBS_FRONTEND_EVENT_SCENE_CHANGED:
update_osc();
break;

case OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED:
stored.increment_save_count();
stored_data.increment_save_count();
update_osc();
break;

Expand All @@ -46,14 +85,72 @@ void frontend_cb(enum obs_frontend_event event, void *priv_data)
}

void on_update_recv(osc_message message) {
blog(LOG_INFO, "Received update message for address %s", message.address);

if (strcmp(message.address, "/avatar/change") == 0)
update_osc();

if (strcmp(message.address, "/avatar/parameters/OBSRecordToggle") == 0) {
if (message.type == 'T' && !stored_data.get_recording_active()) {
obs_frontend_recording_start();
blog(LOG_INFO, "Recording started");
} else if (message.type == 'F' && stored_data.get_recording_active()) {
obs_frontend_recording_stop();
blog(LOG_INFO, "Recording stopped");
}
}

if (strcmp(message.address, "/avatar/parameters/OBSStreamToggle") == 0) {
if (message.type == 'T' && !stored_data.get_streaming_active())
obs_frontend_streaming_start();
else if (message.type == 'F' && stored_data.get_streaming_active())
obs_frontend_streaming_stop();
}

if (strcmp(message.address, "/avatar/parameters/OBSReplayBufferToggle") == 0) {
if (message.type == 'T' && !stored_data.get_replay_buffer_active())
obs_frontend_replay_buffer_start();
else if (message.type == 'F' && stored_data.get_replay_buffer_active())
obs_frontend_replay_buffer_stop();
}

if (strcmp(message.address, "/avatar/parameters/OBSReplayBufferCapture") == 0 && message.type == 'T')
obs_frontend_replay_buffer_save();

if (strcmp(message.address, "/avatar/parameters/OBSScreenshotCapture") == 0 && message.type == 'T')
obs_frontend_take_screenshot();

if (strcmp(message.address, "/avatar/parameters/OBSSceneSwitchSelector") == 0 && message.type == 'f') {
// We'll have to read the value from the message
osc_float_message* intMessage = (osc_float_message*)&message;
int newSceneIndex = intMessage->parse()*100;
blog(LOG_INFO, "Switching to scene %d", newSceneIndex);
std::unique_lock<std::mutex> lock(tasks_mutex);
task_t task = [newSceneIndex]() {
handle_scene_switch(newSceneIndex);
};
tasks.push(task);
}
}

void update_loop(void* data, float seconds) {
while(!tasks.empty()) {
auto task = tasks.front();
tasks.pop();
task();
}
}

bool obs_module_load()
{
obs_frontend_source_list sceneList = {};
obs_frontend_get_scenes(&sceneList);
// Log how many scenes we have
blog(LOG_INFO, "There are %d scenes", sceneList.sources.num);

sockets = new socket_helper("127.0.0.1", 9001, 9000, on_update_recv);


obs_add_tick_callback(update_loop, &stored_data);
obs_frontend_add_event_callback(frontend_cb, nullptr);

return true;
Expand Down
33 changes: 24 additions & 9 deletions osc_message.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "osc_message.h"
#include <util/base.h>
#include "osc_message.h"

osc_message::osc_message(char* address, char type) : address(address), type(type)
{
Expand All @@ -14,21 +15,21 @@ osc_message::osc_message(char* address, char type) : address(address), type(type

osc_message::osc_message(char* data, int size)
{
memcpy(message, data, size);

// Read the address string
int len = strlen(data)+1;
int len = strlen(message)+1;
address = new char[len];
memcpy(address, data, len);

memcpy(address, message, len);
// Offset the writerIndex by the address length quantized to 4 bytes
writerIndex = quantize(len, 4);

// Ensure the next 2 bytes are a comma and the type
if (data[writerIndex++] != ',') {
throw "Invalid OSC message";
if (message[writerIndex++] != ',') {
blog(LOG_ERROR, "[OBSC] Expected comma after address");
}

type = data[writerIndex++];
writerIndex += 2;
type = message[writerIndex++];
writerIndex += 2; // Skip the two null bytes
}

osc_float_message::osc_float_message(char* address, float value): osc_message(address, 'f')
Expand All @@ -39,6 +40,13 @@ osc_float_message::osc_float_message(char* address, float value): osc_message(ad
writerIndex += sizeof value;
}

float osc_float_message::parse() {
float value;
memcpy(&value, &message[writerIndex], sizeof value);
swap_endianness((char*)&value, sizeof value);
return value;
}

osc_string_message::osc_string_message(char* address, char* value) : osc_message(address, 's')
{
int len = strlen(value)+1;
Expand All @@ -54,3 +62,10 @@ osc_int_message::osc_int_message(char* address, int value) : osc_message(address
memcpy(&message[writerIndex], bytes, sizeof value);
writerIndex += sizeof value;
}

int osc_int_message::parse() {
int value;
memcpy(&value, &message[writerIndex], sizeof value);
swap_endianness((char*)&value, sizeof value);
return value;
}
7 changes: 6 additions & 1 deletion osc_message.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ class osc_message
osc_message(char* address, char type);

inline static int quantize(int in, int multiple) {
return in + multiple - in % multiple;
if (in % multiple == 0) {
return in;
}
return in + multiple - (in % multiple);
}

inline static void swap_endianness(char* inBytes, int size) {
Expand All @@ -31,6 +34,7 @@ class osc_float_message : public osc_message
{
public:
osc_float_message(char* address, float value);
float parse();
};

class osc_string_message : public osc_message
Expand All @@ -42,6 +46,7 @@ class osc_string_message : public osc_message
class osc_int_message : public osc_message {
public:
osc_int_message(char* address, int value);
int parse();
};

class osc_bool_message : public osc_message {
Expand Down
23 changes: 18 additions & 5 deletions stored.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
#pragma once

class stored
struct stored
{
int replay_buffer_save_count = 0;

public:
void increment_save_count() { replay_buffer_save_count++; }
inline void increment_save_count() { replay_buffer_save_count++; }

int get_replay_buffer_save_count() const { return replay_buffer_save_count; }
bool get_recording_active() const { return obs_frontend_recording_active(); }
bool get_streaming_active() const { return obs_frontend_streaming_active(); }
inline int get_replay_buffer_save_count() const { return replay_buffer_save_count; }
inline bool get_recording_active() const { return obs_frontend_recording_active(); }
inline bool get_streaming_active() const { return obs_frontend_streaming_active(); }
inline bool get_replay_buffer_active() const { return obs_frontend_replay_buffer_active(); }
inline int get_scene_index() {
obs_frontend_source_list_free(&sceneList);
obs_frontend_get_scenes(&sceneList);
for (size_t i = 0; i < sceneList.sources.num; i++) {
obs_source_t* source = sceneList.sources.array[i];
if (source == obs_frontend_get_current_scene())
return i;
}
return -1;
}

obs_frontend_source_list sceneList = {};
};

0 comments on commit b955415

Please sign in to comment.