No internet connection
  1. Home
  2. How to

How to remote control OBS

By Christian Scheuer @chrscheuer2020-04-10 16:01:42.035Z2020-04-10 21:09:10.094Z

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

  • 11 replies
  1. Another example could be:

    function startStopRecording() {
        sendMessage({ 'request-type': 'StartStopRecording' });
    }
    
    1. Andrew Scheps @Andrew_Scheps
        2020-04-10 19:47:50.505Z

        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)
        
        1. 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.

          1. Andrew Scheps @Andrew_Scheps
              2020-04-10 21:12:42.642Z

              Ok, no worries, I just got excited trying things. I don't really need it.

              1. 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);
                });
                
                1. Andrew Scheps @Andrew_Scheps
                    2020-04-12 16:37:37.404Z

                    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.

                    1. 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 :)

          2. In reply tochrscheuer:
            Andrew Scheps @Andrew_Scheps
              2020-04-10 21:19:54.525Z

              Just posted a bug with OBS and SoundFlow stopping talking to each other.

              1. In reply tochrscheuer:
                Jesper Ankarfeldt @JesperA
                  2021-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'})
                  
                  1. 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.

                    1. Jesper Ankarfeldt @JesperA
                        2021-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