Merge branch '4.x-current' into feature/createsource

This commit is contained in:
Stéphane Lepin 2020-11-27 12:24:13 +01:00
commit e30dce8b21
27 changed files with 873 additions and 342 deletions

View File

@ -35,13 +35,8 @@ done
# qtwebsockets deps # qtwebsockets deps
echo "[obs-websocket] Installing obs-websocket dependency 'QT 5.10.1'.." echo "[obs-websocket] Installing obs-websocket dependency 'QT 5.10.1'.."
# =!= NOTICE =!=
# When building QT5 from sources on macOS 10.13+, use local qt5 formula:
# brew install ./CI/macos/qt.rb
# Pouring from the bottle is much quicker though, so use bottle for now.
# =!= NOTICE =!=
brew install https://gist.githubusercontent.com/DDRBoxman/b3956fab6073335a4bf151db0dcbd4ad/raw/ed1342a8a86793ea8c10d8b4d712a654da121ace/qt.rb brew install ./CI/macos/qt.rb
# Pin this version of QT5 to avoid `brew upgrade` # Pin this version of QT5 to avoid `brew upgrade`
# upgrading it to incompatible version # upgrading it to incompatible version

View File

@ -3,10 +3,10 @@
class Qt < Formula class Qt < Formula
desc "Cross-platform application and UI framework" desc "Cross-platform application and UI framework"
homepage "https://www.qt.io/" homepage "https://www.qt.io/"
url "https://download.qt.io/archive/qt/5.10/5.10.1/single/qt-everywhere-src-5.10.1.tar.xz" url "https://download.qt.io/official_releases/qt/5.10/5.10.1/single/qt-everywhere-src-5.10.1.tar.xz"
mirror "https://mirrorservice.org/sites/download.qt-project.org/official_releases/qt/5.10/5.10.1/single/qt-everywhere-src-5.10.1.tar.xz" mirror "https://www.mirrorservice.org/sites/download.qt-project.org/official_releases/qt/5.10/5.10.1/single/qt-everywhere-src-5.10.1.tar.xz"
sha256 "05ffba7b811b854ed558abf2be2ddbd3bb6ddd0b60ea4b5da75d277ac15e740a" sha256 "05ffba7b811b854ed558abf2be2ddbd3bb6ddd0b60ea4b5da75d277ac15e740a"
head "https://code.qt.io/qt/qt5.git", :branch => "5.10.1", :shallow => false head "https://code.qt.io/qt/qt5.git", :branch => "5.10", :shallow => false
bottle do bottle do
sha256 "8b4bad005596a5f8790150fe455db998ac2406f4e0f04140d6656205d844d266" => :high_sierra sha256 "8b4bad005596a5f8790150fe455db998ac2406f4e0f04140d6656205d844d266" => :high_sierra
@ -18,17 +18,16 @@ class Qt < Formula
option "with-docs", "Build documentation" option "with-docs", "Build documentation"
option "with-examples", "Build examples" option "with-examples", "Build examples"
option "without-proprietary-codecs", "Don't build with proprietary codecs (e.g. mp3)"
deprecated_option "with-mysql" => "with-mysql-client"
# OS X 10.7 Lion is still supported in Qt 5.5, but is no longer a reference # OS X 10.7 Lion is still supported in Qt 5.5, but is no longer a reference
# configuration and thus untested in practice. Builds on OS X 10.7 have been # configuration and thus untested in practice. Builds on OS X 10.7 have been
# reported to fail: <https://github.com/Homebrew/homebrew/issues/45284>. # reported to fail: <https://github.com/Homebrew/homebrew/issues/45284>.
depends_on :macos => :mountain_lion # depends_on :macos => :mountain_lion
depends_on "pkg-config" => :build depends_on "pkg-config" => :build
depends_on :xcode => :build depends_on :xcode => :build
depends_on "mysql-client" => :optional depends_on "mysql" => :optional
depends_on "postgresql" => :optional depends_on "postgresql" => :optional
# Restore `.pc` files for framework-based build of Qt 5 on OS X. This # Restore `.pc` files for framework-based build of Qt 5 on OS X. This
@ -44,23 +43,6 @@ class Qt < Formula
sha256 "48ff18be2f4050de7288bddbae7f47e949512ac4bcd126c2f504be2ac701158b" sha256 "48ff18be2f4050de7288bddbae7f47e949512ac4bcd126c2f504be2ac701158b"
end end
# Fix compile error on macOS 10.13 around QFixed:
# https://github.com/Homebrew/homebrew-core/issues/27095
# https://bugreports.qt.io/browse/QTBUG-67545
patch do
url "https://raw.githubusercontent.com/z00m1n/formula-patches/0de0e229/qt/QTBUG-67545.patch"
sha256 "4a115097c7582c7dce4207f5500d13feb8c990eb8a05a43f41953985976ebe6c"
end
# Fix compile error on macOS 10.13 caused by qtlocation dependency
# mapbox-gl-native using Boost 1.62.0 does not build with C++ 17:
# https://github.com/Homebrew/homebrew-core/issues/27095
# https://bugreports.qt.io/browse/QTBUG-67810
patch do
url "https://raw.githubusercontent.com/z00m1n/formula-patches/a1a1f0dd/qt/QTBUG-67810.patch"
sha256 "8ee0bf71df1043f08ebae3aa35036be29c4d9ebff8a27e3b0411a6bd635e9382"
end
def install def install
args = %W[ args = %W[
-verbose -verbose
@ -76,12 +58,11 @@ class Qt < Formula
-no-rpath -no-rpath
-pkg-config -pkg-config
-dbus-runtime -dbus-runtime
-no-assimp
] ]
args << "-nomake" << "examples" if build.without? "examples" args << "-nomake" << "examples" if build.without? "examples"
if build.with? "mysql-client" if build.with? "mysql"
args << "-plugin-sql-mysql" args << "-plugin-sql-mysql"
(buildpath/"brew_shim/mysql_config").write <<~EOS (buildpath/"brew_shim/mysql_config").write <<~EOS
#!/bin/sh #!/bin/sh
@ -96,6 +77,7 @@ class Qt < Formula
end end
args << "-plugin-sql-psql" if build.with? "postgresql" args << "-plugin-sql-psql" if build.with? "postgresql"
args << "-proprietary-codecs" if build.with? "proprietary-codecs"
system "./configure", *args system "./configure", *args
system "make" system "make"

View File

@ -11,6 +11,10 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_definitions(-DASIO_STANDALONE) add_definitions(-DASIO_STANDALONE)
if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm")
set(CMAKE_CXX_FLAGS "-mfpu=neon")
endif()
if (WIN32 OR APPLE) if (WIN32 OR APPLE)
include(external/FindLibObs.cmake) include(external/FindLibObs.cmake)
endif() endif()

View File

@ -16,7 +16,10 @@ Binaries for Windows, MacOS, and Linux are available in the [Releases](https://g
## Using obs-websocket ## Using obs-websocket
A web client and frontend made by [t2t2](https://github.com/t2t2/obs-tablet-remote) (compatible with tablets and other touch interfaces) is available here : http://t2t2.github.io/obs-tablet-remote/ Here is a list of available web clients: (compatible with tablets and other touch interfaces)
- [Niek/obs-web](https://github.com/Niek/obs-web)
- [t2t2/obs-tablet-remote](https://github.com/t2t2/obs-tablet-remote)
It is **highly recommended** to protect obs-websocket with a password against unauthorized control. To do this, open the "Websocket server settings" dialog under OBS' "Tools" menu. In the settings dialogs, you can enable or disable authentication and set a password for it. It is **highly recommended** to protect obs-websocket with a password against unauthorized control. To do this, open the "Websocket server settings" dialog under OBS' "Tools" menu. In the settings dialogs, you can enable or disable authentication and set a password for it.

View File

@ -3,6 +3,7 @@ OBSWebsocket.Settings.ServerEnable="Enable WebSockets server"
OBSWebsocket.Settings.ServerPort="Server Port" OBSWebsocket.Settings.ServerPort="Server Port"
OBSWebsocket.Settings.AuthRequired="Enable authentication" OBSWebsocket.Settings.AuthRequired="Enable authentication"
OBSWebsocket.Settings.Password="Password" OBSWebsocket.Settings.Password="Password"
OBSWebsocket.Settings.LockToIPv4="Lock server to only using IPv4"
OBSWebsocket.Settings.DebugEnable="Enable debug logging" OBSWebsocket.Settings.DebugEnable="Enable debug logging"
OBSWebsocket.Settings.AlertsEnable="Enable System Tray Alerts" OBSWebsocket.Settings.AlertsEnable="Enable System Tray Alerts"
OBSWebsocket.NotifyConnect.Title="New WebSocket connection" OBSWebsocket.NotifyConnect.Title="New WebSocket connection"

View File

@ -2515,7 +2515,8 @@
"{String} `sourceName` Source name", "{String} `sourceName` Source name",
"{Array<Object>} `filters` Ordered Filters list", "{Array<Object>} `filters` Ordered Filters list",
"{String} `filters.*.name` Filter name", "{String} `filters.*.name` Filter name",
"{String} `filters.*.type` Filter type" "{String} `filters.*.type` Filter type",
"{boolean} `filters.*.enabled` Filter visibility status"
], ],
"api": "events", "api": "events",
"name": "SourceFiltersReordered", "name": "SourceFiltersReordered",
@ -2541,6 +2542,11 @@
"type": "String", "type": "String",
"name": "filters.*.type", "name": "filters.*.type",
"description": "Filter type" "description": "Filter type"
},
{
"type": "boolean",
"name": "filters.*.enabled",
"description": "Filter visibility status"
} }
], ],
"names": [ "names": [
@ -4059,6 +4065,120 @@
"lead": "", "lead": "",
"type": "class", "type": "class",
"examples": [] "examples": []
},
{
"subheads": [],
"description": "Executes hotkey routine, identified by hotkey unique name",
"param": "{String} `hotkeyName` Unique name of the hotkey, as defined when registering the hotkey (e.g. \"ReplayBuffer.Save\")",
"api": "requests",
"name": "TriggerHotkeyByName",
"category": "general",
"since": "unreleased",
"params": [
{
"type": "String",
"name": "hotkeyName",
"description": "Unique name of the hotkey, as defined when registering the hotkey (e.g. \"ReplayBuffer.Save\")"
}
],
"names": [
{
"name": "",
"description": "TriggerHotkeyByName"
}
],
"categories": [
{
"name": "",
"description": "general"
}
],
"sinces": [
{
"name": "",
"description": "unreleased"
}
],
"heading": {
"level": 2,
"text": "TriggerHotkeyByName"
},
"lead": "",
"type": "class",
"examples": []
},
{
"subheads": [],
"description": "Executes hotkey routine, identified by bound combination of keys. A single key combination might trigger multiple hotkey routines depending on user settings",
"param": [
"{String} `keyId` Main key identifier (e.g. `OBS_KEY_A` for key \"A\"). Available identifiers [here](https://github.com/obsproject/obs-studio/blob/master/libobs/obs-hotkeys.h)",
"{Object (Optional)} `keyModifiers` Optional key modifiers object. False entries can be ommitted",
"{boolean} `keyModifiers.shift` Trigger Shift Key",
"{boolean} `keyModifiers.alt` Trigger Alt Key",
"{boolean} `keyModifiers.control` Trigger Control (Ctrl) Key",
"{boolean} `keyModifiers.command` Trigger Command Key (Mac)"
],
"api": "requests",
"name": "TriggerHotkeyBySequence",
"category": "general",
"since": "unreleased",
"params": [
{
"type": "String",
"name": "keyId",
"description": "Main key identifier (e.g. `OBS_KEY_A` for key \"A\"). Available identifiers [here](https://github.com/obsproject/obs-studio/blob/master/libobs/obs-hotkeys.h)"
},
{
"type": "Object (Optional)",
"name": "keyModifiers",
"description": "Optional key modifiers object. False entries can be ommitted"
},
{
"type": "boolean",
"name": "keyModifiers.shift",
"description": "Trigger Shift Key"
},
{
"type": "boolean",
"name": "keyModifiers.alt",
"description": "Trigger Alt Key"
},
{
"type": "boolean",
"name": "keyModifiers.control",
"description": "Trigger Control (Ctrl) Key"
},
{
"type": "boolean",
"name": "keyModifiers.command",
"description": "Trigger Command Key (Mac)"
}
],
"names": [
{
"name": "",
"description": "TriggerHotkeyBySequence"
}
],
"categories": [
{
"name": "",
"description": "general"
}
],
"sinces": [
{
"name": "",
"description": "unreleased"
}
],
"heading": {
"level": 2,
"text": "TriggerHotkeyBySequence"
},
"lead": "",
"type": "class",
"examples": []
} }
], ],
"media control": [ "media control": [
@ -7972,8 +8092,9 @@
{ {
"subheads": [], "subheads": [],
"description": "Get a list of all scene items in a scene.", "description": "Get a list of all scene items in a scene.",
"param": "{String} `sceneName` Name of the scene to get the list of scene items from.", "param": "{String (optional)} `sceneName` Name of the scene to get the list of scene items from. Defaults to the current scene if not specified.",
"return": [ "return": [
"{String} `sceneName` Name of the requested (or current) scene",
"{Array<Object>} `sceneItems` Array of scene items", "{Array<Object>} `sceneItems` Array of scene items",
"{int} `sceneItems.*.itemId` Unique item id of the source item", "{int} `sceneItems.*.itemId` Unique item id of the source item",
"{String} `sceneItems.*.sourceKind` ID if the scene item's source. For example `vlc_source` or `image_source`", "{String} `sceneItems.*.sourceKind` ID if the scene item's source. For example `vlc_source` or `image_source`",
@ -7985,6 +8106,11 @@
"category": "scene items", "category": "scene items",
"since": "unreleased", "since": "unreleased",
"returns": [ "returns": [
{
"type": "String",
"name": "sceneName",
"description": "Name of the requested (or current) scene"
},
{ {
"type": "Array<Object>", "type": "Array<Object>",
"name": "sceneItems", "name": "sceneItems",
@ -8013,9 +8139,9 @@
], ],
"params": [ "params": [
{ {
"type": "String", "type": "String (optional)",
"name": "sceneName", "name": "sceneName",
"description": "Name of the scene to get the list of scene items from." "description": "Name of the scene to get the list of scene items from. Defaults to the current scene if not specified."
} }
], ],
"names": [ "names": [
@ -9233,7 +9359,7 @@
"api": "requests", "api": "requests",
"name": "SetSceneTransitionOverride", "name": "SetSceneTransitionOverride",
"category": "scenes", "category": "scenes",
"since": "unreleased", "since": "4.8.0",
"params": [ "params": [
{ {
"type": "String", "type": "String",
@ -9266,7 +9392,7 @@
"sinces": [ "sinces": [
{ {
"name": "", "name": "",
"description": "unreleased" "description": "4.8.0"
} }
], ],
"heading": { "heading": {
@ -9284,7 +9410,7 @@
"api": "requests", "api": "requests",
"name": "RemoveSceneTransitionOverride", "name": "RemoveSceneTransitionOverride",
"category": "scenes", "category": "scenes",
"since": "unreleased", "since": "4.8.0",
"params": [ "params": [
{ {
"type": "String", "type": "String",
@ -9307,7 +9433,7 @@
"sinces": [ "sinces": [
{ {
"name": "", "name": "",
"description": "unreleased" "description": "4.8.0"
} }
], ],
"heading": { "heading": {
@ -9329,7 +9455,7 @@
"api": "requests", "api": "requests",
"name": "GetSceneTransitionOverride", "name": "GetSceneTransitionOverride",
"category": "scenes", "category": "scenes",
"since": "unreleased", "since": "4.8.0",
"returns": [ "returns": [
{ {
"type": "String", "type": "String",
@ -9364,7 +9490,7 @@
"sinces": [ "sinces": [
{ {
"name": "", "name": "",
"description": "unreleased" "description": "4.8.0"
} }
], ],
"heading": { "heading": {
@ -10395,6 +10521,112 @@
"lead": "", "lead": "",
"type": "class", "type": "class",
"examples": [] "examples": []
},
{
"subheads": [],
"description": "Get the current settings of a transition",
"param": "{String} `transitionName` Transition name",
"return": "{Object} `transitionSettings` Current transition settings",
"api": "requests",
"name": "GetTransitionSettings",
"category": "transitions",
"since": "unreleased",
"returns": [
{
"type": "Object",
"name": "transitionSettings",
"description": "Current transition settings"
}
],
"params": [
{
"type": "String",
"name": "transitionName",
"description": "Transition name"
}
],
"names": [
{
"name": "",
"description": "GetTransitionSettings"
}
],
"categories": [
{
"name": "",
"description": "transitions"
}
],
"sinces": [
{
"name": "",
"description": "unreleased"
}
],
"heading": {
"level": 2,
"text": "GetTransitionSettings"
},
"lead": "",
"type": "class",
"examples": []
},
{
"subheads": [],
"description": "Change the current settings of a transition",
"param": [
"{String} `transitionName` Transition name",
"{Object} `transitionSettings` Transition settings (they can be partial)"
],
"return": "{Object} `transitionSettings` Updated transition settings",
"api": "requests",
"name": "SetTransitionSettings",
"category": "transitions",
"since": "unreleased",
"returns": [
{
"type": "Object",
"name": "transitionSettings",
"description": "Updated transition settings"
}
],
"params": [
{
"type": "String",
"name": "transitionName",
"description": "Transition name"
},
{
"type": "Object",
"name": "transitionSettings",
"description": "Transition settings (they can be partial)"
}
],
"names": [
{
"name": "",
"description": "SetTransitionSettings"
}
],
"categories": [
{
"name": "",
"description": "transitions"
}
],
"sinces": [
{
"name": "",
"description": "unreleased"
}
],
"heading": {
"level": 2,
"text": "SetTransitionSettings"
},
"lead": "",
"type": "class",
"examples": []
} }
] ]
} }

View File

@ -136,6 +136,8 @@ You can also refer to any of the client libraries listed on the [README](README.
+ [BroadcastCustomMessage](#broadcastcustommessage-1) + [BroadcastCustomMessage](#broadcastcustommessage-1)
+ [GetVideoInfo](#getvideoinfo) + [GetVideoInfo](#getvideoinfo)
+ [OpenProjector](#openprojector) + [OpenProjector](#openprojector)
+ [TriggerHotkeyByName](#triggerhotkeybyname)
+ [TriggerHotkeyBySequence](#triggerhotkeybysequence)
* [Media Control](#media-control) * [Media Control](#media-control)
+ [PlayPauseMedia](#playpausemedia) + [PlayPauseMedia](#playpausemedia)
+ [RestartMedia](#restartmedia) + [RestartMedia](#restartmedia)
@ -253,6 +255,8 @@ You can also refer to any of the client libraries listed on the [README](README.
+ [SetTransitionDuration](#settransitionduration) + [SetTransitionDuration](#settransitionduration)
+ [GetTransitionDuration](#gettransitionduration) + [GetTransitionDuration](#gettransitionduration)
+ [GetTransitionPosition](#gettransitionposition) + [GetTransitionPosition](#gettransitionposition)
+ [GetTransitionSettings](#gettransitionsettings)
+ [SetTransitionSettings](#settransitionsettings)
<!-- tocstop --> <!-- tocstop -->
@ -1073,6 +1077,7 @@ Filters in a source have been reordered.
| `filters` | _Array&lt;Object&gt;_ | Ordered Filters list | | `filters` | _Array&lt;Object&gt;_ | Ordered Filters list |
| `filters.*.name` | _String_ | Filter name | | `filters.*.name` | _String_ | Filter name |
| `filters.*.type` | _String_ | Filter type | | `filters.*.type` | _String_ | Filter type |
| `filters.*.enabled` | _boolean_ | Filter visibility status |
--- ---
@ -1648,6 +1653,51 @@ Open a projector window or create a projector on a monitor. Requires OBS v24.0.4
| `name` | _String (Optional)_ | Name of the source or scene to be displayed (ignored for other projector types). | | `name` | _String (Optional)_ | Name of the source or scene to be displayed (ignored for other projector types). |
**Response Items:**
_No additional response items._
---
### TriggerHotkeyByName
- Unreleased
Executes hotkey routine, identified by hotkey unique name
**Request Fields:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `hotkeyName` | _String_ | Unique name of the hotkey, as defined when registering the hotkey (e.g. "ReplayBuffer.Save") |
**Response Items:**
_No additional response items._
---
### TriggerHotkeyBySequence
- Unreleased
Executes hotkey routine, identified by bound combination of keys. A single key combination might trigger multiple hotkey routines depending on user settings
**Request Fields:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `keyId` | _String_ | Main key identifier (e.g. `OBS_KEY_A` for key "A"). Available identifiers [here](https://github.com/obsproject/obs-studio/blob/master/libobs/obs-hotkeys.h) |
| `keyModifiers` | _Object (Optional)_ | Optional key modifiers object. False entries can be ommitted |
| `keyModifiers.shift` | _boolean_ | Trigger Shift Key |
| `keyModifiers.alt` | _boolean_ | Trigger Alt Key |
| `keyModifiers.control` | _boolean_ | Trigger Control (Ctrl) Key |
| `keyModifiers.command` | _boolean_ | Trigger Command Key (Mac) |
**Response Items:** **Response Items:**
_No additional response items._ _No additional response items._
@ -3213,13 +3263,14 @@ Get a list of all scene items in a scene.
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `sceneName` | _String_ | Name of the scene to get the list of scene items from. | | `sceneName` | _String (optional)_ | Name of the scene to get the list of scene items from. Defaults to the current scene if not specified. |
**Response Items:** **Response Items:**
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `sceneName` | _String_ | Name of the requested (or current) scene |
| `sceneItems` | _Array&lt;Object&gt;_ | Array of scene items | | `sceneItems` | _Array&lt;Object&gt;_ | Array of scene items |
| `sceneItems.*.itemId` | _int_ | Unique item id of the source item | | `sceneItems.*.itemId` | _int_ | Unique item id of the source item |
| `sceneItems.*.sourceKind` | _String_ | ID if the scene item's source. For example `vlc_source` or `image_source` | | `sceneItems.*.sourceKind` | _String_ | ID if the scene item's source. For example `vlc_source` or `image_source` |
@ -3629,7 +3680,7 @@ _No additional response items._
### SetSceneTransitionOverride ### SetSceneTransitionOverride
- Unreleased - Added in v4.8.0
Set a scene to use a specific transition override. Set a scene to use a specific transition override.
@ -3651,7 +3702,7 @@ _No additional response items._
### RemoveSceneTransitionOverride ### RemoveSceneTransitionOverride
- Unreleased - Added in v4.8.0
Remove any transition override on a scene. Remove any transition override on a scene.
@ -3671,7 +3722,7 @@ _No additional response items._
### GetSceneTransitionOverride ### GetSceneTransitionOverride
- Unreleased - Added in v4.8.0
Get the current scene transition override. Get the current scene transition override.
@ -4136,3 +4187,50 @@ _No specified parameters._
--- ---
### GetTransitionSettings
- Unreleased
Get the current settings of a transition
**Request Fields:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `transitionName` | _String_ | Transition name |
**Response Items:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `transitionSettings` | _Object_ | Current transition settings |
---
### SetTransitionSettings
- Unreleased
Change the current settings of a transition
**Request Fields:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `transitionName` | _String_ | Transition name |
| `transitionSettings` | _Object_ | Transition settings (they can be partial) |
**Response Items:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `transitionSettings` | _Object_ | Updated transition settings |
---

View File

@ -23,6 +23,7 @@ DefaultGroupName={#MyAppName}
OutputBaseFilename=obs-websocket-Windows-Installer OutputBaseFilename=obs-websocket-Windows-Installer
Compression=lzma Compression=lzma
SolidCompression=yes SolidCompression=yes
DirExistsWarning=no
[Languages] [Languages]
Name: "english"; MessagesFile: "compiler:Default.isl" Name: "english"; MessagesFile: "compiler:Default.isl"

View File

@ -25,6 +25,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#define SECTION_NAME "WebsocketAPI" #define SECTION_NAME "WebsocketAPI"
#define PARAM_ENABLE "ServerEnabled" #define PARAM_ENABLE "ServerEnabled"
#define PARAM_PORT "ServerPort" #define PARAM_PORT "ServerPort"
#define PARAM_LOCKTOIPV4 "LockToIPv4"
#define PARAM_DEBUG "DebugEnabled" #define PARAM_DEBUG "DebugEnabled"
#define PARAM_ALERT "AlertsEnabled" #define PARAM_ALERT "AlertsEnabled"
#define PARAM_AUTHREQUIRED "AuthRequired" #define PARAM_AUTHREQUIRED "AuthRequired"
@ -41,6 +42,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
Config::Config() : Config::Config() :
ServerEnabled(true), ServerEnabled(true),
ServerPort(4444), ServerPort(4444),
LockToIPv4(false),
DebugEnabled(false), DebugEnabled(false),
AlertsEnabled(true), AlertsEnabled(true),
AuthRequired(false), AuthRequired(false),
@ -67,6 +69,7 @@ void Config::Load()
ServerEnabled = config_get_bool(obsConfig, SECTION_NAME, PARAM_ENABLE); ServerEnabled = config_get_bool(obsConfig, SECTION_NAME, PARAM_ENABLE);
ServerPort = config_get_uint(obsConfig, SECTION_NAME, PARAM_PORT); ServerPort = config_get_uint(obsConfig, SECTION_NAME, PARAM_PORT);
LockToIPv4 = config_get_bool(obsConfig, SECTION_NAME, PARAM_LOCKTOIPV4);
DebugEnabled = config_get_bool(obsConfig, SECTION_NAME, PARAM_DEBUG); DebugEnabled = config_get_bool(obsConfig, SECTION_NAME, PARAM_DEBUG);
AlertsEnabled = config_get_bool(obsConfig, SECTION_NAME, PARAM_ALERT); AlertsEnabled = config_get_bool(obsConfig, SECTION_NAME, PARAM_ALERT);
@ -82,6 +85,7 @@ void Config::Save()
config_set_bool(obsConfig, SECTION_NAME, PARAM_ENABLE, ServerEnabled); config_set_bool(obsConfig, SECTION_NAME, PARAM_ENABLE, ServerEnabled);
config_set_uint(obsConfig, SECTION_NAME, PARAM_PORT, ServerPort); config_set_uint(obsConfig, SECTION_NAME, PARAM_PORT, ServerPort);
config_set_bool(obsConfig, SECTION_NAME, PARAM_LOCKTOIPV4, LockToIPv4);
config_set_bool(obsConfig, SECTION_NAME, PARAM_DEBUG, DebugEnabled); config_set_bool(obsConfig, SECTION_NAME, PARAM_DEBUG, DebugEnabled);
config_set_bool(obsConfig, SECTION_NAME, PARAM_ALERT, AlertsEnabled); config_set_bool(obsConfig, SECTION_NAME, PARAM_ALERT, AlertsEnabled);
@ -104,6 +108,8 @@ void Config::SetDefaults()
SECTION_NAME, PARAM_ENABLE, ServerEnabled); SECTION_NAME, PARAM_ENABLE, ServerEnabled);
config_set_default_uint(obsConfig, config_set_default_uint(obsConfig,
SECTION_NAME, PARAM_PORT, ServerPort); SECTION_NAME, PARAM_PORT, ServerPort);
config_set_default_bool(obsConfig,
SECTION_NAME, PARAM_LOCKTOIPV4, LockToIPv4);
config_set_default_bool(obsConfig, config_set_default_bool(obsConfig,
SECTION_NAME, PARAM_DEBUG, DebugEnabled); SECTION_NAME, PARAM_DEBUG, DebugEnabled);
@ -205,16 +211,17 @@ void Config::OnFrontendEvent(enum obs_frontend_event event, void* param)
bool previousEnabled = config->ServerEnabled; bool previousEnabled = config->ServerEnabled;
uint64_t previousPort = config->ServerPort; uint64_t previousPort = config->ServerPort;
bool previousLock = config->LockToIPv4;
config->SetDefaults(); config->SetDefaults();
config->Load(); config->Load();
if (config->ServerEnabled != previousEnabled || config->ServerPort != previousPort) { if (config->ServerEnabled != previousEnabled || config->ServerPort != previousPort || config->LockToIPv4 != previousLock) {
auto server = GetServer(); auto server = GetServer();
server->stop(); server->stop();
if (config->ServerEnabled) { if (config->ServerEnabled) {
server->start(config->ServerPort); server->start(config->ServerPort, config->LockToIPv4);
if (previousEnabled != config->ServerEnabled) { if (previousEnabled != config->ServerEnabled) {
Utils::SysTrayNotify(startMessage, QSystemTrayIcon::MessageIcon::Information); Utils::SysTrayNotify(startMessage, QSystemTrayIcon::MessageIcon::Information);
@ -247,6 +254,13 @@ void Config::MigrateFromGlobalSettings()
config_remove_value(source, SECTION_NAME, PARAM_PORT); config_remove_value(source, SECTION_NAME, PARAM_PORT);
} }
if(config_has_user_value(source, SECTION_NAME, PARAM_LOCKTOIPV4)) {
bool value = config_get_bool(source, SECTION_NAME, PARAM_LOCKTOIPV4);
config_set_bool(destination, SECTION_NAME, PARAM_LOCKTOIPV4, value);
config_remove_value(source, SECTION_NAME, PARAM_LOCKTOIPV4);
}
if(config_has_user_value(source, SECTION_NAME, PARAM_DEBUG)) { if(config_has_user_value(source, SECTION_NAME, PARAM_DEBUG)) {
bool value = config_get_bool(source, SECTION_NAME, PARAM_DEBUG); bool value = config_get_bool(source, SECTION_NAME, PARAM_DEBUG);
config_set_bool(destination, SECTION_NAME, PARAM_DEBUG, value); config_set_bool(destination, SECTION_NAME, PARAM_DEBUG, value);

View File

@ -42,6 +42,7 @@ class Config {
bool ServerEnabled; bool ServerEnabled;
uint64_t ServerPort; uint64_t ServerPort;
bool LockToIPv4;
bool DebugEnabled; bool DebugEnabled;
bool AlertsEnabled; bool AlertsEnabled;

View File

@ -51,6 +51,25 @@ obs_bounds_type getBoundsTypeFromName(QString name) {
return boundTypeNames.key(name); return boundTypeNames.key(name);
} }
bool Utils::StringInStringList(char** strings, const char* string) {
if (!strings) {
return false;
}
size_t index = 0;
while (strings[index] != NULL) {
char* value = strings[index];
if (strcmp(value, string) == 0) {
return true;
}
index++;
}
return false;
}
obs_data_array_t* Utils::StringListToArray(char** strings, const char* key) { obs_data_array_t* Utils::StringListToArray(char** strings, const char* key) {
obs_data_array_t* list = obs_data_array_create(); obs_data_array_t* list = obs_data_array_create();
@ -485,11 +504,8 @@ QString Utils::OBSVersionString() {
} }
QSystemTrayIcon* Utils::GetTrayIcon() { QSystemTrayIcon* Utils::GetTrayIcon() {
QMainWindow* main = (QMainWindow*)obs_frontend_get_main_window(); void* systemTray = obs_frontend_get_system_tray();
if (!main) return nullptr; return reinterpret_cast<QSystemTrayIcon*>(systemTray);
QList<QSystemTrayIcon*> trays = main->findChildren<QSystemTrayIcon*>();
return trays.isEmpty() ? nullptr : trays.first();
} }
void Utils::SysTrayNotify(QString text, void Utils::SysTrayNotify(QString text,

View File

@ -35,6 +35,7 @@ typedef void(*PauseRecordingFunction)(bool);
typedef bool(*RecordingPausedFunction)(); typedef bool(*RecordingPausedFunction)();
namespace Utils { namespace Utils {
bool StringInStringList(char** strings, const char* string);
obs_data_array_t* StringListToArray(char** strings, const char* key); obs_data_array_t* StringListToArray(char** strings, const char* key);
obs_data_array_t* GetSceneItems(obs_source_t* source); obs_data_array_t* GetSceneItems(obs_source_t* source);
obs_data_t* GetSceneItemData(obs_sceneitem_t* item); obs_data_t* GetSceneItemData(obs_sceneitem_t* item);

View File

@ -1397,6 +1397,7 @@ void WSEvents::OnSourceFilterVisibilityChanged(void* param, calldata_t* data) {
* @return {Array<Object>} `filters` Ordered Filters list * @return {Array<Object>} `filters` Ordered Filters list
* @return {String} `filters.*.name` Filter name * @return {String} `filters.*.name` Filter name
* @return {String} `filters.*.type` Filter type * @return {String} `filters.*.type` Filter type
* @return {boolean} `filters.*.enabled` Filter visibility status
* *
* @api events * @api events
* @name SourceFiltersReordered * @name SourceFiltersReordered

View File

@ -28,7 +28,7 @@
using namespace std::placeholders; using namespace std::placeholders;
const QHash<QString, RpcMethodHandler> WSRequestHandler::messageMap { const QHash<QString, RpcMethodHandler> WSRequestHandler::messageMap{
{ "GetVersion", &WSRequestHandler::GetVersion }, { "GetVersion", &WSRequestHandler::GetVersion },
{ "GetAuthRequired", &WSRequestHandler::GetAuthRequired }, { "GetAuthRequired", &WSRequestHandler::GetAuthRequired },
{ "Authenticate", &WSRequestHandler::Authenticate }, { "Authenticate", &WSRequestHandler::Authenticate },
@ -43,6 +43,9 @@ const QHash<QString, RpcMethodHandler> WSRequestHandler::messageMap {
{ "BroadcastCustomMessage", &WSRequestHandler::BroadcastCustomMessage }, { "BroadcastCustomMessage", &WSRequestHandler::BroadcastCustomMessage },
{ "TriggerHotkeyByName", &WSRequestHandler::TriggerHotkeyByName },
{ "TriggerHotkeyBySequence", &WSRequestHandler::TriggerHotkeyBySequence },
{ "SetCurrentScene", &WSRequestHandler::SetCurrentScene }, { "SetCurrentScene", &WSRequestHandler::SetCurrentScene },
{ "GetCurrentScene", &WSRequestHandler::GetCurrentScene }, { "GetCurrentScene", &WSRequestHandler::GetCurrentScene },
{ "GetSceneList", &WSRequestHandler::GetSceneList }, { "GetSceneList", &WSRequestHandler::GetSceneList },
@ -93,6 +96,8 @@ const QHash<QString, RpcMethodHandler> WSRequestHandler::messageMap {
{ "SetTransitionDuration", &WSRequestHandler::SetTransitionDuration }, { "SetTransitionDuration", &WSRequestHandler::SetTransitionDuration },
{ "GetTransitionDuration", &WSRequestHandler::GetTransitionDuration }, { "GetTransitionDuration", &WSRequestHandler::GetTransitionDuration },
{ "GetTransitionPosition", &WSRequestHandler::GetTransitionPosition }, { "GetTransitionPosition", &WSRequestHandler::GetTransitionPosition },
{ "GetTransitionSettings", &WSRequestHandler::GetTransitionSettings },
{ "SetTransitionSettings", &WSRequestHandler::SetTransitionSettings },
{ "CreateSource", &WSRequestHandler::CreateSource }, { "CreateSource", &WSRequestHandler::CreateSource },
{ "SetVolume", &WSRequestHandler::SetVolume }, { "SetVolume", &WSRequestHandler::SetVolume },

View File

@ -61,6 +61,9 @@ class WSRequestHandler {
RpcResponse BroadcastCustomMessage(const RpcRequest&); RpcResponse BroadcastCustomMessage(const RpcRequest&);
RpcResponse TriggerHotkeyByName(const RpcRequest&);
RpcResponse TriggerHotkeyBySequence(const RpcRequest&);
RpcResponse SetCurrentScene(const RpcRequest&); RpcResponse SetCurrentScene(const RpcRequest&);
RpcResponse GetCurrentScene(const RpcRequest&); RpcResponse GetCurrentScene(const RpcRequest&);
RpcResponse GetSceneList(const RpcRequest&); RpcResponse GetSceneList(const RpcRequest&);
@ -110,6 +113,8 @@ class WSRequestHandler {
RpcResponse SetTransitionDuration(const RpcRequest&); RpcResponse SetTransitionDuration(const RpcRequest&);
RpcResponse GetTransitionDuration(const RpcRequest&); RpcResponse GetTransitionDuration(const RpcRequest&);
RpcResponse GetTransitionPosition(const RpcRequest&); RpcResponse GetTransitionPosition(const RpcRequest&);
RpcResponse GetTransitionSettings(const RpcRequest&);
RpcResponse SetTransitionSettings(const RpcRequest&);
RpcResponse CreateSource(const RpcRequest&); RpcResponse CreateSource(const RpcRequest&);
RpcResponse SetVolume(const RpcRequest&); RpcResponse SetVolume(const RpcRequest&);

View File

@ -345,3 +345,73 @@ RpcResponse WSRequestHandler::OpenProjector(const RpcRequest& request) {
obs_frontend_open_projector(type, monitor, geometry, name); obs_frontend_open_projector(type, monitor, geometry, name);
return request.success(); return request.success();
} }
/**
* Executes hotkey routine, identified by hotkey unique name
*
* @param {String} `hotkeyName` Unique name of the hotkey, as defined when registering the hotkey (e.g. "ReplayBuffer.Save")
*
* @api requests
* @name TriggerHotkeyByName
* @category general
* @since unreleased
*/
RpcResponse WSRequestHandler::TriggerHotkeyByName(const RpcRequest& request) {
const char* name = obs_data_get_string(request.parameters(), "hotkeyName");
obs_hotkey_t* hk = Utils::FindHotkeyByName(name);
if (!hk) {
return request.failed("hotkey not found");
}
obs_hotkey_trigger_routed_callback(obs_hotkey_get_id(hk), true);
return request.success();
}
/**
* Executes hotkey routine, identified by bound combination of keys. A single key combination might trigger multiple hotkey routines depending on user settings
*
* @param {String} `keyId` Main key identifier (e.g. `OBS_KEY_A` for key "A"). Available identifiers [here](https://github.com/obsproject/obs-studio/blob/master/libobs/obs-hotkeys.h)
* @param {Object (Optional)} `keyModifiers` Optional key modifiers object. False entries can be ommitted
* @param {boolean} `keyModifiers.shift` Trigger Shift Key
* @param {boolean} `keyModifiers.alt` Trigger Alt Key
* @param {boolean} `keyModifiers.control` Trigger Control (Ctrl) Key
* @param {boolean} `keyModifiers.command` Trigger Command Key (Mac)
*
* @api requests
* @name TriggerHotkeyBySequence
* @category general
* @since unreleased
*/
RpcResponse WSRequestHandler::TriggerHotkeyBySequence(const RpcRequest& request) {
if (!request.hasField("keyId")) {
return request.failed("missing request keyId parameter");
}
OBSDataAutoRelease data = obs_data_get_obj(request.parameters(), "keyModifiers");
obs_key_combination_t combo = {0};
uint32_t modifiers = 0;
if (obs_data_get_bool(data, "shift"))
modifiers |= INTERACT_SHIFT_KEY;
if (obs_data_get_bool(data, "control"))
modifiers |= INTERACT_CONTROL_KEY;
if (obs_data_get_bool(data, "alt"))
modifiers |= INTERACT_ALT_KEY;
if (obs_data_get_bool(data, "command"))
modifiers |= INTERACT_COMMAND_KEY;
combo.modifiers = modifiers;
combo.key = obs_key_from_name(obs_data_get_string(request.parameters(), "keyId"));
if (!modifiers
&& (combo.key == OBS_KEY_NONE || combo.key >= OBS_KEY_LAST_VALUE)) {
return request.failed("invalid key-modifier combination");
}
// Inject hotkey press-release sequence
obs_hotkey_inject_event(combo, false);
obs_hotkey_inject_event(combo, true);
obs_hotkey_inject_event(combo, false);
return request.success();
}

View File

@ -17,13 +17,22 @@ RpcResponse WSRequestHandler::SetCurrentProfile(const RpcRequest& request) {
return request.failed("missing request parameters"); return request.failed("missing request parameters");
} }
QString profileName = obs_data_get_string(request.parameters(), "profile-name"); const char* profileName = obs_data_get_string(request.parameters(), "profile-name");
if (profileName.isEmpty()) { if (!profileName) {
return request.failed("invalid request parameters"); return request.failed("invalid request parameters");
} }
// TODO : check if profile exists char** profiles = obs_frontend_get_profiles();
obs_frontend_set_current_profile(profileName.toUtf8()); bool profileExists = Utils::StringInStringList(profiles, profileName);
bfree(profiles);
if (!profileExists) {
return request.failed("profile does not exist");
}
obs_queue_task(OBS_TASK_UI, [](void* param) {
obs_frontend_set_current_profile(reinterpret_cast<const char*>(param));
}, (void*)profileName, true);
return request.success(); return request.success();
} }

View File

@ -17,13 +17,22 @@ RpcResponse WSRequestHandler::SetCurrentSceneCollection(const RpcRequest& reques
return request.failed("missing request parameters"); return request.failed("missing request parameters");
} }
QString sceneCollection = obs_data_get_string(request.parameters(), "sc-name"); const char* sceneCollection = obs_data_get_string(request.parameters(), "sc-name");
if (sceneCollection.isEmpty()) { if (!sceneCollection) {
return request.failed("invalid request parameters"); return request.failed("invalid request parameters");
} }
// TODO : Check if specified collection exists and if changing is allowed char** collections = obs_frontend_get_scene_collections();
obs_frontend_set_current_scene_collection(sceneCollection.toUtf8()); bool collectionExists = Utils::StringInStringList(collections, sceneCollection);
bfree(collections);
if (!collectionExists) {
return request.failed("scene collection does not exist");
}
obs_queue_task(OBS_TASK_UI, [](void* param) {
obs_frontend_set_current_scene_collection(reinterpret_cast<const char*>(param));
}, (void*)sceneCollection, true);
return request.success(); return request.success();
} }

View File

@ -5,8 +5,9 @@
/** /**
* Get a list of all scene items in a scene. * Get a list of all scene items in a scene.
* *
* @param {String} `sceneName` Name of the scene to get the list of scene items from. * @param {String (optional)} `sceneName` Name of the scene to get the list of scene items from. Defaults to the current scene if not specified.
* *
* @return {String} `sceneName` Name of the requested (or current) scene
* @return {Array<Object>} `sceneItems` Array of scene items * @return {Array<Object>} `sceneItems` Array of scene items
* @return {int} `sceneItems.*.itemId` Unique item id of the source item * @return {int} `sceneItems.*.itemId` Unique item id of the source item
* @return {String} `sceneItems.*.sourceKind` ID if the scene item's source. For example `vlc_source` or `image_source` * @return {String} `sceneItems.*.sourceKind` ID if the scene item's source. For example `vlc_source` or `image_source`
@ -19,12 +20,15 @@
* @since unreleased * @since unreleased
*/ */
RpcResponse WSRequestHandler::GetSceneItemList(const RpcRequest& request) { RpcResponse WSRequestHandler::GetSceneItemList(const RpcRequest& request) {
if (!request.hasField("sceneName")) { const char* sceneName = obs_data_get_string(request.parameters(), "sceneName");
return request.failed("missing request parameters");
OBSSourceAutoRelease sceneSource;
if (sceneName && strcmp(sceneName, "") != 0) {
sceneSource = obs_get_source_by_name(sceneName);
} else {
sceneSource = obs_frontend_get_current_scene();
} }
const char* sceneName = obs_data_get_string(request.parameters(), "sceneName");
OBSSourceAutoRelease sceneSource = obs_get_source_by_name(sceneName);
OBSScene scene = obs_scene_from_source(sceneSource); OBSScene scene = obs_scene_from_source(sceneSource);
if (!scene) { if (!scene) {
return request.failed("requested scene is invalid or doesnt exist"); return request.failed("requested scene is invalid or doesnt exist");
@ -64,6 +68,7 @@ RpcResponse WSRequestHandler::GetSceneItemList(const RpcRequest& request) {
obs_scene_enum_items(scene, sceneItemEnumProc, sceneItemArray); obs_scene_enum_items(scene, sceneItemEnumProc, sceneItemArray);
OBSDataAutoRelease response = obs_data_create(); OBSDataAutoRelease response = obs_data_create();
obs_data_set_string(response, "sceneName", obs_source_get_name(sceneSource));
obs_data_set_array(response, "sceneItems", sceneItemArray); obs_data_set_array(response, "sceneItems", sceneItemArray);
return request.success(response); return request.success(response);

View File

@ -184,7 +184,7 @@ RpcResponse WSRequestHandler::ReorderSceneItems(const RpcRequest& request) {
* @api requests * @api requests
* @name SetSceneTransitionOverride * @name SetSceneTransitionOverride
* @category scenes * @category scenes
* @since unreleased * @since 4.8.0
*/ */
RpcResponse WSRequestHandler::SetSceneTransitionOverride(const RpcRequest& request) { RpcResponse WSRequestHandler::SetSceneTransitionOverride(const RpcRequest& request) {
if (!request.hasField("sceneName") || !request.hasField("transitionName")) { if (!request.hasField("sceneName") || !request.hasField("transitionName")) {
@ -230,7 +230,7 @@ RpcResponse WSRequestHandler::SetSceneTransitionOverride(const RpcRequest& reque
* @api requests * @api requests
* @name RemoveSceneTransitionOverride * @name RemoveSceneTransitionOverride
* @category scenes * @category scenes
* @since unreleased * @since 4.8.0
*/ */
RpcResponse WSRequestHandler::RemoveSceneTransitionOverride(const RpcRequest& request) { RpcResponse WSRequestHandler::RemoveSceneTransitionOverride(const RpcRequest& request) {
if (!request.hasField("sceneName")) { if (!request.hasField("sceneName")) {
@ -266,7 +266,7 @@ RpcResponse WSRequestHandler::RemoveSceneTransitionOverride(const RpcRequest& re
* @api requests * @api requests
* @name GetSceneTransitionOverride * @name GetSceneTransitionOverride
* @category scenes * @category scenes
* @since unreleased * @since 4.8.0
*/ */
RpcResponse WSRequestHandler::GetSceneTransitionOverride(const RpcRequest& request) { RpcResponse WSRequestHandler::GetSceneTransitionOverride(const RpcRequest& request) {
if (!request.hasField("sceneName")) { if (!request.hasField("sceneName")) {

View File

@ -586,6 +586,7 @@ RpcResponse WSRequestHandler::GetSourceSettings(const RpcRequest& request)
const char* sourceName = obs_data_get_string(request.parameters(), "sourceName"); const char* sourceName = obs_data_get_string(request.parameters(), "sourceName");
OBSSourceAutoRelease source = obs_get_source_by_name(sourceName); OBSSourceAutoRelease source = obs_get_source_by_name(sourceName);
if (!source) { if (!source) {
return request.failed("specified source doesn't exist"); return request.failed("specified source doesn't exist");
} }
@ -646,21 +647,17 @@ RpcResponse WSRequestHandler::SetSourceSettings(const RpcRequest& request)
} }
} }
OBSDataAutoRelease currentSettings = obs_source_get_settings(source);
OBSDataAutoRelease newSettings = obs_data_get_obj(request.parameters(), "sourceSettings"); OBSDataAutoRelease newSettings = obs_data_get_obj(request.parameters(), "sourceSettings");
OBSDataAutoRelease sourceSettings = obs_data_create(); obs_source_update(source, newSettings);
obs_data_apply(sourceSettings, currentSettings);
obs_data_apply(sourceSettings, newSettings);
obs_source_update(source, sourceSettings);
obs_source_update_properties(source); obs_source_update_properties(source);
OBSDataAutoRelease updatedSettings = obs_source_get_settings(source);
OBSDataAutoRelease response = obs_data_create(); OBSDataAutoRelease response = obs_data_create();
obs_data_set_string(response, "sourceName", obs_source_get_name(source)); obs_data_set_string(response, "sourceName", obs_source_get_name(source));
obs_data_set_string(response, "sourceType", obs_source_get_id(source)); obs_data_set_string(response, "sourceType", obs_source_get_id(source));
obs_data_set_obj(response, "sourceSettings", sourceSettings); obs_data_set_obj(response, "sourceSettings", updatedSettings);
return request.success(response); return request.success(response);
} }

View File

@ -139,3 +139,68 @@ RpcResponse WSRequestHandler::GetTransitionPosition(const RpcRequest& request) {
return request.success(response); return request.success(response);
} }
/**
* Get the current settings of a transition
*
* @param {String} `transitionName` Transition name
*
* @return {Object} `transitionSettings` Current transition settings
*
* @api requests
* @name GetTransitionSettings
* @category transitions
* @since unreleased
*/
RpcResponse WSRequestHandler::GetTransitionSettings(const RpcRequest& request) {
if (!request.hasField("transitionName")) {
return request.failed("missing request parameters");
}
const char* transitionName = obs_data_get_string(request.parameters(), "transitionName");
OBSSourceAutoRelease transition = Utils::GetTransitionFromName(transitionName);
if (!transition) {
return request.failed("specified transition doesn't exist");
}
OBSDataAutoRelease transitionSettings = obs_source_get_settings(transition);
OBSDataAutoRelease response = obs_data_create();
obs_data_set_obj(response, "transitionSettings", transitionSettings);
return request.success(response);
}
/**
* Change the current settings of a transition
*
* @param {String} `transitionName` Transition name
* @param {Object} `transitionSettings` Transition settings (they can be partial)
*
* @return {Object} `transitionSettings` Updated transition settings
*
* @api requests
* @name SetTransitionSettings
* @category transitions
* @since unreleased
*/
RpcResponse WSRequestHandler::SetTransitionSettings(const RpcRequest& request) {
if (!request.hasField("transitionName") || !request.hasField("transitionSettings")) {
return request.failed("missing request parameters");
}
const char* transitionName = obs_data_get_string(request.parameters(), "transitionName");
OBSSourceAutoRelease transition = Utils::GetTransitionFromName(transitionName);
if (!transition) {
return request.failed("specified transition doesn't exist");
}
OBSDataAutoRelease newSettings = obs_data_get_obj(request.parameters(), "transitionSettings");
obs_source_update(transition, newSettings);
obs_source_update_properties(transition);
OBSDataAutoRelease updatedSettings = obs_source_get_settings(transition);
OBSDataAutoRelease response = obs_data_create();
obs_data_set_obj(response, "transitionSettings", updatedSettings);
return request.success(response);
}

View File

@ -60,10 +60,10 @@ WSServer::~WSServer()
stop(); stop();
} }
void WSServer::start(quint16 port) void WSServer::start(quint16 port, bool lockToIPv4)
{ {
if (_server.is_listening() && port == _serverPort) { if (_server.is_listening() && (port == _serverPort && _lockToIPv4 == lockToIPv4)) {
blog(LOG_INFO, "WSServer::start: server already on this port. no restart needed"); blog(LOG_INFO, "WSServer::start: server already on this port and protocol mode. no restart needed");
return; return;
} }
@ -74,9 +74,16 @@ void WSServer::start(quint16 port)
_server.reset(); _server.reset();
_serverPort = port; _serverPort = port;
_lockToIPv4 = lockToIPv4;
websocketpp::lib::error_code errorCode; websocketpp::lib::error_code errorCode;
if (lockToIPv4) {
blog(LOG_INFO, "WSServer::start: Locked to IPv4 bindings");
_server.listen(websocketpp::lib::asio::ip::tcp::v4(), _serverPort, errorCode);
} else {
blog(LOG_INFO, "WSServer::start: Not locked to IPv4 bindings");
_server.listen(_serverPort, errorCode); _server.listen(_serverPort, errorCode);
}
if (errorCode) { if (errorCode) {
std::string errorCodeMessage = errorCode.message(); std::string errorCodeMessage = errorCode.message();

View File

@ -44,7 +44,7 @@ Q_OBJECT
public: public:
explicit WSServer(); explicit WSServer();
virtual ~WSServer(); virtual ~WSServer();
void start(quint16 port); void start(quint16 port, bool lockToIPv4);
void stop(); void stop();
void broadcast(const RpcEvent& event); void broadcast(const RpcEvent& event);
QThreadPool* threadPool() { QThreadPool* threadPool() {
@ -62,6 +62,7 @@ private:
server _server; server _server;
quint16 _serverPort; quint16 _serverPort;
bool _lockToIPv4;
std::set<connection_hdl, std::owner_less<connection_hdl>> _connections; std::set<connection_hdl, std::owner_less<connection_hdl>> _connections;
std::map<connection_hdl, ConnectionProperties, std::owner_less<connection_hdl>> _connectionProperties; std::map<connection_hdl, ConnectionProperties, std::owner_less<connection_hdl>> _connectionProperties;
QMutex _clMutex; QMutex _clMutex;

View File

@ -45,6 +45,7 @@ void SettingsDialog::showEvent(QShowEvent* event) {
ui->serverEnabled->setChecked(conf->ServerEnabled); ui->serverEnabled->setChecked(conf->ServerEnabled);
ui->serverPort->setValue(conf->ServerPort); ui->serverPort->setValue(conf->ServerPort);
ui->lockToIPv4->setChecked(conf->LockToIPv4);
ui->debugEnabled->setChecked(conf->DebugEnabled); ui->debugEnabled->setChecked(conf->DebugEnabled);
ui->alertsEnabled->setChecked(conf->AlertsEnabled); ui->alertsEnabled->setChecked(conf->AlertsEnabled);
@ -72,6 +73,7 @@ void SettingsDialog::FormAccepted() {
conf->ServerEnabled = ui->serverEnabled->isChecked(); conf->ServerEnabled = ui->serverEnabled->isChecked();
conf->ServerPort = ui->serverPort->value(); conf->ServerPort = ui->serverPort->value();
conf->LockToIPv4 = ui->lockToIPv4->isChecked();
conf->DebugEnabled = ui->debugEnabled->isChecked(); conf->DebugEnabled = ui->debugEnabled->isChecked();
conf->AlertsEnabled = ui->alertsEnabled->isChecked(); conf->AlertsEnabled = ui->alertsEnabled->isChecked();
@ -95,7 +97,7 @@ void SettingsDialog::FormAccepted() {
auto server = GetServer(); auto server = GetServer();
if (conf->ServerEnabled) { if (conf->ServerEnabled) {
server->start(conf->ServerPort); server->start(conf->ServerPort, conf->LockToIPv4);
} else { } else {
server->stop(); server->stop();
} }

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>407</width> <width>407</width>
<height>195</height> <height>216</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -79,7 +79,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="1"> <item row="6" column="1">
<widget class="QCheckBox" name="alertsEnabled"> <widget class="QCheckBox" name="alertsEnabled">
<property name="text"> <property name="text">
<string>OBSWebsocket.Settings.AlertsEnable</string> <string>OBSWebsocket.Settings.AlertsEnable</string>
@ -89,7 +89,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="6" column="1"> <item row="7" column="1">
<widget class="QCheckBox" name="debugEnabled"> <widget class="QCheckBox" name="debugEnabled">
<property name="text"> <property name="text">
<string>OBSWebsocket.Settings.DebugEnable</string> <string>OBSWebsocket.Settings.DebugEnable</string>
@ -99,6 +99,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="1">
<widget class="QCheckBox" name="lockToIPv4">
<property name="text">
<string>OBSWebsocket.Settings.LockToIPv4</string>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item> <item>

View File

@ -81,7 +81,7 @@ bool obs_module_load(void) {
auto eventCallback = [](enum obs_frontend_event event, void *param) { auto eventCallback = [](enum obs_frontend_event event, void *param) {
if (event == OBS_FRONTEND_EVENT_FINISHED_LOADING) { if (event == OBS_FRONTEND_EVENT_FINISHED_LOADING) {
if (_config->ServerEnabled) { if (_config->ServerEnabled) {
_server->start(_config->ServerPort); _server->start(_config->ServerPort, _config->LockToIPv4);
} }
obs_frontend_remove_event_callback((obs_frontend_event_cb)param, nullptr); obs_frontend_remove_event_callback((obs_frontend_event_cb)param, nullptr);
} }