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
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`
# upgrading it to incompatible version

View File

@ -1,163 +1,145 @@
# Patches for Qt must be at the very least submitted to Qt's Gerrit codereview
# rather than their bug-report Jira. The latter is rarely reviewed by Qt.
class Qt < Formula
desc "Cross-platform application and UI framework"
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"
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"
sha256 "05ffba7b811b854ed558abf2be2ddbd3bb6ddd0b60ea4b5da75d277ac15e740a"
head "https://code.qt.io/qt/qt5.git", :branch => "5.10.1", :shallow => false
desc "Cross-platform application and UI framework"
homepage "https://www.qt.io/"
url "https://download.qt.io/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"
head "https://code.qt.io/qt/qt5.git", :branch => "5.10", :shallow => false
bottle do
sha256 "8b4bad005596a5f8790150fe455db998ac2406f4e0f04140d6656205d844d266" => :high_sierra
sha256 "9c488554935fb573554a4e36d36d3c81e47245b7fefc4b61edef894e67ba1740" => :sierra
sha256 "c0407afba5951df6cc4c6f6c1c315972bd41c99cecb4e029919c4c15ab6f7bdc" => :el_capitan
end
bottle do
sha256 "8b4bad005596a5f8790150fe455db998ac2406f4e0f04140d6656205d844d266" => :high_sierra
sha256 "9c488554935fb573554a4e36d36d3c81e47245b7fefc4b61edef894e67ba1740" => :sierra
sha256 "c0407afba5951df6cc4c6f6c1c315972bd41c99cecb4e029919c4c15ab6f7bdc" => :el_capitan
end
keg_only "Qt 5 has CMake issues when linked"
keg_only "Qt 5 has CMake issues when linked"
option "with-docs", "Build documentation"
option "with-examples", "Build examples"
option "with-docs", "Build documentation"
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
# configuration and thus untested in practice. Builds on OS X 10.7 have been
# reported to fail: <https://github.com/Homebrew/homebrew/issues/45284>.
# depends_on :macos => :mountain_lion
# 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
# reported to fail: <https://github.com/Homebrew/homebrew/issues/45284>.
depends_on :macos => :mountain_lion
depends_on "pkg-config" => :build
depends_on :xcode => :build
depends_on "mysql" => :optional
depends_on "postgresql" => :optional
depends_on "pkg-config" => :build
depends_on :xcode => :build
depends_on "mysql-client" => :optional
depends_on "postgresql" => :optional
# Restore `.pc` files for framework-based build of Qt 5 on OS X. This
# partially reverts <https://codereview.qt-project.org/#/c/140954/> merged
# between the 5.5.1 and 5.6.0 releases. (Remove this as soon as feasible!)
#
# Core formulae known to fail without this patch (as of 2016-10-15):
# * gnuplot (with `--with-qt` option)
# * mkvtoolnix (with `--with-qt` option, silent build failure)
# * poppler (with `--with-qt` option)
patch do
url "https://raw.githubusercontent.com/Homebrew/formula-patches/e8fe6567/qt5/restore-pc-files.patch"
sha256 "48ff18be2f4050de7288bddbae7f47e949512ac4bcd126c2f504be2ac701158b"
end
# Restore `.pc` files for framework-based build of Qt 5 on OS X. This
# partially reverts <https://codereview.qt-project.org/#/c/140954/> merged
# between the 5.5.1 and 5.6.0 releases. (Remove this as soon as feasible!)
#
# Core formulae known to fail without this patch (as of 2016-10-15):
# * gnuplot (with `--with-qt` option)
# * mkvtoolnix (with `--with-qt` option, silent build failure)
# * poppler (with `--with-qt` option)
patch do
url "https://raw.githubusercontent.com/Homebrew/formula-patches/e8fe6567/qt5/restore-pc-files.patch"
sha256 "48ff18be2f4050de7288bddbae7f47e949512ac4bcd126c2f504be2ac701158b"
end
def install
args = %W[
-verbose
-prefix #{prefix}
-release
-opensource -confirm-license
-system-zlib
-qt-libpng
-qt-libjpeg
-qt-freetype
-qt-pcre
-nomake tests
-no-rpath
-pkg-config
-dbus-runtime
]
# 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
args << "-nomake" << "examples" if build.without? "examples"
# 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
if build.with? "mysql"
args << "-plugin-sql-mysql"
(buildpath/"brew_shim/mysql_config").write <<~EOS
#!/bin/sh
if [ x"$1" = x"--libs" ]; then
mysql_config --libs | sed "s/-lssl -lcrypto//"
else
exec mysql_config "$@"
fi
EOS
chmod 0755, "brew_shim/mysql_config"
args << "-mysql_config" << buildpath/"brew_shim/mysql_config"
end
def install
args = %W[
-verbose
-prefix #{prefix}
-release
-opensource -confirm-license
-system-zlib
-qt-libpng
-qt-libjpeg
-qt-freetype
-qt-pcre
-nomake tests
-no-rpath
-pkg-config
-dbus-runtime
-no-assimp
]
args << "-plugin-sql-psql" if build.with? "postgresql"
args << "-proprietary-codecs" if build.with? "proprietary-codecs"
args << "-nomake" << "examples" if build.without? "examples"
system "./configure", *args
system "make"
ENV.deparallelize
system "make", "install"
if build.with? "mysql-client"
args << "-plugin-sql-mysql"
(buildpath/"brew_shim/mysql_config").write <<~EOS
#!/bin/sh
if [ x"$1" = x"--libs" ]; then
mysql_config --libs | sed "s/-lssl -lcrypto//"
else
exec mysql_config "$@"
fi
EOS
chmod 0755, "brew_shim/mysql_config"
args << "-mysql_config" << buildpath/"brew_shim/mysql_config"
end
if build.with? "docs"
system "make", "docs"
system "make", "install_docs"
end
args << "-plugin-sql-psql" if build.with? "postgresql"
# Some config scripts will only find Qt in a "Frameworks" folder
frameworks.install_symlink Dir["#{lib}/*.framework"]
system "./configure", *args
system "make"
ENV.deparallelize
system "make", "install"
# The pkg-config files installed suggest that headers can be found in the
# `include` directory. Make this so by creating symlinks from `include` to
# the Frameworks' Headers folders.
Pathname.glob("#{lib}/*.framework/Headers") do |path|
include.install_symlink path => path.parent.basename(".framework")
end
if build.with? "docs"
system "make", "docs"
system "make", "install_docs"
end
# Move `*.app` bundles into `libexec` to expose them to `brew linkapps` and
# because we don't like having them in `bin`.
# (Note: This move breaks invocation of Assistant via the Help menu
# of both Designer and Linguist as that relies on Assistant being in `bin`.)
libexec.mkpath
Pathname.glob("#{bin}/*.app") { |app| mv app, libexec }
end
# Some config scripts will only find Qt in a "Frameworks" folder
frameworks.install_symlink Dir["#{lib}/*.framework"]
def caveats; <<~EOS
We agreed to the Qt opensource license for you.
If this is unacceptable you should uninstall.
EOS
end
# The pkg-config files installed suggest that headers can be found in the
# `include` directory. Make this so by creating symlinks from `include` to
# the Frameworks' Headers folders.
Pathname.glob("#{lib}/*.framework/Headers") do |path|
include.install_symlink path => path.parent.basename(".framework")
end
test do
(testpath/"hello.pro").write <<~EOS
QT += core
QT -= gui
TARGET = hello
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp
EOS
# Move `*.app` bundles into `libexec` to expose them to `brew linkapps` and
# because we don't like having them in `bin`.
# (Note: This move breaks invocation of Assistant via the Help menu
# of both Designer and Linguist as that relies on Assistant being in `bin`.)
libexec.mkpath
Pathname.glob("#{bin}/*.app") { |app| mv app, libexec }
end
(testpath/"main.cpp").write <<~EOS
#include <QCoreApplication>
#include <QDebug>
def caveats; <<~EOS
We agreed to the Qt opensource license for you.
If this is unacceptable you should uninstall.
EOS
end
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "Hello World!";
return 0;
}
EOS
test do
(testpath/"hello.pro").write <<~EOS
QT += core
QT -= gui
TARGET = hello
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp
EOS
(testpath/"main.cpp").write <<~EOS
#include <QCoreApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "Hello World!";
return 0;
}
EOS
system bin/"qmake", testpath/"hello.pro"
system "make"
assert_predicate testpath/"hello", :exist?
assert_predicate testpath/"main.o", :exist?
system "./hello"
end
end
system bin/"qmake", testpath/"hello.pro"
system "make"
assert_predicate testpath/"hello", :exist?
assert_predicate testpath/"main.o", :exist?
system "./hello"
end
end

View File

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

View File

@ -16,7 +16,10 @@ Binaries for Windows, MacOS, and Linux are available in the [Releases](https://g
## 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.

View File

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

View File

@ -2515,7 +2515,8 @@
"{String} `sourceName` Source name",
"{Array<Object>} `filters` Ordered Filters list",
"{String} `filters.*.name` Filter name",
"{String} `filters.*.type` Filter type"
"{String} `filters.*.type` Filter type",
"{boolean} `filters.*.enabled` Filter visibility status"
],
"api": "events",
"name": "SourceFiltersReordered",
@ -2541,6 +2542,11 @@
"type": "String",
"name": "filters.*.type",
"description": "Filter type"
},
{
"type": "boolean",
"name": "filters.*.enabled",
"description": "Filter visibility status"
}
],
"names": [
@ -4059,6 +4065,120 @@
"lead": "",
"type": "class",
"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": [
@ -7972,8 +8092,9 @@
{
"subheads": [],
"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": [
"{String} `sceneName` Name of the requested (or current) scene",
"{Array<Object>} `sceneItems` Array of scene items",
"{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`",
@ -7985,6 +8106,11 @@
"category": "scene items",
"since": "unreleased",
"returns": [
{
"type": "String",
"name": "sceneName",
"description": "Name of the requested (or current) scene"
},
{
"type": "Array<Object>",
"name": "sceneItems",
@ -8013,9 +8139,9 @@
],
"params": [
{
"type": "String",
"type": "String (optional)",
"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": [
@ -9233,7 +9359,7 @@
"api": "requests",
"name": "SetSceneTransitionOverride",
"category": "scenes",
"since": "unreleased",
"since": "4.8.0",
"params": [
{
"type": "String",
@ -9266,7 +9392,7 @@
"sinces": [
{
"name": "",
"description": "unreleased"
"description": "4.8.0"
}
],
"heading": {
@ -9284,7 +9410,7 @@
"api": "requests",
"name": "RemoveSceneTransitionOverride",
"category": "scenes",
"since": "unreleased",
"since": "4.8.0",
"params": [
{
"type": "String",
@ -9307,7 +9433,7 @@
"sinces": [
{
"name": "",
"description": "unreleased"
"description": "4.8.0"
}
],
"heading": {
@ -9329,7 +9455,7 @@
"api": "requests",
"name": "GetSceneTransitionOverride",
"category": "scenes",
"since": "unreleased",
"since": "4.8.0",
"returns": [
{
"type": "String",
@ -9364,7 +9490,7 @@
"sinces": [
{
"name": "",
"description": "unreleased"
"description": "4.8.0"
}
],
"heading": {
@ -10395,6 +10521,112 @@
"lead": "",
"type": "class",
"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)
+ [GetVideoInfo](#getvideoinfo)
+ [OpenProjector](#openprojector)
+ [TriggerHotkeyByName](#triggerhotkeybyname)
+ [TriggerHotkeyBySequence](#triggerhotkeybysequence)
* [Media Control](#media-control)
+ [PlayPauseMedia](#playpausemedia)
+ [RestartMedia](#restartmedia)
@ -253,6 +255,8 @@ You can also refer to any of the client libraries listed on the [README](README.
+ [SetTransitionDuration](#settransitionduration)
+ [GetTransitionDuration](#gettransitionduration)
+ [GetTransitionPosition](#gettransitionposition)
+ [GetTransitionSettings](#gettransitionsettings)
+ [SetTransitionSettings](#settransitionsettings)
<!-- tocstop -->
@ -1073,6 +1077,7 @@ Filters in a source have been reordered.
| `filters` | _Array&lt;Object&gt;_ | Ordered Filters list |
| `filters.*.name` | _String_ | Filter name |
| `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). |
**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:**
_No additional response items._
@ -3213,13 +3263,14 @@ Get a list of all scene items in a scene.
| 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:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `sceneName` | _String_ | Name of the requested (or current) scene |
| `sceneItems` | _Array&lt;Object&gt;_ | Array of scene items |
| `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` |
@ -3629,7 +3680,7 @@ _No additional response items._
### SetSceneTransitionOverride
- Unreleased
- Added in v4.8.0
Set a scene to use a specific transition override.
@ -3651,7 +3702,7 @@ _No additional response items._
### RemoveSceneTransitionOverride
- Unreleased
- Added in v4.8.0
Remove any transition override on a scene.
@ -3671,7 +3722,7 @@ _No additional response items._
### GetSceneTransitionOverride
- Unreleased
- Added in v4.8.0
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
Compression=lzma
SolidCompression=yes
DirExistsWarning=no
[Languages]
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 PARAM_ENABLE "ServerEnabled"
#define PARAM_PORT "ServerPort"
#define PARAM_LOCKTOIPV4 "LockToIPv4"
#define PARAM_DEBUG "DebugEnabled"
#define PARAM_ALERT "AlertsEnabled"
#define PARAM_AUTHREQUIRED "AuthRequired"
@ -41,6 +42,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
Config::Config() :
ServerEnabled(true),
ServerPort(4444),
LockToIPv4(false),
DebugEnabled(false),
AlertsEnabled(true),
AuthRequired(false),
@ -67,6 +69,7 @@ void Config::Load()
ServerEnabled = config_get_bool(obsConfig, SECTION_NAME, PARAM_ENABLE);
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);
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_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_ALERT, AlertsEnabled);
@ -104,6 +108,8 @@ void Config::SetDefaults()
SECTION_NAME, PARAM_ENABLE, ServerEnabled);
config_set_default_uint(obsConfig,
SECTION_NAME, PARAM_PORT, ServerPort);
config_set_default_bool(obsConfig,
SECTION_NAME, PARAM_LOCKTOIPV4, LockToIPv4);
config_set_default_bool(obsConfig,
SECTION_NAME, PARAM_DEBUG, DebugEnabled);
@ -205,16 +211,17 @@ void Config::OnFrontendEvent(enum obs_frontend_event event, void* param)
bool previousEnabled = config->ServerEnabled;
uint64_t previousPort = config->ServerPort;
bool previousLock = config->LockToIPv4;
config->SetDefaults();
config->Load();
if (config->ServerEnabled != previousEnabled || config->ServerPort != previousPort) {
if (config->ServerEnabled != previousEnabled || config->ServerPort != previousPort || config->LockToIPv4 != previousLock) {
auto server = GetServer();
server->stop();
if (config->ServerEnabled) {
server->start(config->ServerPort);
server->start(config->ServerPort, config->LockToIPv4);
if (previousEnabled != config->ServerEnabled) {
Utils::SysTrayNotify(startMessage, QSystemTrayIcon::MessageIcon::Information);
@ -246,6 +253,13 @@ void Config::MigrateFromGlobalSettings()
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)) {
bool value = config_get_bool(source, SECTION_NAME, PARAM_DEBUG);

View File

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

View File

@ -51,6 +51,25 @@ obs_bounds_type getBoundsTypeFromName(QString 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* list = obs_data_array_create();
@ -485,11 +504,8 @@ QString Utils::OBSVersionString() {
}
QSystemTrayIcon* Utils::GetTrayIcon() {
QMainWindow* main = (QMainWindow*)obs_frontend_get_main_window();
if (!main) return nullptr;
QList<QSystemTrayIcon*> trays = main->findChildren<QSystemTrayIcon*>();
return trays.isEmpty() ? nullptr : trays.first();
void* systemTray = obs_frontend_get_system_tray();
return reinterpret_cast<QSystemTrayIcon*>(systemTray);
}
void Utils::SysTrayNotify(QString text,

View File

@ -35,6 +35,7 @@ typedef void(*PauseRecordingFunction)(bool);
typedef bool(*RecordingPausedFunction)();
namespace Utils {
bool StringInStringList(char** strings, const char* string);
obs_data_array_t* StringListToArray(char** strings, const char* key);
obs_data_array_t* GetSceneItems(obs_source_t* source);
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 {String} `filters.*.name` Filter name
* @return {String} `filters.*.type` Filter type
* @return {boolean} `filters.*.enabled` Filter visibility status
*
* @api events
* @name SourceFiltersReordered

View File

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

View File

@ -61,6 +61,9 @@ class WSRequestHandler {
RpcResponse BroadcastCustomMessage(const RpcRequest&);
RpcResponse TriggerHotkeyByName(const RpcRequest&);
RpcResponse TriggerHotkeyBySequence(const RpcRequest&);
RpcResponse SetCurrentScene(const RpcRequest&);
RpcResponse GetCurrentScene(const RpcRequest&);
RpcResponse GetSceneList(const RpcRequest&);
@ -110,6 +113,8 @@ class WSRequestHandler {
RpcResponse SetTransitionDuration(const RpcRequest&);
RpcResponse GetTransitionDuration(const RpcRequest&);
RpcResponse GetTransitionPosition(const RpcRequest&);
RpcResponse GetTransitionSettings(const RpcRequest&);
RpcResponse SetTransitionSettings(const RpcRequest&);
RpcResponse CreateSource(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);
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");
}
QString profileName = obs_data_get_string(request.parameters(), "profile-name");
if (profileName.isEmpty()) {
const char* profileName = obs_data_get_string(request.parameters(), "profile-name");
if (!profileName) {
return request.failed("invalid request parameters");
}
// TODO : check if profile exists
obs_frontend_set_current_profile(profileName.toUtf8());
char** profiles = obs_frontend_get_profiles();
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();
}

View File

@ -17,13 +17,22 @@ RpcResponse WSRequestHandler::SetCurrentSceneCollection(const RpcRequest& reques
return request.failed("missing request parameters");
}
QString sceneCollection = obs_data_get_string(request.parameters(), "sc-name");
if (sceneCollection.isEmpty()) {
const char* sceneCollection = obs_data_get_string(request.parameters(), "sc-name");
if (!sceneCollection) {
return request.failed("invalid request parameters");
}
// TODO : Check if specified collection exists and if changing is allowed
obs_frontend_set_current_scene_collection(sceneCollection.toUtf8());
char** collections = obs_frontend_get_scene_collections();
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();
}

View File

@ -5,8 +5,9 @@
/**
* 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 {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`
@ -19,12 +20,15 @@
* @since unreleased
*/
RpcResponse WSRequestHandler::GetSceneItemList(const RpcRequest& request) {
if (!request.hasField("sceneName")) {
return request.failed("missing request parameters");
const char* sceneName = obs_data_get_string(request.parameters(), "sceneName");
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);
if (!scene) {
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);
OBSDataAutoRelease response = obs_data_create();
obs_data_set_string(response, "sceneName", obs_source_get_name(sceneSource));
obs_data_set_array(response, "sceneItems", sceneItemArray);
return request.success(response);

View File

@ -184,7 +184,7 @@ RpcResponse WSRequestHandler::ReorderSceneItems(const RpcRequest& request) {
* @api requests
* @name SetSceneTransitionOverride
* @category scenes
* @since unreleased
* @since 4.8.0
*/
RpcResponse WSRequestHandler::SetSceneTransitionOverride(const RpcRequest& request) {
if (!request.hasField("sceneName") || !request.hasField("transitionName")) {
@ -230,7 +230,7 @@ RpcResponse WSRequestHandler::SetSceneTransitionOverride(const RpcRequest& reque
* @api requests
* @name RemoveSceneTransitionOverride
* @category scenes
* @since unreleased
* @since 4.8.0
*/
RpcResponse WSRequestHandler::RemoveSceneTransitionOverride(const RpcRequest& request) {
if (!request.hasField("sceneName")) {
@ -266,7 +266,7 @@ RpcResponse WSRequestHandler::RemoveSceneTransitionOverride(const RpcRequest& re
* @api requests
* @name GetSceneTransitionOverride
* @category scenes
* @since unreleased
* @since 4.8.0
*/
RpcResponse WSRequestHandler::GetSceneTransitionOverride(const RpcRequest& request) {
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");
OBSSourceAutoRelease source = obs_get_source_by_name(sourceName);
if (!source) {
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 sourceSettings = obs_data_create();
obs_data_apply(sourceSettings, currentSettings);
obs_data_apply(sourceSettings, newSettings);
obs_source_update(source, sourceSettings);
obs_source_update(source, newSettings);
obs_source_update_properties(source);
OBSDataAutoRelease updatedSettings = obs_source_get_settings(source);
OBSDataAutoRelease response = obs_data_create();
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_obj(response, "sourceSettings", sourceSettings);
obs_data_set_obj(response, "sourceSettings", updatedSettings);
return request.success(response);
}

View File

@ -139,3 +139,68 @@ RpcResponse WSRequestHandler::GetTransitionPosition(const RpcRequest& request) {
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();
}
void WSServer::start(quint16 port)
void WSServer::start(quint16 port, bool lockToIPv4)
{
if (_server.is_listening() && port == _serverPort) {
blog(LOG_INFO, "WSServer::start: server already on this port. no restart needed");
if (_server.is_listening() && (port == _serverPort && _lockToIPv4 == lockToIPv4)) {
blog(LOG_INFO, "WSServer::start: server already on this port and protocol mode. no restart needed");
return;
}
@ -74,9 +74,16 @@ void WSServer::start(quint16 port)
_server.reset();
_serverPort = port;
_lockToIPv4 = lockToIPv4;
websocketpp::lib::error_code errorCode;
_server.listen(_serverPort, 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);
}
if (errorCode) {
std::string errorCodeMessage = errorCode.message();

View File

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

View File

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

View File

@ -2,150 +2,157 @@
<ui version="4.0">
<class>SettingsDialog</class>
<widget class="QDialog" name="SettingsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>407</width>
<height>195</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>OBSWebsocket.Settings.DialogTitle</string>
</property>
<property name="sizeGripEnabled">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<layout class="QFormLayout" name="formLayout">
<item row="3" column="1">
<widget class="QCheckBox" name="authRequired">
<property name="text">
<string>OBSWebsocket.Settings.AuthRequired</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="lbl_password">
<property name="text">
<string>OBSWebsocket.Settings.Password</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="password">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="serverEnabled">
<property name="text">
<string>OBSWebsocket.Settings.ServerEnable</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lbl_serverPort">
<property name="text">
<string>OBSWebsocket.Settings.ServerPort</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="serverPort">
<property name="minimum">
<number>1024</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
<property name="value">
<number>4444</number>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="alertsEnabled">
<property name="text">
<string>OBSWebsocket.Settings.AlertsEnable</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QCheckBox" name="debugEnabled">
<property name="text">
<string>OBSWebsocket.Settings.DebugEnable</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>407</width>
<height>216</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>OBSWebsocket.Settings.DialogTitle</string>
</property>
<property name="sizeGripEnabled">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<layout class="QFormLayout" name="formLayout">
<item row="3" column="1">
<widget class="QCheckBox" name="authRequired">
<property name="text">
<string>OBSWebsocket.Settings.AuthRequired</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="lbl_password">
<property name="text">
<string>OBSWebsocket.Settings.Password</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="password">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="serverEnabled">
<property name="text">
<string>OBSWebsocket.Settings.ServerEnable</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lbl_serverPort">
<property name="text">
<string>OBSWebsocket.Settings.ServerPort</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="serverPort">
<property name="minimum">
<number>1024</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
<property name="value">
<number>4444</number>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QCheckBox" name="alertsEnabled">
<property name="text">
<string>OBSWebsocket.Settings.AlertsEnable</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QCheckBox" name="debugEnabled">
<property name="text">
<string>OBSWebsocket.Settings.DebugEnable</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="lockToIPv4">
<property name="text">
<string>OBSWebsocket.Settings.LockToIPv4</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>SettingsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>294</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>314</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>SettingsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>300</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>314</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>SettingsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>294</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>314</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>SettingsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>300</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>314</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

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