Streamdelay enables streams to have "broadcast delay" for content redaction/filtering. Stream upload is delayed by a customizable duration, allowing a pixelization and audio blocking filter to be applied ahead of sensitive content being broadcast.
Streamdelay accepts an input stream using the SRT protocol (supported by OBS and ffmpeg), and can output to either an SRT or RTMP endpoint (such as twitch.tv or restream.io).
A UI is currently not provided. The streamdelay
package is designed to run as a local service, controlled via its built-in API server. This is meant to be integrated into a larger stream management dashboard, such as streamwall
.
Binaries may be available via the releases page. You will need to install the GStreamer runtime for your platform.
- Ensure you have the buildchain for your platform installed necessary to build binary node modules using node-gyp.
- Install GStreamer. You will need both the runtime and development headers installed.
- Run
npm install
. This will install dependencies and build thenode-gstreamer-superficial
library.
- Copy
example.config.toml
toconfig.toml
and customize to suit your needs. - Configure your streaming software to output to the SRT endpoint specified in
"srtInUri"
. - Run (binary)
streamdelay --config=config.toml
or (development)npm start -- --config=config.toml
. - Start streaming.
Streamdelay runs an HTTP server on the hostname and port you configure.
Requests must either contain:
- a
Streamdelay-API-Key
header equal to theapiKey
value configured - a
?key=API_KEY
query param equal to theapiKey
value configured
All responses are Content-Type: application/json
.
GET /status
returns:
{
isCensored: bool,
isStreamRunning: bool,
startTime: number?,
state: {... full state object ...}
}
The state
object can be matched using xstate
's State.from
constructor:
// Check if the stream is waiting for a connection
State.from(state).matches('stream.running.waiting')
// Check if the stream is connected and rolling
State.from(state).matches('stream.running.started')
// Check if we're in the process of deactivating the censorship mode
State.from(state).matches('censorship.censored.deactivating')
Start / stop the streaming pipeline. When stopped, streamdelay disconnects from its input and output endpoints.
PATCH /status
Content-Type: application/json
{isStreamRunning: false} or {isStreamRunning: true}
returns: same as /status
Set the stream status to censored (redacted) or not. When transitioning from censored to uncensored status, Streamdelay will wait the configured delaySeconds
before turning off the censored status. This helps prevent early release of the censored mode before the delayed content has been broadcast.
PATCH /status
Content-Type: application/json
{isCensored: false} or {isCensored: true}
returns: same as /status
GET /ws?key=API_KEY
Upgrade: websocket
Upon initial connection, the current status will be sent in JSON format. It will be sent again whenever the status or state changes.
Sending a JSON message has the same behavior as PATCH /status
.