obs_websocket

obs_websocket allows dart-based connections to the OBS (Open Broadcaster Software) plugin obs-websocket


License
MIT

Documentation

obs_websocket

This package gives access to all of the methods and events outlined by the obs-websocket 5.1.0 protocol reference through the send method documented below, but also has helper methods for many of the more popular requests that are made available through the protocol reference.

pub package License: MIT

Build Status github last commit github build github issues

Buy me a coffee

Breaking changes from v2.4.3 (obs-websocket v4.9.1 protocol)

The short answer is that everything has changed. The obs-websocket v5.1.0 protocol is very different from the older v4.9.1 protocol. Any code written for the v4.9.1 protocol needs to be re-written for v5.x

Getting Started

Requirements

  • The OBS v27.x or above application needs to be installed on a machine reachable on the local network
  • The obs-websocket is included with OBS in current versions.

In your project add the dependency:

dependencies:
  ...
  obs_websocket: ^5.1.0+6

For help getting started with dart, check out these guides.

Usage Example

Import the websocket connection library and the response library.

import 'package:obs_websocket/obs_websocket.dart';

Opening a websocket Connection

The WebSocket protocol, described in the specification RFC 6455 provides a way to exchange data between client and server via a persistent connection. The data can be passed in both directions as “packets”.

Before a websocket connection can be made to a running instance of OBS, you will need to have the obs-websocket plugin installed and configured. The instruction and links to downloaded and install are available on the project Release page.

To open a websocket connection, we need to create new ObsWebSocket using the special protocol ws in the url:

final obsWebSocket =
    await ObsWebSocket.connect('ws://[obs-studio host ip]:[port]', password: '[password]');

obs-studio host ip - is the ip address or host name of the OBS device running obs-websocket protocol v5.0.0 that wou would like to send remote control commands to.

port is the port number used to connect to the OBS device running obs-websocket protocol v5.0.0

password - is the password configured for obs-websocket.

These settings are available to change and review through the OBS user interface by clicking Tools, obs-websocket Settings.

Authenticating to OBS

If a password is supplied to the connect method, authentication will occur automatically assuming that it is enabled for OBS.

Sending Commands to OBS

The available commands/requests are documented on the protocol page of the obs-websocket github page. Note that not all commands listed on the protocol page have been implemented in code at this time. For any command not yet implemented, refer to the low-level method of sending commands, documented below.

final status = await obs.stream.status;

// or this works too
// final status = await obs.stream.getStreamStatus();

if (!status.outputActive) {
  await obsWebSocket.stream.start();
}

Supported high-level commands

For any of the items that have an [x] from the list below, a high level helper command is available for that operation, i.e. obsWebSocket.general.version or obsWebSocket.general.getVersion(). Otherwise a low-level command can be used to perform the operation, i.e. obsWebSocket.send('GetVersion').

Supported Requests

Helper methods

browserEvent

A custom helper method that wraps CallVendorRequest, and can be used to send data to the obs-browser plugin.

await obsWebSocket.general.obsBrowserEvent(
  eventName: 'obs-websocket-test-event',
  eventData: {
    'my': 'data',
    'that': 'will be displayed in an event',
  },
);

The Dart code above will send an event to the obs-browser plugin. By including the Javascript shown below in a page referenced by the plugin, that page can receive and react to events generated by Dart code.

window.addEventListener('obs-websocket-test-event', function(event) {
  console.log(event); //  {"my":"data","that":"will be displayed in an event"}
});

Sending Commands to OBS - low level

Alternatively, there is a low-level interface for sending commands. This can be used in place of the above, or in the case that a specific documented Request has not been implemented as a helper method yet. The available commands are documented on the protocol page of the obs-websocket github page

var response = await obsWebSocket.send('GetStreamStatus');

print('request status: ${response?.requestStatus.code}'); // 100 - for success

print('is streaming: ${response?.responseData?['outputActive']}'); // false - if not currently streaming

response?.requestStatus.result will be true on success. response?.requestStatus.code will give a response code that is explained in the RequestStatus portion of the protocol documentation.

response?.requestStatus.comment will sometimes give additional information about errors that might be generated.

Dealing with a list in the responseData.

var response = await obs.send('GetSceneList');

var scenes = response?.responseData?['scenes'];

scenes.forEach(
    (scene) => print('${scene['sceneName']} - ${scene['sceneIndex']}'));

Additionally you can provide arguments with a command:

response = await obs.send('GetVideoSettings');

var newSettings =
    Map<String, dynamic>.from(response?.responseData as Map<String, dynamic>);

newSettings.addAll({
  'baseWidth': 1440,
  'baseHeight': 1080,
  'outputWidth': 1440,
  'outputHeight': 1080
});

// send the settings as an additional parameter.
await obs.send('SetVideoSettings', newSettings);

Events

Events generated by OBS through the websocket can be hooked into by supplying an event listener in the form of addHandler<T>(Function handler). In the sample code below a hook is created that waits for a SceneItemEnableStateChanged event. If the specified SceneItem is visible the code hides the SceneItem after 13 seconds. This code from the show_scene_item.dart example could be used in a cron job to show and then hide an OBS SceneItem periodically.

final obsWebSocket = await ObsWebSocket.connect(config['host'], password: config['password']);

// sceneItem to show/hide
final sceneItem = 'ytBell';

// tell obsWebSocket to listen to events, since the default is to ignore them
await obsWebSocket.listen(EventSubscription.all.code);

// get the current scene
final currentScene = await obsWebSocket.scenes.getCurrentProgramScene();

// get the id of the required sceneItem
final sceneItemId = await obsWebSocket.sceneItems.getSceneItemId(SceneItemId(
  sceneName: currentScene,
  sourceName: sceneItem,
));

// this handler will only run when a SceneItemEnableStateChanged event is generated
obsWebSocket.addHandler<SceneItemEnableStateChanged>(
    (SceneItemEnableStateChanged sceneItemEnableStateChanged) async {
  print(
      'event: ${sceneItemEnableStateChanged.sceneName} ${sceneItemEnableStateChanged.sceneItemEnabled}');

  // make sure we have the correct sceneItem and that it's currently visible
  if (sceneItemEnableStateChanged.sceneName == currentScene &&
      sceneItemEnableStateChanged.sceneItemEnabled) {
    // wait 13 seconds
    await Future.delayed(Duration(seconds: 13));

    // hide the sceneItem
    await obsWebSocket.sceneItems.setSceneItemEnabled(SceneItemEnableStateChanged(
        sceneName: currentScene,
        sceneItemId: sceneItemId,
        sceneItemEnabled: false));

    // close the socket when complete
    await obsWebSocket.close();
  }
});

// get the current state of the sceneItem
final sceneItemEnabled =
    await obsWebSocket.sceneItems.getSceneItemEnabled(SceneItemEnabled(
  sceneName: currentScene,
  sceneItemId: sceneItemId,
));

// if the sceneItem is hidden, show it
if (!sceneItemEnabled) {
  await obsWebSocket.sceneItems.setSceneItemEnabled(SceneItemEnableStateChanged(
      sceneName: currentScene,
      sceneItemId: sceneItemId,
      sceneItemEnabled: true));
}

Supported Events for addHandler<T>

Handling events not yet supported

You can supply a fallbackEvent to the ObsWebSocket constructor to handle events that are not yet supported directly in the code. The following code snippet provides an example of this.

final obs = await ObsWebSocket.connect(
  'ws://[obs-studio host ip]:4455',
  password: '[password]',
  fallbackEventHandler: (Event event) =>
      print('type: ${event.eventType} data: ${event.eventData}'),
);

// tell obsWebSocket to listen to events, since the default is to ignore them
await obsWebSocket.listen(EventSubscription.all);

Closing the websocket

Finally before your code completes, you will should close the websocket connection. Failing to close the connection can lead to unexpected performance related issues for your OBS instance.

obsWebSocket.close();

obs_websocket cli (OBS at the command prompt)

A command line interface for controlling an OBS with cli commands

Please see the cli documentation README.md for more detailed usage information.

Install using dart pub:

dart pub global activate easy_obs_websocket

Install using brew:

brew tap faithoflifedev/obs_websocket
brew install obs

Run the following command to see help:

obs --help

Result,

A command line interface for controlling OBS.

Usage: obs <command> [arguments]

Global options:
-h, --help                        Print this usage information.
-u, --uri=<ws://[host]:[port]>    The url and port for OBS websocket
-t, --timeout=<int>               The timeout in seconds for the web socket connection.
-l, --log-level                   [all, debug, info, warning, error, off (default)]
-p, --passwd=<string>             The OBS websocket password, only required if enabled in OBS

Available commands:
  authorize     Generate an authentication file for an OBS connection
  config        Config Requests
  general       General commands
  listen        Generate OBS events to stdout
  scene-items   Scene Items Requests
  send          Send a low-level websocket request to OBS
  sources       Commands that manipulate OBS sources
  stream        Commands that manipulate OBS streams
  ui            Commands that manipulate the OBS user interface.
  version       Display the package name and version

Contributors

Contributing

Any help from the open-source community is always welcome and needed:

  • Found an issue?
    • Please fill a bug report with details.
  • Need a feature?
    • Open a feature request with use cases.
  • Are you using and liking the project?
    • Promote the project: create an article or post about it
    • Make a donation
  • Do you have a project that uses this package
    • let's cross promote, let me know and I'll add a link to your project
  • Are you a developer?
    • Fix a bug and send a pull request.
    • Implement a new feature.
    • Improve the Unit Tests.
  • Have you already helped in any way?
    • Many thanks from me, the contributors and everybody that uses this project!

If you donate 1 hour of your time, you can contribute a lot, because others will do the same, just be part and start with your 1 hour.