How to remote control OBS
Prerelease information: This requires SoundFlow 3.6
It's possible to remote control the screen recording/broadcasting software OBS.
First, install the newest version of "obs-websocket" from here:
https://github.com/Palakis/obs-websocket/releases
Make sure to choose the mac pkg installer. For a direct link to the 4.7.0 installer that I used to test, click here:
https://github.com/Palakis/obs-websocket/releases/download/4.7.0/obs-websocket-4.7.0-macOS.pkg
Now run the installer. By default it sets up a websocket server to listen on port 4444, but you can change the port in OBS, in the menu Tools -> WebSockets Server Settings. For now just keep it on port 4444.
Now we're ready to run some code.
Here's a script that selects the scene "Scene 2":
function getConnection(port, alwaysReconnect) {
/** @type {AxWebSocketClientConnection} */
var connection = globalState.obsConnection;
if (connection && alwaysReconnect) {
connection.close();
globalState.obsConnection = null;
connection = null;
}
if (!connection) {
connection = sf.net.wsOpenClient({
url: `ws://127.0.0.1:${port}/ws`,
}).connection;
globalState.obsConnection = connection;
}
return connection;
}
function sendMessage(msg) {
var connection = getConnection(4444);
msg['message-id'] = globalState.obsMessageCounter === undefined ? (globalState.obsMessageCounter = 1) : (++globalState.obsMessageCounter);
connection.sendJson({
json: msg
});
}
function selectScene(sceneName) {
sendMessage({
'request-type': 'SetCurrentScene',
'scene-name': sceneName,
})
}
selectScene("Scene 2");
The actual message is sent in selectScene
function.
For a list of all the request types that can be sent, see this reference:
https://github.com/Palakis/obs-websocket/blob/4.x-current/docs/generated/protocol.md#requests
- Christian Scheuer @chrscheuer2020-04-10 16:10:33.991Z
Another example could be:
function startStopRecording() { sendMessage({ 'request-type': 'StartStopRecording' }); }
Andrew Scheps @Andrew_Scheps
I've got it all working sending messages, but I can't quite figure out how to get info back from OBS. The following code gives me an error that sceneName is undefined. It should contain the results of the GetCurrentScene request shouldn't it? I'm assuming it's in a format that needs to be converted. I've tried String() and JSON.stringify() but still the same error.
const OBS = require('package:ck8uk78nd000hma105p2rdzgz'); var sceneName = OBS.sendMessage({ 'request-type': 'GetCurrentScene', }) log(sceneName.name)
Christian Scheuer @chrscheuer2020-04-10 20:26:22.708Z
Hi Andrew.
Currently the script doesn't send back results from messages. If we want that, due to the async nature of websockets, we'll need to use callbacks - I can give you an example.
Andrew Scheps @Andrew_Scheps
Ok, no worries, I just got excited trying things. I don't really need it.
Christian Scheuer @chrscheuer2020-04-10 21:16:59.175Z
Just for completeness, here is an example that also listens for responses:
function getConnection(port, alwaysReconnect) { /** @type {AxWebSocketClientConnection} */ var connection = globalState.obsConnection; var messageHandlers = globalState.obsMessageHandlers = (globalState.obsMessageHandlers || {}); if (connection && alwaysReconnect) { connection.close(); globalState.obsConnection = null; connection = null; } if (!connection) { connection = sf.net.wsOpenClient({ url: `ws://127.0.0.1:${port}/ws`, onMessage: msg => { var msgObj = msg.asJson(); var msgId = msgObj['message-id']; var handler = messageHandlers[msgId]; if (handler) { delete messageHandlers[msgId]; handler(msgObj); } } }).connection; globalState.obsConnection = connection; } return connection; } function sendMessage(msg, callback) { var connection = getConnection(4444); var msgId = globalState.obsMessageCounter === undefined ? (globalState.obsMessageCounter = 1) : (++globalState.obsMessageCounter); msg['message-id'] = 'm' + msgId; if (callback) { globalState.obsMessageHandlers['m' + msgId] = callback; } connection.sendJson({ json: msg }); } function getSceneName(callback) { sendMessage({ 'request-type': 'GetCurrentScene', }, msg => { callback(msg['name']); }); } getSceneName(name => { log('name: ' + name); });
Andrew Scheps @Andrew_Scheps
For some reason this script has stopped working today. Did you change anything in the web socket code? The one way commands are still working.
Christian Scheuer @chrscheuer2020-04-12 16:39:43.367Z
Hm I don't think I changed anything related to this, but we're on fairly untested ground so I may have to do some more debugging here to ensure the stability. I'll be working on stability testing this throughout the week so I'm sure I'll be sending you some more builds to test with :)
- In reply tochrscheuer⬆:Andrew Scheps @Andrew_Scheps
Just posted a bug with OBS and SoundFlow stopping talking to each other.
- In reply tochrscheuer⬆:Jesper Ankarfeldt @JesperA2021-04-23 13:32:37.161Z
is the
sf.net.wsOpenClient
also listening to messages coming in in general or only responses from messages send?I might be using it wrong, but I'm experimenting with Vienna Instrument Pro (VIP), and can see it creates the websocket so VIP is able to be controlled and send it's data, but I only see this message in my log:
when running
sf.net.wsOpenClient({ url: `ws://10.0.111.1:8080/`, onMessage: msg => { log(msg) } }).connection
In terms of sending messages to the socket / VIP I guess I might need to change/transform the string message into bytes or something else (was looking through socket.io-client which I'm currently using for sending messages to VIP and tried to follow the path of information, but was a bit above my level of experience).
At least this doesn't work:sf.net.wsOpenClient({ url: `ws://10.0.111.1:8080/`}).connection.sendText({text: 'SETB'})
Christian Scheuer @chrscheuer2021-04-24 14:08:15.910Z
Let's have a look at this together some time, where we can compare with our nodejs code together. I can't remember exactly how this was set up originally.
Jesper Ankarfeldt @JesperA2021-04-24 16:46:37.191Z
Sure thing. That would be really cool.
It's pretty awesome to see how it instantly connects/creates a websocket. I just need to get that sweet data from it :P- In reply tochrscheuer⬆:
Jesper Ankarfeldt @JesperA2022-03-31 11:01:19.237Z
Yes, finally figured out how to get the info from the Vienna server. Just had to add
.asString()
to the function.
It's so smooth compared having to run a webserver in terminal 😁 Now I just need to run over all commands in the script.sf.net.wsOpenClient({ url: `ws://${url}:${port}/`, onMessage: msg => { log(msg.asString() }, }).connection;
Christian Scheuer @chrscheuer2022-03-31 11:32:47.526Z
Yay!!
- In reply tochrscheuer⬆:
Jesper Ankarfeldt @JesperA2022-04-22 16:38:00.966Z
Gave it another (long) shot to see if I could figure out how to send messages to the WebSocket.
Tried a whole bunch of things, also with nodejs (which I might understand a little bit better now) and the terminal as well.
No luck. But it also seems that even with the old nodejs, it creates some errors and ultimately doesn't connect, so maybe it's something with Monterey and dependencies.The way that the Vienna Player (and the nodejs) seems to send is via socket-io. This is just an outtake of those lines of the script related to sending:
const io = require("socket.io-client"); var wsURL = 'ws://127.0.0.1:8080' wsock = io.connect(wsURL, { 'reconnection limit': 3000, 'max reconnection attempts': Infinity }); wsock.send('SETB')
Can't figure out if what is being send is text or json if I would have to use the build in SF function. Attached the code if that could give some hints.
Would love help one day to figure it out :)
Christian Scheuer @chrscheuer2022-04-23 10:52:32.424Z
Jesper Ankarfeldt @JesperA2022-04-23 11:12:51.164Z
Alright, that could maybe explain some things :)
So maybe I will have to make a solution with something external from SF.Christian Scheuer @chrscheuer2022-04-23 11:19:36.915Z
Yea I think that's the easiest now.
Jesper Ankarfeldt @JesperA2022-04-25 11:26:32.658Z
So awesome. Got it to work with socket.io 0.9.6 which is 10 years old, haha.
Thank you!
- DIn reply tochrscheuer⬆:DeLaVanta Tabor @DeLaVanta_Tabor
Am I reading this correctly that in order for me to control OBS with the StreamDeck, I need to use the StreamDeck App or get a second deck to assign specially to OBS utilizing the StreamDeck OS application, which upon setting up SF was instructed to quit that app and stop it from opening on launch?
Christian Scheuer @chrscheuer2022-05-18 09:29:43.715Z
Hi @DeLaVanta_Tabor,
No, you can just install the OBS package from our Store :) It should have instructions. If you need help setting it up, please use the Script Help feature (bit.ly/sfscripthelp)