mirror of
https://github.com/Palakis/obs-websocket.git
synced 2024-08-30 18:12:16 +00:00
Compare commits
40 Commits
5.0.0-nota
...
5.0.0-beta
Author | SHA1 | Date | |
---|---|---|---|
b02a32ce06 | |||
ce31ed177d | |||
71a32c981c | |||
4440327141 | |||
bbf9c283c0 | |||
9ac7c5890e | |||
a7698a732f | |||
e15b2edb4f | |||
7fade98407 | |||
e0057b05db | |||
aa13828cf5 | |||
db2ffa569a | |||
66c14dced5 | |||
29b2b1bd5d | |||
361547a96d | |||
b3a5c55bef | |||
f76de69b34 | |||
0b294734a2 | |||
7b52d7e015 | |||
9664f28483 | |||
d9070f9edb | |||
559212682a | |||
fa8a091a3e | |||
ab137ce8a4 | |||
5a3bed7d8b | |||
341259e610 | |||
c64e360c2d | |||
7c35d6e738 | |||
b206321b05 | |||
403c69463a | |||
ddf752fd03 | |||
e80bcad1e1 | |||
d2ddde3229 | |||
931a1630ce | |||
5cbc1019ff | |||
14227237d7 | |||
3e2984fd7a | |||
96a2fd8c25 | |||
38d78596ce | |||
13c7b83c34 |
1
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
1
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@ -69,6 +69,7 @@ body:
|
||||
label: obs-websocket Version
|
||||
description: What version of obs-websocket are you using?
|
||||
options:
|
||||
- 5.0.0-beta1
|
||||
- 5.0.0-alpha3
|
||||
- 5.0.0-alpha2
|
||||
- 4.9.1
|
||||
|
34
.github/workflows/main.yml
vendored
34
.github/workflows/main.yml
vendored
@ -5,7 +5,7 @@ on:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
branches:
|
||||
- '*'
|
||||
- master
|
||||
tags:
|
||||
- '[45].[0-9]+.[0-9]+*'
|
||||
pull_request:
|
||||
@ -18,7 +18,7 @@ on:
|
||||
jobs:
|
||||
windows:
|
||||
name: 'Windows 32/64-bit'
|
||||
runs-on: [windows-latest]
|
||||
runs-on: [windows-2019]
|
||||
if: contains(github.event.head_commit.message, '[skip ci]') != true
|
||||
env:
|
||||
QT_CACHE_VERSION: '2' # Change whenever updating OBS dependencies URL, in order to force a cache reset
|
||||
@ -367,6 +367,7 @@ jobs:
|
||||
path: ${{ github.workspace }}/obs-studio
|
||||
submodules: 'recursive'
|
||||
- name: 'Install Prerequisite: Binary Signing Certificate'
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: apple-actions/import-codesign-certs@v1
|
||||
with:
|
||||
p12-file-base64: ${{ secrets.MACOS_SIGNING_CERT }}
|
||||
@ -374,6 +375,7 @@ jobs:
|
||||
create-keychain: true
|
||||
keychain-password: ${{ secrets.MACOS_TEMP_CI_KEYCHAIN_PASSWORD }}
|
||||
- name: 'Install Prerequisite: Installer Signing Certificate'
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: apple-actions/import-codesign-certs@v1
|
||||
with:
|
||||
p12-file-base64: ${{ secrets.MACOS_INSTALLER_CERT }}
|
||||
@ -442,12 +444,12 @@ jobs:
|
||||
mkdir -p ./build
|
||||
cd ./build
|
||||
cmake .. \
|
||||
-DQTDIR=${{ github.workspace }}/obsdeps \
|
||||
-DDepsPath=${{ github.workspace }}/obsdeps \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 \
|
||||
-DDISABLE_PLUGINS=true \
|
||||
-DENABLE_SCRIPTING=0 \
|
||||
-DCMAKE_PREFIX_PATH=${{ github.workspace }}/obsdeps/lib/cmake
|
||||
-DQTDIR=${{ github.workspace }}/obsdeps \
|
||||
-DDepsPath=${{ github.workspace }}/obsdeps \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 \
|
||||
-DDISABLE_PLUGINS=true \
|
||||
-DENABLE_SCRIPTING=0 \
|
||||
-DCMAKE_PREFIX_PATH=${{ github.workspace }}/obsdeps/lib/cmake
|
||||
- name: 'Build OBS Studio'
|
||||
if: steps.cache-obs-build.outputs.cache-hit != 'true'
|
||||
working-directory: ${{ github.workspace }}/obs-studio/build
|
||||
@ -462,13 +464,14 @@ jobs:
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake .. \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 \
|
||||
-DQTDIR=${{ github.workspace }}/obsdeps \
|
||||
-DLIBOBS_INCLUDE_DIR=${{ github.workspace }}/obs-studio/libobs \
|
||||
-DLIBOBS_LIB=${{ github.workspace }}/obs-studio/libobs \
|
||||
-DOBS_FRONTEND_LIB="${{ github.workspace }}/obs-studio/build/UI/obs-frontend-api/libobs-frontend-api.dylib" \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 \
|
||||
-DQTDIR=${{ github.workspace }}/obsdeps \
|
||||
-DLIBOBS_INCLUDE_DIR=${{ github.workspace }}/obs-studio/libobs \
|
||||
-DLIBOBS_LIB=${{ github.workspace }}/obs-studio/libobs \
|
||||
-DOBS_FRONTEND_LIB="${{ github.workspace }}/obs-studio/build/UI/obs-frontend-api/libobs-frontend-api.dylib" \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||
-DOBS_WEBSOCKET_VERSION_SUFFIX="${{ env.CMAKE_VERSION_SUFFIX }}"
|
||||
- name: 'Build obs-websocket'
|
||||
working-directory: ${{ github.workspace }}/obs-websocket/build
|
||||
shell: bash
|
||||
@ -492,6 +495,7 @@ jobs:
|
||||
@executable_path/../Frameworks/QtSvg.framework/Versions/5/QtSvg \
|
||||
./obs-websocket.so
|
||||
- name: 'Sign plugin binary'
|
||||
if: github.event_name != 'pull_request'
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/obs-websocket/build
|
||||
run: |
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -11,3 +11,4 @@
|
||||
/docs/node_modules/
|
||||
/src/plugin-macros.generated.h
|
||||
/installer/installer-windows.generated.iss
|
||||
/cmake-build-debug/
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
WebSocket API for OBS Studio.
|
||||
|
||||
[](https://github.com/obs-websocket/obs-websocket/actions/workflows/main.yml)
|
||||
[](https://github.com/obsproject/obs-websocket/actions/workflows/main.yml)
|
||||
[](https://discord.gg/WBaSQ3A)
|
||||
[](https://opencollective.com/obs-websocket-dev)
|
||||
|
||||
@ -27,18 +27,19 @@ It is **highly recommended** to protect obs-websocket with a password against un
|
||||
- Automate scene switching with a third-party program (e.g. : auto-pilot, foot pedal, ...)
|
||||
|
||||
### Client software
|
||||
- (No known clients supporting 5.0.0 at the moment. Send a message in Discord if you have one!)
|
||||
- (No known clients supporting 5.0.0 at the moment. Ping us in the Discord if you have one!)
|
||||
|
||||
### Client libraries (for developers)
|
||||
|
||||
Here's a list of available language APIs for obs-websocket:
|
||||
- Python 3.7+ (Asyncio): [simpleobsws](https://github.com/IRLToolkit/simpleobsws/tree/master) by IRLToolkit
|
||||
- Rust: [obws](https://github.com/dnaka91/obws/tree/v5-api) by dnaka91
|
||||
- Godot 3.4.x: [obs-websocket-gd](https://github.com/you-win/obs-websocket-gd) by you-win
|
||||
|
||||
The server is a typical Websockets server running by default on port 4444 (the port number can be changed in the Settings dialog under `Tools`).
|
||||
The 5.x server is a typical WebSocket server running by default on port 4455 (the port number can be changed in the Settings dialog under `Tools`).
|
||||
The protocol we use is documented in [PROTOCOL.md](docs/generated/protocol.md).
|
||||
|
||||
We'd like to know what you're building with or for obs-websocket. If you do something in this fashion, feel free to drop a message in `#project-showoff` in the [discord server!](https://discord.gg/WBaSQ3A)
|
||||
We'd like to know what you're building with obs-websocket! If you do something in this fashion, feel free to drop a message in `#project-showoff` in the [discord server!](https://discord.gg/WBaSQ3A)
|
||||
|
||||
## Contributors
|
||||
|
||||
|
@ -405,6 +405,14 @@
|
||||
"initialVersion": "5.0.0",
|
||||
"enumValue": 606
|
||||
},
|
||||
{
|
||||
"description": "The specified filter (obs_source_t-OBS_SOURCE_TYPE_FILTER) had the wrong kind.",
|
||||
"enumIdentifier": "InvalidFilterKind",
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"enumValue": 607
|
||||
},
|
||||
{
|
||||
"description": "Creating the resource failed.",
|
||||
"enumIdentifier": "ResourceCreationFailed",
|
||||
@ -1129,6 +1137,183 @@
|
||||
],
|
||||
"responseFields": []
|
||||
},
|
||||
{
|
||||
"description": "Gets the current directory that the record output is set to.",
|
||||
"requestType": "GetRecordDirectory",
|
||||
"complexity": 1,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "rconfig",
|
||||
"requestFields": [],
|
||||
"responseFields": [
|
||||
{
|
||||
"valueName": "recordDirectory",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Output directory"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Gets an array of all of a source's filters.",
|
||||
"requestType": "GetSourceFilterList",
|
||||
"complexity": 2,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "filters",
|
||||
"requestFields": [
|
||||
{
|
||||
"valueName": "sourceName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the source",
|
||||
"valueRestrictions": null,
|
||||
"valueOptional": false,
|
||||
"valueOptionalBehavior": null
|
||||
}
|
||||
],
|
||||
"responseFields": [
|
||||
{
|
||||
"valueName": "filters",
|
||||
"valueType": "Array<Object>",
|
||||
"valueDescription": "Array of filters"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Gets the default settings for a filter kind.",
|
||||
"requestType": "GetSourceFilterDefaultSettings",
|
||||
"complexity": 3,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "filters",
|
||||
"requestFields": [
|
||||
{
|
||||
"valueName": "filterKind",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Filter kind to get the default settings for",
|
||||
"valueRestrictions": null,
|
||||
"valueOptional": false,
|
||||
"valueOptionalBehavior": null
|
||||
}
|
||||
],
|
||||
"responseFields": [
|
||||
{
|
||||
"valueName": "defaultFilterSettings",
|
||||
"valueType": "Object",
|
||||
"valueDescription": "Object of default settings for the filter kind"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Creates a new filter, adding it to the specified source.",
|
||||
"requestType": "CreateSourceFilter",
|
||||
"complexity": 3,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "filters",
|
||||
"requestFields": [
|
||||
{
|
||||
"valueName": "sourceName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the source to add the filter to",
|
||||
"valueRestrictions": null,
|
||||
"valueOptional": false,
|
||||
"valueOptionalBehavior": null
|
||||
},
|
||||
{
|
||||
"valueName": "filterName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the new filter to be created",
|
||||
"valueRestrictions": null,
|
||||
"valueOptional": false,
|
||||
"valueOptionalBehavior": null
|
||||
},
|
||||
{
|
||||
"valueName": "filterKind",
|
||||
"valueType": "String",
|
||||
"valueDescription": "The kind of filter to be created",
|
||||
"valueRestrictions": null,
|
||||
"valueOptional": false,
|
||||
"valueOptionalBehavior": null
|
||||
},
|
||||
{
|
||||
"valueName": "filterSettings",
|
||||
"valueType": "Object",
|
||||
"valueDescription": "Settings object to initialize the filter with",
|
||||
"valueRestrictions": null,
|
||||
"valueOptional": true,
|
||||
"valueOptionalBehavior": "Default settings used"
|
||||
}
|
||||
],
|
||||
"responseFields": []
|
||||
},
|
||||
{
|
||||
"description": "Removes a filter from a source.",
|
||||
"requestType": "RemoveSourceFilter",
|
||||
"complexity": 2,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "filters",
|
||||
"requestFields": [
|
||||
{
|
||||
"valueName": "sourceName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the source the filter is on",
|
||||
"valueRestrictions": null,
|
||||
"valueOptional": false,
|
||||
"valueOptionalBehavior": null
|
||||
},
|
||||
{
|
||||
"valueName": "filterName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the filter to remove",
|
||||
"valueRestrictions": null,
|
||||
"valueOptional": false,
|
||||
"valueOptionalBehavior": null
|
||||
}
|
||||
],
|
||||
"responseFields": []
|
||||
},
|
||||
{
|
||||
"description": "Sets the name of a source filter (rename).",
|
||||
"requestType": "SetSourceFilterName",
|
||||
"complexity": 2,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "filters",
|
||||
"requestFields": [
|
||||
{
|
||||
"valueName": "sourceName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the source the filter is on",
|
||||
"valueRestrictions": null,
|
||||
"valueOptional": false,
|
||||
"valueOptionalBehavior": null
|
||||
},
|
||||
{
|
||||
"valueName": "filterName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Current name of the filter",
|
||||
"valueRestrictions": null,
|
||||
"valueOptional": false,
|
||||
"valueOptionalBehavior": null
|
||||
},
|
||||
{
|
||||
"valueName": "newFilterName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "New name for the filter",
|
||||
"valueRestrictions": null,
|
||||
"valueOptional": false,
|
||||
"valueOptionalBehavior": null
|
||||
}
|
||||
],
|
||||
"responseFields": []
|
||||
},
|
||||
{
|
||||
"description": "Gets the info for a specific source filter.",
|
||||
"requestType": "GetSourceFilter",
|
||||
@ -1178,6 +1363,86 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Sets the index position of a filter on a source.",
|
||||
"requestType": "SetSourceFilterIndex",
|
||||
"complexity": 3,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "filters",
|
||||
"requestFields": [
|
||||
{
|
||||
"valueName": "sourceName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the source the filter is on",
|
||||
"valueRestrictions": null,
|
||||
"valueOptional": false,
|
||||
"valueOptionalBehavior": null
|
||||
},
|
||||
{
|
||||
"valueName": "filterName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the filter",
|
||||
"valueRestrictions": null,
|
||||
"valueOptional": false,
|
||||
"valueOptionalBehavior": null
|
||||
},
|
||||
{
|
||||
"valueName": "filterIndex",
|
||||
"valueType": "Number",
|
||||
"valueDescription": "New index position of the filter",
|
||||
"valueRestrictions": ">= 0",
|
||||
"valueOptional": false,
|
||||
"valueOptionalBehavior": null
|
||||
}
|
||||
],
|
||||
"responseFields": []
|
||||
},
|
||||
{
|
||||
"description": "Sets the settings of a source filter.",
|
||||
"requestType": "SetSourceFilterSettings",
|
||||
"complexity": 3,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "filters",
|
||||
"requestFields": [
|
||||
{
|
||||
"valueName": "sourceName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the source the filter is on",
|
||||
"valueRestrictions": null,
|
||||
"valueOptional": false,
|
||||
"valueOptionalBehavior": null
|
||||
},
|
||||
{
|
||||
"valueName": "filterName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the filter to set the settings of",
|
||||
"valueRestrictions": null,
|
||||
"valueOptional": false,
|
||||
"valueOptionalBehavior": null
|
||||
},
|
||||
{
|
||||
"valueName": "filterSettings",
|
||||
"valueType": "Object",
|
||||
"valueDescription": "Object of settings to apply",
|
||||
"valueRestrictions": null,
|
||||
"valueOptional": false,
|
||||
"valueOptionalBehavior": null
|
||||
},
|
||||
{
|
||||
"valueName": "overlay",
|
||||
"valueType": "Boolean",
|
||||
"valueDescription": "True == apply the settings on top of existing ones, False == reset the input to its defaults, then apply settings.",
|
||||
"valueRestrictions": null,
|
||||
"valueOptional": true,
|
||||
"valueOptionalBehavior": "true"
|
||||
}
|
||||
],
|
||||
"responseFields": []
|
||||
},
|
||||
{
|
||||
"description": "Gets data about the current plugin and RPC version.",
|
||||
"requestType": "GetVersion",
|
||||
@ -2363,6 +2628,90 @@
|
||||
"requestFields": [],
|
||||
"responseFields": []
|
||||
},
|
||||
{
|
||||
"description": "Gets the status of the replay buffer output.",
|
||||
"requestType": "GetReplayBufferStatus",
|
||||
"complexity": 1,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "outputs",
|
||||
"requestFields": [],
|
||||
"responseFields": [
|
||||
{
|
||||
"valueName": "outputActive",
|
||||
"valueType": "Boolean",
|
||||
"valueDescription": "Whether the output is active"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Toggles the state of the replay buffer output.",
|
||||
"requestType": "ToggleReplayBuffer",
|
||||
"complexity": 1,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "outputs",
|
||||
"requestFields": [],
|
||||
"responseFields": [
|
||||
{
|
||||
"valueName": "outputActive",
|
||||
"valueType": "Boolean",
|
||||
"valueDescription": "Whether the output is active"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Starts the replay buffer output.",
|
||||
"requestType": "StartReplayBuffer",
|
||||
"complexity": 1,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "outputs",
|
||||
"requestFields": [],
|
||||
"responseFields": []
|
||||
},
|
||||
{
|
||||
"description": "Stops the replay buffer output.",
|
||||
"requestType": "StopReplayBuffer",
|
||||
"complexity": 1,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "outputs",
|
||||
"requestFields": [],
|
||||
"responseFields": []
|
||||
},
|
||||
{
|
||||
"description": "Saves the contents of the replay buffer output.",
|
||||
"requestType": "SaveReplayBuffer",
|
||||
"complexity": 1,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "outputs",
|
||||
"requestFields": [],
|
||||
"responseFields": []
|
||||
},
|
||||
{
|
||||
"description": "Gets the filename of the last replay buffer save file.",
|
||||
"requestType": "GetLastReplayBufferReplay",
|
||||
"complexity": 2,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "outputs",
|
||||
"requestFields": [],
|
||||
"responseFields": [
|
||||
{
|
||||
"valueName": "savedReplayPath",
|
||||
"valueType": "String",
|
||||
"valueDescription": "File path"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Gets the status of the record output.",
|
||||
"requestType": "GetRecordStatus",
|
||||
@ -2466,23 +2815,6 @@
|
||||
"requestFields": [],
|
||||
"responseFields": []
|
||||
},
|
||||
{
|
||||
"description": "Gets the current directory that the record output is set to.",
|
||||
"requestType": "GetRecordDirectory",
|
||||
"complexity": 1,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "record",
|
||||
"requestFields": [],
|
||||
"responseFields": [
|
||||
{
|
||||
"valueName": "recordDirectory",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Output directory"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Gets a list of all scene items in a scene.\n\nScenes only",
|
||||
"requestType": "GetSceneItemList",
|
||||
@ -3217,6 +3549,73 @@
|
||||
],
|
||||
"responseFields": []
|
||||
},
|
||||
{
|
||||
"description": "Gets the scene transition overridden for a scene.",
|
||||
"requestType": "GetSceneSceneTransitionOverride",
|
||||
"complexity": 2,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "scenes",
|
||||
"requestFields": [
|
||||
{
|
||||
"valueName": "sceneName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the scene",
|
||||
"valueRestrictions": null,
|
||||
"valueOptional": false,
|
||||
"valueOptionalBehavior": null
|
||||
}
|
||||
],
|
||||
"responseFields": [
|
||||
{
|
||||
"valueName": "transitionName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the overridden scene transition, else `null`"
|
||||
},
|
||||
{
|
||||
"valueName": "transitionDuration",
|
||||
"valueType": "Number",
|
||||
"valueDescription": "Duration of the overridden scene transition, else `null`"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Gets the scene transition overridden for a scene.",
|
||||
"requestType": "SetSceneSceneTransitionOverride",
|
||||
"complexity": 2,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "scenes",
|
||||
"requestFields": [
|
||||
{
|
||||
"valueName": "sceneName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the scene",
|
||||
"valueRestrictions": null,
|
||||
"valueOptional": false,
|
||||
"valueOptionalBehavior": null
|
||||
},
|
||||
{
|
||||
"valueName": "transitionName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the scene transition to use as override. Specify `null` to remove",
|
||||
"valueRestrictions": null,
|
||||
"valueOptional": true,
|
||||
"valueOptionalBehavior": "Unchanged"
|
||||
},
|
||||
{
|
||||
"valueName": "transitionDuration",
|
||||
"valueType": "Number",
|
||||
"valueDescription": "Duration to use for any overridden transition. Specify `null` to remove",
|
||||
"valueRestrictions": ">= 50, <= 20000",
|
||||
"valueOptional": true,
|
||||
"valueOptionalBehavior": "Unchanged"
|
||||
}
|
||||
],
|
||||
"responseFields": []
|
||||
},
|
||||
{
|
||||
"description": "Gets the active and show state of a source.\n\n**Compatible with inputs and scenes.**",
|
||||
"requestType": "GetSourceActive",
|
||||
@ -3458,6 +3857,26 @@
|
||||
"requestFields": [],
|
||||
"responseFields": []
|
||||
},
|
||||
{
|
||||
"description": "Sends CEA-608 caption text over the stream output.",
|
||||
"requestType": "SendStreamCaption",
|
||||
"complexity": 2,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "stream",
|
||||
"requestFields": [
|
||||
{
|
||||
"valueName": "captionText",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Caption text",
|
||||
"valueRestrictions": null,
|
||||
"valueOptional": false,
|
||||
"valueOptionalBehavior": null
|
||||
}
|
||||
],
|
||||
"responseFields": []
|
||||
},
|
||||
{
|
||||
"description": "Gets an array of all available transition kinds.\n\nSimilar to `GetInputKindList`",
|
||||
"requestType": "GetTransitionKindList",
|
||||
@ -3612,6 +4031,23 @@
|
||||
],
|
||||
"responseFields": []
|
||||
},
|
||||
{
|
||||
"description": "Gets the cursor position of the current scene transition.\n\nNote: `transitionCursor` will return 1.0 when the transition is inactive.",
|
||||
"requestType": "GetCurrentSceneTransitionCursor",
|
||||
"complexity": 2,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "transitions",
|
||||
"requestFields": [],
|
||||
"responseFields": [
|
||||
{
|
||||
"valueName": "transitionCursor",
|
||||
"valueType": "Number",
|
||||
"valueDescription": "Cursor position, between 0.0 and 1.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Triggers the current scene transition. Same functionality as the `Transition` button in studio mode.",
|
||||
"requestType": "TriggerStudioModeTransition",
|
||||
@ -3623,6 +4059,34 @@
|
||||
"requestFields": [],
|
||||
"responseFields": []
|
||||
},
|
||||
{
|
||||
"description": "Sets the position of the TBar.\n\n**Very important note**: This will be deprecated and replaced in a future version of obs-websocket.",
|
||||
"requestType": "SetTBarPosition",
|
||||
"complexity": 3,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "transitions",
|
||||
"requestFields": [
|
||||
{
|
||||
"valueName": "position",
|
||||
"valueType": "Number",
|
||||
"valueDescription": "New position",
|
||||
"valueRestrictions": ">= 0.0, <= 1.0",
|
||||
"valueOptional": false,
|
||||
"valueOptionalBehavior": null
|
||||
},
|
||||
{
|
||||
"valueName": "release",
|
||||
"valueType": "Boolean",
|
||||
"valueDescription": "Whether to release the TBar. Only set `false` if you know that you will be sending another position update",
|
||||
"valueRestrictions": null,
|
||||
"valueOptional": true,
|
||||
"valueOptionalBehavior": "`true`"
|
||||
}
|
||||
],
|
||||
"responseFields": []
|
||||
},
|
||||
{
|
||||
"description": "Gets whether studio is enabled.",
|
||||
"requestType": "GetStudioModeEnabled",
|
||||
@ -3824,6 +4288,146 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "A source's filter list has been reindexed.",
|
||||
"eventType": "SourceFilterListReindexed",
|
||||
"eventSubscription": "Filters",
|
||||
"complexity": 3,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "filters",
|
||||
"dataFields": [
|
||||
{
|
||||
"valueName": "sourceName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the source"
|
||||
},
|
||||
{
|
||||
"valueName": "filters",
|
||||
"valueType": "Array<Object>",
|
||||
"valueDescription": "Array of filter objects"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "A filter has been added to a source.",
|
||||
"eventType": "SourceFilterCreated",
|
||||
"eventSubscription": "Filters",
|
||||
"complexity": 2,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "filters",
|
||||
"dataFields": [
|
||||
{
|
||||
"valueName": "sourceName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the source the filter was added to"
|
||||
},
|
||||
{
|
||||
"valueName": "filterName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the filter"
|
||||
},
|
||||
{
|
||||
"valueName": "filterKind",
|
||||
"valueType": "String",
|
||||
"valueDescription": "The kind of the filter"
|
||||
},
|
||||
{
|
||||
"valueName": "filterIndex",
|
||||
"valueType": "Number",
|
||||
"valueDescription": "Index position of the filter"
|
||||
},
|
||||
{
|
||||
"valueName": "filterSettings",
|
||||
"valueType": "Object",
|
||||
"valueDescription": "The settings configured to the filter when it was created"
|
||||
},
|
||||
{
|
||||
"valueName": "defaultFilterSettings",
|
||||
"valueType": "Object",
|
||||
"valueDescription": "The default settings for the filter"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "A filter has been removed from a source.",
|
||||
"eventType": "SourceFilterRemoved",
|
||||
"eventSubscription": "Filters",
|
||||
"complexity": 2,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "filters",
|
||||
"dataFields": [
|
||||
{
|
||||
"valueName": "sourceName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the source the filter was on"
|
||||
},
|
||||
{
|
||||
"valueName": "filterName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the filter"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "The name of a source filter has changed.",
|
||||
"eventType": "SourceFilterNameChanged",
|
||||
"eventSubscription": "Filters",
|
||||
"complexity": 2,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "filters",
|
||||
"dataFields": [
|
||||
{
|
||||
"valueName": "sourceName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "The source the filter is on"
|
||||
},
|
||||
{
|
||||
"valueName": "oldFilterName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Old name of the filter"
|
||||
},
|
||||
{
|
||||
"valueName": "filterName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "New name of the filter"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "A source filter's enable state has changed.",
|
||||
"eventType": "SourceFilterEnableStateChanged",
|
||||
"eventSubscription": "Filters",
|
||||
"complexity": 3,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "filters",
|
||||
"dataFields": [
|
||||
{
|
||||
"valueName": "sourceName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the source the filter is on"
|
||||
},
|
||||
{
|
||||
"valueName": "filterName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the filter"
|
||||
},
|
||||
{
|
||||
"valueName": "filterEnabled",
|
||||
"valueType": "Boolean",
|
||||
"valueDescription": "Whether the filter is enabled"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "OBS has begun the shutdown process.",
|
||||
"eventType": "ExitStarted",
|
||||
@ -4399,12 +5003,34 @@
|
||||
"valueDescription": "Numeric ID of the scene item"
|
||||
},
|
||||
{
|
||||
"valueName": "sceneItemEnabled",
|
||||
"valueName": "sceneItemLocked",
|
||||
"valueType": "Boolean",
|
||||
"valueDescription": "Whether the scene item is locked"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "A scene item has been selected in the Ui.",
|
||||
"eventType": "SceneItemSelected",
|
||||
"eventSubscription": "SceneItems",
|
||||
"complexity": 2,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "scene items",
|
||||
"dataFields": [
|
||||
{
|
||||
"valueName": "sceneName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the scene the item is in"
|
||||
},
|
||||
{
|
||||
"valueName": "sceneItemId",
|
||||
"valueType": "Number",
|
||||
"valueDescription": "Numeric ID of the scene item"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "The transform/crop of a scene item has changed.",
|
||||
"eventType": "SceneItemTransformChanged",
|
||||
@ -4549,6 +5175,91 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "The current scene transition has changed.",
|
||||
"eventType": "CurrentSceneTransitionChanged",
|
||||
"eventSubscription": "Transitions",
|
||||
"complexity": 2,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "transitions",
|
||||
"dataFields": [
|
||||
{
|
||||
"valueName": "transitionName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Name of the new transition"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "The current scene transition duration has changed.",
|
||||
"eventType": "CurrentSceneTransitionDurationChanged",
|
||||
"eventSubscription": "Transitions",
|
||||
"complexity": 2,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "transitions",
|
||||
"dataFields": [
|
||||
{
|
||||
"valueName": "transitionDuration",
|
||||
"valueType": "Number",
|
||||
"valueDescription": "Transition duration in milliseconds"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "A scene transition has started.",
|
||||
"eventType": "SceneTransitionStarted",
|
||||
"eventSubscription": "Transitions",
|
||||
"complexity": 2,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "transitions",
|
||||
"dataFields": [
|
||||
{
|
||||
"valueName": "transitionName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Scene transition name"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "A scene transition has completed fully.\n\nNote: Does not appear to trigger when the transition is interrupted by the user.",
|
||||
"eventType": "SceneTransitionEnded",
|
||||
"eventSubscription": "Transitions",
|
||||
"complexity": 2,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "transitions",
|
||||
"dataFields": [
|
||||
{
|
||||
"valueName": "transitionName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Scene transition name"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "A scene transition's video has completed fully.\n\nUseful for stinger transitions to tell when the video *actually* ends.\n`SceneTransitionEnded` only signifies the cut point, not the completion of transition playback.\n\nNote: Appears to be called by every transition, regardless of relevance.",
|
||||
"eventType": "SceneTransitionVideoEnded",
|
||||
"eventSubscription": "Transitions",
|
||||
"complexity": 2,
|
||||
"rpcVersion": "1",
|
||||
"deprecated": false,
|
||||
"initialVersion": "5.0.0",
|
||||
"category": "transitions",
|
||||
"dataFields": [
|
||||
{
|
||||
"valueName": "transitionName",
|
||||
"valueType": "String",
|
||||
"valueDescription": "Scene transition name"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Studio mode has been enabled or disabled.",
|
||||
"eventType": "StudioModeStateChanged",
|
||||
|
@ -443,6 +443,7 @@ These are enumeration declarations, which are referenced throughout obs-websocke
|
||||
- [RequestStatus::InvalidResourceState](#requeststatusinvalidresourcestate)
|
||||
- [RequestStatus::InvalidInputKind](#requeststatusinvalidinputkind)
|
||||
- [RequestStatus::ResourceNotConfigurable](#requeststatusresourcenotconfigurable)
|
||||
- [RequestStatus::InvalidFilterKind](#requeststatusinvalidfilterkind)
|
||||
- [RequestStatus::ResourceCreationFailed](#requeststatusresourcecreationfailed)
|
||||
- [RequestStatus::ResourceActionFailed](#requeststatusresourceactionfailed)
|
||||
- [RequestStatus::RequestProcessingFailed](#requeststatusrequestprocessingfailed)
|
||||
@ -1025,6 +1026,16 @@ This is particularly relevant to transitions, where they do not always have chan
|
||||
|
||||
---
|
||||
|
||||
### RequestStatus::InvalidFilterKind
|
||||
|
||||
The specified filter (obs_source_t-OBS_SOURCE_TYPE_FILTER) had the wrong kind.
|
||||
|
||||
- Identifier Value: `607`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
---
|
||||
|
||||
### RequestStatus::ResourceCreationFailed
|
||||
|
||||
Creating the resource failed.
|
||||
@ -1268,12 +1279,25 @@ Subscription value to receive the `SceneItemTransformChanged` high-volume event.
|
||||
- [InputAudioTracksChanged](#inputaudiotrackschanged)
|
||||
- [InputAudioMonitorTypeChanged](#inputaudiomonitortypechanged)
|
||||
- [InputVolumeMeters](#inputvolumemeters)
|
||||
- [Transitions](#transitions)
|
||||
- [CurrentSceneTransitionChanged](#currentscenetransitionchanged)
|
||||
- [CurrentSceneTransitionDurationChanged](#currentscenetransitiondurationchanged)
|
||||
- [SceneTransitionStarted](#scenetransitionstarted)
|
||||
- [SceneTransitionEnded](#scenetransitionended)
|
||||
- [SceneTransitionVideoEnded](#scenetransitionvideoended)
|
||||
- [Filters](#filters)
|
||||
- [SourceFilterListReindexed](#sourcefilterlistreindexed)
|
||||
- [SourceFilterCreated](#sourcefiltercreated)
|
||||
- [SourceFilterRemoved](#sourcefilterremoved)
|
||||
- [SourceFilterNameChanged](#sourcefilternamechanged)
|
||||
- [SourceFilterEnableStateChanged](#sourcefilterenablestatechanged)
|
||||
- [Scene Items](#scene-items)
|
||||
- [SceneItemCreated](#sceneitemcreated)
|
||||
- [SceneItemRemoved](#sceneitemremoved)
|
||||
- [SceneItemListReindexed](#sceneitemlistreindexed)
|
||||
- [SceneItemEnableStateChanged](#sceneitemenablestatechanged)
|
||||
- [SceneItemLockStateChanged](#sceneitemlockstatechanged)
|
||||
- [SceneItemSelected](#sceneitemselected)
|
||||
- [SceneItemTransformChanged](#sceneitemtransformchanged)
|
||||
- [Outputs](#outputs)
|
||||
- [StreamStateChanged](#streamstatechanged)
|
||||
@ -1758,6 +1782,192 @@ A high-volume event providing volume levels of all active inputs every 50 millis
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ----------- |
|
||||
| inputs | Array<Object> | Array of active inputs with their associated volume levels |
|
||||
## Transitions
|
||||
|
||||
### CurrentSceneTransitionChanged
|
||||
|
||||
The current scene transition has changed.
|
||||
|
||||
- Complexity Rating: `2/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Data Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ----------- |
|
||||
| transitionName | String | Name of the new transition |
|
||||
|
||||
---
|
||||
|
||||
### CurrentSceneTransitionDurationChanged
|
||||
|
||||
The current scene transition duration has changed.
|
||||
|
||||
- Complexity Rating: `2/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Data Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ----------- |
|
||||
| transitionDuration | Number | Transition duration in milliseconds |
|
||||
|
||||
---
|
||||
|
||||
### SceneTransitionStarted
|
||||
|
||||
A scene transition has started.
|
||||
|
||||
- Complexity Rating: `2/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Data Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ----------- |
|
||||
| transitionName | String | Scene transition name |
|
||||
|
||||
---
|
||||
|
||||
### SceneTransitionEnded
|
||||
|
||||
A scene transition has completed fully.
|
||||
|
||||
Note: Does not appear to trigger when the transition is interrupted by the user.
|
||||
|
||||
- Complexity Rating: `2/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Data Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ----------- |
|
||||
| transitionName | String | Scene transition name |
|
||||
|
||||
---
|
||||
|
||||
### SceneTransitionVideoEnded
|
||||
|
||||
A scene transition's video has completed fully.
|
||||
|
||||
Useful for stinger transitions to tell when the video *actually* ends.
|
||||
`SceneTransitionEnded` only signifies the cut point, not the completion of transition playback.
|
||||
|
||||
Note: Appears to be called by every transition, regardless of relevance.
|
||||
|
||||
- Complexity Rating: `2/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Data Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ----------- |
|
||||
| transitionName | String | Scene transition name |
|
||||
## Filters
|
||||
|
||||
### SourceFilterListReindexed
|
||||
|
||||
A source's filter list has been reindexed.
|
||||
|
||||
- Complexity Rating: `3/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Data Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ----------- |
|
||||
| sourceName | String | Name of the source |
|
||||
| filters | Array<Object> | Array of filter objects |
|
||||
|
||||
---
|
||||
|
||||
### SourceFilterCreated
|
||||
|
||||
A filter has been added to a source.
|
||||
|
||||
- Complexity Rating: `2/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Data Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ----------- |
|
||||
| sourceName | String | Name of the source the filter was added to |
|
||||
| filterName | String | Name of the filter |
|
||||
| filterKind | String | The kind of the filter |
|
||||
| filterIndex | Number | Index position of the filter |
|
||||
| filterSettings | Object | The settings configured to the filter when it was created |
|
||||
| defaultFilterSettings | Object | The default settings for the filter |
|
||||
|
||||
---
|
||||
|
||||
### SourceFilterRemoved
|
||||
|
||||
A filter has been removed from a source.
|
||||
|
||||
- Complexity Rating: `2/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Data Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ----------- |
|
||||
| sourceName | String | Name of the source the filter was on |
|
||||
| filterName | String | Name of the filter |
|
||||
|
||||
---
|
||||
|
||||
### SourceFilterNameChanged
|
||||
|
||||
The name of a source filter has changed.
|
||||
|
||||
- Complexity Rating: `2/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Data Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ----------- |
|
||||
| sourceName | String | The source the filter is on |
|
||||
| oldFilterName | String | Old name of the filter |
|
||||
| filterName | String | New name of the filter |
|
||||
|
||||
---
|
||||
|
||||
### SourceFilterEnableStateChanged
|
||||
|
||||
A source filter's enable state has changed.
|
||||
|
||||
- Complexity Rating: `3/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Data Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ----------- |
|
||||
| sourceName | String | Name of the source the filter is on |
|
||||
| filterName | String | Name of the filter |
|
||||
| filterEnabled | Boolean | Whether the filter is enabled |
|
||||
## Scene Items
|
||||
|
||||
### SceneItemCreated
|
||||
@ -1853,7 +2063,25 @@ A scene item's lock state has changed.
|
||||
| ---- | :---: | ----------- |
|
||||
| sceneName | String | Name of the scene the item is in |
|
||||
| sceneItemId | Number | Numeric ID of the scene item |
|
||||
| sceneItemEnabled | Boolean | Whether the scene item is locked |
|
||||
| sceneItemLocked | Boolean | Whether the scene item is locked |
|
||||
|
||||
---
|
||||
|
||||
### SceneItemSelected
|
||||
|
||||
A scene item has been selected in the Ui.
|
||||
|
||||
- Complexity Rating: `2/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Data Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ----------- |
|
||||
| sceneName | String | Name of the scene the item is in |
|
||||
| sceneItemId | Number | Numeric ID of the scene item |
|
||||
|
||||
---
|
||||
|
||||
@ -2072,6 +2300,8 @@ Studio mode has been enabled or disabled.
|
||||
- [CreateScene](#createscene)
|
||||
- [RemoveScene](#removescene)
|
||||
- [SetSceneName](#setscenename)
|
||||
- [GetSceneSceneTransitionOverride](#getscenescenetransitionoverride)
|
||||
- [SetSceneSceneTransitionOverride](#setscenescenetransitionoverride)
|
||||
- [Inputs](#inputs-1)
|
||||
- [GetInputList](#getinputlist)
|
||||
- [GetInputKindList](#getinputkindlist)
|
||||
@ -2097,16 +2327,25 @@ Studio mode has been enabled or disabled.
|
||||
- [SetInputAudioTracks](#setinputaudiotracks)
|
||||
- [GetInputPropertiesListPropertyItems](#getinputpropertieslistpropertyitems)
|
||||
- [PressInputPropertiesButton](#pressinputpropertiesbutton)
|
||||
- [Transitions](#transitions)
|
||||
- [Transitions](#transitions-1)
|
||||
- [GetTransitionKindList](#gettransitionkindlist)
|
||||
- [GetSceneTransitionList](#getscenetransitionlist)
|
||||
- [GetCurrentSceneTransition](#getcurrentscenetransition)
|
||||
- [SetCurrentSceneTransition](#setcurrentscenetransition)
|
||||
- [SetCurrentSceneTransitionDuration](#setcurrentscenetransitionduration)
|
||||
- [SetCurrentSceneTransitionSettings](#setcurrentscenetransitionsettings)
|
||||
- [GetCurrentSceneTransitionCursor](#getcurrentscenetransitioncursor)
|
||||
- [TriggerStudioModeTransition](#triggerstudiomodetransition)
|
||||
- [Filters](#filters)
|
||||
- [SetTBarPosition](#settbarposition)
|
||||
- [Filters](#filters-1)
|
||||
- [GetSourceFilterList](#getsourcefilterlist)
|
||||
- [GetSourceFilterDefaultSettings](#getsourcefilterdefaultsettings)
|
||||
- [CreateSourceFilter](#createsourcefilter)
|
||||
- [RemoveSourceFilter](#removesourcefilter)
|
||||
- [SetSourceFilterName](#setsourcefiltername)
|
||||
- [GetSourceFilter](#getsourcefilter)
|
||||
- [SetSourceFilterIndex](#setsourcefilterindex)
|
||||
- [SetSourceFilterSettings](#setsourcefiltersettings)
|
||||
- [Scene Items](#scene-items-1)
|
||||
- [GetSceneItemList](#getsceneitemlist)
|
||||
- [GetGroupItemList](#getgroupitemlist)
|
||||
@ -2129,11 +2368,18 @@ Studio mode has been enabled or disabled.
|
||||
- [ToggleVirtualCam](#togglevirtualcam)
|
||||
- [StartVirtualCam](#startvirtualcam)
|
||||
- [StopVirtualCam](#stopvirtualcam)
|
||||
- [GetReplayBufferStatus](#getreplaybufferstatus)
|
||||
- [ToggleReplayBuffer](#togglereplaybuffer)
|
||||
- [StartReplayBuffer](#startreplaybuffer)
|
||||
- [StopReplayBuffer](#stopreplaybuffer)
|
||||
- [SaveReplayBuffer](#savereplaybuffer)
|
||||
- [GetLastReplayBufferReplay](#getlastreplaybufferreplay)
|
||||
- [Stream](#stream)
|
||||
- [GetStreamStatus](#getstreamstatus)
|
||||
- [ToggleStream](#togglestream)
|
||||
- [StartStream](#startstream)
|
||||
- [StopStream](#stopstream)
|
||||
- [SendStreamCaption](#sendstreamcaption)
|
||||
- [Record](#record)
|
||||
- [GetRecordStatus](#getrecordstatus)
|
||||
- [ToggleRecord](#togglerecord)
|
||||
@ -2142,7 +2388,6 @@ Studio mode has been enabled or disabled.
|
||||
- [ToggleRecordPause](#togglerecordpause)
|
||||
- [PauseRecord](#pauserecord)
|
||||
- [ResumeRecord](#resumerecord)
|
||||
- [GetRecordDirectory](#getrecorddirectory)
|
||||
- [Media Inputs](#media-inputs-1)
|
||||
- [GetMediaInputStatus](#getmediainputstatus)
|
||||
- [SetMediaInputCursor](#setmediainputcursor)
|
||||
@ -2885,6 +3130,50 @@ Sets the name of a scene (rename).
|
||||
| sceneName | String | Name of the scene to be renamed | None | N/A |
|
||||
| newSceneName | String | New name for the scene | None | N/A |
|
||||
|
||||
---
|
||||
|
||||
### GetSceneSceneTransitionOverride
|
||||
|
||||
Gets the scene transition overridden for a scene.
|
||||
|
||||
- Complexity Rating: `2/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Request Fields:**
|
||||
|
||||
| Name | Type | Description | Value Restrictions | ?Default Behavior |
|
||||
| ---- | :---: | ----------- | :----------------: | ----------------- |
|
||||
| sceneName | String | Name of the scene | None | N/A |
|
||||
|
||||
|
||||
**Response Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ----------- |
|
||||
| transitionName | String | Name of the overridden scene transition, else `null` |
|
||||
| transitionDuration | Number | Duration of the overridden scene transition, else `null` |
|
||||
|
||||
---
|
||||
|
||||
### SetSceneSceneTransitionOverride
|
||||
|
||||
Gets the scene transition overridden for a scene.
|
||||
|
||||
- Complexity Rating: `2/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Request Fields:**
|
||||
|
||||
| Name | Type | Description | Value Restrictions | ?Default Behavior |
|
||||
| ---- | :---: | ----------- | :----------------: | ----------------- |
|
||||
| sceneName | String | Name of the scene | None | N/A |
|
||||
| ?transitionName | String | Name of the scene transition to use as override. Specify `null` to remove | None | Unchanged |
|
||||
| ?transitionDuration | Number | Duration to use for any overridden transition. Specify `null` to remove | >= 50, <= 20000 | Unchanged |
|
||||
|
||||
|
||||
## Inputs
|
||||
|
||||
@ -3540,6 +3829,25 @@ Sets the settings of the current scene transition.
|
||||
|
||||
---
|
||||
|
||||
### GetCurrentSceneTransitionCursor
|
||||
|
||||
Gets the cursor position of the current scene transition.
|
||||
|
||||
Note: `transitionCursor` will return 1.0 when the transition is inactive.
|
||||
|
||||
- Complexity Rating: `2/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Response Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ----------- |
|
||||
| transitionCursor | Number | Cursor position, between 0.0 and 1.0 |
|
||||
|
||||
---
|
||||
|
||||
### TriggerStudioModeTransition
|
||||
|
||||
Triggers the current scene transition. Same functionality as the `Transition` button in studio mode.
|
||||
@ -3548,9 +3856,134 @@ Triggers the current scene transition. Same functionality as the `Transition` bu
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
---
|
||||
|
||||
### SetTBarPosition
|
||||
|
||||
Sets the position of the TBar.
|
||||
|
||||
**Very important note**: This will be deprecated and replaced in a future version of obs-websocket.
|
||||
|
||||
- Complexity Rating: `3/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Request Fields:**
|
||||
|
||||
| Name | Type | Description | Value Restrictions | ?Default Behavior |
|
||||
| ---- | :---: | ----------- | :----------------: | ----------------- |
|
||||
| position | Number | New position | >= 0.0, <= 1.0 | N/A |
|
||||
| ?release | Boolean | Whether to release the TBar. Only set `false` if you know that you will be sending another position update | None | `true` |
|
||||
|
||||
|
||||
## Filters
|
||||
|
||||
### GetSourceFilterList
|
||||
|
||||
Gets an array of all of a source's filters.
|
||||
|
||||
- Complexity Rating: `2/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Request Fields:**
|
||||
|
||||
| Name | Type | Description | Value Restrictions | ?Default Behavior |
|
||||
| ---- | :---: | ----------- | :----------------: | ----------------- |
|
||||
| sourceName | String | Name of the source | None | N/A |
|
||||
|
||||
|
||||
**Response Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ----------- |
|
||||
| filters | Array<Object> | Array of filters |
|
||||
|
||||
---
|
||||
|
||||
### GetSourceFilterDefaultSettings
|
||||
|
||||
Gets the default settings for a filter kind.
|
||||
|
||||
- Complexity Rating: `3/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Request Fields:**
|
||||
|
||||
| Name | Type | Description | Value Restrictions | ?Default Behavior |
|
||||
| ---- | :---: | ----------- | :----------------: | ----------------- |
|
||||
| filterKind | String | Filter kind to get the default settings for | None | N/A |
|
||||
|
||||
|
||||
**Response Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ----------- |
|
||||
| defaultFilterSettings | Object | Object of default settings for the filter kind |
|
||||
|
||||
---
|
||||
|
||||
### CreateSourceFilter
|
||||
|
||||
Creates a new filter, adding it to the specified source.
|
||||
|
||||
- Complexity Rating: `3/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Request Fields:**
|
||||
|
||||
| Name | Type | Description | Value Restrictions | ?Default Behavior |
|
||||
| ---- | :---: | ----------- | :----------------: | ----------------- |
|
||||
| sourceName | String | Name of the source to add the filter to | None | N/A |
|
||||
| filterName | String | Name of the new filter to be created | None | N/A |
|
||||
| filterKind | String | The kind of filter to be created | None | N/A |
|
||||
| ?filterSettings | Object | Settings object to initialize the filter with | None | Default settings used |
|
||||
|
||||
---
|
||||
|
||||
### RemoveSourceFilter
|
||||
|
||||
Removes a filter from a source.
|
||||
|
||||
- Complexity Rating: `2/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Request Fields:**
|
||||
|
||||
| Name | Type | Description | Value Restrictions | ?Default Behavior |
|
||||
| ---- | :---: | ----------- | :----------------: | ----------------- |
|
||||
| sourceName | String | Name of the source the filter is on | None | N/A |
|
||||
| filterName | String | Name of the filter to remove | None | N/A |
|
||||
|
||||
---
|
||||
|
||||
### SetSourceFilterName
|
||||
|
||||
Sets the name of a source filter (rename).
|
||||
|
||||
- Complexity Rating: `2/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Request Fields:**
|
||||
|
||||
| Name | Type | Description | Value Restrictions | ?Default Behavior |
|
||||
| ---- | :---: | ----------- | :----------------: | ----------------- |
|
||||
| sourceName | String | Name of the source the filter is on | None | N/A |
|
||||
| filterName | String | Current name of the filter | None | N/A |
|
||||
| newFilterName | String | New name for the filter | None | N/A |
|
||||
|
||||
---
|
||||
|
||||
### GetSourceFilter
|
||||
|
||||
Gets the info for a specific source filter.
|
||||
@ -3577,6 +4010,45 @@ Gets the info for a specific source filter.
|
||||
| filterKind | String | The kind of filter |
|
||||
| filterSettings | Object | Settings object associated with the filter |
|
||||
|
||||
---
|
||||
|
||||
### SetSourceFilterIndex
|
||||
|
||||
Sets the index position of a filter on a source.
|
||||
|
||||
- Complexity Rating: `3/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Request Fields:**
|
||||
|
||||
| Name | Type | Description | Value Restrictions | ?Default Behavior |
|
||||
| ---- | :---: | ----------- | :----------------: | ----------------- |
|
||||
| sourceName | String | Name of the source the filter is on | None | N/A |
|
||||
| filterName | String | Name of the filter | None | N/A |
|
||||
| filterIndex | Number | New index position of the filter | >= 0 | N/A |
|
||||
|
||||
---
|
||||
|
||||
### SetSourceFilterSettings
|
||||
|
||||
Sets the settings of a source filter.
|
||||
|
||||
- Complexity Rating: `3/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Request Fields:**
|
||||
|
||||
| Name | Type | Description | Value Restrictions | ?Default Behavior |
|
||||
| ---- | :---: | ----------- | :----------------: | ----------------- |
|
||||
| sourceName | String | Name of the source the filter is on | None | N/A |
|
||||
| filterName | String | Name of the filter to set the settings of | None | N/A |
|
||||
| filterSettings | Object | Object of settings to apply | None | N/A |
|
||||
| ?overlay | Boolean | True == apply the settings on top of existing ones, False == reset the input to its defaults, then apply settings. | None | true |
|
||||
|
||||
|
||||
## Scene Items
|
||||
|
||||
@ -4040,6 +4512,87 @@ Stops the virtualcam output.
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
---
|
||||
|
||||
### GetReplayBufferStatus
|
||||
|
||||
Gets the status of the replay buffer output.
|
||||
|
||||
- Complexity Rating: `1/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Response Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ----------- |
|
||||
| outputActive | Boolean | Whether the output is active |
|
||||
|
||||
---
|
||||
|
||||
### ToggleReplayBuffer
|
||||
|
||||
Toggles the state of the replay buffer output.
|
||||
|
||||
- Complexity Rating: `1/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Response Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ----------- |
|
||||
| outputActive | Boolean | Whether the output is active |
|
||||
|
||||
---
|
||||
|
||||
### StartReplayBuffer
|
||||
|
||||
Starts the replay buffer output.
|
||||
|
||||
- Complexity Rating: `1/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
---
|
||||
|
||||
### StopReplayBuffer
|
||||
|
||||
Stops the replay buffer output.
|
||||
|
||||
- Complexity Rating: `1/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
---
|
||||
|
||||
### SaveReplayBuffer
|
||||
|
||||
Saves the contents of the replay buffer output.
|
||||
|
||||
- Complexity Rating: `1/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
---
|
||||
|
||||
### GetLastReplayBufferReplay
|
||||
|
||||
Gets the filename of the last replay buffer save file.
|
||||
|
||||
- Complexity Rating: `2/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Response Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ----------- |
|
||||
| savedReplayPath | String | File path |
|
||||
|
||||
|
||||
## Stream
|
||||
|
||||
@ -4101,6 +4654,23 @@ Stops the stream output.
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
---
|
||||
|
||||
### SendStreamCaption
|
||||
|
||||
Sends CEA-608 caption text over the stream output.
|
||||
|
||||
- Complexity Rating: `2/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Request Fields:**
|
||||
|
||||
| Name | Type | Description | Value Restrictions | ?Default Behavior |
|
||||
| ---- | :---: | ----------- | :----------------: | ----------------- |
|
||||
| captionText | String | Caption text | None | N/A |
|
||||
|
||||
|
||||
## Record
|
||||
|
||||
@ -4183,23 +4753,6 @@ Resumes the record output.
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
---
|
||||
|
||||
### GetRecordDirectory
|
||||
|
||||
Gets the current directory that the record output is set to.
|
||||
|
||||
- Complexity Rating: `1/5`
|
||||
- Latest Supported RPC Version: `1`
|
||||
- Added in v5.0.0
|
||||
|
||||
|
||||
**Response Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ----------- |
|
||||
| recordDirectory | String | Output directory |
|
||||
|
||||
|
||||
## Media Inputs
|
||||
|
||||
|
@ -41,7 +41,7 @@ Config::Config() :
|
||||
PasswordOverridden(false),
|
||||
FirstLoad(true),
|
||||
ServerEnabled(true),
|
||||
ServerPort(4444),
|
||||
ServerPort(4455),
|
||||
DebugEnabled(false),
|
||||
AlertsEnabled(false),
|
||||
AuthRequired(true),
|
||||
|
@ -115,6 +115,7 @@ void EventHandler::BroadcastEvent(uint64_t requiredIntent, std::string eventType
|
||||
_broadcastCallback(requiredIntent, eventType, eventData, rpcVersion);
|
||||
}
|
||||
|
||||
// Connect source signals for Inputs, Scenes, and Transitions. Filters are automatically connected.
|
||||
void EventHandler::ConnectSourceSignals(obs_source_t *source) // Applies to inputs and scenes
|
||||
{
|
||||
if (!source || obs_source_removed(source))
|
||||
@ -128,18 +129,17 @@ void EventHandler::ConnectSourceSignals(obs_source_t *source) // Applies to inpu
|
||||
obs_source_type sourceType = obs_source_get_type(source);
|
||||
|
||||
// Inputs
|
||||
signal_handler_connect(sh, "activate", HandleInputActiveStateChanged, this);
|
||||
signal_handler_connect(sh, "deactivate", HandleInputActiveStateChanged, this);
|
||||
signal_handler_connect(sh, "show", HandleInputShowStateChanged, this);
|
||||
signal_handler_connect(sh, "hide", HandleInputShowStateChanged, this);
|
||||
signal_handler_connect(sh, "mute", HandleInputMuteStateChanged, this);
|
||||
signal_handler_connect(sh, "volume", HandleInputVolumeChanged, this);
|
||||
signal_handler_connect(sh, "audio_balance", HandleInputAudioBalanceChanged, this);
|
||||
signal_handler_connect(sh, "audio_sync", HandleInputAudioSyncOffsetChanged, this);
|
||||
signal_handler_connect(sh, "audio_mixers", HandleInputAudioTracksChanged, this);
|
||||
signal_handler_connect(sh, "audio_monitoring", HandleInputAudioMonitorTypeChanged, this);
|
||||
|
||||
if (sourceType == OBS_SOURCE_TYPE_INPUT) {
|
||||
signal_handler_connect(sh, "activate", HandleInputActiveStateChanged, this);
|
||||
signal_handler_connect(sh, "deactivate", HandleInputActiveStateChanged, this);
|
||||
signal_handler_connect(sh, "show", HandleInputShowStateChanged, this);
|
||||
signal_handler_connect(sh, "hide", HandleInputShowStateChanged, this);
|
||||
signal_handler_connect(sh, "mute", HandleInputMuteStateChanged, this);
|
||||
signal_handler_connect(sh, "volume", HandleInputVolumeChanged, this);
|
||||
signal_handler_connect(sh, "audio_balance", HandleInputAudioBalanceChanged, this);
|
||||
signal_handler_connect(sh, "audio_sync", HandleInputAudioSyncOffsetChanged, this);
|
||||
signal_handler_connect(sh, "audio_mixers", HandleInputAudioTracksChanged, this);
|
||||
signal_handler_connect(sh, "audio_monitoring", HandleInputAudioMonitorTypeChanged, this);
|
||||
signal_handler_connect(sh, "media_started", HandleMediaInputPlaybackStarted, this);
|
||||
signal_handler_connect(sh, "media_ended", HandleMediaInputPlaybackEnded, this);
|
||||
signal_handler_connect(sh, "media_pause", SourceMediaPauseMultiHandler, this);
|
||||
@ -157,10 +157,37 @@ void EventHandler::ConnectSourceSignals(obs_source_t *source) // Applies to inpu
|
||||
signal_handler_connect(sh, "reorder", HandleSceneItemListReindexed, this);
|
||||
signal_handler_connect(sh, "item_visible", HandleSceneItemEnableStateChanged, this);
|
||||
signal_handler_connect(sh, "item_locked", HandleSceneItemLockStateChanged, this);
|
||||
signal_handler_connect(sh, "item_select", HandleSceneItemSelected, this);
|
||||
signal_handler_connect(sh, "item_transform", HandleSceneItemTransformChanged, this);
|
||||
}
|
||||
|
||||
// Scenes and Inputs
|
||||
if (sourceType == OBS_SOURCE_TYPE_INPUT || sourceType == OBS_SOURCE_TYPE_SCENE) {
|
||||
signal_handler_connect(sh, "reorder_filters", HandleSourceFilterListReindexed, this);
|
||||
signal_handler_connect(sh, "filter_add", FilterAddMultiHandler, this);
|
||||
signal_handler_connect(sh, "filter_remove", FilterRemoveMultiHandler, this);
|
||||
auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *param){
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
eventHandler->ConnectSourceSignals(filter);
|
||||
};
|
||||
obs_source_enum_filters(source, enumFilters, this);
|
||||
}
|
||||
|
||||
// Transitions
|
||||
if (sourceType == OBS_SOURCE_TYPE_TRANSITION) {
|
||||
signal_handler_connect(sh, "transition_start", HandleSceneTransitionStarted, this);
|
||||
signal_handler_connect(sh, "transition_stop", HandleSceneTransitionEnded, this);
|
||||
signal_handler_connect(sh, "transition_video_stop", HandleSceneTransitionVideoEnded, this);
|
||||
}
|
||||
|
||||
// Filters
|
||||
if (sourceType == OBS_SOURCE_TYPE_FILTER) {
|
||||
signal_handler_connect(sh, "enable", HandleSourceFilterEnableStateChanged, this);
|
||||
signal_handler_connect(sh, "rename", HandleSourceFilterNameChanged, this);
|
||||
}
|
||||
}
|
||||
|
||||
// Disconnect source signals for Inputs, Scenes, and Transitions. Filters are automatically disconnected.
|
||||
void EventHandler::DisconnectSourceSignals(obs_source_t *source)
|
||||
{
|
||||
if (!source)
|
||||
@ -168,71 +195,120 @@ void EventHandler::DisconnectSourceSignals(obs_source_t *source)
|
||||
|
||||
signal_handler_t* sh = obs_source_get_signal_handler(source);
|
||||
|
||||
obs_source_type sourceType = obs_source_get_type(source);
|
||||
|
||||
// Inputs
|
||||
signal_handler_disconnect(sh, "activate", HandleInputActiveStateChanged, this);
|
||||
signal_handler_disconnect(sh, "deactivate", HandleInputActiveStateChanged, this);
|
||||
signal_handler_disconnect(sh, "show", HandleInputShowStateChanged, this);
|
||||
signal_handler_disconnect(sh, "hide", HandleInputShowStateChanged, this);
|
||||
signal_handler_disconnect(sh, "mute", HandleInputMuteStateChanged, this);
|
||||
signal_handler_disconnect(sh, "volume", HandleInputVolumeChanged, this);
|
||||
signal_handler_disconnect(sh, "audio_balance", HandleInputAudioBalanceChanged, this);
|
||||
signal_handler_disconnect(sh, "audio_sync", HandleInputAudioSyncOffsetChanged, this);
|
||||
signal_handler_disconnect(sh, "audio_mixers", HandleInputAudioTracksChanged, this);
|
||||
signal_handler_disconnect(sh, "audio_monitoring", HandleInputAudioMonitorTypeChanged, this);
|
||||
signal_handler_disconnect(sh, "media_started", HandleMediaInputPlaybackStarted, this);
|
||||
signal_handler_disconnect(sh, "media_ended", HandleMediaInputPlaybackEnded, this);
|
||||
signal_handler_disconnect(sh, "media_pause", SourceMediaPauseMultiHandler, this);
|
||||
signal_handler_disconnect(sh, "media_play", SourceMediaPlayMultiHandler, this);
|
||||
signal_handler_disconnect(sh, "media_restart", SourceMediaRestartMultiHandler, this);
|
||||
signal_handler_disconnect(sh, "media_stopped", SourceMediaStopMultiHandler, this);
|
||||
signal_handler_disconnect(sh, "media_next", SourceMediaNextMultiHandler, this);
|
||||
signal_handler_disconnect(sh, "media_previous", SourceMediaPreviousMultiHandler, this);
|
||||
if (sourceType == OBS_SOURCE_TYPE_INPUT) {
|
||||
signal_handler_disconnect(sh, "activate", HandleInputActiveStateChanged, this);
|
||||
signal_handler_disconnect(sh, "deactivate", HandleInputActiveStateChanged, this);
|
||||
signal_handler_disconnect(sh, "show", HandleInputShowStateChanged, this);
|
||||
signal_handler_disconnect(sh, "hide", HandleInputShowStateChanged, this);
|
||||
signal_handler_disconnect(sh, "mute", HandleInputMuteStateChanged, this);
|
||||
signal_handler_disconnect(sh, "volume", HandleInputVolumeChanged, this);
|
||||
signal_handler_disconnect(sh, "audio_balance", HandleInputAudioBalanceChanged, this);
|
||||
signal_handler_disconnect(sh, "audio_sync", HandleInputAudioSyncOffsetChanged, this);
|
||||
signal_handler_disconnect(sh, "audio_mixers", HandleInputAudioTracksChanged, this);
|
||||
signal_handler_disconnect(sh, "audio_monitoring", HandleInputAudioMonitorTypeChanged, this);
|
||||
signal_handler_disconnect(sh, "media_started", HandleMediaInputPlaybackStarted, this);
|
||||
signal_handler_disconnect(sh, "media_ended", HandleMediaInputPlaybackEnded, this);
|
||||
signal_handler_disconnect(sh, "media_pause", SourceMediaPauseMultiHandler, this);
|
||||
signal_handler_disconnect(sh, "media_play", SourceMediaPlayMultiHandler, this);
|
||||
signal_handler_disconnect(sh, "media_restart", SourceMediaRestartMultiHandler, this);
|
||||
signal_handler_disconnect(sh, "media_stopped", SourceMediaStopMultiHandler, this);
|
||||
signal_handler_disconnect(sh, "media_next", SourceMediaNextMultiHandler, this);
|
||||
signal_handler_disconnect(sh, "media_previous", SourceMediaPreviousMultiHandler, this);
|
||||
}
|
||||
|
||||
// Scenes
|
||||
signal_handler_disconnect(sh, "item_add", HandleSceneItemCreated, this);
|
||||
signal_handler_disconnect(sh, "item_remove", HandleSceneItemRemoved, this);
|
||||
signal_handler_disconnect(sh, "reorder", HandleSceneItemListReindexed, this);
|
||||
signal_handler_disconnect(sh, "item_visible", HandleSceneItemEnableStateChanged, this);
|
||||
signal_handler_disconnect(sh, "item_locked", HandleSceneItemLockStateChanged, this);
|
||||
signal_handler_disconnect(sh, "item_transform", HandleSceneItemTransformChanged, this);
|
||||
if (sourceType == OBS_SOURCE_TYPE_SCENE) {
|
||||
signal_handler_disconnect(sh, "item_add", HandleSceneItemCreated, this);
|
||||
signal_handler_disconnect(sh, "item_remove", HandleSceneItemRemoved, this);
|
||||
signal_handler_disconnect(sh, "reorder", HandleSceneItemListReindexed, this);
|
||||
signal_handler_disconnect(sh, "item_visible", HandleSceneItemEnableStateChanged, this);
|
||||
signal_handler_disconnect(sh, "item_locked", HandleSceneItemLockStateChanged, this);
|
||||
signal_handler_disconnect(sh, "item_select", HandleSceneItemSelected, this);
|
||||
signal_handler_disconnect(sh, "item_transform", HandleSceneItemTransformChanged, this);
|
||||
}
|
||||
|
||||
// Inputs and Scenes
|
||||
if (sourceType == OBS_SOURCE_TYPE_INPUT || sourceType == OBS_SOURCE_TYPE_SCENE) {
|
||||
signal_handler_disconnect(sh, "reorder_filters", HandleSourceFilterListReindexed, this);
|
||||
signal_handler_disconnect(sh, "filter_add", FilterAddMultiHandler, this);
|
||||
signal_handler_disconnect(sh, "filter_remove", FilterRemoveMultiHandler, this);
|
||||
auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *param){
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
eventHandler->DisconnectSourceSignals(filter);
|
||||
};
|
||||
obs_source_enum_filters(source, enumFilters, this);
|
||||
}
|
||||
|
||||
// Transitions
|
||||
if (sourceType == OBS_SOURCE_TYPE_TRANSITION) {
|
||||
signal_handler_disconnect(sh, "transition_start", HandleSceneTransitionStarted, this);
|
||||
signal_handler_disconnect(sh, "transition_stop", HandleSceneTransitionEnded, this);
|
||||
signal_handler_disconnect(sh, "transition_video_stop", HandleSceneTransitionVideoEnded, this);
|
||||
}
|
||||
|
||||
// Filters
|
||||
if (sourceType == OBS_SOURCE_TYPE_FILTER) {
|
||||
signal_handler_disconnect(sh, "enable", HandleSourceFilterEnableStateChanged, this);
|
||||
signal_handler_disconnect(sh, "rename", HandleSourceFilterNameChanged, this);
|
||||
}
|
||||
}
|
||||
|
||||
void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_data)
|
||||
{
|
||||
auto eventHandler = static_cast<EventHandler*>(private_data);
|
||||
|
||||
if (!eventHandler->_obsLoaded.load()) {
|
||||
if (event == OBS_FRONTEND_EVENT_FINISHED_LOADING) {
|
||||
if (!eventHandler->_obsLoaded.load() && event != OBS_FRONTEND_EVENT_FINISHED_LOADING)
|
||||
return;
|
||||
|
||||
switch (event) {
|
||||
// General
|
||||
case OBS_FRONTEND_EVENT_FINISHED_LOADING:
|
||||
blog_debug("[EventHandler::OnFrontendEvent] OBS has finished loading. Connecting final handlers and enabling events...");
|
||||
|
||||
// Connect source signals and enable events only after OBS has fully loaded (to reduce extra logging).
|
||||
eventHandler->_obsLoaded.store(true);
|
||||
|
||||
// In the case that plugins become hotloadable, this will have to go back into `EventHandler::EventHandler()`
|
||||
// Enumerate inputs and connect each one
|
||||
obs_enum_sources([](void* param, obs_source_t* source) {
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
eventHandler->ConnectSourceSignals(source);
|
||||
return true;
|
||||
}, private_data);
|
||||
{
|
||||
auto enumInputs = [](void *param, obs_source_t *source) {
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
eventHandler->ConnectSourceSignals(source);
|
||||
return true;
|
||||
};
|
||||
obs_enum_sources(enumInputs, private_data);
|
||||
}
|
||||
|
||||
// Enumerate scenes and connect each one
|
||||
obs_enum_scenes([](void* param, obs_source_t* source) {
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
eventHandler->ConnectSourceSignals(source);
|
||||
return true;
|
||||
}, private_data);
|
||||
{
|
||||
auto enumScenes = [](void *param, obs_source_t *source) {
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
eventHandler->ConnectSourceSignals(source);
|
||||
return true;
|
||||
};
|
||||
obs_enum_scenes(enumScenes, private_data);
|
||||
}
|
||||
|
||||
// Enumerate all scene transitions and connect each one
|
||||
{
|
||||
obs_frontend_source_list transitions = {};
|
||||
obs_frontend_get_transitions(&transitions);
|
||||
for (size_t i = 0; i < transitions.sources.num; i++) {
|
||||
obs_source_t* transition = transitions.sources.array[i];
|
||||
eventHandler->ConnectSourceSignals(transition);
|
||||
}
|
||||
obs_frontend_source_list_free(&transitions);
|
||||
}
|
||||
|
||||
blog_debug("[EventHandler::OnFrontendEvent] Finished.");
|
||||
|
||||
if (eventHandler->_obsLoadedCallback)
|
||||
eventHandler->_obsLoadedCallback();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
// General
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_EXIT:
|
||||
eventHandler->HandleExitStarted();
|
||||
|
||||
@ -242,18 +318,35 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_
|
||||
|
||||
// In the case that plugins become hotloadable, this will have to go back into `EventHandler::~EventHandler()`
|
||||
// Enumerate inputs and disconnect each one
|
||||
obs_enum_sources([](void* param, obs_source_t* source) {
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
eventHandler->DisconnectSourceSignals(source);
|
||||
return true;
|
||||
}, private_data);
|
||||
{
|
||||
auto enumInputs = [](void *param, obs_source_t *source) {
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
eventHandler->DisconnectSourceSignals(source);
|
||||
return true;
|
||||
};
|
||||
obs_enum_sources(enumInputs, private_data);
|
||||
}
|
||||
|
||||
// Enumerate scenes and disconnect each one
|
||||
obs_enum_scenes([](void* param, obs_source_t* source) {
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
eventHandler->DisconnectSourceSignals(source);
|
||||
return true;
|
||||
}, private_data);
|
||||
{
|
||||
auto enumScenes = [](void *param, obs_source_t *source) {
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
eventHandler->DisconnectSourceSignals(source);
|
||||
return true;
|
||||
};
|
||||
obs_enum_scenes(enumScenes, private_data);
|
||||
}
|
||||
|
||||
// Enumerate all scene transitions and disconnect each one
|
||||
{
|
||||
obs_frontend_source_list transitions = {};
|
||||
obs_frontend_get_transitions(&transitions);
|
||||
for (size_t i = 0; i < transitions.sources.num; i++) {
|
||||
obs_source_t* transition = transitions.sources.array[i];
|
||||
eventHandler->DisconnectSourceSignals(transition);
|
||||
}
|
||||
obs_frontend_source_list_free(&transitions);
|
||||
}
|
||||
|
||||
blog_debug("[EventHandler::OnFrontendEvent] Finished.");
|
||||
|
||||
@ -267,9 +360,27 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_
|
||||
|
||||
// Config
|
||||
case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGING:
|
||||
{
|
||||
obs_frontend_source_list transitions = {};
|
||||
obs_frontend_get_transitions(&transitions);
|
||||
for (size_t i = 0; i < transitions.sources.num; i++) {
|
||||
obs_source_t* transition = transitions.sources.array[i];
|
||||
eventHandler->DisconnectSourceSignals(transition);
|
||||
}
|
||||
obs_frontend_source_list_free(&transitions);
|
||||
}
|
||||
eventHandler->HandleCurrentSceneCollectionChanging();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED:
|
||||
{
|
||||
obs_frontend_source_list transitions = {};
|
||||
obs_frontend_get_transitions(&transitions);
|
||||
for (size_t i = 0; i < transitions.sources.num; i++) {
|
||||
obs_source_t* transition = transitions.sources.array[i];
|
||||
eventHandler->ConnectSourceSignals(transition);
|
||||
}
|
||||
obs_frontend_source_list_free(&transitions);
|
||||
}
|
||||
eventHandler->HandleCurrentSceneCollectionChanged();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED:
|
||||
@ -298,10 +409,21 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_
|
||||
|
||||
// Transitions
|
||||
case OBS_FRONTEND_EVENT_TRANSITION_CHANGED:
|
||||
eventHandler->HandleCurrentSceneTransitionChanged();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED:
|
||||
{
|
||||
obs_frontend_source_list transitions = {};
|
||||
obs_frontend_get_transitions(&transitions);
|
||||
for (size_t i = 0; i < transitions.sources.num; i++) {
|
||||
obs_source_t* transition = transitions.sources.array[i];
|
||||
eventHandler->ConnectSourceSignals(transition);
|
||||
}
|
||||
obs_frontend_source_list_free(&transitions);
|
||||
}
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_TRANSITION_DURATION_CHANGED:
|
||||
eventHandler->HandleCurrentSceneTransitionDurationChanged();
|
||||
break;
|
||||
|
||||
// Outputs
|
||||
@ -461,8 +583,6 @@ void EventHandler::SourceRenamedMultiHandler(void *param, calldata_t *data)
|
||||
case OBS_SOURCE_TYPE_INPUT:
|
||||
eventHandler->HandleInputNameChanged(source, oldSourceName, sourceName);
|
||||
break;
|
||||
case OBS_SOURCE_TYPE_FILTER:
|
||||
break;
|
||||
case OBS_SOURCE_TYPE_TRANSITION:
|
||||
break;
|
||||
case OBS_SOURCE_TYPE_SCENE:
|
||||
|
@ -112,6 +112,22 @@ class EventHandler
|
||||
static void HandleInputAudioTracksChanged(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleInputAudioMonitorTypeChanged(void *param, calldata_t *data); // Direct callback
|
||||
|
||||
// Transitions
|
||||
void HandleCurrentSceneTransitionChanged();
|
||||
void HandleCurrentSceneTransitionDurationChanged();
|
||||
static void HandleSceneTransitionStarted(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleSceneTransitionEnded(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleSceneTransitionVideoEnded(void *param, calldata_t *data); // Direct callback
|
||||
|
||||
// Filters
|
||||
static void FilterAddMultiHandler(void *param, calldata_t *data); // Direct callback
|
||||
static void FilterRemoveMultiHandler(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleSourceFilterListReindexed(void *param, calldata_t *data); // Direct callback
|
||||
void HandleSourceFilterCreated(obs_source_t *source, obs_source_t *filter);
|
||||
void HandleSourceFilterRemoved(obs_source_t *source, obs_source_t *filter);
|
||||
static void HandleSourceFilterNameChanged(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleSourceFilterEnableStateChanged(void *param, calldata_t *data); // Direct callback
|
||||
|
||||
// Outputs
|
||||
void HandleStreamStateChanged(ObsOutputState state);
|
||||
void HandleRecordStateChanged(ObsOutputState state);
|
||||
@ -125,6 +141,7 @@ class EventHandler
|
||||
static void HandleSceneItemListReindexed(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleSceneItemEnableStateChanged(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleSceneItemLockStateChanged(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleSceneItemSelected(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleSceneItemTransformChanged(void *param, calldata_t *data); // Direct callback
|
||||
|
||||
// Media Inputs
|
||||
|
@ -18,3 +18,184 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "EventHandler.h"
|
||||
|
||||
void EventHandler::FilterAddMultiHandler(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
obs_source_t *filter = GetCalldataPointer<obs_source_t>(data, "filter");
|
||||
|
||||
if (!(source && filter))
|
||||
return;
|
||||
|
||||
eventHandler->ConnectSourceSignals(filter);
|
||||
|
||||
eventHandler->HandleSourceFilterCreated(source, filter);
|
||||
}
|
||||
|
||||
void EventHandler::FilterRemoveMultiHandler(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
obs_source_t *filter = GetCalldataPointer<obs_source_t>(data, "filter");
|
||||
|
||||
if (!(source && filter))
|
||||
return;
|
||||
|
||||
eventHandler->DisconnectSourceSignals(filter);
|
||||
|
||||
eventHandler->HandleSourceFilterRemoved(source, filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* A source's filter list has been reindexed.
|
||||
*
|
||||
* @dataField sourceName | String | Name of the source
|
||||
* @dataField filters | Array<Object> | Array of filter objects
|
||||
*
|
||||
* @eventType SourceFilterListReindexed
|
||||
* @eventSubscription Filters
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category filters
|
||||
*/
|
||||
void EventHandler::HandleSourceFilterListReindexed(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!source)
|
||||
return;
|
||||
|
||||
json eventData;
|
||||
eventData["sourceName"] = obs_source_get_name(source);
|
||||
eventData["filters"] = Utils::Obs::ArrayHelper::GetSourceFilterList(source);
|
||||
eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterListReindexed", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filter has been added to a source.
|
||||
*
|
||||
* @dataField sourceName | String | Name of the source the filter was added to
|
||||
* @dataField filterName | String | Name of the filter
|
||||
* @dataField filterKind | String | The kind of the filter
|
||||
* @dataField filterIndex | Number | Index position of the filter
|
||||
* @dataField filterSettings | Object | The settings configured to the filter when it was created
|
||||
* @dataField defaultFilterSettings | Object | The default settings for the filter
|
||||
*
|
||||
* @eventType SourceFilterCreated
|
||||
* @eventSubscription Filters
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category filters
|
||||
*/
|
||||
void EventHandler::HandleSourceFilterCreated(obs_source_t *source, obs_source_t *filter)
|
||||
{
|
||||
std::string filterKind = obs_source_get_id(filter);
|
||||
OBSDataAutoRelease filterSettings = obs_source_get_settings(filter);
|
||||
OBSDataAutoRelease defaultFilterSettings = obs_get_source_defaults(filterKind.c_str());
|
||||
|
||||
json eventData;
|
||||
eventData["sourceName"] = obs_source_get_name(source);
|
||||
eventData["filterName"] = obs_source_get_name(filter);
|
||||
eventData["filterKind"] = filterKind;
|
||||
eventData["filterIndex"] = Utils::Obs::NumberHelper::GetSourceFilterIndex(source, filter);
|
||||
eventData["filterSettings"] = Utils::Json::ObsDataToJson(filterSettings);
|
||||
eventData["defaultFilterSettings"] = Utils::Json::ObsDataToJson(defaultFilterSettings, true);
|
||||
BroadcastEvent(EventSubscription::Filters, "SourceFilterCreated", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filter has been removed from a source.
|
||||
*
|
||||
* @dataField sourceName | String | Name of the source the filter was on
|
||||
* @dataField filterName | String | Name of the filter
|
||||
*
|
||||
* @eventType SourceFilterRemoved
|
||||
* @eventSubscription Filters
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category filters
|
||||
*/
|
||||
void EventHandler::HandleSourceFilterRemoved(obs_source_t *source, obs_source_t *filter)
|
||||
{
|
||||
json eventData;
|
||||
eventData["sourceName"] = obs_source_get_name(source);
|
||||
eventData["filterName"] = obs_source_get_name(filter);
|
||||
BroadcastEvent(EventSubscription::Filters, "SourceFilterRemoved", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of a source filter has changed.
|
||||
*
|
||||
* @dataField sourceName | String | The source the filter is on
|
||||
* @dataField oldFilterName | String | Old name of the filter
|
||||
* @dataField filterName | String | New name of the filter
|
||||
*
|
||||
* @eventType SourceFilterNameChanged
|
||||
* @eventSubscription Filters
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category filters
|
||||
*/
|
||||
void EventHandler::HandleSourceFilterNameChanged(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *filter = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!filter)
|
||||
return;
|
||||
|
||||
json eventData;
|
||||
eventData["sourceName"] = obs_source_get_name(obs_filter_get_parent(filter));
|
||||
eventData["oldFilterName"] = calldata_string(data, "prev_name");
|
||||
eventData["filterName"] = calldata_string(data, "new_name");
|
||||
eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterNameChanged", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* A source filter's enable state has changed.
|
||||
*
|
||||
* @dataField sourceName | String | Name of the source the filter is on
|
||||
* @dataField filterName | String | Name of the filter
|
||||
* @dataField filterEnabled | Boolean | Whether the filter is enabled
|
||||
*
|
||||
* @eventType SourceFilterEnableStateChanged
|
||||
* @eventSubscription Filters
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category filters
|
||||
*/
|
||||
void EventHandler::HandleSourceFilterEnableStateChanged(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *filter = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!filter)
|
||||
return;
|
||||
|
||||
// Not OBSSourceAutoRelease as get_parent doesn't increment refcount
|
||||
obs_source_t *source = obs_filter_get_parent(filter);
|
||||
if (!source)
|
||||
return;
|
||||
|
||||
bool filterEnabled = calldata_bool(data, "enabled");
|
||||
|
||||
json eventData;
|
||||
eventData["sourceName"] = obs_source_get_name(source);
|
||||
eventData["filterName"] = obs_source_get_name(filter);
|
||||
eventData["filterEnabled"] = filterEnabled;
|
||||
eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterEnableStateChanged", eventData);
|
||||
}
|
||||
|
@ -158,9 +158,9 @@ void EventHandler::HandleSceneItemEnableStateChanged(void *param, calldata_t *da
|
||||
/**
|
||||
* A scene item's lock state has changed.
|
||||
*
|
||||
* @dataField sceneName | String | Name of the scene the item is in
|
||||
* @dataField sceneItemId | Number | Numeric ID of the scene item
|
||||
* @dataField sceneItemEnabled | Boolean | Whether the scene item is locked
|
||||
* @dataField sceneName | String | Name of the scene the item is in
|
||||
* @dataField sceneItemId | Number | Numeric ID of the scene item
|
||||
* @dataField sceneItemLocked | Boolean | Whether the scene item is locked
|
||||
*
|
||||
* @eventType SceneItemLockStateChanged
|
||||
* @eventSubscription SceneItems
|
||||
@ -191,6 +191,38 @@ void EventHandler::HandleSceneItemLockStateChanged(void *param, calldata_t *data
|
||||
eventHandler->BroadcastEvent(EventSubscription::SceneItems, "SceneItemLockStateChanged", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* A scene item has been selected in the Ui.
|
||||
*
|
||||
* @dataField sceneName | String | Name of the scene the item is in
|
||||
* @dataField sceneItemId | Number | Numeric ID of the scene item
|
||||
*
|
||||
* @eventType SceneItemSelected
|
||||
* @eventSubscription SceneItems
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category scene items
|
||||
*/
|
||||
void EventHandler::HandleSceneItemSelected(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_scene_t *scene = GetCalldataPointer<obs_scene_t>(data, "scene");
|
||||
if (!scene)
|
||||
return;
|
||||
|
||||
obs_sceneitem_t *sceneItem = GetCalldataPointer<obs_sceneitem_t>(data, "item");
|
||||
if (!sceneItem)
|
||||
return;
|
||||
|
||||
json eventData;
|
||||
eventData["sceneName"] = obs_source_get_name(obs_scene_get_source(scene));
|
||||
eventData["sceneItemId"] = obs_sceneitem_get_id(sceneItem);
|
||||
eventHandler->BroadcastEvent(EventSubscription::SceneItems, "SceneItemSelected", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* The transform/crop of a scene item has changed.
|
||||
*
|
||||
|
@ -18,3 +18,130 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "EventHandler.h"
|
||||
|
||||
/**
|
||||
* The current scene transition has changed.
|
||||
*
|
||||
* @dataField transitionName | String | Name of the new transition
|
||||
*
|
||||
* @eventType CurrentSceneTransitionChanged
|
||||
* @eventSubscription Transitions
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category transitions
|
||||
*/
|
||||
void EventHandler::HandleCurrentSceneTransitionChanged()
|
||||
{
|
||||
OBSSourceAutoRelease transition = obs_frontend_get_current_transition();
|
||||
|
||||
json eventData;
|
||||
eventData["transitionName"] = obs_source_get_name(transition);
|
||||
BroadcastEvent(EventSubscription::Transitions, "CurrentSceneTransitionChanged", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* The current scene transition duration has changed.
|
||||
*
|
||||
* @dataField transitionDuration | Number | Transition duration in milliseconds
|
||||
*
|
||||
* @eventType CurrentSceneTransitionDurationChanged
|
||||
* @eventSubscription Transitions
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category transitions
|
||||
*/
|
||||
void EventHandler::HandleCurrentSceneTransitionDurationChanged()
|
||||
{
|
||||
json eventData;
|
||||
eventData["transitionDuration"] = obs_frontend_get_transition_duration();
|
||||
BroadcastEvent(EventSubscription::Transitions, "CurrentSceneTransitionDurationChanged", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* A scene transition has started.
|
||||
*
|
||||
* @dataField transitionName | String | Scene transition name
|
||||
*
|
||||
* @eventType SceneTransitionStarted
|
||||
* @eventSubscription Transitions
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category transitions
|
||||
*/
|
||||
void EventHandler::HandleSceneTransitionStarted(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!source)
|
||||
return;
|
||||
|
||||
json eventData;
|
||||
eventData["transitionName"] = obs_source_get_name(source);
|
||||
eventHandler->BroadcastEvent(EventSubscription::Transitions, "SceneTransitionStarted", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* A scene transition has completed fully.
|
||||
*
|
||||
* Note: Does not appear to trigger when the transition is interrupted by the user.
|
||||
*
|
||||
* @dataField transitionName | String | Scene transition name
|
||||
*
|
||||
* @eventType SceneTransitionEnded
|
||||
* @eventSubscription Transitions
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category transitions
|
||||
*/
|
||||
void EventHandler::HandleSceneTransitionEnded(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!source)
|
||||
return;
|
||||
|
||||
json eventData;
|
||||
eventData["transitionName"] = obs_source_get_name(source);
|
||||
eventHandler->BroadcastEvent(EventSubscription::Transitions, "SceneTransitionEnded", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* A scene transition's video has completed fully.
|
||||
*
|
||||
* Useful for stinger transitions to tell when the video *actually* ends.
|
||||
* `SceneTransitionEnded` only signifies the cut point, not the completion of transition playback.
|
||||
*
|
||||
* Note: Appears to be called by every transition, regardless of relevance.
|
||||
*
|
||||
* @dataField transitionName | String | Scene transition name
|
||||
*
|
||||
* @eventType SceneTransitionVideoEnded
|
||||
* @eventSubscription Transitions
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category transitions
|
||||
*/
|
||||
void EventHandler::HandleSceneTransitionVideoEnded(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!source)
|
||||
return;
|
||||
|
||||
json eventData;
|
||||
eventData["transitionName"] = obs_source_get_name(source);
|
||||
eventHandler->BroadcastEvent(EventSubscription::Transitions, "SceneTransitionVideoEnded", eventData);
|
||||
}
|
||||
|
@ -151,7 +151,7 @@
|
||||
<number>65534</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>4444</number>
|
||||
<number>4455</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -51,6 +51,7 @@ const std::unordered_map<std::string, RequestMethodHandler> RequestHandler::_han
|
||||
{"SetVideoSettings", &RequestHandler::SetVideoSettings},
|
||||
{"GetStreamServiceSettings", &RequestHandler::GetStreamServiceSettings},
|
||||
{"SetStreamServiceSettings", &RequestHandler::SetStreamServiceSettings},
|
||||
{"GetRecordDirectory", &RequestHandler::GetRecordDirectory},
|
||||
|
||||
// Sources
|
||||
{"GetSourceActive", &RequestHandler::GetSourceActive},
|
||||
@ -69,6 +70,8 @@ const std::unordered_map<std::string, RequestMethodHandler> RequestHandler::_han
|
||||
{"CreateScene", &RequestHandler::CreateScene},
|
||||
{"RemoveScene", &RequestHandler::RemoveScene},
|
||||
{"SetSceneName", &RequestHandler::SetSceneName},
|
||||
{"GetSceneSceneTransitionOverride", &RequestHandler::GetSceneSceneTransitionOverride},
|
||||
{"SetSceneSceneTransitionOverride", &RequestHandler::SetSceneSceneTransitionOverride},
|
||||
|
||||
// Inputs
|
||||
{"GetInputList", &RequestHandler::GetInputList},
|
||||
@ -103,10 +106,20 @@ const std::unordered_map<std::string, RequestMethodHandler> RequestHandler::_han
|
||||
{"SetCurrentSceneTransition", &RequestHandler::SetCurrentSceneTransition},
|
||||
{"SetCurrentSceneTransitionDuration", &RequestHandler::SetCurrentSceneTransitionDuration},
|
||||
{"SetCurrentSceneTransitionSettings", &RequestHandler::SetCurrentSceneTransitionSettings},
|
||||
{"GetCurrentSceneTransitionCursor", &RequestHandler::GetCurrentSceneTransitionCursor},
|
||||
{"TriggerStudioModeTransition", &RequestHandler::TriggerStudioModeTransition},
|
||||
{"SetTBarPosition", &RequestHandler::SetTBarPosition},
|
||||
|
||||
// Filters
|
||||
{"GetSourceFilterList", &RequestHandler::GetSourceFilterList},
|
||||
{"GetSourceFilterDefaultSettings", &RequestHandler::GetSourceFilterDefaultSettings},
|
||||
{"CreateSourceFilter", &RequestHandler::CreateSourceFilter},
|
||||
{"RemoveSourceFilter", &RequestHandler::RemoveSourceFilter},
|
||||
{"SetSourceFilterName", &RequestHandler::SetSourceFilterName},
|
||||
{"GetSourceFilter", &RequestHandler::GetSourceFilter},
|
||||
{"SetSourceFilterIndex", &RequestHandler::SetSourceFilterIndex},
|
||||
{"SetSourceFilterSettings", &RequestHandler::SetSourceFilterSettings},
|
||||
{"SetSourceFilterEnabled", &RequestHandler::SetSourceFilterEnabled},
|
||||
|
||||
// Scene Items
|
||||
{"GetSceneItemList", &RequestHandler::GetSceneItemList},
|
||||
@ -131,12 +144,19 @@ const std::unordered_map<std::string, RequestMethodHandler> RequestHandler::_han
|
||||
{"ToggleVirtualCam", &RequestHandler::ToggleVirtualCam},
|
||||
{"StartVirtualCam", &RequestHandler::StartVirtualCam},
|
||||
{"StopVirtualCam", &RequestHandler::StopVirtualCam},
|
||||
{"GetReplayBufferStatus", &RequestHandler::GetReplayBufferStatus},
|
||||
{"ToggleReplayBuffer", &RequestHandler::ToggleReplayBuffer},
|
||||
{"StartReplayBuffer", &RequestHandler::StartReplayBuffer},
|
||||
{"StopReplayBuffer", &RequestHandler::StopReplayBuffer},
|
||||
{"SaveReplayBuffer", &RequestHandler::SaveReplayBuffer},
|
||||
{"GetLastReplayBufferReplay", &RequestHandler::GetLastReplayBufferReplay},
|
||||
|
||||
// Stream
|
||||
{"GetStreamStatus", &RequestHandler::GetStreamStatus},
|
||||
{"ToggleStream", &RequestHandler::ToggleStream},
|
||||
{"StartStream", &RequestHandler::StartStream},
|
||||
{"StopStream", &RequestHandler::StopStream},
|
||||
{"SendStreamCaption", &RequestHandler::SendStreamCaption},
|
||||
|
||||
// Record
|
||||
{"GetRecordStatus", &RequestHandler::GetRecordStatus},
|
||||
@ -146,7 +166,6 @@ const std::unordered_map<std::string, RequestMethodHandler> RequestHandler::_han
|
||||
{"ToggleRecordPause", &RequestHandler::ToggleRecordPause},
|
||||
{"PauseRecord", &RequestHandler::PauseRecord},
|
||||
{"ResumeRecord", &RequestHandler::ResumeRecord},
|
||||
{"GetRecordDirectory", &RequestHandler::GetRecordDirectory},
|
||||
|
||||
// Media Inputs
|
||||
{"GetMediaInputStatus", &RequestHandler::GetMediaInputStatus},
|
||||
|
@ -69,6 +69,7 @@ class RequestHandler {
|
||||
RequestResult SetVideoSettings(const Request&);
|
||||
RequestResult GetStreamServiceSettings(const Request&);
|
||||
RequestResult SetStreamServiceSettings(const Request&);
|
||||
RequestResult GetRecordDirectory(const Request&);
|
||||
|
||||
// Sources
|
||||
RequestResult GetSourceActive(const Request&);
|
||||
@ -87,6 +88,8 @@ class RequestHandler {
|
||||
RequestResult CreateScene(const Request&);
|
||||
RequestResult RemoveScene(const Request&);
|
||||
RequestResult SetSceneName(const Request&);
|
||||
RequestResult GetSceneSceneTransitionOverride(const Request&);
|
||||
RequestResult SetSceneSceneTransitionOverride(const Request&);
|
||||
|
||||
// Inputs
|
||||
RequestResult GetInputList(const Request&);
|
||||
@ -121,10 +124,20 @@ class RequestHandler {
|
||||
RequestResult SetCurrentSceneTransition(const Request&);
|
||||
RequestResult SetCurrentSceneTransitionDuration(const Request&);
|
||||
RequestResult SetCurrentSceneTransitionSettings(const Request&);
|
||||
RequestResult GetCurrentSceneTransitionCursor(const Request&);
|
||||
RequestResult TriggerStudioModeTransition(const Request&);
|
||||
RequestResult SetTBarPosition(const Request&);
|
||||
|
||||
// Filters
|
||||
RequestResult GetSourceFilterList(const Request&);
|
||||
RequestResult GetSourceFilterDefaultSettings(const Request&);
|
||||
RequestResult CreateSourceFilter(const Request&);
|
||||
RequestResult RemoveSourceFilter(const Request&);
|
||||
RequestResult SetSourceFilterName(const Request&);
|
||||
RequestResult GetSourceFilter(const Request&);
|
||||
RequestResult SetSourceFilterIndex(const Request&);
|
||||
RequestResult SetSourceFilterSettings(const Request&);
|
||||
RequestResult SetSourceFilterEnabled(const Request&);
|
||||
|
||||
// Scene Items
|
||||
RequestResult GetSceneItemList(const Request&);
|
||||
@ -149,12 +162,19 @@ class RequestHandler {
|
||||
RequestResult ToggleVirtualCam(const Request&);
|
||||
RequestResult StartVirtualCam(const Request&);
|
||||
RequestResult StopVirtualCam(const Request&);
|
||||
RequestResult GetReplayBufferStatus(const Request&);
|
||||
RequestResult ToggleReplayBuffer(const Request&);
|
||||
RequestResult StartReplayBuffer(const Request&);
|
||||
RequestResult StopReplayBuffer(const Request&);
|
||||
RequestResult SaveReplayBuffer(const Request&);
|
||||
RequestResult GetLastReplayBufferReplay(const Request&);
|
||||
|
||||
// Stream
|
||||
RequestResult GetStreamStatus(const Request&);
|
||||
RequestResult ToggleStream(const Request&);
|
||||
RequestResult StartStream(const Request&);
|
||||
RequestResult StopStream(const Request&);
|
||||
RequestResult SendStreamCaption(const Request&);
|
||||
|
||||
// Record
|
||||
RequestResult GetRecordStatus(const Request&);
|
||||
@ -164,7 +184,6 @@ class RequestHandler {
|
||||
RequestResult ToggleRecordPause(const Request&);
|
||||
RequestResult PauseRecord(const Request&);
|
||||
RequestResult ResumeRecord(const Request&);
|
||||
RequestResult GetRecordDirectory(const Request&);
|
||||
|
||||
// Media Inputs
|
||||
RequestResult GetMediaInputStatus(const Request&);
|
||||
|
@ -408,6 +408,8 @@ RequestResult RequestHandler::SetProfileParameter(const Request& request)
|
||||
return RequestResult::Error(RequestStatus::InvalidRequestFieldType, "The field `parameterValue` must be a string.");
|
||||
}
|
||||
|
||||
config_save(profile);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
@ -592,3 +594,23 @@ RequestResult RequestHandler::SetStreamServiceSettings(const Request& request)
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current directory that the record output is set to.
|
||||
*
|
||||
* @responseField recordDirectory | String | Output directory
|
||||
*
|
||||
* @requestType GetRecordDirectory
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category rconfig
|
||||
*/
|
||||
RequestResult RequestHandler::GetRecordDirectory(const Request&)
|
||||
{
|
||||
json responseData;
|
||||
responseData["recordDirectory"] = Utils::Obs::StringHelper::GetCurrentRecordOutputPath();
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
@ -19,6 +19,178 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
#include "RequestHandler.h"
|
||||
|
||||
/**
|
||||
* Gets an array of all of a source's filters.
|
||||
*
|
||||
* @requestField sourceName | String | Name of the source
|
||||
*
|
||||
* @responseField filters | Array<Object> | Array of filters
|
||||
*
|
||||
* @requestType GetSourceFilterList
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category filters
|
||||
*/
|
||||
RequestResult RequestHandler::GetSourceFilterList(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease source = request.ValidateSource("sourceName", statusCode, comment);
|
||||
if(!source)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
json responseData;
|
||||
responseData["filters"] = Utils::Obs::ArrayHelper::GetSourceFilterList(source);
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default settings for a filter kind.
|
||||
*
|
||||
* @requestField filterKind | String | Filter kind to get the default settings for
|
||||
*
|
||||
* @responseField defaultFilterSettings | Object | Object of default settings for the filter kind
|
||||
*
|
||||
* @requestType GetSourceFilterDefaultSettings
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category filters
|
||||
*/
|
||||
RequestResult RequestHandler::GetSourceFilterDefaultSettings(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
if (!request.ValidateString("filterKind", statusCode, comment))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
std::string filterKind = request.RequestData["filterKind"];
|
||||
auto kinds = Utils::Obs::ArrayHelper::GetFilterKindList();
|
||||
if (std::find(kinds.begin(), kinds.end(), filterKind) == kinds.end())
|
||||
return RequestResult::Error(RequestStatus::InvalidFilterKind);
|
||||
|
||||
OBSDataAutoRelease defaultSettings = obs_get_source_defaults(filterKind.c_str());
|
||||
if (!defaultSettings)
|
||||
return RequestResult::Error(RequestStatus::InvalidFilterKind);
|
||||
|
||||
json responseData;
|
||||
responseData["defaultFilterSettings"] = Utils::Json::ObsDataToJson(defaultSettings, true);
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new filter, adding it to the specified source.
|
||||
*
|
||||
* @requestField sourceName | String | Name of the source to add the filter to
|
||||
* @requestField filterName | String | Name of the new filter to be created
|
||||
* @requestField filterKind | String | The kind of filter to be created
|
||||
* @requestField ?filterSettings | Object | Settings object to initialize the filter with | Default settings used
|
||||
*
|
||||
* @requestType CreateSourceFilter
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category filters
|
||||
*/
|
||||
RequestResult RequestHandler::CreateSourceFilter(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
|
||||
OBSSourceAutoRelease source = request.ValidateSource("sourceName", statusCode, comment);
|
||||
if (!(source && request.ValidateString("filterName", statusCode, comment) && request.ValidateString("filterKind", statusCode, comment)))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
std::string filterName = request.RequestData["filterName"];
|
||||
OBSSourceAutoRelease existingFilter = obs_source_get_filter_by_name(source, filterName.c_str());
|
||||
if (existingFilter)
|
||||
return RequestResult::Error(RequestStatus::ResourceAlreadyExists, "A filter already exists by that name.");
|
||||
|
||||
std::string filterKind = request.RequestData["filterKind"];
|
||||
auto kinds = Utils::Obs::ArrayHelper::GetFilterKindList();
|
||||
if (std::find(kinds.begin(), kinds.end(), filterKind) == kinds.end())
|
||||
return RequestResult::Error(RequestStatus::InvalidFilterKind, "Your specified filter kind is not supported by OBS. Check that any necessary plugins are loaded.");
|
||||
|
||||
OBSDataAutoRelease filterSettings = nullptr;
|
||||
if (request.Contains("filterSettings")) {
|
||||
if (!request.ValidateOptionalObject("filterSettings", statusCode, comment, true))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
filterSettings = Utils::Json::JsonToObsData(request.RequestData["filterSettings"]);
|
||||
}
|
||||
|
||||
OBSSourceAutoRelease filter = Utils::Obs::ActionHelper::CreateSourceFilter(source, filterName, filterKind, filterSettings);
|
||||
|
||||
if(!filter)
|
||||
return RequestResult::Error(RequestStatus::ResourceCreationFailed, "Creation of the filter failed.");
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a filter from a source.
|
||||
*
|
||||
* @requestField sourceName | String | Name of the source the filter is on
|
||||
* @requestField filterName | String | Name of the filter to remove
|
||||
*
|
||||
* @requestType RemoveSourceFilter
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category filters
|
||||
*/
|
||||
RequestResult RequestHandler::RemoveSourceFilter(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment);
|
||||
if (!pair.filter)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
obs_source_filter_remove(pair.source, pair.filter);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of a source filter (rename).
|
||||
*
|
||||
* @requestField sourceName | String | Name of the source the filter is on
|
||||
* @requestField filterName | String | Current name of the filter
|
||||
* @requestField newFilterName | String | New name for the filter
|
||||
*
|
||||
* @requestType SetSourceFilterName
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category filters
|
||||
*/
|
||||
RequestResult RequestHandler::SetSourceFilterName(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment);
|
||||
if (!pair.filter || !request.ValidateString("newFilterName", statusCode, comment))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
std::string newFilterName = request.RequestData["newFilterName"];
|
||||
|
||||
OBSSourceAutoRelease existingFilter = obs_source_get_filter_by_name(pair.source, newFilterName.c_str());
|
||||
if (existingFilter)
|
||||
return RequestResult::Error(RequestStatus::ResourceAlreadyExists, "A filter already exists by that new name.");
|
||||
|
||||
obs_source_set_name(pair.filter, newFilterName.c_str());
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the info for a specific source filter.
|
||||
*
|
||||
@ -55,3 +227,108 @@ RequestResult RequestHandler::GetSourceFilter(const Request& request)
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the index position of a filter on a source.
|
||||
*
|
||||
* @requestField sourceName | String | Name of the source the filter is on
|
||||
* @requestField filterName | String | Name of the filter
|
||||
* @requestField filterIndex | Number | New index position of the filter | >= 0
|
||||
*
|
||||
* @requestType SetSourceFilterIndex
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category filters
|
||||
*/
|
||||
RequestResult RequestHandler::SetSourceFilterIndex(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment);
|
||||
if (!(pair.filter && request.ValidateNumber("filterIndex", statusCode, comment, 0, 8192)))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
int filterIndex = request.RequestData["filterIndex"];
|
||||
|
||||
Utils::Obs::ActionHelper::SetSourceFilterIndex(pair.source, pair.filter, filterIndex);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the settings of a source filter.
|
||||
*
|
||||
* @requestField sourceName | String | Name of the source the filter is on
|
||||
* @requestField filterName | String | Name of the filter to set the settings of
|
||||
* @requestField filterSettings | Object | Object of settings to apply
|
||||
* @requestField ?overlay | Boolean | True == apply the settings on top of existing ones, False == reset the input to its defaults, then apply settings. | true
|
||||
*
|
||||
* @requestType SetSourceFilterSettings
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category filters
|
||||
*/
|
||||
RequestResult RequestHandler::SetSourceFilterSettings(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment);
|
||||
if (!(pair.filter && request.ValidateObject("filterSettings", statusCode, comment, true)))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
// Almost identical to SetInputSettings
|
||||
|
||||
bool overlay = true;
|
||||
if (request.Contains("overlay")) {
|
||||
if (!request.ValidateOptionalBoolean("overlay", statusCode, comment))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
overlay = request.RequestData["overlay"];
|
||||
}
|
||||
|
||||
OBSDataAutoRelease newSettings = Utils::Json::JsonToObsData(request.RequestData["filterSettings"]);
|
||||
if (!newSettings)
|
||||
return RequestResult::Error(RequestStatus::RequestProcessingFailed, "An internal data conversion operation failed. Please report this!");
|
||||
|
||||
if (overlay)
|
||||
obs_source_update(pair.filter, newSettings);
|
||||
else
|
||||
obs_source_reset_settings(pair.filter, newSettings);
|
||||
|
||||
obs_source_update_properties(pair.filter);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the enable state of a source filter.
|
||||
*
|
||||
* @requestField sourceName | String | Name of the source the filter is on
|
||||
* @requestField filterName | Number | Name of the filter
|
||||
* @requestField filterEnabled | Boolean | New enable state of the filter
|
||||
*
|
||||
* @requestType SetSourceFilterEnabled
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category filters
|
||||
*/
|
||||
RequestResult RequestHandler::SetSourceFilterEnabled(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment);
|
||||
if (!(pair.filter && request.ValidateBoolean("filterEnabled", statusCode, comment)))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
bool filterEnabled = request.RequestData["filterEnabled"];
|
||||
|
||||
obs_source_set_enabled(pair.filter, filterEnabled);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
@ -269,6 +269,9 @@ RequestResult RequestHandler::GetInputDefaultSettings(const Request& request)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
std::string inputKind = request.RequestData["inputKind"];
|
||||
auto kinds = Utils::Obs::ArrayHelper::GetInputKindList();
|
||||
if (std::find(kinds.begin(), kinds.end(), inputKind) == kinds.end())
|
||||
return RequestResult::Error(RequestStatus::InvalidInputKind);
|
||||
|
||||
OBSDataAutoRelease defaultSettings = obs_get_source_defaults(inputKind.c_str());
|
||||
if (!defaultSettings)
|
||||
|
@ -28,6 +28,12 @@ static bool VirtualCamAvailable()
|
||||
return obs_data_get_bool(privateData, "vcamEnabled");
|
||||
}
|
||||
|
||||
static bool ReplayBufferAvailable()
|
||||
{
|
||||
OBSOutputAutoRelease output = obs_frontend_get_replay_buffer_output();
|
||||
return output != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the status of the virtualcam output.
|
||||
*
|
||||
@ -124,3 +130,148 @@ RequestResult RequestHandler::StopVirtualCam(const Request&)
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the status of the replay buffer output.
|
||||
*
|
||||
* @responseField outputActive | Boolean | Whether the output is active
|
||||
*
|
||||
* @requestType GetReplayBufferStatus
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @category outputs
|
||||
* @api requests
|
||||
*/
|
||||
RequestResult RequestHandler::GetReplayBufferStatus(const Request&)
|
||||
{
|
||||
if (!ReplayBufferAvailable())
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available.");
|
||||
|
||||
json responseData;
|
||||
responseData["outputActive"] = obs_frontend_replay_buffer_active();
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the state of the replay buffer output.
|
||||
*
|
||||
* @responseField outputActive | Boolean | Whether the output is active
|
||||
*
|
||||
* @requestType ToggleReplayBuffer
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @category outputs
|
||||
* @api requests
|
||||
*/
|
||||
RequestResult RequestHandler::ToggleReplayBuffer(const Request&)
|
||||
{
|
||||
if (!ReplayBufferAvailable())
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available.");
|
||||
|
||||
bool outputActive = obs_frontend_replay_buffer_active();
|
||||
|
||||
if (outputActive)
|
||||
obs_frontend_replay_buffer_stop();
|
||||
else
|
||||
obs_frontend_replay_buffer_start();
|
||||
|
||||
json responseData;
|
||||
responseData["outputActive"] = !outputActive;
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the replay buffer output.
|
||||
*
|
||||
* @requestType StartReplayBuffer
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category outputs
|
||||
*/
|
||||
RequestResult RequestHandler::StartReplayBuffer(const Request&)
|
||||
{
|
||||
if (!ReplayBufferAvailable())
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available.");
|
||||
|
||||
if (obs_frontend_replay_buffer_active())
|
||||
return RequestResult::Error(RequestStatus::OutputRunning);
|
||||
|
||||
obs_frontend_replay_buffer_start();
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the replay buffer output.
|
||||
*
|
||||
* @requestType StopReplayBuffer
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category outputs
|
||||
*/
|
||||
RequestResult RequestHandler::StopReplayBuffer(const Request&)
|
||||
{
|
||||
if (!ReplayBufferAvailable())
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available.");
|
||||
|
||||
if (!obs_frontend_replay_buffer_active())
|
||||
return RequestResult::Error(RequestStatus::OutputNotRunning);
|
||||
|
||||
obs_frontend_replay_buffer_stop();
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the contents of the replay buffer output.
|
||||
*
|
||||
* @requestType SaveReplayBuffer
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category outputs
|
||||
*/
|
||||
RequestResult RequestHandler::SaveReplayBuffer(const Request&)
|
||||
{
|
||||
if (!ReplayBufferAvailable())
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available.");
|
||||
|
||||
if (!obs_frontend_replay_buffer_active())
|
||||
return RequestResult::Error(RequestStatus::OutputNotRunning);
|
||||
|
||||
obs_frontend_replay_buffer_save();
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the filename of the last replay buffer save file.
|
||||
*
|
||||
* @responseField savedReplayPath | String | File path
|
||||
*
|
||||
* @requestType GetLastReplayBufferReplay
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category outputs
|
||||
*/
|
||||
RequestResult RequestHandler::GetLastReplayBufferReplay(const Request&)
|
||||
{
|
||||
if (!ReplayBufferAvailable())
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available.");
|
||||
|
||||
if (!obs_frontend_replay_buffer_active())
|
||||
return RequestResult::Error(RequestStatus::OutputNotRunning);
|
||||
|
||||
json responseData;
|
||||
responseData["savedReplayPath"] = Utils::Obs::StringHelper::GetLastReplayBufferFilePath();
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
@ -182,23 +182,3 @@ RequestResult RequestHandler::ResumeRecord(const Request&)
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current directory that the record output is set to.
|
||||
*
|
||||
* @responseField recordDirectory | String | Output directory
|
||||
*
|
||||
* @requestType GetRecordDirectory
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category record
|
||||
*/
|
||||
RequestResult RequestHandler::GetRecordDirectory(const Request&)
|
||||
{
|
||||
json responseData;
|
||||
responseData["recordDirectory"] = Utils::Obs::StringHelper::GetCurrentRecordOutputPath();
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
@ -232,8 +232,9 @@ RequestResult RequestHandler::DuplicateSceneItem(const Request& request)
|
||||
if (!destinationScene)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
} else {
|
||||
destinationScene = obs_sceneitem_get_scene(sceneItem);
|
||||
obs_scene_addref(destinationScene);
|
||||
destinationScene = obs_scene_get_ref(obs_sceneitem_get_scene(sceneItem));
|
||||
if (!destinationScene)
|
||||
return RequestResult::Error(RequestStatus::RequestProcessingFailed, "Internal error: Failed to get ref for scene of scene item.");
|
||||
}
|
||||
|
||||
if (obs_sceneitem_is_group(sceneItem) && obs_sceneitem_get_scene(sceneItem) == destinationScene) {
|
||||
|
@ -273,3 +273,105 @@ RequestResult RequestHandler::SetSceneName(const Request& request)
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scene transition overridden for a scene.
|
||||
*
|
||||
* @requestField sceneName | String | Name of the scene
|
||||
*
|
||||
* @responseField transitionName | String | Name of the overridden scene transition, else `null`
|
||||
* @responseField transitionDuration | Number | Duration of the overridden scene transition, else `null`
|
||||
*
|
||||
* @requestType GetSceneSceneTransitionOverride
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category scenes
|
||||
*/
|
||||
RequestResult RequestHandler::GetSceneSceneTransitionOverride(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease scene = request.ValidateScene("sceneName", statusCode, comment);
|
||||
if (!scene)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
OBSDataAutoRelease privateSettings = obs_source_get_private_settings(scene);
|
||||
|
||||
json responseData;
|
||||
const char *transitionName = obs_data_get_string(privateSettings, "transition");
|
||||
if (transitionName && strlen(transitionName))
|
||||
responseData["transitionName"] = transitionName;
|
||||
else
|
||||
responseData["transitionName"] = nullptr;
|
||||
|
||||
if (obs_data_has_user_value(privateSettings, "transition_duration"))
|
||||
responseData["transitionDuration"] = obs_data_get_int(privateSettings, "transition_duration");
|
||||
else
|
||||
responseData["transitionDuration"] = nullptr;
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scene transition overridden for a scene.
|
||||
*
|
||||
* @requestField sceneName | String | Name of the scene
|
||||
* @requestField ?transitionName | String | Name of the scene transition to use as override. Specify `null` to remove | Unchanged
|
||||
* @requestField ?transitionDuration | Number | Duration to use for any overridden transition. Specify `null` to remove | >= 50, <= 20000 | Unchanged
|
||||
*
|
||||
* @requestType SetSceneSceneTransitionOverride
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category scenes
|
||||
*/
|
||||
RequestResult RequestHandler::SetSceneSceneTransitionOverride(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease scene = request.ValidateScene("sceneName", statusCode, comment);
|
||||
if (!scene)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
OBSDataAutoRelease privateSettings = obs_source_get_private_settings(scene);
|
||||
|
||||
bool hasName = request.RequestData.contains("transitionName");
|
||||
if (hasName && !request.RequestData["transitionName"].is_null()) {
|
||||
if (!request.ValidateOptionalString("transitionName", statusCode, comment))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
OBSSourceAutoRelease transition = Utils::Obs::SearchHelper::GetSceneTransitionByName(request.RequestData["transitionName"]);
|
||||
if (!transition)
|
||||
return RequestResult::Error(RequestStatus::ResourceNotFound, "No scene transition was found by that name.");
|
||||
}
|
||||
|
||||
bool hasDuration = request.RequestData.contains("transitionDuration");
|
||||
if (hasDuration && !request.RequestData["transitionDuration"].is_null()) {
|
||||
if (!request.ValidateOptionalNumber("transitionDuration", statusCode, comment, 50, 20000))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
}
|
||||
|
||||
if (!hasName && !hasDuration)
|
||||
return RequestResult::Error(RequestStatus::MissingRequestField, "Your request data must include either `transitionName` or `transitionDuration`.");
|
||||
|
||||
if (hasName) {
|
||||
if (request.RequestData["transitionName"].is_null()) {
|
||||
obs_data_erase(privateSettings, "transition");
|
||||
} else {
|
||||
std::string transitionName = request.RequestData["transitionName"];
|
||||
obs_data_set_string(privateSettings, "transition", transitionName.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (hasDuration) {
|
||||
if (request.RequestData["transitionDuration"].is_null()) {
|
||||
obs_data_erase(privateSettings, "transition_duration");
|
||||
} else {
|
||||
obs_data_set_int(privateSettings, "transition_duration", request.RequestData["transitionDuration"]);
|
||||
}
|
||||
}
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
@ -122,3 +122,35 @@ RequestResult RequestHandler::StopStream(const Request&)
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends CEA-608 caption text over the stream output.
|
||||
*
|
||||
* @requestField captionText | String | Caption text
|
||||
*
|
||||
* @requestType SendStreamCaption
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @category stream
|
||||
* @api requests
|
||||
*/
|
||||
RequestResult RequestHandler::SendStreamCaption(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
if (!request.ValidateString("captionText", statusCode, comment, true))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
if (!obs_frontend_streaming_active())
|
||||
return RequestResult::Error(RequestStatus::OutputNotRunning);
|
||||
|
||||
std::string captionText = request.RequestData["captionText"];
|
||||
|
||||
OBSOutputAutoRelease output = obs_frontend_get_streaming_output();
|
||||
|
||||
// 0.0 means no delay until the next caption can be sent
|
||||
obs_output_output_caption_text2(output, captionText.c_str(), 0.0);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ You should have received a copy of the GNU General Public License along
|
||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "RequestHandler.h"
|
||||
|
||||
/**
|
||||
@ -226,6 +228,32 @@ RequestResult RequestHandler::SetCurrentSceneTransitionSettings(const Request& r
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cursor position of the current scene transition.
|
||||
*
|
||||
* Note: `transitionCursor` will return 1.0 when the transition is inactive.
|
||||
*
|
||||
* @responseField transitionCursor | Number | Cursor position, between 0.0 and 1.0
|
||||
*
|
||||
* @requestType GetCurrentSceneTransitionCursor
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category transitions
|
||||
*/
|
||||
RequestResult RequestHandler::GetCurrentSceneTransitionCursor(const Request&)
|
||||
{
|
||||
OBSSourceAutoRelease transition = obs_frontend_get_current_transition();
|
||||
if (!transition)
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "OBS does not currently have a scene transition set."); // This should not happen!
|
||||
|
||||
json responseData;
|
||||
responseData["transitionCursor"] = obs_transition_get_time(transition);
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the current scene transition. Same functionality as the `Transition` button in studio mode.
|
||||
*
|
||||
@ -247,3 +275,48 @@ RequestResult RequestHandler::TriggerStudioModeTransition(const Request&)
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position of the TBar.
|
||||
*
|
||||
* **Very important note**: This will be deprecated and replaced in a future version of obs-websocket.
|
||||
*
|
||||
* @requestField position | Number | New position | >= 0.0, <= 1.0
|
||||
* @requestField ?release | Boolean | Whether to release the TBar. Only set `false` if you know that you will be sending another position update | `true`
|
||||
*
|
||||
* @requestType SetTBarPosition
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category transitions
|
||||
*/
|
||||
RequestResult RequestHandler::SetTBarPosition(const Request& request)
|
||||
{
|
||||
if (!obs_frontend_preview_program_mode_active())
|
||||
return RequestResult::Error(RequestStatus::StudioModeNotActive);
|
||||
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
if (!request.ValidateNumber("position", statusCode, comment, 0.0, 1.0))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
bool release = true;
|
||||
if (request.Contains("release")) {
|
||||
if (!request.ValidateOptionalBoolean("release", statusCode, comment))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
}
|
||||
|
||||
OBSSourceAutoRelease transition = obs_frontend_get_current_transition();
|
||||
if (!transition)
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "OBS does not currently have a scene transition set."); // This should not happen!
|
||||
|
||||
float position = request.RequestData["position"];
|
||||
|
||||
obs_frontend_set_tbar_position((int)round(position * 1024.0));
|
||||
|
||||
if (release)
|
||||
obs_frontend_release_tbar();
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
@ -264,18 +264,14 @@ obs_scene_t *Request::ValidateScene2(const std::string &keyName, RequestStatus::
|
||||
comment = "The specified source is not a scene. (Is group)";
|
||||
return nullptr;
|
||||
}
|
||||
OBSScene ret = obs_group_from_source(sceneSource);
|
||||
obs_scene_addref(ret);
|
||||
return ret;
|
||||
return obs_scene_get_ref(obs_group_from_source(sceneSource));
|
||||
} else {
|
||||
if (filter == OBS_WEBSOCKET_SCENE_FILTER_GROUP_ONLY) {
|
||||
statusCode = RequestStatus::InvalidResourceType;
|
||||
comment = "The specified source is not a group. (Is scene)";
|
||||
return nullptr;
|
||||
}
|
||||
OBSScene ret = obs_scene_from_source(sceneSource);
|
||||
obs_scene_addref(ret);
|
||||
return ret;
|
||||
return obs_scene_get_ref(obs_scene_from_source(sceneSource));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace RequestBatchExecutionType {
|
||||
enum RequestBatchExecutionType {
|
||||
enum RequestBatchExecutionType: int8_t {
|
||||
/**
|
||||
* Not a request batch.
|
||||
*
|
||||
@ -77,7 +77,7 @@ namespace RequestBatchExecutionType {
|
||||
Parallel = 2,
|
||||
};
|
||||
|
||||
inline bool IsValid(int executionType)
|
||||
inline bool IsValid(int8_t executionType)
|
||||
{
|
||||
return executionType >= None && executionType <= Parallel;
|
||||
}
|
||||
|
@ -345,6 +345,17 @@ namespace RequestStatus {
|
||||
* @api enums
|
||||
*/
|
||||
ResourceNotConfigurable = 606,
|
||||
/**
|
||||
* The specified filter (obs_source_t-OBS_SOURCE_TYPE_FILTER) had the wrong kind.
|
||||
*
|
||||
* @enumIdentifier InvalidFilterKind
|
||||
* @enumValue 607
|
||||
* @enumType RequestStatus
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api enums
|
||||
*/
|
||||
InvalidFilterKind = 607,
|
||||
|
||||
/**
|
||||
* Creating the resource failed.
|
||||
|
@ -193,6 +193,8 @@ namespace Utils {
|
||||
std::vector<json> GetListPropertyItems(obs_property_t *property);
|
||||
std::vector<std::string> GetTransitionKindList();
|
||||
std::vector<json> GetSceneTransitionList();
|
||||
std::vector<json> GetSourceFilterList(obs_source_t *source);
|
||||
std::vector<std::string> GetFilterKindList();
|
||||
}
|
||||
|
||||
namespace ObjectHelper {
|
||||
@ -209,6 +211,8 @@ namespace Utils {
|
||||
namespace ActionHelper {
|
||||
obs_sceneitem_t *CreateSceneItem(obs_source_t *source, obs_scene_t *scene, bool sceneItemEnabled = true, obs_transform_info *sceneItemTransform = nullptr, obs_sceneitem_crop *sceneItemCrop = nullptr); // Increments ref. Use OBSSceneItemAutoRelease
|
||||
obs_sceneitem_t *CreateInput(std::string inputName, std::string inputKind, obs_data_t *inputSettings, obs_scene_t *scene, bool sceneItemEnabled = true); // Increments ref. Use OBSSceneItemAutoRelease
|
||||
obs_source_t *CreateSourceFilter(obs_source_t *source, std::string filterName, std::string filterKind, obs_data_t *filterSettings); // Increments source ref. Use OBSSourceAutoRelease
|
||||
void SetSourceFilterIndex(obs_source_t *source, obs_source_t *filter, size_t index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -87,3 +87,30 @@ obs_sceneitem_t *Utils::Obs::ActionHelper::CreateInput(std::string inputName, st
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
obs_source_t *Utils::Obs::ActionHelper::CreateSourceFilter(obs_source_t *source, std::string filterName, std::string filterKind, obs_data_t *filterSettings)
|
||||
{
|
||||
obs_source_t *filter = obs_source_create_private(filterKind.c_str(), filterName.c_str(), filterSettings);
|
||||
|
||||
if (!filter)
|
||||
return nullptr;
|
||||
|
||||
obs_source_filter_add(source, filter);
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
void Utils::Obs::ActionHelper::SetSourceFilterIndex(obs_source_t *source, obs_source_t *filter, size_t index)
|
||||
{
|
||||
size_t currentIndex = Utils::Obs::NumberHelper::GetSourceFilterIndex(source, filter);
|
||||
obs_order_movement direction = index > currentIndex ? OBS_ORDER_MOVE_DOWN : OBS_ORDER_MOVE_UP;
|
||||
|
||||
while(currentIndex != index) {
|
||||
obs_source_filter_set_order(source, filter, direction);
|
||||
|
||||
if (direction == OBS_ORDER_MOVE_DOWN)
|
||||
currentIndex++;
|
||||
else
|
||||
currentIndex--;
|
||||
}
|
||||
}
|
||||
|
@ -88,6 +88,7 @@ std::vector<json> Utils::Obs::ArrayHelper::GetSceneList()
|
||||
obs_frontend_get_scenes(&sceneList);
|
||||
|
||||
std::vector<json> ret;
|
||||
ret.reserve(sceneList.sources.num);
|
||||
for (size_t i = 0; i < sceneList.sources.num; i++) {
|
||||
obs_source_t *scene = sceneList.sources.array[i];
|
||||
|
||||
@ -225,6 +226,8 @@ std::vector<json> Utils::Obs::ArrayHelper::GetListPropertyItems(obs_property_t *
|
||||
enum obs_combo_format itemFormat = obs_property_list_format(property);
|
||||
size_t itemCount = obs_property_list_item_count(property);
|
||||
|
||||
ret.reserve(itemCount);
|
||||
|
||||
for (size_t i = 0; i < itemCount; i++) {
|
||||
json itemData;
|
||||
itemData["itemName"] = obs_property_list_item_name(property, i);
|
||||
@ -262,6 +265,7 @@ std::vector<json> Utils::Obs::ArrayHelper::GetSceneTransitionList()
|
||||
obs_frontend_get_transitions(&transitionList);
|
||||
|
||||
std::vector<json> ret;
|
||||
ret.reserve(transitionList.sources.num);
|
||||
for (size_t i = 0; i < transitionList.sources.num; i++) {
|
||||
obs_source_t *transition = transitionList.sources.array[i];
|
||||
json transitionJson;
|
||||
@ -276,3 +280,38 @@ std::vector<json> Utils::Obs::ArrayHelper::GetSceneTransitionList()
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::string> Utils::Obs::ArrayHelper::GetFilterKindList()
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
|
||||
size_t idx = 0;
|
||||
const char *kind;
|
||||
while(obs_enum_filter_types(idx++, &kind))
|
||||
ret.push_back(kind);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<json> Utils::Obs::ArrayHelper::GetSourceFilterList(obs_source_t *source)
|
||||
{
|
||||
std::vector<json> filters;
|
||||
|
||||
auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *param) {
|
||||
auto filters = reinterpret_cast<std::vector<json>*>(param);
|
||||
|
||||
json filterJson;
|
||||
filterJson["filterEnabled"] = obs_source_enabled(filter);
|
||||
filterJson["filterIndex"] = filters->size();
|
||||
filterJson["filterKind"] = obs_source_get_id(filter);
|
||||
filterJson["filterName"] = obs_source_get_name(filter);
|
||||
|
||||
OBSDataAutoRelease filterSettings = obs_source_get_settings(filter);
|
||||
filterJson["filterSettings"] = Utils::Json::ObsDataToJson(filterSettings);
|
||||
|
||||
filters->push_back(filterJson);
|
||||
};
|
||||
obs_source_enum_filters(source, enumFilters, &filters);
|
||||
|
||||
return filters;
|
||||
}
|
||||
|
@ -120,12 +120,19 @@ std::string Utils::Obs::StringHelper::GetMediaInputState(obs_source_t *input)
|
||||
std::string Utils::Obs::StringHelper::GetLastReplayBufferFilePath()
|
||||
{
|
||||
OBSOutputAutoRelease output = obs_frontend_get_replay_buffer_output();
|
||||
if (!output)
|
||||
return "";
|
||||
|
||||
calldata_t cd = {0};
|
||||
proc_handler_t *ph = obs_output_get_proc_handler(output);
|
||||
proc_handler_call(ph, "get_last_replay", &cd);
|
||||
auto ret = calldata_string(&cd, "path");
|
||||
const char *savedReplayPath = calldata_string(&cd, "path");
|
||||
calldata_free(&cd);
|
||||
return ret;
|
||||
|
||||
if (!savedReplayPath)
|
||||
return "";
|
||||
|
||||
return savedReplayPath;
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetSceneItemBoundsType(enum obs_bounds_type type)
|
||||
|
@ -233,7 +233,7 @@ void WebSocketServer::ProcessMessage(SessionPtr session, WebSocketServer::Proces
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t requestedExecutionType = payloadData["executionType"];
|
||||
int8_t requestedExecutionType = payloadData["executionType"];
|
||||
if (!RequestBatchExecutionType::IsValid(requestedExecutionType) || requestedExecutionType == RequestBatchExecutionType::None) {
|
||||
ret.closeCode = WebSocketCloseCode::InvalidDataFieldValue;
|
||||
ret.closeReason = "Your `executionType` has an invalid value.";
|
||||
|
Reference in New Issue
Block a user