Compare commits

...

108 Commits
4.3.1 ... 4.5.1

Author SHA1 Message Date
ef5480dd7b docs(jsdoc): clean up types for compatability with obs-websocket-js typedef generator 2019-03-30 22:08:40 +01:00
de13707f8b ci(linux): fix Ubuntu package 2019-03-30 11:36:33 +01:00
7b81b81a3e readme: fix building.md 2019-03-30 11:34:16 +01:00
2854c4e1b5 ci(macos): fix artifacts publishing 2019-03-30 11:34:07 +01:00
1848442e91 ci(macos): remove set -ev 2019-03-30 11:33:55 +01:00
7a19b168b7 ci(macos): fix typo 2019-03-30 11:33:48 +01:00
9adea8bab4 readme: Azure Pipelines CI badge 2019-03-30 11:33:37 +01:00
1db18e12b3 ci(macos): setup Azure Pipelines 2019-03-30 11:33:05 +01:00
3be4c8ae0e chore: bump to 4.5.1 2019-03-30 11:32:32 +01:00
437f4df84c requests(sources): missing return statements 2019-03-30 11:30:30 +01:00
974d6b48b2 chore: 4.5.0 release 2018-12-30 21:02:56 +01:00
db2b1e2dc7 docs(travis): Update protocol.md - 98656b5 [skip ci] 2018-12-30 17:41:58 +00:00
98656b5d2f Merge pull request #263 from Palakis/sceneitem-order
add SetSceneItemOrder from master
2018-12-30 18:40:55 +01:00
3c7570d814 scenes: rename SetSceneItemOrder to ReorderSceneItems + fix item freeing 2018-12-30 14:47:59 +01:00
fc3e30a826 docs(travis): Update protocol.md - 2f0476b [skip ci] 2018-12-30 13:34:11 +00:00
2f0476b43c docs: fix version + plugin name 2018-12-30 14:32:38 +01:00
e310c7d744 move SetSceneItemOrder to Scenes 2018-12-24 18:34:18 +01:00
8a649b89c8 scene items: import reorder method from master 2018-12-24 02:43:58 +01:00
95f52987ef docs(travis): Update protocol.md - 82b8c66 [skip ci] 2018-12-24 01:09:18 +00:00
82b8c66d51 docs: fix branch name in generation script 2018-12-24 02:07:55 +01:00
83fb1843ee Merge pull request #262 from Palakis/sources-methods-without-scene-name
sources: get rid of unnecessary `scene-name` param on Source Request Types
2018-12-24 00:33:19 +01:00
58b10069ab sources: fix issues 2018-12-24 00:10:45 +01:00
9cda739672 sceneitems: fix docs 2018-12-24 00:02:21 +01:00
276bba050b sources: nitpicking 2018-12-23 23:59:30 +01:00
147e49b362 sources + scene items: refactor + get rid of scene-name params 2018-12-23 23:54:25 +01:00
bc338c1f4a Merge pull request #261 from Palakis/freetype2-source-properties
FreeType 2 Sources: Get/Set Properties
2018-12-23 23:04:52 +01:00
e8fbb18a71 sources(ft2): fix docs 2018-12-23 23:00:33 +01:00
682c349831 sources(ft2): simplified qstring compare 2018-12-23 18:30:27 +01:00
14b311f6ab sources(ft2): fix errors 2018-12-23 18:26:57 +01:00
8a40f355c8 sources: fix indents again 2018-12-23 18:21:31 +01:00
ae2f90c5c2 sources: fix indents 2018-12-23 18:20:45 +01:00
7aff773e2c sources: fix ft2 method indents 2018-12-23 18:19:29 +01:00
0cdfa6e7f6 sources: import ft2 methods + fix them 2018-12-23 18:16:44 +01:00
fc637eef6d Merge pull request #254 from Lange/typedefs
docs: improve consistency of array typings; introduce typedefs category
2018-12-07 20:45:30 +01:00
b4c3141170 wip: remove redundant "as object" descriptions 2018-12-05 14:02:25 -06:00
41257f7af5 Merge pull request #249 from PatTheMav/4.x-current
Fix compile error and added dependency check in build script
2018-12-04 14:29:53 -08:00
b204f3ec90 wip: remove extraneous dash 2018-11-28 14:57:59 -06:00
b4926b3535 docs: improve consistency of comment docs; introduce typedefs category 2018-11-27 17:49:54 -06:00
77d63e9848 Added check for already installed packagesbuild 2018-11-08 21:29:39 +01:00
94dcd58c2e Merge pull request #251 from Palakis/auth-without-mbedtls
auth: get rid of mbedtls
2018-11-08 19:01:13 +01:00
689ce16f1b config: use RNG compatible with QT < 5.10 2018-11-08 08:58:26 +01:00
edc64b8336 auth: get rid of mbedtls 2018-11-08 00:52:26 +01:00
03db5bfd8d bugfix(actual): TransitionBegin not triggered after switching scene collections (#250) 2018-11-07 21:13:13 +01:00
9ad340ab02 bugfix: TransitionBegin not emitted after scene collection change (#250) 2018-11-07 13:08:03 +01:00
962e26040d ci(windows): build OBS with VS2015 2018-11-07 00:02:34 +01:00
b07884c1da ci(win): use VS2015 to fix build errors
`constexpr function 'qCountLeadingZeroBits' cannot result in a constant expression`
2018-11-06 23:52:03 +01:00
bad0fb62ed ci(windows): remove hardcoded image 2018-11-06 23:42:06 +01:00
28e522ce97 WSRequestHandler: fix typo 2018-11-06 20:49:33 +01:00
c206cdfa4c chore(release): version bump 2018-11-01 13:22:26 +01:00
c31ec077f5 docs(travis): Update protocol.md - afc6a60 [skip ci] 2018-11-01 12:15:56 +00:00
afc6a60746 Merge pull request #248 from RytoEX/4.3-fix-typos
general: Fix several typos throughout
2018-11-01 13:13:24 +01:00
0a495b67e6 bugfix(requests): register DuplicateSceneItem and DeleteSceneItem 2018-11-01 13:00:07 +01:00
37ea7073d5 general: Fix several typos throughout 2018-11-01 00:42:02 -04:00
feaeef5a70 Merge pull request #246 from PatTheMav/4.4-macOS-build-update
4.4 macOS build system update
2018-10-30 14:58:17 +01:00
5586670d38 Utils: add missing scene item methods 2018-10-30 14:53:48 +01:00
65a9139ffe Fixes Travis builds for macOS
Switching to Xcode 9.4 achieves parity with obs-studio.
Also QT 5.10.1 is not available as a bottle for Sierra
anymore, which leads to Travis building qt from sources.

By enabling output of the qt install step, the "missing
output" timeout in Travis should be fixed as well, once
qt is not available for High Sieera anymore.
2018-10-24 19:39:32 +02:00
3d76f078cd Silenced Homebrew update 2018-10-24 18:57:44 +02:00
a1de1b11bc Fixed Codacy commit check 2018-10-24 18:17:54 +02:00
b5a3e3a4f0 Fixed dependency check for homebrew packages 2018-10-24 16:04:09 +02:00
d7b0ad4916 Removed duplicate code (thanks CodeFactor..) 2018-10-24 15:17:43 +02:00
2a80a6b217 More POSIX sh fixes. 2018-10-24 15:14:50 +02:00
9df72f54d5 Fixed OS check and POSIX sh compatibility 2018-10-24 15:12:54 +02:00
ef75ca36c9 Added missing OS check in packaging script 2018-10-24 14:59:12 +02:00
84c0b698f5 Updated build files for macOS build
* Checks for OS type before executing
* Checks for Homebrew
* Checks for git (obs-studio build phase)
* Checks for cmake (obs-studio build phase)
* Installs/Updates depdencies
* Installs QT 5.10.1 from bottle (just like obs-studio)
* Pins QT so homebrew does not forcefully update it
* Removed wget dependency, uses macOS' curl
* More output
2018-10-24 14:55:17 +02:00
3d9a4ef1e6 cpp: fix build errors 2018-10-23 13:12:51 +02:00
cf51fdceef ci(macos): fix wget install error 2018-10-23 12:56:37 +02:00
85a52ab01f general: convert indents to tabs 2018-10-19 18:22:34 +02:00
f2792c0b40 docs(travis): Update protocol.md - 9710908 [skip ci] 2018-10-19 16:06:06 +00:00
97109087a4 DuplicateSceneItem bug fix
Courtesy of @TStod
2018-10-19 18:04:34 +02:00
953f07f21f new request types for filter management 2018-10-19 18:01:14 +02:00
03f1035690 Merge pull request #241 from caseymrm/patch-1
Add wget to install-dependencies-macos.sh
2018-10-19 17:32:59 +02:00
a561c60f7e Merge pull request #245 from PatTheMav/macos-10.14-qt-fix
CI: Fix QT 5.10 not building under macOS 10.13+
2018-10-19 17:32:19 +02:00
7963b328f9 Applied patches to enable QT 5.10 building 10.13+
Issue: https://github.com/Homebrew/homebrew-core/issues/27095
Applied: https://github.com/Homebrew/formula-patches/pull/237
Applied: https://github.com/Homebrew/homebrew-core/pull/27139
2018-10-18 01:26:00 +02:00
3b7e216409 Merge branch 'macos-qt-fix' into 4.3-maintenance 2018-10-06 12:24:21 +02:00
9ae43a6f75 ci(macos): fix Qt 5.10.0 installation 2018-10-06 12:06:43 +02:00
6b86de1fb9 Add wget to install-dependencies-macos.sh
wget is not installed by default, so when doing the build on a fresh machine, brew install it first
2018-09-27 14:07:14 -07:00
4e6d4ac437 events: fix triggering of PreviewSceneChanged 2018-07-31 11:27:10 +02:00
3b197651cc general: step by one commit to have CI running 2018-07-30 19:17:35 +02:00
c675f1c20c docs(travis): Update protocol.md - e87955d [skip ci] 2018-07-30 17:04:19 +00:00
e87955d59a ci(docs): fix docs deployment 2018-07-30 19:02:29 +02:00
c718d8d803 general: version bump + minor CI fixes 2018-07-30 18:57:24 +02:00
454a68d1b7 Merge pull request #199 from Palakis/4.3-jimtree-studiomode-fix
[not ready] events: fix triggering of PreviewSceneChanged
2018-07-29 17:01:48 +02:00
45f6f74cbe cmake: remove copy operation 2018-07-21 23:05:38 +02:00
cb7412a457 events: fix triggering of PreviewSceneChanged 2018-07-08 12:58:06 +02:00
a9fc82365c TransitionBegin: add source and destination scene names 2018-06-24 22:33:07 +02:00
edc0fed9e2 Merge branch 'transition-override-begin-event' into 4.3-maintenance 2018-06-24 22:20:55 +02:00
1c718963ea TransitionBegin: support for transition overrides 2018-06-24 22:19:45 +02:00
cd40ccdb9d Merge pull request #211 from wherget/build-fixes
MacOS Build fixes
2018-05-27 18:38:39 +02:00
80e1dc2446 Merge pull request #210 from RytoEX/build-instruction-update
Build instruction update
2018-05-27 18:35:07 +02:00
d03c4cc4b9 Merge pull request #219 from christopher-dG/cdg/replaystopping
docs: Fix ReplayStopping description
2018-05-27 18:34:58 +02:00
7bd434e755 ci(macos): get rid of manual Packages versioning 2018-04-28 23:53:47 +02:00
640bcb90c6 CI(macOS): Split off obs-studio build task
Split off the obs-studio build task to help separate CI log sections.
2018-04-28 23:53:42 +02:00
08e86a1378 CI(macOS): Use latest Qt from Homebrew
OBS Studio CI currently uses the latest Qt version in Homebrew.
2018-04-28 23:53:36 +02:00
fefcc3937a CI(macOS): Update Packages version
Update Packages to version 1.2.3, which released on April 7, 2018.
2018-04-28 23:53:28 +02:00
25210dfa52 CI and CMake improvements (#205)
* CMake: Copy PDB file to OBS build directory on Debug build

All native OBS build objects also bundle the associated PDB file for
debugging and handling crash reports.

* CMake: Add post-build commands for RelWithDebInfo

Add post-build commands for the RelWithDebInfo build config. OBS
official builds use RelWithDebInfo, so we should be able to treat it as
a release config.

* CI: Disable building OBS native plugins

Use the OBS CMake flag DISABLE_PLUGINS to disable building plugins
included with OBS (including submodule plugins like obs-browser). This
should speed up builds on Windows when we have to rebuild OBS and on
Mac.

* CI: Don't clone/update OBS submodules

The only submodules presently in OBS are in its plugins, which we don't
need to build.

* CI: Use obsproject/obs-studio instead of jp9000/obs-studio

The OBS GitHub recently changed from jp9000/obs-studio to
obsproject/obs-studio, so use that instead.

* CI: Build as RelWithDebInfo instead of Release

OBS official builds are produced with RelWithDebInfo. This will produce
a PDB file for the plugin, similar to the native OBS plugins.

* CI(Windows): Build OBS if current build config doesn't exist

If OBS libs for the current build config do not exist, build OBS before
building obs-websocket.
2018-03-26 11:12:39 +02:00
56fbb7b9cf CI(Windows): Build OBS with Visual Studio 2017
We should also build OBS with Visual Studio 2017.
2018-03-26 11:12:19 +02:00
c55d33b956 CI(Windows): Use Visual Studio 2017
Official OBS releases have switched to Visual Studio 2017. There is no
32-bit Qt 5.10.1 package for Visual Studio 2017, but the Visual Studio
2015 package is compatible.
2018-03-26 11:11:18 +02:00
0c5bce101e CI(linux): forgot to install checkinstall 2018-03-20 14:27:04 +01:00
0a50e2a95c ci(linux): use OBS dev deps from PPA release 2018-03-20 14:11:33 +01:00
5ad940924b CI(windows): build installer
ci(windows): escape path


ci(windows): add inno setup compiler to PATH


ci(windows): fix installer.iss path
2018-03-19 02:36:24 +01:00
6eb49930bf general: version bump to 4.3.3 2018-03-19 01:11:35 +01:00
3a0d5fb190 CI: let's try with VS2015 instead 2018-03-18 23:25:38 +01:00
8c2eee2e25 CI: update Windows builds to VS2017 and Qt 5.10.1 2018-03-18 23:25:31 +01:00
2e19c5f08a docs: update version 2018-03-14 23:03:14 +01:00
548b53437f general: version bump to 4.3.2 2018-03-14 22:58:53 +01:00
e1ca9a8029 notifications: check if system tray is available before notifying 2018-03-14 22:26:08 +01:00
389ef2aea9 Config: remove flawed qstring_data_copy and add toUtf8() macro 2018-03-14 22:26:00 +01:00
357691bad5 CI: bump to latest OBS version 2018-01-22 23:24:09 +01:00
52 changed files with 5205 additions and 3021 deletions

9
.editorconfig Normal file
View File

@ -0,0 +1,9 @@
[*]
insert_final_newline = true
[*.{c,cpp,h,hpp}]
indent_style = tab
[*.{yml,yaml}]
indent_style = space
indent_size = 2

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "deps/mbedtls"]
path = deps/mbedtls
url = https://github.com/ARMmbed/mbedtls

View File

@ -32,14 +32,6 @@ matrix:
after_success: after_success:
- docker exec -it xenial /root/obs-websocket/CI/package-xenial.sh - docker exec -it xenial /root/obs-websocket/CI/package-xenial.sh
- os: osx
env: _macos_build
osx_image: xcode8.3
before_install: "./CI/install-dependencies-macos.sh"
script: "./CI/build-macos.sh"
after_success:
- ./CI/package-macos.sh
deploy: deploy:
- provider: s3 - provider: s3
region: eu-central-1 region: eu-central-1
@ -55,15 +47,3 @@ deploy:
- "$TRAVIS_OS_NAME = linux" - "$TRAVIS_OS_NAME = linux"
- "-d /home/travis/package" - "-d /home/travis/package"
all_branches: true all_branches: true
- provider: s3
region: eu-central-1
bucket: obs-websocket-osx-builds
access_key_id: "$AWS_ID"
secret_access_key: "$AWS_SECRET"
local_dir: release
skip_cleanup: true
acl: public_read
on:
repo: Palakis/obs-websocket
condition: "$TRAVIS_OS_NAME = osx"
all_branches: true

View File

@ -1,6 +1,9 @@
# Compiling obs-websocket # Compiling obs-websocket
## Prerequisites ## Prerequisites
You'll need [QT 5.9.0](https://download.qt.io/official_releases/qt/5.7/5.7.0/), CMake, and a working development environment for OBS Studio installed on your computer. You'll need [Qt 5.10.x](https://download.qt.io/official_releases/qt/5.10/),
[CMake](https://cmake.org/download/), and a working [development environment for
OBS Studio](https://obsproject.com/wiki/install-instructions) installed on your
computer.
## Windows ## Windows
In cmake-gui, you'll have to set the following variables : In cmake-gui, you'll have to set the following variables :
@ -22,17 +25,31 @@ sudo make install
``` ```
## OS X ## OS X
Use of the Travis macOS CI scripts is recommended. Please note that these scripts install new software and can change several settings on your system. An existing obs-studio development environment is not required, as `install-dependencies-macos.sh` will install it for you. As a prerequisite, you will need Xcode for your current OSX version, the command line tools, and [Homebrew](https://brew.sh/).
Of course, you're encouraged to dig through the contents of these scripts to look for issues or specificities. Homebrew's setup will guide you in getting your system set up, you should be good to go once Homebrew is successfully up and running.
Use of the Travis macOS CI scripts is recommended. Please note that these
scripts install new software and can change several settings on your system. An
existing obs-studio development environment is not required, as
`install-build-obs-macos.sh` will install it for you. If you already have a
working obs-studio development environment and have built obs-studio, you can
skip that script.
Of course, you're encouraged to dig through the contents of these scripts to
look for issues or specificities.
``` ```
git clone --recursive https://github.com/Palakis/obs-websocket.git git clone --recursive https://github.com/Palakis/obs-websocket.git
cd obs-websocket cd obs-websocket
./CI/install-dependencies-macos.sh ./CI/install-dependencies-macos.sh
./CI/install-build-obs-macos.sh
./CI/build-macos.sh ./CI/build-macos.sh
./CI/package-macos.sh ./CI/package-macos.sh
``` ```
This will result in a ready-to-use `obs-websocket.pkg` installer in the `release` subfolder. This will result in a ready-to-use `obs-websocket.pkg` installer in the `release` subfolder.
## Automated Builds ## Automated Builds
- Windows: [![Automated Build status for Windows](https://ci.appveyor.com/api/projects/status/github/Palakis/obs-websocket)](https://ci.appveyor.com/project/Palakis/obs-websocket/history) - Windows: [![Automated Build status for Windows](https://ci.appveyor.com/api/projects/status/github/Palakis/obs-websocket)](https://ci.appveyor.com/project/Palakis/obs-websocket/history)
- Linux & OS X : [![Automated Build status for Linux & OS X](https://travis-ci.org/Palakis/obs-websocket.svg?branch=master)](https://travis-ci.org/Palakis/obs-websocket) - Linux: [![Automated Build status for Linux](https://travis-ci.org/Palakis/obs-websocket.svg?branch=master)](https://travis-ci.org/Palakis/obs-websocket)
- macOS: [![Automated Build status for macOS](https://img.shields.io/azure-devops/build/Palakis/obs-websocket/Palakis.obs-websocket.svg)](https://dev.azure.com/Palakis/obs-websocket/_build)

View File

@ -1,13 +1,28 @@
#!/bin/sh #!/bin/sh
set -ex
OSTYPE=$(uname)
if [ "${OSTYPE}" != "Darwin" ]; then
echo "[obs-websocket - Error] macOS build script can be run on Darwin-type OS only."
exit 1
fi
HAS_CMAKE=$(type cmake 2>/dev/null)
if [ "${HAS_CMAKE}" = "" ]; then
echo "[obs-websocket - Error] CMake not installed - please run 'install-dependencies-macos.sh' first."
exit 1
fi
#export QT_PREFIX="$(find /usr/local/Cellar/qt5 -d 1 | tail -n 1)" #export QT_PREFIX="$(find /usr/local/Cellar/qt5 -d 1 | tail -n 1)"
mkdir build && cd build echo "[obs-websocket] Building 'obs-websocket' for macOS."
mkdir -p build && cd build
cmake .. \ cmake .. \
-DQTDIR=/usr/local/opt/qt \ -DQTDIR=/usr/local/opt/qt \
-DLIBOBS_INCLUDE_DIR=../../obs-studio/libobs \ -DLIBOBS_INCLUDE_DIR=../../obs-studio/libobs \
-DLIBOBS_LIB=../../obs-studio/libobs \ -DLIBOBS_LIB=../../obs-studio/libobs \
-DOBS_FRONTEND_LIB="$(pwd)/../../obs-studio/build/UI/obs-frontend-api/libobs-frontend-api.dylib" \ -DOBS_FRONTEND_LIB="$(pwd)/../../obs-studio/build/UI/obs-frontend-api/libobs-frontend-api.dylib" \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_INSTALL_PREFIX=/usr \ -DCMAKE_INSTALL_PREFIX=/usr \
&& make -j4 && make -j4

View File

@ -4,5 +4,5 @@ set -ex
cd /root/obs-websocket cd /root/obs-websocket
mkdir build && cd build mkdir build && cd build
cmake -DLIBOBS_INCLUDE_DIR="../../obs-studio/libobs" -DCMAKE_INSTALL_PREFIX=/usr .. cmake -DCMAKE_INSTALL_PREFIX=/usr ..
make -j4 make -j4

View File

@ -15,7 +15,7 @@ if git diff --quiet; then
exit 0 exit 0
fi fi
if [ "$TRAVIS_PULL_REQUEST" != "false" -o "$TRAVIS_BRANCH" != "master" ]; then if [ "$TRAVIS_PULL_REQUEST" != "false" -o "$TRAVIS_BRANCH" != "4.x-current" ]; then
echo "-- Skipping documentation deployment because this is either a pull request or a non-master branch." echo "-- Skipping documentation deployment because this is either a pull request or a non-master branch."
exit 0 exit 0
fi fi

41
CI/install-build-obs-macos.sh Executable file
View File

@ -0,0 +1,41 @@
#!/bin/sh
OSTYPE=$(uname)
if [ "${OSTYPE}" != "Darwin" ]; then
echo "[obs-websocket - Error] macOS obs-studio build script can be run on Darwin-type OS only."
exit 1
fi
HAS_CMAKE=$(type cmake 2>/dev/null)
HAS_GIT=$(type git 2>/dev/null)
if [ "${HAS_CMAKE}" = "" ]; then
echo "[obs-websocket - Error] CMake not installed - please run 'install-dependencies-macos.sh' first."
exit 1
fi
if [ "${HAS_GIT}" = "" ]; then
echo "[obs-websocket - Error] Git not installed - please install Xcode developer tools or via Homebrew."
exit 1
fi
echo "[obs-websocket] Downloading and unpacking OBS dependencies"
wget --quiet --retry-connrefused --waitretry=1 https://obs-nightly.s3.amazonaws.com/osx-deps-2018-08-09.tar.gz
tar -xf ./osx-deps-2018-08-09.tar.gz -C /tmp
# Build obs-studio
cd ..
echo "[obs-websocket] Cloning obs-studio from GitHub.."
git clone https://github.com/obsproject/obs-studio
cd obs-studio
OBSLatestTag=$(git describe --tags --abbrev=0)
git checkout $OBSLatestTag
mkdir build && cd build
echo "[obs-websocket] Building obs-studio.."
cmake .. \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.11 \
-DDISABLE_PLUGINS=true \
-DDepsPath=/tmp/obsdeps \
-DCMAKE_PREFIX_PATH=/usr/local/opt/qt/lib/cmake \
&& make -j4

View File

@ -60,13 +60,24 @@ REM If obs-studio directory does not exist, clone the git repo, get the latest
REM tag number, and set the build flag. REM tag number, and set the build flag.
if not exist C:\projects\obs-studio ( if not exist C:\projects\obs-studio (
echo obs-studio directory does not exist echo obs-studio directory does not exist
git clone --recursive https://github.com/jp9000/obs-studio git clone https://github.com/obsproject/obs-studio
cd C:\projects\obs-studio\ cd C:\projects\obs-studio\
git describe --tags --abbrev=0 > C:\projects\obs-studio-latest-tag.txt git describe --tags --abbrev=0 > C:\projects\obs-studio-latest-tag.txt
set /p OBSLatestTag=<C:\projects\obs-studio-latest-tag.txt set /p OBSLatestTag=<C:\projects\obs-studio-latest-tag.txt
set BuildOBS=true set BuildOBS=true
) )
REM If the needed obs-studio libs for this build_config do not exist,
REM set the build flag.
if not exist C:\projects\obs-studio\build32\libobs\%build_config%\obs.lib (
echo obs-studio\build32\libobs\%build_config%\obs.lib does not exist
set BuildOBS=true
)
if not exist C:\projects\obs-studio\build32\UI\obs-frontend-api\%build_config%\obs-frontend-api.lib (
echo obs-studio\build32\UI\obs-frontend-api\%build_config%\obs-frontend-api.lib does not exist
set BuildOBS=true
)
REM Some debug info REM Some debug info
echo: echo:
echo Latest tag pre-pull: %OBSLatestTagPrePull% echo Latest tag pre-pull: %OBSLatestTagPrePull%
@ -97,12 +108,12 @@ if defined BuildOBS (
mkdir build64 mkdir build64
echo Running cmake for obs-studio %OBSLatestTag% 32-bit... echo Running cmake for obs-studio %OBSLatestTag% 32-bit...
cd ./build32 cd ./build32
cmake -G "Visual Studio 12 2013" -DCOPIED_DEPENDENCIES=false -DCOPY_DEPENDENCIES=true .. cmake -G "Visual Studio 14 2015" -DDISABLE_PLUGINS=true -DCOPIED_DEPENDENCIES=false -DCOPY_DEPENDENCIES=true ..
echo: echo:
echo: echo:
echo Running cmake for obs-studio %OBSLatestTag% 64-bit... echo Running cmake for obs-studio %OBSLatestTag% 64-bit...
cd ../build64 cd ../build64
cmake -G "Visual Studio 12 2013 Win64" -DCOPIED_DEPENDENCIES=false -DCOPY_DEPENDENCIES=true .. cmake -G "Visual Studio 14 2015 Win64" -DDISABLE_PLUGINS=true -DCOPIED_DEPENDENCIES=false -DCOPY_DEPENDENCIES=true ..
echo: echo:
echo: echo:
echo Building obs-studio %OBSLatestTag% 32-bit ^(Build Config: %build_config%^)... echo Building obs-studio %OBSLatestTag% 32-bit ^(Build Config: %build_config%^)...

View File

@ -1,32 +1,61 @@
#!/bin/sh #!/bin/sh
set -ex
OSTYPE=$(uname)
if [ "${OSTYPE}" != "Darwin" ]; then
echo "[obs-websocket - Error] macOS install dependencies script can be run on Darwin-type OS only."
exit 1
fi
HAS_BREW=$(type brew 2>/dev/null)
if [ "${HAS_BREW}" = "" ]; then
echo "[obs-websocket - Error] Please install Homebrew (https://www.brew.sh/) to build obs-websocket on macOS."
exit 1
fi
# OBS Studio deps # OBS Studio deps
brew update echo "[obs-websocket] Updating Homebrew.."
brew install ffmpeg brew update >/dev/null
brew install libav echo "[obs-websocket] Checking installed Homebrew formulas.."
BREW_PACKAGES=$(brew list)
BREW_DEPENDENCIES="jack speexdsp ccache swig mbedtls"
for DEPENDENCY in ${BREW_DEPENDENCIES}; do
if echo "${BREW_PACKAGES}" | grep -q "^${DEPENDENCY}\$"; then
echo "[obs-websocket] Upgrading OBS-Studio dependency '${DEPENDENCY}'.."
brew upgrade ${DEPENDENCY} 2>/dev/null
else
echo "[obs-websocket] Installing OBS-Studio dependency '${DEPENDENCY}'.."
brew install ${DEPENDENCY} 2>/dev/null
fi
done
# qtwebsockets deps # qtwebsockets deps
# qt latest echo "[obs-websocket] Installing obs-websocket dependency 'QT 5.10.1'.."
#brew install qt5 # =!= 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 =!=
# qt 5.9.2 brew install https://gist.githubusercontent.com/DDRBoxman/b3956fab6073335a4bf151db0dcbd4ad/raw/ed1342a8a86793ea8c10d8b4d712a654da121ace/qt.rb
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/2b121c9a96e58a5da14228630cb71d5bead7137e/Formula/qt.rb
#echo "Qt path: $(find /usr/local/Cellar/qt5 -d 1 | tail -n 1)" # Pin this version of QT5 to avoid `brew upgrade`
# upgrading it to incompatible version
brew pin qt
# Build obs-studio # Fetch and install Packages app
cd .. # =!= NOTICE =!=
git clone --recursive https://github.com/jp9000/obs-studio # Installs a LaunchDaemon under /Library/LaunchDaemons/fr.whitebox.packages.build.dispatcher.plist
cd obs-studio # =!= NOTICE =!=
git checkout 20.1.0
mkdir build && cd build
cmake .. \
-DCMAKE_PREFIX_PATH=/usr/local/opt/qt/lib/cmake \
&& make -j4
# Packages app HAS_PACKAGES=$(type packagesbuild 2>/dev/null)
cd ..
curl -L -O http://s.sudre.free.fr/Software/files/Packages.dmg -f --retry 5 -C - if [ "${HAS_PACKAGES}" = "" ]; then
hdiutil attach ./Packages.dmg echo "[obs-websocket] Installing Packaging app (might require password due to 'sudo').."
sudo installer -pkg /Volumes/Packages\ 1.2.2/packages/Packages.pkg -target / curl -o './Packages.pkg' --retry-connrefused -s --retry-delay 1 'https://s3-us-west-2.amazonaws.com/obs-nightly/Packages.pkg'
sudo installer -pkg ./Packages.pkg -target /
fi

View File

@ -1,57 +1,19 @@
#!/bin/sh #!/bin/sh
set -ex set -ex
# OBS Studio deps add-apt-repository -y ppa:obsproject/obs-studio
apt-get -qq update apt-get -qq update
apt-get install -y \
libc-dev-bin libc6-dev \
git \
build-essential
apt-get install -y \ apt-get install -y \
libc-dev-bin \
libc6-dev git \
build-essential \ build-essential \
checkinstall \ checkinstall \
cmake \ cmake \
libasound2-dev \ obs-studio \
libavcodec-dev \ libqt5websockets5-dev
libavdevice-dev \
libavfilter-dev \
libavformat-dev \
libavutil-dev \
libcurl4-openssl-dev \
libfontconfig-dev \
libfreetype6-dev \
libgl1-mesa-dev \
libjack-jackd2-dev \
libjansson-dev \
libpulse-dev \
libqt5x11extras5-dev \
libspeexdsp-dev \
libswresample-dev \
libswscale-dev \
libudev-dev \
libv4l-dev \
libvlc-dev \
libx11-dev \
libx264-dev \
libxcb-shm0-dev \
libxcb-xinerama0-dev \
libxcomposite-dev \
libxinerama-dev \
pkg-config \
qtbase5-dev
# obs-websocket deps # Dirty hack
apt-get install -y libqt5websockets5-dev wget -O /usr/include/obs/obs-frontend-api.h https://raw.githubusercontent.com/obsproject/obs-studio/master/UI/obs-frontend-api/obs-frontend-api.h
# Build obs-studio
cd /root
git clone https://github.com/jp9000/obs-studio ./obs-studio
cd obs-studio
git checkout 20.1.0
mkdir build && cd build
cmake -DUNIX_STRUCTURE=1 -DCMAKE_INSTALL_PREFIX=/usr ..
make -j4
make install
ldconfig ldconfig

View File

@ -1,20 +1,6 @@
@echo off @echo off
REM Set default values to use AppVeyor's built-in Qt. REM Set default values to use AppVeyor's built-in Qt.
set QTDIR32=C:\Qt\5.7\msvc2013 set QTDIR32=C:\Qt\5.10.1\msvc2015
set QTDIR64=C:\Qt\5.7\msvc2013_64 set QTDIR64=C:\Qt\5.10.1\msvc2015_64
set QTCompileVersion=5.7.1 set QTCompileVersion=5.10.1
REM If the AppVeyor cache couldn't recover qt570.7z,
REM try to fetch Qt 5.7.0 from slepin.fr.
if not exist qt570.7z (
curl -kLO https://www.slepin.fr/obs-plugins/deps/qt570.7z -f --retry 5 -C -
)
REM If qt570.7z exists now, use that instead of AppVeyor's built-in Qt.
if exist qt570.7z (
7z x qt570.7z -o"Qt5.7.0"
set QTDIR32=%CD%\Qt5.7.0\msvc2013
set QTDIR64=%CD%\Qt5.7.0\msvc2013_64
set QTCompileVersion=5.7.0
)

View File

@ -635,7 +635,7 @@
<key>OVERWRITE_PERMISSIONS</key> <key>OVERWRITE_PERMISSIONS</key>
<false/> <false/>
<key>VERSION</key> <key>VERSION</key>
<string>4.3.1</string> <string>4.5.1</string>
</dict> </dict>
<key>PROJECT_COMMENTS</key> <key>PROJECT_COMMENTS</key>
<dict> <dict>

163
CI/macos/qt.rb Normal file
View File

@ -0,0 +1,163 @@
# 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
bottle do
sha256 "8b4bad005596a5f8790150fe455db998ac2406f4e0f04140d6656205d844d266" => :high_sierra
sha256 "9c488554935fb573554a4e36d36d3c81e47245b7fefc4b61edef894e67ba1740" => :sierra
sha256 "c0407afba5951df6cc4c6f6c1c315972bd41c99cecb4e029919c4c15ab6f7bdc" => :el_capitan
end
keg_only "Qt 5 has CMake issues when linked"
option "with-docs", "Build documentation"
option "with-examples", "Build examples"
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
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
# 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
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 << "-nomake" << "examples" if build.without? "examples"
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
args << "-plugin-sql-psql" if build.with? "postgresql"
system "./configure", *args
system "make"
ENV.deparallelize
system "make", "install"
if build.with? "docs"
system "make", "docs"
system "make", "install_docs"
end
# Some config scripts will only find Qt in a "Frameworks" folder
frameworks.install_symlink Dir["#{lib}/*.framework"]
# 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
# 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
def caveats; <<~EOS
We agreed to the Qt opensource license for you.
If this is unacceptable you should uninstall.
EOS
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
(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

View File

@ -2,44 +2,50 @@
set -e set -e
echo "-- Preparing package build" OSTYPE=$(uname)
export QT_CELLAR_PREFIX="$(find /usr/local/Cellar/qt -d 1 | tail -n 1)"
if [ "${OSTYPE}" != "Darwin" ]; then
echo "[obs-websocket - Error] macOS package script can be run on Darwin-type OS only."
exit 1
fi
echo "[obs-websocket] Preparing package build"
export QT_CELLAR_PREFIX="$(/usr/bin/find /usr/local/Cellar/qt -d 1 | sort -t '.' -k 1,1n -k 2,2n -k 3,3n | tail -n 1)"
export WS_LIB="/usr/local/opt/qt/lib/QtWebSockets.framework/QtWebSockets" export WS_LIB="/usr/local/opt/qt/lib/QtWebSockets.framework/QtWebSockets"
export NET_LIB="/usr/local/opt/qt/lib/QtNetwork.framework/QtNetwork" export NET_LIB="/usr/local/opt/qt/lib/QtNetwork.framework/QtNetwork"
export GIT_HASH=$(git rev-parse --short HEAD) export GIT_HASH=$(git rev-parse --short HEAD)
export GIT_BRANCH_OR_TAG=$(git name-rev --name-only HEAD | awk -F/ '{print $NF}')
export VERSION="$GIT_HASH-$TRAVIS_BRANCH" export VERSION="$GIT_HASH-$GIT_BRANCH_OR_TAG"
export LATEST_VERSION="$TRAVIS_BRANCH" export LATEST_VERSION="$GIT_BRANCH_OR_TAG"
if [ -n "${TRAVIS_TAG}" ]; then
export VERSION="$TRAVIS_TAG"
export LATEST_VERSION="$TRAVIS_TAG"
fi
export FILENAME="obs-websocket-$VERSION.pkg" export FILENAME="obs-websocket-$VERSION.pkg"
export LATEST_FILENAME="obs-websocket-latest-$LATEST_VERSION.pkg" export LATEST_FILENAME="obs-websocket-latest-$LATEST_VERSION.pkg"
echo "-- Copying Qt dependencies" echo "[obs-websocket] Copying Qt dependencies"
cp $WS_LIB ./build if [ ! -f ./build/$(basename $WS_LIB) ]; then cp $WS_LIB ./build; fi
cp $NET_LIB ./build if [ ! -f ./build/$(basename $NET_LIB) ]; then cp $NET_LIB ./build; fi
chmod +rw ./build/QtWebSockets ./build/QtNetwork chmod +rw ./build/QtWebSockets ./build/QtNetwork
echo "-- Modifying QtNetwork" echo "[obs-websocket] Modifying QtNetwork"
install_name_tool \ install_name_tool \
-id @rpath/QtNetwork \
-change /usr/local/opt/qt/lib/QtNetwork.framework/Versions/5/QtNetwork @rpath/QtNetwork \ -change /usr/local/opt/qt/lib/QtNetwork.framework/Versions/5/QtNetwork @rpath/QtNetwork \
-change $QT_CELLAR_PREFIX/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore \ -change $QT_CELLAR_PREFIX/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore \
./build/QtNetwork ./build/QtNetwork
echo "-- Modifying QtWebSockets" echo "[obs-websocket] Modifying QtWebSockets"
install_name_tool \ install_name_tool \
-id @rpath/QtWebSockets \
-change /usr/local/opt/qt/lib/QtWebSockets.framework/Versions/5/QtWebSockets @rpath/QtWebSockets \ -change /usr/local/opt/qt/lib/QtWebSockets.framework/Versions/5/QtWebSockets @rpath/QtWebSockets \
-change $QT_CELLAR_PREFIX/lib/QtNetwork.framework/Versions/5/QtNetwork @rpath/QtNetwork \ -change $QT_CELLAR_PREFIX/lib/QtNetwork.framework/Versions/5/QtNetwork @rpath/QtNetwork \
-change $QT_CELLAR_PREFIX/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore \ -change $QT_CELLAR_PREFIX/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore \
./build/QtWebSockets ./build/QtWebSockets
echo "-- Modifying obs-websocket.so" echo "[obs-websocket] Modifying obs-websocket.so"
install_name_tool \ install_name_tool \
-change /usr/local/opt/qt/lib/QtWebSockets.framework/Versions/5/QtWebSockets @rpath/QtWebSockets \ -change /usr/local/opt/qt/lib/QtWebSockets.framework/Versions/5/QtWebSockets @rpath/QtWebSockets \
-change /usr/local/opt/qt/lib/QtWidgets.framework/Versions/5/QtWidgets @rpath/QtWidgets \ -change /usr/local/opt/qt/lib/QtWidgets.framework/Versions/5/QtWidgets @rpath/QtWidgets \
@ -49,18 +55,18 @@ install_name_tool \
./build/obs-websocket.so ./build/obs-websocket.so
# Check if replacement worked # Check if replacement worked
echo "-- Dependencies for QtNetwork" echo "[obs-websocket] Dependencies for QtNetwork"
otool -L ./build/QtNetwork otool -L ./build/QtNetwork
echo "-- Dependencies for QtWebSockets" echo "[obs-websocket] Dependencies for QtWebSockets"
otool -L ./build/QtWebSockets otool -L ./build/QtWebSockets
echo "-- Dependencies for obs-websocket" echo "[obs-websocket] Dependencies for obs-websocket"
otool -L ./build/obs-websocket.so otool -L ./build/obs-websocket.so
chmod -w ./build/QtWebSockets ./build/QtNetwork chmod -w ./build/QtWebSockets ./build/QtNetwork
echo "-- Actual package build" echo "[obs-websocket] Actual package build"
packagesbuild ./CI/macos/obs-websocket.pkgproj packagesbuild ./CI/macos/obs-websocket.pkgproj
echo "-- Renaming obs-websocket.pkg to $FILENAME" echo "[obs-websocket] Renaming obs-websocket.pkg to $FILENAME"
mv ./release/obs-websocket.pkg ./release/$FILENAME mv ./release/obs-websocket.pkg ./release/$FILENAME
cp ./release/$FILENAME ./release/$LATEST_FILENAME cp ./release/$FILENAME ./release/$LATEST_FILENAME

View File

@ -6,16 +6,15 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOUIC ON)
if (WIN32 OR APPLE)
include(external/FindLibObs.cmake) include(external/FindLibObs.cmake)
endif()
find_package(LibObs REQUIRED) find_package(LibObs REQUIRED)
find_package(Qt5Core REQUIRED) find_package(Qt5Core REQUIRED)
find_package(Qt5WebSockets REQUIRED) find_package(Qt5WebSockets REQUIRED)
find_package(Qt5Widgets REQUIRED) find_package(Qt5Widgets REQUIRED)
add_subdirectory(deps/mbedtls EXCLUDE_FROM_ALL)
set(ENABLE_PROGRAMS false)
set(obs-websocket_SOURCES set(obs-websocket_SOURCES
src/obs-websocket.cpp src/obs-websocket.cpp
src/WSServer.cpp src/WSServer.cpp
@ -50,22 +49,17 @@ add_library(obs-websocket MODULE
${obs-websocket_SOURCES} ${obs-websocket_SOURCES}
${obs-websocket_HEADERS}) ${obs-websocket_HEADERS})
add_dependencies(obs-websocket mbedcrypto)
include_directories( include_directories(
"${LIBOBS_INCLUDE_DIR}/../UI/obs-frontend-api" "${LIBOBS_INCLUDE_DIR}/../UI/obs-frontend-api"
${Qt5Core_INCLUDES} ${Qt5Core_INCLUDES}
${Qt5WebSockets_INCLUDES} ${Qt5WebSockets_INCLUDES}
${Qt5Widgets_INCLUDES} ${Qt5Widgets_INCLUDES})
${mbedcrypto_INCLUDES}
"${CMAKE_SOURCE_DIR}/deps/mbedtls/include")
target_link_libraries(obs-websocket target_link_libraries(obs-websocket
libobs libobs
Qt5::Core Qt5::Core
Qt5::WebSockets Qt5::WebSockets
Qt5::Widgets Qt5::Widgets)
mbedcrypto)
# --- End of section --- # --- End of section ---
@ -73,7 +67,7 @@ target_link_libraries(obs-websocket
if(WIN32) if(WIN32)
if(NOT DEFINED OBS_FRONTEND_LIB) if(NOT DEFINED OBS_FRONTEND_LIB)
set(OBS_FRONTEND_LIB "OBS_FRONTEND_LIB-NOTFOUND" CACHE FILEPATH "OBS frontend library") set(OBS_FRONTEND_LIB "OBS_FRONTEND_LIB-NOTFOUND" CACHE FILEPATH "OBS frontend library")
message(FATAL_ERROR "Could not find OBS Frontend API\'s library !") message(FATAL_ERROR "Could not find OBS Frontend API's library !")
endif() endif()
if(CMAKE_SIZEOF_VOID_P EQUAL 8) if(CMAKE_SIZEOF_VOID_P EQUAL 8)
@ -91,23 +85,12 @@ if(WIN32)
target_link_libraries(obs-websocket target_link_libraries(obs-websocket
"${OBS_FRONTEND_LIB}") "${OBS_FRONTEND_LIB}")
add_custom_command(TARGET obs-websocket POST_BUILD
COMMAND if $<CONFIG:Release>==1 ("${CMAKE_COMMAND}" -E copy
"${QTDIR}/bin/Qt5WebSockets.dll"
"${QTDIR}/bin/Qt5Network.dll"
"${CMAKE_BINARY_DIR}/$<CONFIG>")
COMMAND if $<CONFIG:Debug>==1 ("${CMAKE_COMMAND}" -E copy
"${QTDIR}/bin/Qt5WebSocketsd.dll"
"${QTDIR}/bin/Qt5Networkd.dll"
"${CMAKE_BINARY_DIR}/$<CONFIG>")
)
# --- Release package helper --- # --- Release package helper ---
# The "release" folder has a structure similar OBS' one on Windows # The "release" folder has a structure similar OBS' one on Windows
set(RELEASE_DIR "${PROJECT_SOURCE_DIR}/release") set(RELEASE_DIR "${PROJECT_SOURCE_DIR}/release")
add_custom_command(TARGET obs-websocket POST_BUILD add_custom_command(TARGET obs-websocket POST_BUILD
# If config is Release, package release files
COMMAND if $<CONFIG:Release>==1 ( COMMAND if $<CONFIG:Release>==1 (
"${CMAKE_COMMAND}" -E make_directory "${CMAKE_COMMAND}" -E make_directory
"${RELEASE_DIR}/data/obs-plugins/obs-websocket" "${RELEASE_DIR}/data/obs-plugins/obs-websocket"
@ -123,6 +106,26 @@ if(WIN32)
"${QTDIR}/bin/Qt5Network.dll" "${QTDIR}/bin/Qt5Network.dll"
"${RELEASE_DIR}/obs-plugins/${ARCH_NAME}") "${RELEASE_DIR}/obs-plugins/${ARCH_NAME}")
# If config is RelWithDebInfo, package release files
COMMAND if $<CONFIG:RelWithDebInfo>==1 (
"${CMAKE_COMMAND}" -E make_directory
"${RELEASE_DIR}/data/obs-plugins/obs-websocket"
"${RELEASE_DIR}/obs-plugins/${ARCH_NAME}")
COMMAND if $<CONFIG:RelWithDebInfo>==1 ("${CMAKE_COMMAND}" -E copy_directory
"${PROJECT_SOURCE_DIR}/data"
"${RELEASE_DIR}/data/obs-plugins/obs-websocket")
COMMAND if $<CONFIG:RelWithDebInfo>==1 ("${CMAKE_COMMAND}" -E copy
"$<TARGET_FILE:obs-websocket>"
"${QTDIR}/bin/Qt5WebSockets.dll"
"${QTDIR}/bin/Qt5Network.dll"
"${RELEASE_DIR}/obs-plugins/${ARCH_NAME}")
COMMAND if $<CONFIG:RelWithDebInfo>==1 ("${CMAKE_COMMAND}" -E copy
"$<TARGET_PDB_FILE:obs-websocket>"
"${RELEASE_DIR}/obs-plugins/${ARCH_NAME}")
# Copy to obs-studio dev environment for immediate testing # Copy to obs-studio dev environment for immediate testing
COMMAND if $<CONFIG:Debug>==1 ( COMMAND if $<CONFIG:Debug>==1 (
"${CMAKE_COMMAND}" -E copy "${CMAKE_COMMAND}" -E copy
@ -131,6 +134,11 @@ if(WIN32)
"${QTDIR}/bin/Qt5Networkd.dll" "${QTDIR}/bin/Qt5Networkd.dll"
"${LIBOBS_INCLUDE_DIR}/../${OBS_BUILDDIR_ARCH}/rundir/$<CONFIG>/obs-plugins/${ARCH_NAME}") "${LIBOBS_INCLUDE_DIR}/../${OBS_BUILDDIR_ARCH}/rundir/$<CONFIG>/obs-plugins/${ARCH_NAME}")
COMMAND if $<CONFIG:Debug>==1 (
"${CMAKE_COMMAND}" -E copy
"$<TARGET_PDB_FILE:obs-websocket>"
"${LIBOBS_INCLUDE_DIR}/../${OBS_BUILDDIR_ARCH}/rundir/$<CONFIG>/obs-plugins/${ARCH_NAME}")
COMMAND if $<CONFIG:Debug>==1 ( COMMAND if $<CONFIG:Debug>==1 (
"${CMAKE_COMMAND}" -E make_directory "${CMAKE_COMMAND}" -E make_directory
"${LIBOBS_INCLUDE_DIR}/../${OBS_BUILDDIR_ARCH}/rundir/$<CONFIG>/data/obs-plugins/obs-websocket") "${LIBOBS_INCLUDE_DIR}/../${OBS_BUILDDIR_ARCH}/rundir/$<CONFIG>/data/obs-plugins/obs-websocket")
@ -149,15 +157,19 @@ endif()
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
target_compile_options(mbedcrypto PRIVATE -fPIC)
set_target_properties(obs-websocket PROPERTIES PREFIX "") set_target_properties(obs-websocket PROPERTIES PREFIX "")
target_link_libraries(obs-websocket target_link_libraries(obs-websocket
obs-frontend-api) obs-frontend-api)
file(GLOB locale_files data/locale/*.ini) file(GLOB locale_files data/locale/*.ini)
execute_process(COMMAND uname -m COMMAND tr -d '\n' OUTPUT_VARIABLE UNAME_MACHINE)
install(TARGETS obs-websocket install(TARGETS obs-websocket
LIBRARY DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/obs-plugins") LIBRARY DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/obs-plugins")
# Dirty fix for Ubuntu
install(TARGETS obs-websocket
LIBRARY DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/${UNAME_MACHINE}-linux-gnu/obs-plugins")
install(FILES ${locale_files} install(FILES ${locale_files}
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/obs/obs-plugins/obs-websocket/locale") DESTINATION "${CMAKE_INSTALL_PREFIX}/share/obs/obs-plugins/obs-websocket/locale")
endif() endif()
@ -167,6 +179,7 @@ endif()
if(APPLE) if(APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -fvisibility=default") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -fvisibility=default")
set(CMAKE_SKIP_RPATH TRUE)
set_target_properties(obs-websocket PROPERTIES PREFIX "") set_target_properties(obs-websocket PROPERTIES PREFIX "")
target_link_libraries(obs-websocket "${OBS_FRONTEND_LIB}") target_link_libraries(obs-websocket "${OBS_FRONTEND_LIB}")
endif() endif()

View File

@ -4,20 +4,20 @@ environment:
install: install:
- git submodule update --init --recursive - git submodule update --init --recursive
- cd C:\projects\ - cd C:\projects\
- if not exist dependencies2013.zip curl -kLO https://obsproject.com/downloads/dependencies2013.zip -f --retry 5 -C - - if not exist dependencies2015.zip curl -kLO https://obsproject.com/downloads/dependencies2015.zip -f --retry 5 -C -
- 7z x dependencies2013.zip -odependencies2013 - 7z x dependencies2015.zip -odependencies2015
- set DepsPath32=%CD%\dependencies2013\win32 - set DepsPath32=%CD%\dependencies2015\win32
- set DepsPath64=%CD%\dependencies2013\win64 - set DepsPath64=%CD%\dependencies2015\win64
- call C:\projects\obs-websocket\CI\install-setup-qt.cmd - call C:\projects\obs-websocket\CI\install-setup-qt.cmd
- set build_config=Release - set build_config=RelWithDebInfo
- call C:\projects\obs-websocket\CI\install-build-obs.cmd - call C:\projects\obs-websocket\CI\install-build-obs.cmd
- cd C:\projects\obs-websocket\ - cd C:\projects\obs-websocket\
- mkdir build32 - mkdir build32
- mkdir build64 - mkdir build64
- cd ./build32 - cd ./build32
- cmake -G "Visual Studio 12 2013" -DQTDIR="%QTDIR32%" -DLibObs_DIR="C:\projects\obs-studio\build32\libobs" -DLIBOBS_INCLUDE_DIR="C:\projects\obs-studio\libobs" -DLIBOBS_LIB="C:\projects\obs-studio\build32\libobs\%build_config%\obs.lib" -DOBS_FRONTEND_LIB="C:\projects\obs-studio\build32\UI\obs-frontend-api\%build_config%\obs-frontend-api.lib" .. - cmake -G "Visual Studio 14 2015" -DQTDIR="%QTDIR32%" -DLibObs_DIR="C:\projects\obs-studio\build32\libobs" -DLIBOBS_INCLUDE_DIR="C:\projects\obs-studio\libobs" -DLIBOBS_LIB="C:\projects\obs-studio\build32\libobs\%build_config%\obs.lib" -DOBS_FRONTEND_LIB="C:\projects\obs-studio\build32\UI\obs-frontend-api\%build_config%\obs-frontend-api.lib" ..
- cd ../build64 - cd ../build64
- cmake -G "Visual Studio 12 2013 Win64" -DQTDIR="%QTDIR64%" -DLibObs_DIR="C:\projects\obs-studio\build64\libobs" -DLIBOBS_INCLUDE_DIR="C:\projects\obs-studio\libobs" -DLIBOBS_LIB="C:\projects\obs-studio\build64\libobs\%build_config%\obs.lib" -DOBS_FRONTEND_LIB="C:\projects\obs-studio\build64\UI\obs-frontend-api\%build_config%\obs-frontend-api.lib" .. - cmake -G "Visual Studio 14 2015 Win64" -DQTDIR="%QTDIR64%" -DLibObs_DIR="C:\projects\obs-studio\build64\libobs" -DLIBOBS_INCLUDE_DIR="C:\projects\obs-studio\libobs" -DLIBOBS_LIB="C:\projects\obs-studio\build64\libobs\%build_config%\obs.lib" -DOBS_FRONTEND_LIB="C:\projects\obs-studio\build64\UI\obs-frontend-api\%build_config%\obs-frontend-api.lib" ..
build_script: build_script:
- call msbuild /m /p:Configuration=%build_config% C:\projects\obs-websocket\build32\obs-websocket.sln /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" - call msbuild /m /p:Configuration=%build_config% C:\projects\obs-websocket\build32\obs-websocket.sln /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
@ -25,14 +25,16 @@ build_script:
before_deploy: before_deploy:
- 7z a "C:\projects\obs-websocket\build.zip" C:\projects\obs-websocket\release\* - 7z a "C:\projects\obs-websocket\build.zip" C:\projects\obs-websocket\release\*
- set PATH=%PATH%;"C:\\Program Files (x86)\\Inno Setup 5"
- iscc "C:\projects\obs-websocket\installer\installer.iss"
deploy_script: deploy_script:
- ps: Push-AppveyorArtifact "C:\projects\obs-websocket\build.zip" -FileName "obs-websocket-$(git log --pretty=format:'%h' -n 1).zip" - ps: Push-AppveyorArtifact "C:\projects\obs-websocket\build.zip" -FileName "obs-websocket-$(git log --pretty=format:'%h' -n 1)-Windows.zip"
- ps: Push-AppveyorArtifact "C:\projects\obs-websocket\installer\Output\obs-websocket-Windows-Installer.exe" -FileName "obs-websocket-$(git log --pretty=format:'%h' -n 1)-Windows-Installer.exe"
test: off test: off
cache: cache:
- C:\projects\dependencies2013.zip - C:\projects\dependencies2015.zip
- C:\projects\qt570.7z
- C:\projects\obs-studio-last-tag-built.txt - C:\projects\obs-studio-last-tag-built.txt
- C:\projects\obs-studio\ - C:\projects\obs-studio\

20
azure-pipelines.yml Normal file
View File

@ -0,0 +1,20 @@
pool:
vmImage: 'macOS-10.13'
steps:
- script: ./CI/install-dependencies-macos.sh
displayName: 'Install Dependencies'
- script: ./CI/install-build-obs-macos.sh
displayName: 'Build OBS'
- script: ./CI/build-macos.sh
displayName: 'Build obs-websocket'
- script: ./CI/package-macos.sh
displayName: 'Package'
- task: PublishBuildArtifacts@1
inputs:
pathtoPublish: './release'
artifactName: 'build'

1
deps/mbedtls vendored

Submodule deps/mbedtls deleted from 1a6a15c795

View File

@ -30,6 +30,14 @@ const processComments = comments => {
let errors = []; let errors = [];
comments.forEach(comment => { comments.forEach(comment => {
if (comment.typedef) {
comment.comment = undefined;
comment.context = undefined;
sorted['typedefs'] = sorted['typedefs'] || [];
sorted['typedefs'].push(comment);
return;
}
if (typeof comment.api === 'undefined') return; if (typeof comment.api === 'undefined') return;
let validationFailures = validateComment(comment); let validationFailures = validateComment(comment);
@ -84,9 +92,7 @@ const validateComment = comment => {
fullContext: Object.assign({}, comment) fullContext: Object.assign({}, comment)
}; };
} }
};
return;
}
const files = glob.sync(config.srcGlob); const files = glob.sync(config.srcGlob);
const comments = processComments(parseFiles(files)); const comments = processComments(parseFiles(files));

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +1,13 @@
<!-- This file was generated based on handlebars templates. Do not edit directly! --> <!-- This file was generated based on handlebars templates. Do not edit directly! -->
# obs-websocket 4.2.1 protocol reference # obs-websocket 4.5.0 protocol reference
**This is the reference for the unreleased obs-websocket 4.2.1. See the list below for older versions.**
- [4.2.0 protocol reference](https://github.com/Palakis/obs-websocket/blob/4.2.0/docs/generated/protocol.md)
- [4.1.0 protocol reference](https://github.com/Palakis/obs-websocket/blob/4.1.0/PROTOCOL.md)
- [4.0.0 protocol reference](https://github.com/Palakis/obs-websocket/blob/4.0.0/PROTOCOL.md)
# General Introduction # General Introduction
Messages are exchanged between the client and the server as JSON objects. Messages are exchanged between the client and the server as JSON objects.
This protocol is based on the original OBS Remote protocol created by Bill Hamilton, with new commands specific to OBS Studio. This protocol is based on the original OBS Remote protocol created by Bill Hamilton, with new commands specific to OBS Studio.
# Authentication # Authentication
OBSWebSocket uses SHA256 to transmit credentials. `obs-websocket` uses SHA256 to transmit credentials.
A request for [`GetAuthRequired`](#getauthrequired) returns two elements: A request for [`GetAuthRequired`](#getauthrequired) returns two elements:
- A `challenge`: a random string that will be used to generate the auth response. - A `challenge`: a random string that will be used to generate the auth response.
@ -48,6 +42,9 @@ auth_response = base64_encode(auth_response_hash)
<!-- toc --> <!-- toc -->
- [Typedefs](#typedefs)
* [Scene](#scene)
* [Source](#source)
- [Events](#events) - [Events](#events)
* [Scenes](#scenes) * [Scenes](#scenes)
+ [SwitchScenes](#switchscenes) + [SwitchScenes](#switchscenes)
@ -125,10 +122,13 @@ auth_response = base64_encode(auth_response_hash)
+ [SetSceneItemPosition](#setsceneitemposition) + [SetSceneItemPosition](#setsceneitemposition)
+ [SetSceneItemTransform](#setsceneitemtransform) + [SetSceneItemTransform](#setsceneitemtransform)
+ [SetSceneItemCrop](#setsceneitemcrop) + [SetSceneItemCrop](#setsceneitemcrop)
+ [DeleteSceneItem](#deletesceneitem)
+ [DuplicateSceneItem](#duplicatesceneitem)
* [Scenes](#scenes-1) * [Scenes](#scenes-1)
+ [SetCurrentScene](#setcurrentscene) + [SetCurrentScene](#setcurrentscene)
+ [GetCurrentScene](#getcurrentscene) + [GetCurrentScene](#getcurrentscene)
+ [GetSceneList](#getscenelist) + [GetSceneList](#getscenelist)
+ [ReorderSceneItems](#reordersceneitems)
* [Sources](#sources-1) * [Sources](#sources-1)
+ [GetSourcesList](#getsourceslist) + [GetSourcesList](#getsourceslist)
+ [GetSourcesTypesList](#getsourcestypeslist) + [GetSourcesTypesList](#getsourcestypeslist)
@ -143,9 +143,17 @@ auth_response = base64_encode(auth_response_hash)
+ [SetSourceSettings](#setsourcesettings) + [SetSourceSettings](#setsourcesettings)
+ [GetTextGDIPlusProperties](#gettextgdiplusproperties) + [GetTextGDIPlusProperties](#gettextgdiplusproperties)
+ [SetTextGDIPlusProperties](#settextgdiplusproperties) + [SetTextGDIPlusProperties](#settextgdiplusproperties)
+ [GetTextFreetype2Properties](#gettextfreetype2properties)
+ [SetTextFreetype2Properties](#settextfreetype2properties)
+ [GetBrowserSourceProperties](#getbrowsersourceproperties) + [GetBrowserSourceProperties](#getbrowsersourceproperties)
+ [SetBrowserSourceProperties](#setbrowsersourceproperties) + [SetBrowserSourceProperties](#setbrowsersourceproperties)
+ [GetSpecialSources](#getspecialsources) + [GetSpecialSources](#getspecialsources)
+ [GetSourceFilters](#getsourcefilters)
+ [AddFilterToSource](#addfiltertosource)
+ [RemoveFilterFromSource](#removefilterfromsource)
+ [ReorderSourceFilter](#reordersourcefilter)
+ [MoveSourceFilter](#movesourcefilter)
+ [SetSourceFilterSettings](#setsourcefiltersettings)
* [Streaming](#streaming-1) * [Streaming](#streaming-1)
+ [GetStreamingStatus](#getstreamingstatus) + [GetStreamingStatus](#getstreamingstatus)
+ [StartStopStreaming](#startstopstreaming) + [StartStopStreaming](#startstopstreaming)
@ -171,6 +179,31 @@ auth_response = base64_encode(auth_response_hash)
<!-- tocstop --> <!-- tocstop -->
# Typedefs
These are complex types, such as `Source` and `Scene`, which are used as arguments or return values in multiple requests and/or events.
## Scene
| Name | Type | Description |
| ---- | :---: | ------------|
| `name` | _String_ | Name of the currently active scene. |
| `sources` | _Array&lt;Source&gt;_ | Ordered list of the current scene's source items. |
## Source
| Name | Type | Description |
| ---- | :---: | ------------|
| `cy` | _Number_ | |
| `cx` | _Number_ | |
| `name` | _String_ | The name of this Scene Item. |
| `render` | _Boolean_ | Whether or not this Scene Item is set to "visible". |
| `source_cx` | _Number_ | |
| `source_cy` | _Number_ | |
| `type` | _String_ | Source type. Value is one of the following: "input", "filter", "transition", "scene" or "unknown" |
| `volume` | _Number_ | |
| `x` | _Number_ | |
| `y` | _Number_ | |
# Events # Events
Events are broadcast by the server to each connected client when a recognized action occurs within OBS. Events are broadcast by the server to each connected client when a recognized action occurs within OBS.
@ -198,7 +231,7 @@ Indicates a scene change.
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `scene-name` | _String_ | The new scene. | | `scene-name` | _String_ | The new scene. |
| `sources` | _Array_ | List of sources in the new scene. | | `sources` | _Array&lt;Source&gt;_ | List of sources in the new scene. Same specification as [`GetCurrentScene`](#getcurrentscene). |
--- ---
@ -304,6 +337,8 @@ A transition (other than "cut") has begun.
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `name` | _String_ | Transition name. | | `name` | _String_ | Transition name. |
| `duration` | _int_ | Transition duration (in milliseconds). | | `duration` | _int_ | Transition duration (in milliseconds). |
| `from-scene` | _String_ | Source scene of the transition |
| `to-scene` | _String_ | Destination scene of the transition |
--- ---
@ -508,7 +543,7 @@ _No additional response items._
- Added in v4.2.0 - Added in v4.2.0
A request to start the replay buffer has been issued. A request to stop the replay buffer has been issued.
**Response Items:** **Response Items:**
@ -557,7 +592,7 @@ Emitted every 2 seconds after enabling it by calling SetHeartbeat.
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `pulse` | _boolean_ | Toggles between every JSON meassage as an "I am alive" indicator. | | `pulse` | _boolean_ | Toggles between every JSON message as an "I am alive" indicator. |
| `current-profile` | _string (optional)_ | Current active profile. | | `current-profile` | _string (optional)_ | Current active profile. |
| `current-scene` | _string (optional)_ | Current active scene. | | `current-scene` | _string (optional)_ | Current active scene. |
| `streaming` | _boolean (optional)_ | Current streaming state. | | `streaming` | _boolean (optional)_ | Current streaming state. |
@ -656,7 +691,7 @@ The selected preview scene has changed (only available in Studio Mode).
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `scene-name` | _String_ | Name of the scene being previewed. | | `scene-name` | _String_ | Name of the scene being previewed. |
| `sources` | _Source\|Array_ | List of sources composing the scene. Same specification as [`GetCurrentScene`](#getcurrentscene). | | `sources` | _Array&lt;Source&gt;_ | List of sources composing the scene. Same specification as [`GetCurrentScene`](#getcurrentscene). |
--- ---
@ -878,7 +913,7 @@ _No specified parameters._
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `profiles` | _Object\|Array_ | List of available profiles. | | `profiles` | _Array&lt;Object&gt;_ | List of available profiles. |
--- ---
@ -1112,8 +1147,7 @@ _No specified parameters._
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `scene-collections` | _Object\|Array_ | Scene collections list | | `scene-collections` | _Array&lt;String&gt;_ | Scene collections list |
| `scene-collections.*.` | _String_ | |
--- ---
@ -1206,7 +1240,7 @@ Reset a scene item.
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `scene-name` | _String (optional)_ | Name of the scene the source belogns to. Defaults to the current scene. | | `scene-name` | _String (optional)_ | Name of the scene the source belongs to. Defaults to the current scene. |
| `item` | _String_ | Name of the source item. | | `item` | _String_ | Name of the source item. |
@ -1312,6 +1346,59 @@ Sets the crop coordinates of the specified source item.
_No additional response items._ _No additional response items._
---
### DeleteSceneItem
- Added in v4.5.0
Deletes a scene item.
**Request Fields:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `scene` | _String (optional)_ | Name of the scene the source belongs to. Defaults to the current scene. |
| `item` | _Object_ | item to delete (required) |
| `item.name` | _String_ | name of the scene item (prefer `id`, including both is acceptable). |
| `item.id` | _int_ | id of the scene item. |
**Response Items:**
_No additional response items._
---
### DuplicateSceneItem
- Added in v4.5.0
Duplicates a scene item.
**Request Fields:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `fromScene` | _String (optional)_ | Name of the scene to copy the item from. Defaults to the current scene. |
| `toScene` | _String (optional)_ | Name of the scene to create the item in. Defaults to the current scene. |
| `item` | _Object_ | item to duplicate (required) |
| `item.name` | _String_ | name of the scene item (prefer `id`, including both is acceptable). |
| `item.id` | _int_ | id of the scene item. |
**Response Items:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `scene` | _String_ | Name of the scene where the new item was created |
| `item` | _Object_ | New item info |
| `̀item.id` | _int_ | New item ID |
| `item.name` | _String_ | New item name |
--- ---
## Scenes ## Scenes
@ -1352,7 +1439,7 @@ _No specified parameters._
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `name` | _String_ | Name of the currently active scene. | | `name` | _String_ | Name of the currently active scene. |
| `sources` | _Source\|Array_ | Ordered list of the current scene's source items. | | `sources` | _Array&lt;Source&gt;_ | Ordered list of the current scene's source items. |
--- ---
@ -1373,9 +1460,32 @@ _No specified parameters._
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `current-scene` | _String_ | Name of the currently active scene. | | `current-scene` | _String_ | Name of the currently active scene. |
| `scenes` | _Scene\|Array_ | Ordered list of the current profile's scenes (See `[GetCurrentScene](#getcurrentscene)` for more information). | | `scenes` | _Array&lt;Scene&gt;_ | Ordered list of the current profile's scenes (See `[GetCurrentScene](#getcurrentscene)` for more information). |
---
### ReorderSceneItems
- Added in v4.5.0
Changes the order of scene items in the requested scene.
**Request Fields:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `scene` | _String (optional)_ | Name of the scene to reorder (defaults to current). |
| `items` | _Array&lt;Scene&gt;_ | Ordered list of objects with name and/or id specified. Id preferred due to uniqueness per scene |
| `items[].id` | _int (optional)_ | Id of a specific scene item. Unique on a scene by scene basis. |
| `items[].name` | _String (optional)_ | Name of a scene item. Sufficiently unique if no scene items share sources within the scene. |
**Response Items:**
_No additional response items._
--- ---
## Sources ## Sources
@ -1395,7 +1505,7 @@ _No specified parameters._
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `sources` | _Array of Objects_ | Array of sources as objects | | `sources` | _Array&lt;Object&gt;_ | Array of sources |
| `sources.*.name` | _String_ | Unique source name | | `sources.*.name` | _String_ | Unique source name |
| `sources.*.typeId` | _String_ | Non-unique source internal type (a.k.a type id) | | `sources.*.typeId` | _String_ | Non-unique source internal type (a.k.a type id) |
| `sources.*.type` | _String_ | Source type. Value is one of the following: "input", "filter", "transition", "scene" or "unknown" | | `sources.*.type` | _String_ | Source type. Value is one of the following: "input", "filter", "transition", "scene" or "unknown" |
@ -1418,7 +1528,7 @@ _No specified parameters._
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `ids` | _Array of Objects_ | Array of sources as objects | | `ids` | _Array&lt;Object&gt;_ | Array of source types |
| `ids.*.typeId` | _String_ | Non-unique internal source type ID | | `ids.*.typeId` | _String_ | Non-unique internal source type ID |
| `ids.*.displayName` | _String_ | Display name of the source type | | `ids.*.displayName` | _String_ | Display name of the source type |
| `ids.*.type` | _String_ | Type. Value is one of the following: "input", "filter", "transition" or "other" | | `ids.*.type` | _String_ | Type. Value is one of the following: "input", "filter", "transition" or "other" |
@ -1446,16 +1556,16 @@ Get the volume of the specified source.
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `source` | _String_ | Name of the source. | | `source` | _String_ | Source name. |
**Response Items:** **Response Items:**
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `name` | _String_ | Name of the source. | | `name` | _String_ | Source name. |
| `volume` | _double_ | Volume of the source. Between `0.0` and `1.0`. | | `volume` | _double_ | Volume of the source. Between `0.0` and `1.0`. |
| `mute` | _boolean_ | Indicates whether the source is muted. | | `muted` | _boolean_ | Indicates whether the source is muted. |
--- ---
@ -1471,7 +1581,7 @@ Set the volume of the specified source.
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `source` | _String_ | Name of the source. | | `source` | _String_ | Source name. |
| `volume` | _double_ | Desired volume. Must be between `0.0` and `1.0`. | | `volume` | _double_ | Desired volume. Must be between `0.0` and `1.0`. |
@ -1492,14 +1602,14 @@ Get the mute status of a specified source.
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `source` | _String_ | The name of the source. | | `source` | _String_ | Source name. |
**Response Items:** **Response Items:**
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `name` | _String_ | The name of the source. | | `name` | _String_ | Source name. |
| `muted` | _boolean_ | Mute status of the source. | | `muted` | _boolean_ | Mute status of the source. |
@ -1516,7 +1626,7 @@ Sets the mute status of a specified source.
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `source` | _String_ | The name of the source. | | `source` | _String_ | Source name. |
| `mute` | _boolean_ | Desired mute status. | | `mute` | _boolean_ | Desired mute status. |
@ -1537,7 +1647,7 @@ Inverts the mute status of a specified source.
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `source` | _String_ | The name of the source. | | `source` | _String_ | Source name. |
**Response Items:** **Response Items:**
@ -1557,7 +1667,7 @@ Set the audio sync offset of a specified source.
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `source` | _String_ | The name of the source. | | `source` | _String_ | Source name. |
| `offset` | _int_ | The desired audio sync offset (in nanoseconds). | | `offset` | _int_ | The desired audio sync offset (in nanoseconds). |
@ -1578,14 +1688,14 @@ Get the audio sync offset of a specified source.
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `source` | _String_ | The name of the source. | | `source` | _String_ | Source name. |
**Response Items:** **Response Items:**
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `name` | _String_ | The name of the source. | | `name` | _String_ | Source name. |
| `offset` | _int_ | The audio sync offset (in nanoseconds). | | `offset` | _int_ | The audio sync offset (in nanoseconds). |
@ -1602,7 +1712,7 @@ Get settings of the specified source
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `sourceName` | _String_ | Name of the source item. | | `sourceName` | _String_ | Source name. |
| `sourceType` | _String (optional)_ | Type of the specified source. Useful for type-checking if you expect a specific settings schema. | | `sourceType` | _String (optional)_ | Type of the specified source. Useful for type-checking if you expect a specific settings schema. |
@ -1612,7 +1722,7 @@ Get settings of the specified source
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `sourceName` | _String_ | Source name | | `sourceName` | _String_ | Source name |
| `sourceType` | _String_ | Type of the specified source | | `sourceType` | _String_ | Type of the specified source |
| `sourceSettings` | _Object_ | Source settings. Varying between source types. | | `sourceSettings` | _Object_ | Source settings (varies between source types, may require some probing around). |
--- ---
@ -1628,9 +1738,9 @@ Set settings of the specified source.
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `sourceName` | _String_ | Name of the source item. | | `sourceName` | _String_ | Source name. |
| `sourceType` | _String (optional)_ | Type of the specified source. Useful for type-checking to avoid settings a set of settings incompatible with the actual source's type. | | `sourceType` | _String (optional)_ | Type of the specified source. Useful for type-checking to avoid settings a set of settings incompatible with the actual source's type. |
| `sourceSettings` | _Object_ | Source settings. Varying between source types. | | `sourceSettings` | _Object_ | Source settings (varies between source types, may require some probing around). |
**Response Items:** **Response Items:**
@ -1639,7 +1749,7 @@ Set settings of the specified source.
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `sourceName` | _String_ | Source name | | `sourceName` | _String_ | Source name |
| `sourceType` | _String_ | Type of the specified source | | `sourceType` | _String_ | Type of the specified source |
| `sourceSettings` | _Object_ | Source settings. Varying between source types. | | `sourceSettings` | _Object_ | Updated source settings |
--- ---
@ -1655,14 +1765,14 @@ Get the current properties of a Text GDI Plus source.
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `scene-name` | _String (optional)_ | Name of the scene to retrieve. Defaults to the current scene. | | `source` | _String_ | Source name. |
| `source` | _String_ | Name of the source. |
**Response Items:** **Response Items:**
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `source` | _String_ | Source name. |
| `align` | _String_ | Text Alignment ("left", "center", "right"). | | `align` | _String_ | Text Alignment ("left", "center", "right"). |
| `bk-color` | _int_ | Background color. | | `bk-color` | _int_ | Background color. |
| `bk-opacity` | _int_ | Background opacity (0-100). | | `bk-opacity` | _int_ | Background opacity (0-100). |
@ -1690,7 +1800,6 @@ Get the current properties of a Text GDI Plus source.
| `text` | _String_ | Text content to be displayed. | | `text` | _String_ | Text content to be displayed. |
| `valign` | _String_ | Text vertical alignment ("top", "center", "bottom"). | | `valign` | _String_ | Text vertical alignment ("top", "center", "bottom"). |
| `vertical` | _boolean_ | Vertical text enabled. | | `vertical` | _boolean_ | Vertical text enabled. |
| `render` | _boolean_ | Visibility of the scene item. |
--- ---
@ -1700,13 +1809,12 @@ Get the current properties of a Text GDI Plus source.
- Added in v4.1.0 - Added in v4.1.0
Get the current properties of a Text GDI Plus source. Set the current properties of a Text GDI Plus source.
**Request Fields:** **Request Fields:**
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `scene-name` | _String (optional)_ | Name of the scene to retrieve. Defaults to the current scene. |
| `source` | _String_ | Name of the source. | | `source` | _String_ | Name of the source. |
| `align` | _String (optional)_ | Text Alignment ("left", "center", "right"). | | `align` | _String (optional)_ | Text Alignment ("left", "center", "right"). |
| `bk-color` | _int (optional)_ | Background color. | | `bk-color` | _int (optional)_ | Background color. |
@ -1738,6 +1846,79 @@ Get the current properties of a Text GDI Plus source.
| `render` | _boolean (optional)_ | Visibility of the scene item. | | `render` | _boolean (optional)_ | Visibility of the scene item. |
**Response Items:**
_No additional response items._
---
### GetTextFreetype2Properties
- Added in v4.5.0
Get the current properties of a Text Freetype 2 source.
**Request Fields:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `source` | _String_ | Source name. |
**Response Items:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `source` | _String_ | Source name |
| `color1` | _int_ | Gradient top color. |
| `color2` | _int_ | Gradient bottom color. |
| `custom_width` | _int_ | Custom width (0 to disable). |
| `drop_shadow` | _boolean_ | Drop shadow. |
| `font` | _Object_ | Holds data for the font. Ex: `"font": { "face": "Arial", "flags": 0, "size": 150, "style": "" }` |
| `font.face` | _String_ | Font face. |
| `font.flags` | _int_ | Font text styling flag. `Bold=1, Italic=2, Bold Italic=3, Underline=5, Strikeout=8` |
| `font.size` | _int_ | Font text size. |
| `font.style` | _String_ | Font Style (unknown function). |
| `from_file` | _boolean_ | Read text from the specified file. |
| `log_mode` | _boolean_ | Chat log. |
| `outline` | _boolean_ | Outline. |
| `text` | _String_ | Text content to be displayed. |
| `text_file` | _String_ | File path. |
| `word_wrap` | _boolean_ | Word wrap. |
---
### SetTextFreetype2Properties
- Added in v4.5.0
Set the current properties of a Text Freetype 2 source.
**Request Fields:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `source` | _String_ | Source name. |
| `color1` | _int (optional)_ | Gradient top color. |
| `color2` | _int (optional)_ | Gradient bottom color. |
| `custom_width` | _int (optional)_ | Custom width (0 to disable). |
| `drop_shadow` | _boolean (optional)_ | Drop shadow. |
| `font` | _Object (optional)_ | Holds data for the font. Ex: `"font": { "face": "Arial", "flags": 0, "size": 150, "style": "" }` |
| `font.face` | _String (optional)_ | Font face. |
| `font.flags` | _int (optional)_ | Font text styling flag. `Bold=1, Italic=2, Bold Italic=3, Underline=5, Strikeout=8` |
| `font.size` | _int (optional)_ | Font text size. |
| `font.style` | _String (optional)_ | Font Style (unknown function). |
| `from_file` | _boolean (optional)_ | Read text from the specified file. |
| `log_mode` | _boolean (optional)_ | Chat log. |
| `outline` | _boolean (optional)_ | Outline. |
| `text` | _String (optional)_ | Text content to be displayed. |
| `text_file` | _String (optional)_ | File path. |
| `word_wrap` | _boolean (optional)_ | Word wrap. |
**Response Items:** **Response Items:**
_No additional response items._ _No additional response items._
@ -1755,14 +1936,14 @@ Get current properties for a Browser Source.
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `scene-name` | _String (optional)_ | Name of the scene that the source belongs to. Defaults to the current scene. | | `source` | _String_ | Source name. |
| `source` | _String_ | Name of the source. |
**Response Items:** **Response Items:**
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `source` | _String_ | Source name. |
| `is_local_file` | _boolean_ | Indicates that a local file is in use. | | `is_local_file` | _boolean_ | Indicates that a local file is in use. |
| `local_file` | _String_ | file path. | | `local_file` | _String_ | file path. |
| `url` | _String_ | Url. | | `url` | _String_ | Url. |
@ -1771,7 +1952,6 @@ Get current properties for a Browser Source.
| `height` | _int_ | Height. | | `height` | _int_ | Height. |
| `fps` | _int_ | Framerate. | | `fps` | _int_ | Framerate. |
| `shutdown` | _boolean_ | Indicates whether the source should be shutdown when not visible. | | `shutdown` | _boolean_ | Indicates whether the source should be shutdown when not visible. |
| `render` | _boolean (optional)_ | Visibility of the scene item. |
--- ---
@ -1787,7 +1967,6 @@ Set current properties for a Browser Source.
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `scene-name` | _String (optional)_ | Name of the scene that the source belongs to. Defaults to the current scene. |
| `source` | _String_ | Name of the source. | | `source` | _String_ | Name of the source. |
| `is_local_file` | _boolean (optional)_ | Indicates that a local file is in use. | | `is_local_file` | _boolean (optional)_ | Indicates that a local file is in use. |
| `local_file` | _String (optional)_ | file path. | | `local_file` | _String (optional)_ | file path. |
@ -1828,6 +2007,142 @@ _No specified parameters._
| `mic-3` | _String (optional)_ | NAme of the third Mic/Aux input source. | | `mic-3` | _String (optional)_ | NAme of the third Mic/Aux input source. |
---
### GetSourceFilters
- Added in v4.5.0
List filters applied to a source
**Request Fields:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `sourceName` | _String_ | Source name |
**Response Items:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `filters` | _Array&lt;Object&gt;_ | List of filters for the specified source |
| `filters.*.type` | _String_ | Filter type |
| `filters.*.name` | _String_ | Filter name |
| `filters.*.settings` | _Object_ | Filter settings |
---
### AddFilterToSource
- Added in v4.5.0
Add a new filter to a source. Available source types along with their settings properties are available from `GetSourceTypesList`.
**Request Fields:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `sourceName` | _String_ | Name of the source on which the filter is added |
| `filterName` | _String_ | Name of the new filter |
| `filterType` | _String_ | Filter type |
| `filterSettings` | _Object_ | Filter settings |
**Response Items:**
_No additional response items._
---
### RemoveFilterFromSource
- Added in v4.5.0
Remove a filter from a source
**Request Fields:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `sourceName` | _String_ | Name of the source from which the specified filter is removed |
| `filterName` | _String_ | Name of the filter to remove |
**Response Items:**
_No additional response items._
---
### ReorderSourceFilter
- Added in v4.5.0
Move a filter in the chain (absolute index positioning)
**Request Fields:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `sourceName` | _String_ | Name of the source to which the filter belongs |
| `filterName` | _String_ | Name of the filter to reorder |
| `newIndex` | _Integer_ | Desired position of the filter in the chain |
**Response Items:**
_No additional response items._
---
### MoveSourceFilter
- Added in v4.5.0
Move a filter in the chain (relative positioning)
**Request Fields:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `sourceName` | _String_ | Name of the source to which the filter belongs |
| `filterName` | _String_ | Name of the filter to reorder |
| `movementType` | _String_ | How to move the filter around in the source's filter chain. Either "up", "down", "top" or "bottom". |
**Response Items:**
_No additional response items._
---
### SetSourceFilterSettings
- Added in v4.5.0
Update settings of a filter
**Request Fields:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `sourceName` | _String_ | Name of the source to which the filter belongs |
| `filterName` | _String_ | Name of the filter to reconfigure |
| `filterSettings` | _Object_ | New settings. These will be merged to the current filter settings. |
**Response Items:**
_No additional response items._
--- ---
## Streaming ## Streaming
@ -1966,7 +2281,7 @@ _No specified parameters._
| `settings` | _Object_ | Stream settings object. | | `settings` | _Object_ | Stream settings object. |
| `settings.server` | _String_ | The publish URL. | | `settings.server` | _String_ | The publish URL. |
| `settings.key` | _String_ | The publish key of the stream. | | `settings.key` | _String_ | The publish key of the stream. |
| `settings.use-auth` | _boolean_ | Indicates whether audentication should be used when connecting to the streaming server. | | `settings.use-auth` | _boolean_ | Indicates whether authentication should be used when connecting to the streaming server. |
| `settings.username` | _String_ | The username to use when accessing the streaming server. Only present if `use-auth` is `true`. | | `settings.username` | _String_ | The username to use when accessing the streaming server. Only present if `use-auth` is `true`. |
| `settings.password` | _String_ | The password to use when accessing the streaming server. Only present if `use-auth` is `true`. | | `settings.password` | _String_ | The password to use when accessing the streaming server. Only present if `use-auth` is `true`. |
@ -2029,7 +2344,7 @@ _No specified parameters._
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `name` | _String_ | The name of the active preview scene. | | `name` | _String_ | The name of the active preview scene. |
| `sources` | _Source\|Array_ | | | `sources` | _Array&lt;Source&gt;_ | |
--- ---
@ -2147,8 +2462,8 @@ _No specified parameters._
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `current-transition` | _String_ | Name of the currently active transition. | | `current-transition` | _String_ | Name of the currently active transition. |
| `transitions` | _Object\|Array_ | List of transitions. | | `transitions` | _Array&lt;Object&gt;_ | List of transitions. |
| `transitions[].name` | _String_ | Name of the transition. | | `transitions.*.name` | _String_ | Name of the transition. |
--- ---

View File

@ -1,17 +1,11 @@
# obs-websocket 4.2.1 protocol reference # obs-websocket 4.5.0 protocol reference
**This is the reference for the unreleased obs-websocket 4.2.1. See the list below for older versions.**
- [4.2.0 protocol reference](https://github.com/Palakis/obs-websocket/blob/4.2.0/docs/generated/protocol.md)
- [4.1.0 protocol reference](https://github.com/Palakis/obs-websocket/blob/4.1.0/PROTOCOL.md)
- [4.0.0 protocol reference](https://github.com/Palakis/obs-websocket/blob/4.0.0/PROTOCOL.md)
# General Introduction # General Introduction
Messages are exchanged between the client and the server as JSON objects. Messages are exchanged between the client and the server as JSON objects.
This protocol is based on the original OBS Remote protocol created by Bill Hamilton, with new commands specific to OBS Studio. This protocol is based on the original OBS Remote protocol created by Bill Hamilton, with new commands specific to OBS Studio.
# Authentication # Authentication
OBSWebSocket uses SHA256 to transmit credentials. `obs-websocket` uses SHA256 to transmit credentials.
A request for [`GetAuthRequired`](#getauthrequired) returns two elements: A request for [`GetAuthRequired`](#getauthrequired) returns two elements:
- A `challenge`: a random string that will be used to generate the auth response. - A `challenge`: a random string that will be used to generate the auth response.

View File

@ -0,0 +1,2 @@
# Typedefs
These are complex types, such as `Source` and `Scene`, which are used as arguments or return values in multiple requests and/or events.

View File

@ -7,6 +7,19 @@
{{#read "partials/typedefsHeader.md"}}{{/read}}
{{#each typedefs}}
## {{typedefs.0.name}}
| Name | Type | Description |
| ---- | :---: | ------------|
{{#each properties}}
| `{{name}}` | _{{depipe type}}_ | {{{depipe description}}} |
{{/each}}
{{/each}}
{{#read "partials/eventsHeader.md"}}{{/read}} {{#read "partials/eventsHeader.md"}}{{/read}}
{{#each events}} {{#each events}}

View File

@ -2,7 +2,7 @@
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "obs-websocket" #define MyAppName "obs-websocket"
#define MyAppVersion "4.3.1" #define MyAppVersion "4.5.1"
#define MyAppPublisher "Stephane Lepin" #define MyAppPublisher "Stephane Lepin"
#define MyAppURL "http://github.com/Palakis/obs-websocket" #define MyAppURL "http://github.com/Palakis/obs-websocket"
@ -20,7 +20,7 @@ AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL} AppUpdatesURL={#MyAppURL}
DefaultDirName={code:GetDirName} DefaultDirName={code:GetDirName}
DefaultGroupName={#MyAppName} DefaultGroupName={#MyAppName}
OutputBaseFilename=obs-websocket-{#MyAppVersion}-Windows-Installer OutputBaseFilename=obs-websocket-Windows-Installer
Compression=lzma Compression=lzma
SolidCompression=yes SolidCompression=yes
LicenseFile=..\LICENSE LicenseFile=..\LICENSE

View File

@ -16,11 +16,11 @@ You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/> with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#include <mbedtls/base64.h>
#include <mbedtls/sha256.h>
#include <obs-frontend-api.h> #include <obs-frontend-api.h>
#include <util/config-file.h> #include <util/config-file.h>
#include <string>
#include <QCryptographicHash>
#include <QTime>
#define SECTION_NAME "WebsocketAPI" #define SECTION_NAME "WebsocketAPI"
#define PARAM_ENABLE "ServerEnabled" #define PARAM_ENABLE "ServerEnabled"
@ -34,6 +34,8 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#include "Config.h" #include "Config.h"
#include "Utils.h" #include "Utils.h"
#define QT_TO_UTF8(str) str.toUtf8().constData()
Config* Config::_instance = new Config(); Config* Config::_instance = new Config();
Config::Config() : Config::Config() :
@ -46,6 +48,8 @@ Config::Config() :
Salt(""), Salt(""),
SettingsLoaded(false) SettingsLoaded(false)
{ {
qsrand(QTime::currentTime().msec());
// OBS Config defaults // OBS Config defaults
config_t* obsConfig = obs_frontend_get_global_config(); config_t* obsConfig = obs_frontend_get_global_config();
if (obsConfig) { if (obsConfig) {
@ -62,24 +66,20 @@ Config::Config() :
config_set_default_bool(obsConfig, config_set_default_bool(obsConfig,
SECTION_NAME, PARAM_AUTHREQUIRED, AuthRequired); SECTION_NAME, PARAM_AUTHREQUIRED, AuthRequired);
config_set_default_string(obsConfig, config_set_default_string(obsConfig,
SECTION_NAME, PARAM_SECRET, qstring_data_copy(Secret)); SECTION_NAME, PARAM_SECRET, QT_TO_UTF8(Secret));
config_set_default_string(obsConfig, config_set_default_string(obsConfig,
SECTION_NAME, PARAM_SALT, qstring_data_copy(Salt)); SECTION_NAME, PARAM_SALT, QT_TO_UTF8(Salt));
} }
mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_init(&rng);
mbedtls_ctr_drbg_seed(&rng, mbedtls_entropy_func, &entropy, nullptr, 0);
SessionChallenge = GenerateSalt(); SessionChallenge = GenerateSalt();
} }
Config::~Config() { Config::~Config()
mbedtls_ctr_drbg_free(&rng); {
mbedtls_entropy_free(&entropy);
} }
void Config::Load() { void Config::Load()
{
config_t* obsConfig = obs_frontend_get_global_config(); config_t* obsConfig = obs_frontend_get_global_config();
ServerEnabled = config_get_bool(obsConfig, SECTION_NAME, PARAM_ENABLE); ServerEnabled = config_get_bool(obsConfig, SECTION_NAME, PARAM_ENABLE);
@ -93,7 +93,8 @@ void Config::Load() {
Salt = config_get_string(obsConfig, SECTION_NAME, PARAM_SALT); Salt = config_get_string(obsConfig, SECTION_NAME, PARAM_SALT);
} }
void Config::Save() { void Config::Save()
{
config_t* obsConfig = obs_frontend_get_global_config(); config_t* obsConfig = obs_frontend_get_global_config();
config_set_bool(obsConfig, SECTION_NAME, PARAM_ENABLE, ServerEnabled); config_set_bool(obsConfig, SECTION_NAME, PARAM_ENABLE, ServerEnabled);
@ -104,53 +105,49 @@ void Config::Save() {
config_set_bool(obsConfig, SECTION_NAME, PARAM_AUTHREQUIRED, AuthRequired); config_set_bool(obsConfig, SECTION_NAME, PARAM_AUTHREQUIRED, AuthRequired);
config_set_string(obsConfig, SECTION_NAME, PARAM_SECRET, config_set_string(obsConfig, SECTION_NAME, PARAM_SECRET,
qstring_data_copy(Secret)); QT_TO_UTF8(Secret));
config_set_string(obsConfig, SECTION_NAME, PARAM_SALT, config_set_string(obsConfig, SECTION_NAME, PARAM_SALT,
qstring_data_copy(Salt)); QT_TO_UTF8(Salt));
config_save(obsConfig); config_save(obsConfig);
} }
QString Config::GenerateSalt() { QString Config::GenerateSalt()
{
// Generate 32 random chars // Generate 32 random chars
unsigned char* randomChars = (unsigned char*)bzalloc(32); const size_t randomCount = 32;
mbedtls_ctr_drbg_random(&rng, randomChars, 32); QByteArray randomChars;
for (size_t i = 0; i < randomCount; i++) {
randomChars.append((char)qrand());
}
// Convert the 32 random chars to a base64 string // Convert the 32 random chars to a base64 string
char* salt = (char*)bzalloc(64); QString salt = randomChars.toBase64();
size_t saltBytes;
mbedtls_base64_encode(
(unsigned char*)salt, 64, &saltBytes,
randomChars, 32);
bfree(randomChars);
return salt; return salt;
} }
QString Config::GenerateSecret(QString password, QString salt) { QString Config::GenerateSecret(QString password, QString salt)
{
// Concatenate the password and the salt // Concatenate the password and the salt
QString passAndSalt = ""; QString passAndSalt = "";
passAndSalt += password; passAndSalt += password;
passAndSalt += salt; passAndSalt += salt;
// Generate a SHA256 hash of the password // Generate a SHA256 hash of the password and salt
unsigned char* challengeHash = (unsigned char*)bzalloc(32); auto challengeHash = QCryptographicHash::hash(
mbedtls_sha256( passAndSalt.toUtf8(),
(unsigned char*)passAndSalt.toUtf8().constData(), passAndSalt.length(), QCryptographicHash::Algorithm::Sha256
challengeHash, 0); );
// Encode SHA256 hash to Base64 // Encode SHA256 hash to Base64
char* challenge = (char*)bzalloc(64); QString challenge = challengeHash.toBase64();
size_t challengeBytes = 0;
mbedtls_base64_encode(
(unsigned char*)challenge, 64, &challengeBytes,
challengeHash, 32);
bfree(challengeHash);
return challenge; return challenge;
} }
void Config::SetPassword(QString password) { void Config::SetPassword(QString password)
{
QString newSalt = GenerateSalt(); QString newSalt = GenerateSalt();
QString newChallenge = GenerateSecret(password, newSalt); QString newChallenge = GenerateSecret(password, newSalt);
@ -158,37 +155,32 @@ void Config::SetPassword(QString password) {
this->Secret = newChallenge; this->Secret = newChallenge;
} }
bool Config::CheckAuth(QString response) { bool Config::CheckAuth(QString response)
{
// Concatenate auth secret with the challenge sent to the user // Concatenate auth secret with the challenge sent to the user
QString challengeAndResponse = ""; QString challengeAndResponse = "";
challengeAndResponse += Secret; challengeAndResponse += Secret;
challengeAndResponse += SessionChallenge; challengeAndResponse += SessionChallenge;
// Generate a SHA256 hash of challengeAndResponse // Generate a SHA256 hash of challengeAndResponse
unsigned char* hash = (unsigned char*)bzalloc(32); auto hash = QCryptographicHash::hash(
mbedtls_sha256( challengeAndResponse.toUtf8(),
(unsigned char*)challengeAndResponse.toUtf8().constData(), QCryptographicHash::Algorithm::Sha256
challengeAndResponse.length(), );
hash, 0);
// Encode the SHA256 hash to Base64 // Encode the SHA256 hash to Base64
char* expectedResponse = (char*)bzalloc(64); QString expectedResponse = hash.toBase64();
size_t base64_size = 0;
mbedtls_base64_encode(
(unsigned char*)expectedResponse, 64, &base64_size,
hash, 32);
bool authSuccess = false; bool authSuccess = false;
if (response == QString(expectedResponse)) { if (response == expectedResponse) {
SessionChallenge = GenerateSalt(); SessionChallenge = GenerateSalt();
authSuccess = true; authSuccess = true;
} }
bfree(hash);
bfree(expectedResponse);
return authSuccess; return authSuccess;
} }
Config* Config::Current() { Config* Config::Current()
{
return _instance; return _instance;
} }

View File

@ -21,9 +21,6 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#include <QString> #include <QString>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
class Config { class Config {
public: public:
Config(); Config();
@ -53,8 +50,6 @@ class Config {
private: private:
static Config* _instance; static Config* _instance;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context rng;
}; };
#endif // CONFIG_H #endif // CONFIG_H

View File

@ -28,13 +28,6 @@ with this program. If not, see <https://www.gnu.org/licenses/>
Q_DECLARE_METATYPE(OBSScene); Q_DECLARE_METATYPE(OBSScene);
const char* qstring_data_copy(QString value) {
QByteArray stringData = value.toUtf8();
const char* constStringData = new const char[stringData.size()]();
memcpy((void*)constStringData, stringData.constData(), stringData.size());
return constStringData;
}
obs_data_array_t* Utils::StringListToArray(char** strings, char* key) { obs_data_array_t* Utils::StringListToArray(char** strings, char* key) {
if (!strings) if (!strings)
return obs_data_array_create(); return obs_data_array_create();
@ -110,6 +103,22 @@ obs_data_t* Utils::GetSceneItemData(obs_sceneitem_t* item) {
return data; return data;
} }
obs_sceneitem_t* Utils::GetSceneItemFromItem(obs_source_t* source, obs_data_t* item) {
OBSSceneItem sceneItem;
if (obs_data_has_user_value(item, "id")) {
sceneItem = GetSceneItemFromId(source, obs_data_get_int(item, "id"));
if (obs_data_has_user_value(item, "name") &&
(QString)obs_source_get_name(obs_sceneitem_get_source(sceneItem)) !=
(QString)obs_data_get_string(item, "name")) {
return nullptr;
}
}
else if (obs_data_has_user_value(item, "name")) {
sceneItem = GetSceneItemFromName(source, obs_data_get_string(item, "name"));
}
return sceneItem;
}
obs_sceneitem_t* Utils::GetSceneItemFromName(obs_source_t* source, QString name) { obs_sceneitem_t* Utils::GetSceneItemFromName(obs_source_t* source, QString name) {
struct current_search { struct current_search {
QString query; QString query;
@ -146,6 +155,39 @@ obs_sceneitem_t* Utils::GetSceneItemFromName(obs_source_t* source, QString name)
return search.result; return search.result;
} }
obs_sceneitem_t* Utils::GetSceneItemFromId(obs_source_t* source, size_t id) {
struct current_search {
size_t query;
obs_sceneitem_t* result;
};
current_search search;
search.query = id;
search.result = nullptr;
OBSScene scene = obs_scene_from_source(source);
if (!scene)
return nullptr;
obs_scene_enum_items(scene, [](
obs_scene_t* scene,
obs_sceneitem_t* currentItem,
void* param)
{
current_search* search = static_cast<current_search*>(param);
if (obs_sceneitem_get_id(currentItem) == search->query) {
search->result = currentItem;
obs_sceneitem_addref(search->result);
return false;
}
return true;
}, &search);
return search.result;
}
bool Utils::IsValidAlignment(const uint32_t alignment) { bool Utils::IsValidAlignment(const uint32_t alignment) {
switch (alignment) { switch (alignment) {
case OBS_ALIGN_CENTER: case OBS_ALIGN_CENTER:
@ -315,13 +357,19 @@ QString Utils::OBSVersionString() {
QSystemTrayIcon* Utils::GetTrayIcon() { QSystemTrayIcon* Utils::GetTrayIcon() {
QMainWindow* main = (QMainWindow*)obs_frontend_get_main_window(); QMainWindow* main = (QMainWindow*)obs_frontend_get_main_window();
if (!main) return nullptr;
return main->findChildren<QSystemTrayIcon*>().first(); return main->findChildren<QSystemTrayIcon*>().first();
} }
void Utils::SysTrayNotify(QString &text, void Utils::SysTrayNotify(QString &text,
QSystemTrayIcon::MessageIcon icon, QString title) { QSystemTrayIcon::MessageIcon icon, QString title) {
if (!Config::Current()->AlertsEnabled || !QSystemTrayIcon::supportsMessages()) if (!Config::Current()->AlertsEnabled ||
!QSystemTrayIcon::isSystemTrayAvailable() ||
!QSystemTrayIcon::supportsMessages())
{
return; return;
}
QSystemTrayIcon* trayIcon = GetTrayIcon(); QSystemTrayIcon* trayIcon = GetTrayIcon();
if (trayIcon) if (trayIcon)

View File

@ -32,8 +32,6 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#include <obs-module.h> #include <obs-module.h>
#include <util/config-file.h> #include <util/config-file.h>
const char* qstring_data_copy(QString value);
class Utils { class Utils {
public: public:
static obs_data_array_t* StringListToArray(char** strings, char* key); static obs_data_array_t* StringListToArray(char** strings, char* key);
@ -41,6 +39,8 @@ class Utils {
static obs_data_t* GetSceneItemData(obs_sceneitem_t* item); static obs_data_t* GetSceneItemData(obs_sceneitem_t* item);
static obs_sceneitem_t* GetSceneItemFromName( static obs_sceneitem_t* GetSceneItemFromName(
obs_source_t* source, QString name); obs_source_t* source, QString name);
static obs_sceneitem_t* GetSceneItemFromId(obs_source_t* source, size_t id);
static obs_sceneitem_t* GetSceneItemFromItem(obs_source_t* source, obs_data_t* item);
static obs_source_t* GetTransitionFromName(QString transitionName); static obs_source_t* GetTransitionFromName(QString transitionName);
static obs_source_t* GetSceneFromNameOrCurrent(QString sceneName); static obs_source_t* GetSceneFromNameOrCurrent(QString sceneName);
@ -49,8 +49,6 @@ class Utils {
static obs_data_array_t* GetScenes(); static obs_data_array_t* GetScenes();
static obs_data_t* GetSceneData(obs_source_t* source); static obs_data_t* GetSceneData(obs_source_t* source);
static obs_data_array_t* GetProfiles();
static QSpinBox* GetTransitionDurationControl(); static QSpinBox* GetTransitionDurationControl();
static int GetTransitionDuration(); static int GetTransitionDuration();
static void SetTransitionDuration(int ms); static void SetTransitionDuration(int ms);

View File

@ -80,12 +80,7 @@ WSEvents::WSEvents(WSServer* srv) {
this, SLOT(Heartbeat())); this, SLOT(Heartbeat()));
statusTimer->start(2000); // equal to frontend's constant BITRATE_UPDATE_SECONDS statusTimer->start(2000); // equal to frontend's constant BITRATE_UPDATE_SECONDS
QListWidget* sceneList = Utils::GetSceneListControl();
connect(sceneList, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
this, SLOT(SelectedSceneChanged(QListWidgetItem*, QListWidgetItem*)));
currentScene = nullptr; currentScene = nullptr;
currentTransition = nullptr;
QTimer::singleShot(1000, this, SLOT(deferredInitOperations())); QTimer::singleShot(1000, this, SLOT(deferredInitOperations()));
@ -103,8 +98,7 @@ WSEvents::~WSEvents() {
} }
void WSEvents::deferredInitOperations() { void WSEvents::deferredInitOperations() {
OBSSourceAutoRelease transition = obs_frontend_get_current_transition(); hookTransitionBeginEvent();
connectTransitionSignals(transition);
OBSSourceAutoRelease scene = obs_frontend_get_current_scene(); OBSSourceAutoRelease scene = obs_frontend_get_current_scene();
connectSceneSignals(scene); connectSceneSignals(scene);
@ -123,6 +117,7 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void* private
owner->OnSceneListChange(); owner->OnSceneListChange();
} }
else if (event == OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED) { else if (event == OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED) {
owner->hookTransitionBeginEvent();
owner->OnSceneCollectionChange(); owner->OnSceneCollectionChange();
} }
else if (event == OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED) { else if (event == OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED) {
@ -132,6 +127,7 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void* private
owner->OnTransitionChange(); owner->OnTransitionChange();
} }
else if (event == OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED) { else if (event == OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED) {
owner->hookTransitionBeginEvent();
owner->OnTransitionListChange(); owner->OnTransitionListChange();
} }
else if (event == OBS_FRONTEND_EVENT_PROFILE_CHANGED) { else if (event == OBS_FRONTEND_EVENT_PROFILE_CHANGED) {
@ -186,9 +182,11 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void* private
else if (event == OBS_FRONTEND_EVENT_STUDIO_MODE_DISABLED) { else if (event == OBS_FRONTEND_EVENT_STUDIO_MODE_DISABLED) {
owner->OnStudioModeSwitched(false); owner->OnStudioModeSwitched(false);
} }
else if (event == OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED) {
owner->OnPreviewSceneChanged();
}
else if (event == OBS_FRONTEND_EVENT_EXIT) { else if (event == OBS_FRONTEND_EVENT_EXIT) {
owner->connectSceneSignals(nullptr); owner->connectSceneSignals(nullptr);
owner->connectTransitionSignals(nullptr);
owner->OnExit(); owner->OnExit();
} }
} }
@ -222,29 +220,18 @@ void WSEvents::broadcastUpdate(const char* updateType,
blog(LOG_DEBUG, "Update << '%s'", json.toUtf8().constData()); blog(LOG_DEBUG, "Update << '%s'", json.toUtf8().constData());
} }
void WSEvents::connectTransitionSignals(obs_source_t* transition) { void WSEvents::hookTransitionBeginEvent() {
signal_handler_t* sh = nullptr; obs_frontend_source_list transitions = {};
obs_frontend_get_transitions(&transitions);
if (currentTransition) { for (int i = 0; i < transitions.sources.num; i++) {
sh = obs_source_get_signal_handler(currentTransition); obs_source_t* transition = transitions.sources.array[i];
signal_handler_disconnect(sh, signal_handler_t* sh = obs_source_get_signal_handler(transition);
"transition_start", OnTransitionBegin, this); signal_handler_disconnect(sh, "transition_start", OnTransitionBegin, this);
signal_handler_connect(sh, "transition_start", OnTransitionBegin, this);
} }
currentTransition = transition; obs_frontend_source_list_free(&transitions);
if (currentTransition) {
if (!transitionIsCut(transition)) {
currentTransition = transition;
sh = obs_source_get_signal_handler(currentTransition);
signal_handler_connect(sh,
"transition_start", OnTransitionBegin, this);
}
else {
currentTransition = nullptr;
}
}
} }
void WSEvents::connectSceneSignals(obs_source_t* scene) { void WSEvents::connectSceneSignals(obs_source_t* scene) {
@ -305,7 +292,7 @@ const char* WSEvents::GetRecordingTimecode() {
* Indicates a scene change. * Indicates a scene change.
* *
* @return {String} `scene-name` The new scene. * @return {String} `scene-name` The new scene.
* @return {Array} `sources` List of sources in the new scene. * @return {Array<Source>} `sources` List of sources in the new scene. Same specification as [`GetCurrentScene`](#getcurrentscene).
* *
* @api events * @api events
* @name SwitchScenes * @name SwitchScenes
@ -322,13 +309,6 @@ void WSEvents::OnSceneChange() {
obs_data_set_array(data, "sources", sceneItems); obs_data_set_array(data, "sources", sceneItems);
broadcastUpdate("SwitchScenes", data); broadcastUpdate("SwitchScenes", data);
// Dirty fix : OBS blocks signals when swapping scenes in Studio Mode
// after transition end, so SelectedSceneChanged is never called...
if (obs_frontend_preview_program_mode_active()) {
QListWidget* list = Utils::GetSceneListControl();
SelectedSceneChanged(list->currentItem(), nullptr);
}
} }
/** /**
@ -356,7 +336,6 @@ void WSEvents::OnSceneCollectionChange() {
broadcastUpdate("SceneCollectionChanged"); broadcastUpdate("SceneCollectionChanged");
currentScene = nullptr; currentScene = nullptr;
currentTransition = nullptr;
OnTransitionListChange(); OnTransitionListChange();
OnTransitionChange(); OnTransitionChange();
@ -389,7 +368,6 @@ void WSEvents::OnSceneCollectionListChange() {
*/ */
void WSEvents::OnTransitionChange() { void WSEvents::OnTransitionChange() {
OBSSourceAutoRelease currentTransition = obs_frontend_get_current_transition(); OBSSourceAutoRelease currentTransition = obs_frontend_get_current_transition();
connectTransitionSignals(currentTransition);
OBSDataAutoRelease data = obs_data_create(); OBSDataAutoRelease data = obs_data_create();
obs_data_set_string(data, "transition-name", obs_data_set_string(data, "transition-name",
@ -571,7 +549,7 @@ void WSEvents::OnReplayStarted() {
} }
/** /**
* A request to start the replay buffer has been issued. * A request to stop the replay buffer has been issued.
* *
* @api events * @api events
* @name ReplayStopping * @name ReplayStopping
@ -679,7 +657,7 @@ void WSEvents::StreamStatus() {
/** /**
* Emitted every 2 seconds after enabling it by calling SetHeartbeat. * Emitted every 2 seconds after enabling it by calling SetHeartbeat.
* *
* @return {boolean} `pulse` Toggles between every JSON meassage as an "I am alive" indicator. * @return {boolean} `pulse` Toggles between every JSON message as an "I am alive" indicator.
* @return {string (optional)} `current-profile` Current active profile. * @return {string (optional)} `current-profile` Current active profile.
* @return {string (optional)} `current-scene` Current active scene. * @return {string (optional)} `current-scene` Current active scene.
* @return {boolean (optional)} `streaming` Current streaming state. * @return {boolean (optional)} `streaming` Current streaming state.
@ -755,6 +733,8 @@ void WSEvents::TransitionDurationChanged(int ms) {
* *
* @return {String} `name` Transition name. * @return {String} `name` Transition name.
* @return {int} `duration` Transition duration (in milliseconds). * @return {int} `duration` Transition duration (in milliseconds).
* @return {String} `from-scene` Source scene of the transition
* @return {String} `to-scene` Destination scene of the transition
* *
* @api events * @api events
* @name TransitionBegin * @name TransitionBegin
@ -762,14 +742,39 @@ void WSEvents::TransitionDurationChanged(int ms) {
* @since 4.0.0 * @since 4.0.0
*/ */
void WSEvents::OnTransitionBegin(void* param, calldata_t* data) { void WSEvents::OnTransitionBegin(void* param, calldata_t* data) {
UNUSED_PARAMETER(data);
WSEvents* instance = static_cast<WSEvents*>(param); WSEvents* instance = static_cast<WSEvents*>(param);
OBSSourceAutoRelease currentTransition = obs_frontend_get_current_transition(); OBSSource transition = (obs_source_t*)calldata_get_ptr(data, "source");
if (!transition) return;
// Detect if transition is the global transition or a transition override.
// Fetching the duration is different depending on the case.
OBSSourceAutoRelease sourceScene = obs_transition_get_source(transition, OBS_TRANSITION_SOURCE_A);
OBSSourceAutoRelease destinationScene = obs_transition_get_active_source(transition);
OBSDataAutoRelease destinationSettings = obs_source_get_private_settings(destinationScene);
int duration = -1;
if (obs_data_has_default_value(destinationSettings, "transition_duration") ||
obs_data_has_user_value(destinationSettings, "transition_duration"))
{
duration = obs_data_get_int(destinationSettings, "transition_duration");
} else {
duration = Utils::GetTransitionDuration();
}
OBSDataAutoRelease fields = obs_data_create(); OBSDataAutoRelease fields = obs_data_create();
obs_data_set_string(fields, "name", obs_source_get_name(currentTransition)); obs_data_set_string(fields, "name", obs_source_get_name(transition));
obs_data_set_int(fields, "duration", Utils::GetTransitionDuration()); if (duration >= 0) {
obs_data_set_int(fields, "duration", duration);
} else {
blog(LOG_WARNING, "OnTransitionBegin: duration is negative !");
}
if (sourceScene) {
obs_data_set_string(fields, "from-scene", obs_source_get_name(sourceScene));
}
if (destinationScene) {
obs_data_set_string(fields, "to-scene", obs_source_get_name(destinationScene));
}
instance->broadcastUpdate("TransitionBegin", fields); instance->broadcastUpdate("TransitionBegin", fields);
} }
@ -902,24 +907,23 @@ void WSEvents::OnSceneItemVisibilityChanged(void* param, calldata_t* data) {
* The selected preview scene has changed (only available in Studio Mode). * The selected preview scene has changed (only available in Studio Mode).
* *
* @return {String} `scene-name` Name of the scene being previewed. * @return {String} `scene-name` Name of the scene being previewed.
* @return {Source|Array} `sources` List of sources composing the scene. Same specification as [`GetCurrentScene`](#getcurrentscene). * @return {Array<Source>} `sources` List of sources composing the scene. Same specification as [`GetCurrentScene`](#getcurrentscene).
* *
* @api events * @api events
* @name PreviewSceneChanged * @name PreviewSceneChanged
* @category studio mode * @category studio mode
* @since 4.1.0 * @since 4.1.0
*/ */
void WSEvents::SelectedSceneChanged(QListWidgetItem* current, QListWidgetItem* prev) { void WSEvents::OnPreviewSceneChanged() {
if (obs_frontend_preview_program_mode_active()) { if (obs_frontend_preview_program_mode_active()) {
OBSScene scene = Utils::SceneListItemToScene(current); OBSSourceAutoRelease scene = obs_frontend_get_current_preview_scene();
if (!scene) if (!scene)
return; return;
OBSSource sceneSource = obs_scene_get_source(scene); OBSDataArrayAutoRelease sceneItems = Utils::GetSceneItems(scene);
OBSDataArrayAutoRelease sceneItems = Utils::GetSceneItems(sceneSource);
OBSDataAutoRelease data = obs_data_create(); OBSDataAutoRelease data = obs_data_create();
obs_data_set_string(data, "scene-name", obs_source_get_name(sceneSource)); obs_data_set_string(data, "scene-name", obs_source_get_name(scene));
obs_data_set_array(data, "sources", sceneItems); obs_data_set_array(data, "sources", sceneItems);
broadcastUpdate("PreviewSceneChanged", data); broadcastUpdate("PreviewSceneChanged", data);

View File

@ -33,9 +33,10 @@ class WSEvents : public QObject {
static void FrontendEventHandler( static void FrontendEventHandler(
enum obs_frontend_event event, void* privateData); enum obs_frontend_event event, void* privateData);
static WSEvents* Instance; static WSEvents* Instance;
void connectTransitionSignals(obs_source_t* transition);
void connectSceneSignals(obs_source_t* scene); void connectSceneSignals(obs_source_t* scene);
void hookTransitionBeginEvent();
uint64_t GetStreamingTime(); uint64_t GetStreamingTime();
const char* GetStreamingTimecode(); const char* GetStreamingTimecode();
uint64_t GetRecordingTime(); uint64_t GetRecordingTime();
@ -48,13 +49,10 @@ class WSEvents : public QObject {
void StreamStatus(); void StreamStatus();
void Heartbeat(); void Heartbeat();
void TransitionDurationChanged(int ms); void TransitionDurationChanged(int ms);
void SelectedSceneChanged(
QListWidgetItem* current, QListWidgetItem* prev);
private: private:
WSServer* _srv; WSServer* _srv;
OBSSource currentScene; OBSSource currentScene;
OBSSource currentTransition;
bool pulse; bool pulse;
@ -97,6 +95,7 @@ class WSEvents : public QObject {
void OnReplayStopped(); void OnReplayStopped();
void OnStudioModeSwitched(bool enabled); void OnStudioModeSwitched(bool enabled);
void OnPreviewSceneChanged();
void OnExit(); void OnExit();

View File

@ -46,6 +46,9 @@ QHash<QString, void(*)(WSRequestHandler*)> WSRequestHandler::messageMap {
{ "GetSceneItemProperties", WSRequestHandler::HandleGetSceneItemProperties }, { "GetSceneItemProperties", WSRequestHandler::HandleGetSceneItemProperties },
{ "SetSceneItemProperties", WSRequestHandler::HandleSetSceneItemProperties }, { "SetSceneItemProperties", WSRequestHandler::HandleSetSceneItemProperties },
{ "ResetSceneItem", WSRequestHandler::HandleResetSceneItem }, { "ResetSceneItem", WSRequestHandler::HandleResetSceneItem },
{ "DeleteSceneItem", WSRequestHandler::HandleDeleteSceneItem },
{ "DuplicateSceneItem", WSRequestHandler::HandleDuplicateSceneItem },
{ "ReorderSceneItems", WSRequestHandler::HandleReorderSceneItems },
{ "GetStreamingStatus", WSRequestHandler::HandleGetStreamingStatus }, { "GetStreamingStatus", WSRequestHandler::HandleGetStreamingStatus },
{ "StartStopStreaming", WSRequestHandler::HandleStartStopStreaming }, { "StartStopStreaming", WSRequestHandler::HandleStartStopStreaming },
@ -82,6 +85,13 @@ QHash<QString, void(*)(WSRequestHandler*)> WSRequestHandler::messageMap {
{ "GetSourceSettings", WSRequestHandler::HandleGetSourceSettings }, { "GetSourceSettings", WSRequestHandler::HandleGetSourceSettings },
{ "SetSourceSettings", WSRequestHandler::HandleSetSourceSettings }, { "SetSourceSettings", WSRequestHandler::HandleSetSourceSettings },
{ "GetSourceFilters", WSRequestHandler::HandleGetSourceFilters },
{ "AddFilterToSource", WSRequestHandler::HandleAddFilterToSource },
{ "RemoveFilterFromSource", WSRequestHandler::HandleRemoveFilterFromSource },
{ "ReorderSourceFilter", WSRequestHandler::HandleReorderSourceFilter },
{ "MoveSourceFilter", WSRequestHandler::HandleMoveSourceFilter },
{ "SetSourceFilterSettings", WSRequestHandler::HandleSetSourceFilterSettings },
{ "SetCurrentSceneCollection", WSRequestHandler::HandleSetCurrentSceneCollection }, { "SetCurrentSceneCollection", WSRequestHandler::HandleSetCurrentSceneCollection },
{ "GetCurrentSceneCollection", WSRequestHandler::HandleGetCurrentSceneCollection }, { "GetCurrentSceneCollection", WSRequestHandler::HandleGetCurrentSceneCollection },
{ "ListSceneCollections", WSRequestHandler::HandleListSceneCollections }, { "ListSceneCollections", WSRequestHandler::HandleListSceneCollections },
@ -105,6 +115,9 @@ QHash<QString, void(*)(WSRequestHandler*)> WSRequestHandler::messageMap {
{ "SetTextGDIPlusProperties", WSRequestHandler::HandleSetTextGDIPlusProperties }, { "SetTextGDIPlusProperties", WSRequestHandler::HandleSetTextGDIPlusProperties },
{ "GetTextGDIPlusProperties", WSRequestHandler::HandleGetTextGDIPlusProperties }, { "GetTextGDIPlusProperties", WSRequestHandler::HandleGetTextGDIPlusProperties },
{ "SetTextFreetype2Properties", WSRequestHandler::HandleSetTextFreetype2Properties },
{ "GetTextFreetype2Properties", WSRequestHandler::HandleGetTextFreetype2Properties },
{ "GetBrowserSourceProperties", WSRequestHandler::HandleGetBrowserSourceProperties }, { "GetBrowserSourceProperties", WSRequestHandler::HandleGetBrowserSourceProperties },
{ "SetBrowserSourceProperties", WSRequestHandler::HandleSetBrowserSourceProperties } { "SetBrowserSourceProperties", WSRequestHandler::HandleSetBrowserSourceProperties }
}; };

View File

@ -73,6 +73,9 @@ class WSRequestHandler : public QObject {
static void HandleGetSceneItemProperties(WSRequestHandler* req); static void HandleGetSceneItemProperties(WSRequestHandler* req);
static void HandleSetSceneItemProperties(WSRequestHandler* req); static void HandleSetSceneItemProperties(WSRequestHandler* req);
static void HandleResetSceneItem(WSRequestHandler* req); static void HandleResetSceneItem(WSRequestHandler* req);
static void HandleDuplicateSceneItem(WSRequestHandler* req);
static void HandleDeleteSceneItem(WSRequestHandler* req);
static void HandleReorderSceneItems(WSRequestHandler* req);
static void HandleGetStreamingStatus(WSRequestHandler* req); static void HandleGetStreamingStatus(WSRequestHandler* req);
static void HandleStartStopStreaming(WSRequestHandler* req); static void HandleStartStopStreaming(WSRequestHandler* req);
@ -107,6 +110,13 @@ class WSRequestHandler : public QObject {
static void HandleGetSourceSettings(WSRequestHandler* req); static void HandleGetSourceSettings(WSRequestHandler* req);
static void HandleSetSourceSettings(WSRequestHandler* req); static void HandleSetSourceSettings(WSRequestHandler* req);
static void HandleGetSourceFilters(WSRequestHandler* req);
static void HandleAddFilterToSource(WSRequestHandler* req);
static void HandleRemoveFilterFromSource(WSRequestHandler* req);
static void HandleReorderSourceFilter(WSRequestHandler* req);
static void HandleMoveSourceFilter(WSRequestHandler* req);
static void HandleSetSourceFilterSettings(WSRequestHandler* req);
static void HandleSetCurrentSceneCollection(WSRequestHandler* req); static void HandleSetCurrentSceneCollection(WSRequestHandler* req);
static void HandleGetCurrentSceneCollection(WSRequestHandler* req); static void HandleGetCurrentSceneCollection(WSRequestHandler* req);
static void HandleListSceneCollections(WSRequestHandler* req); static void HandleListSceneCollections(WSRequestHandler* req);
@ -132,6 +142,10 @@ class WSRequestHandler : public QObject {
static void HandleSetTextGDIPlusProperties(WSRequestHandler* req); static void HandleSetTextGDIPlusProperties(WSRequestHandler* req);
static void HandleGetTextGDIPlusProperties(WSRequestHandler* req); static void HandleGetTextGDIPlusProperties(WSRequestHandler* req);
static void HandleSetTextFreetype2Properties(WSRequestHandler* req);
static void HandleGetTextFreetype2Properties(WSRequestHandler* req);
static void HandleSetBrowserSourceProperties(WSRequestHandler* req); static void HandleSetBrowserSourceProperties(WSRequestHandler* req);
static void HandleGetBrowserSourceProperties(WSRequestHandler* req); static void HandleGetBrowserSourceProperties(WSRequestHandler* req);
}; };

View File

@ -50,7 +50,7 @@ void WSRequestHandler::HandleGetCurrentProfile(WSRequestHandler* req) {
/** /**
* Get a list of available profiles. * Get a list of available profiles.
* *
* @return {Object|Array} `profiles` List of available profiles. * @return {Array<Object>} `profiles` List of available profiles.
* *
* @api requests * @api requests
* @name ListProfiles * @name ListProfiles

View File

@ -50,8 +50,7 @@ void WSRequestHandler::HandleGetCurrentSceneCollection(WSRequestHandler* req) {
/** /**
* List available scene collections * List available scene collections
* *
* @return {Object|Array} `scene-collections` Scene collections list * @return {Array<String>} `scene-collections` Scene collections list
* @return {String} `scene-collections.*.`
* *
* @api requests * @api requests
* @name ListSceneCollections * @name ListSceneCollections

View File

@ -322,7 +322,7 @@ void WSRequestHandler::HandleSetSceneItemProperties(WSRequestHandler* req) {
/** /**
* Reset a scene item. * Reset a scene item.
* *
* @param {String (optional)} `scene-name` Name of the scene the source belogns to. Defaults to the current scene. * @param {String (optional)} `scene-name` Name of the scene the source belongs to. Defaults to the current scene.
* @param {String} `item` Name of the source item. * @param {String} `item` Name of the source item.
* *
* @api requests * @api requests
@ -566,3 +566,124 @@ void WSRequestHandler::HandleSetSceneItemCrop(WSRequestHandler* req) {
req->SendErrorResponse("specified scene item doesn't exist"); req->SendErrorResponse("specified scene item doesn't exist");
} }
} }
/**
* Deletes a scene item.
*
* @param {String (optional)} `scene` Name of the scene the source belongs to. Defaults to the current scene.
* @param {Object} `item` item to delete (required)
* @param {String} `item.name` name of the scene item (prefer `id`, including both is acceptable).
* @param {int} `item.id` id of the scene item.
*
* @api requests
* @name DeleteSceneItem
* @category scene items
* @since 4.5.0
*/
void WSRequestHandler::HandleDeleteSceneItem(WSRequestHandler* req) {
if (!req->hasField("item")) {
req->SendErrorResponse("missing request parameters");
return;
}
const char* sceneName = obs_data_get_string(req->data, "scene");
OBSSourceAutoRelease scene = Utils::GetSceneFromNameOrCurrent(sceneName);
if (!scene) {
req->SendErrorResponse("requested scene doesn't exist");
return;
}
OBSDataAutoRelease item = obs_data_get_obj(req->data, "item");
OBSSceneItemAutoRelease sceneItem = Utils::GetSceneItemFromItem(scene, item);
if (!sceneItem) {
req->SendErrorResponse("item with id/name combination not found in specified scene");
return;
}
obs_sceneitem_remove(sceneItem);
req->SendOKResponse();
}
struct DuplicateSceneItemData {
obs_sceneitem_t *referenceItem;
obs_source_t *fromSource;
obs_sceneitem_t *newItem;
};
static void DuplicateSceneItem(void *_data, obs_scene_t *scene) {
DuplicateSceneItemData *data = (DuplicateSceneItemData *)_data;
data->newItem = obs_scene_add(scene, data->fromSource);
obs_sceneitem_set_visible(data->newItem, obs_sceneitem_visible(data->referenceItem));
}
/**
* Duplicates a scene item.
*
* @param {String (optional)} `fromScene` Name of the scene to copy the item from. Defaults to the current scene.
* @param {String (optional)} `toScene` Name of the scene to create the item in. Defaults to the current scene.
* @param {Object} `item` item to duplicate (required)
* @param {String} `item.name` name of the scene item (prefer `id`, including both is acceptable).
* @param {int} `item.id` id of the scene item.
*
* @return {String} `scene` Name of the scene where the new item was created
* @return {Object} `item` New item info
* @return {int} `̀item.id` New item ID
* @return {String} `item.name` New item name
*
* @api requests
* @name DuplicateSceneItem
* @category scene items
* @since 4.5.0
*/
void WSRequestHandler::HandleDuplicateSceneItem(WSRequestHandler* req) {
if (!req->hasField("item")) {
req->SendErrorResponse("missing request parameters");
return;
}
const char* fromSceneName = obs_data_get_string(req->data, "fromScene");
OBSSourceAutoRelease fromScene = Utils::GetSceneFromNameOrCurrent(fromSceneName);
if (!fromScene) {
req->SendErrorResponse("requested fromScene doesn't exist");
return;
}
const char* toSceneName = obs_data_get_string(req->data, "toScene");
OBSSourceAutoRelease toScene = Utils::GetSceneFromNameOrCurrent(toSceneName);
if (!toScene) {
req->SendErrorResponse("requested toScene doesn't exist");
return;
}
OBSDataAutoRelease item = obs_data_get_obj(req->data, "item");
OBSSceneItemAutoRelease referenceItem = Utils::GetSceneItemFromItem(fromScene, item);
if (!referenceItem) {
req->SendErrorResponse("item with id/name combination not found in specified scene");
return;
}
DuplicateSceneItemData data;
data.fromSource = obs_sceneitem_get_source(referenceItem);
data.referenceItem = referenceItem;
obs_enter_graphics();
obs_scene_atomic_update(obs_scene_from_source(toScene), DuplicateSceneItem, &data);
obs_leave_graphics();
obs_sceneitem_t *newItem = data.newItem;
if (!newItem) {
req->SendErrorResponse("Error duplicating scene item");
return;
}
OBSDataAutoRelease itemData = obs_data_create();
obs_data_set_int(itemData, "id", obs_sceneitem_get_id(newItem));
obs_data_set_string(itemData, "name", obs_source_get_name(obs_sceneitem_get_source(newItem)));
OBSDataAutoRelease responseData = obs_data_create();
obs_data_set_obj(responseData, "item", itemData);
obs_data_set_string(responseData, "scene", obs_source_get_name(toScene));
req->SendOKResponse(responseData);
}

View File

@ -3,6 +3,12 @@
#include "WSRequestHandler.h" #include "WSRequestHandler.h"
/**
* @typedef {Object} `Scene`
* @property {String} `name` Name of the currently active scene.
* @property {Array<Source>} `sources` Ordered list of the current scene's source items.
*/
/** /**
* Switch to the specified scene. * Switch to the specified scene.
* *
@ -34,7 +40,7 @@
* Get the current scene's name and source items. * Get the current scene's name and source items.
* *
* @return {String} `name` Name of the currently active scene. * @return {String} `name` Name of the currently active scene.
* @return {Source|Array} `sources` Ordered list of the current scene's source items. * @return {Array<Source>} `sources` Ordered list of the current scene's source items.
* *
* @api requests * @api requests
* @name GetCurrentScene * @name GetCurrentScene
@ -56,7 +62,7 @@ void WSRequestHandler::HandleGetCurrentScene(WSRequestHandler* req) {
* Get a list of scenes in the currently active profile. * Get a list of scenes in the currently active profile.
* *
* @return {String} `current-scene` Name of the currently active scene. * @return {String} `current-scene` Name of the currently active scene.
* @return {Scene|Array} `scenes` Ordered list of the current profile's scenes (See `[GetCurrentScene](#getcurrentscene)` for more information). * @return {Array<Scene>} `scenes` Ordered list of the current profile's scenes (See `[GetCurrentScene](#getcurrentscene)` for more information).
* *
* @api requests * @api requests
* @name GetSceneList * @name GetSceneList
@ -74,3 +80,69 @@ void WSRequestHandler::HandleGetSceneList(WSRequestHandler* req) {
req->SendOKResponse(data); req->SendOKResponse(data);
} }
/**
* Changes the order of scene items in the requested scene.
*
* @param {String (optional)} `scene` Name of the scene to reorder (defaults to current).
* @param {Array<Scene>} `items` Ordered list of objects with name and/or id specified. Id preferred due to uniqueness per scene
* @param {int (optional)} `items[].id` Id of a specific scene item. Unique on a scene by scene basis.
* @param {String (optional)} `items[].name` Name of a scene item. Sufficiently unique if no scene items share sources within the scene.
*
* @api requests
* @name ReorderSceneItems
* @category scenes
* @since 4.5.0
*/
void WSRequestHandler::HandleReorderSceneItems(WSRequestHandler* req) {
QString sceneName = obs_data_get_string(req->data, "scene");
OBSSourceAutoRelease scene = Utils::GetSceneFromNameOrCurrent(sceneName);
if (!scene) {
req->SendErrorResponse("requested scene doesn't exist");
return;
}
OBSDataArrayAutoRelease items = obs_data_get_array(req->data, "items");
if (!items) {
req->SendErrorResponse("sceneItem order not specified");
return;
}
size_t count = obs_data_array_count(items);
std::vector<obs_sceneitem_t*> newOrder;
newOrder.reserve(count);
for (size_t i = 0; i < count; ++i) {
OBSDataAutoRelease item = obs_data_array_item(items, i);
OBSSceneItemAutoRelease sceneItem = Utils::GetSceneItemFromItem(scene, item);
obs_sceneitem_release(sceneItem); // ref dec
if (!sceneItem) {
req->SendErrorResponse("Invalid sceneItem id or name specified");
return;
}
for (size_t j = 0; j <= i; ++j) {
if (sceneItem == newOrder[j]) {
req->SendErrorResponse("Duplicate sceneItem in specified order");
return;
}
}
newOrder.push_back(sceneItem);
}
bool success = obs_scene_reorder_items(obs_scene_from_source(scene), newOrder.data(), count);
if (!success) {
req->SendErrorResponse("Invalid sceneItem order");
return;
}
for (auto const& item: newOrder) {
obs_sceneitem_release(item);
}
req->SendOKResponse();
}

File diff suppressed because it is too large Load Diff

View File

@ -252,7 +252,7 @@ void WSRequestHandler::HandleStopStreaming(WSRequestHandler* req) {
* @return {Object} `settings` Stream settings object. * @return {Object} `settings` Stream settings object.
* @return {String} `settings.server` The publish URL. * @return {String} `settings.server` The publish URL.
* @return {String} `settings.key` The publish key of the stream. * @return {String} `settings.key` The publish key of the stream.
* @return {boolean} `settings.use-auth` Indicates whether audentication should be used when connecting to the streaming server. * @return {boolean} `settings.use-auth` Indicates whether authentication should be used when connecting to the streaming server.
* @return {String} `settings.username` The username to use when accessing the streaming server. Only present if `use-auth` is `true`. * @return {String} `settings.username` The username to use when accessing the streaming server. Only present if `use-auth` is `true`.
* @return {String} `settings.password` The password to use when accessing the streaming server. Only present if `use-auth` is `true`. * @return {String} `settings.password` The password to use when accessing the streaming server. Only present if `use-auth` is `true`.
* *

View File

@ -27,7 +27,7 @@
* Will return an `error` if Studio Mode is not enabled. * Will return an `error` if Studio Mode is not enabled.
* *
* @return {String} `name` The name of the active preview scene. * @return {String} `name` The name of the active preview scene.
* @return {Source|Array} `sources` * @return {Array<Source>} `sources`
* *
* @api requests * @api requests
* @name GetPreviewScene * @name GetPreviewScene

View File

@ -7,8 +7,8 @@
* List of all transitions available in the frontend's dropdown menu. * List of all transitions available in the frontend's dropdown menu.
* *
* @return {String} `current-transition` Name of the currently active transition. * @return {String} `current-transition` Name of the currently active transition.
* @return {Object|Array} `transitions` List of transitions. * @return {Array<Object>} `transitions` List of transitions.
* @return {String} `transitions[].name` Name of the transition. * @return {String} `transitions.*.name` Name of the transition.
* *
* @api requests * @api requests
* @name GetTransitionList * @name GetTransitionList

View File

@ -22,7 +22,6 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#include "../Config.h" #include "../Config.h"
#include "../WSServer.h" #include "../WSServer.h"
#include "settings-dialog.h" #include "settings-dialog.h"
#include "ui_settings-dialog.h"
#define CHANGE_ME "changeme" #define CHANGE_ME "changeme"

View File

@ -21,9 +21,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#include <QDialog> #include <QDialog>
namespace Ui { #include "ui_settings-dialog.h"
class SettingsDialog;
}
class SettingsDialog : public QDialog class SettingsDialog : public QDialog
{ {

View File

@ -39,7 +39,7 @@ using OBSOutputAutoRelease =
OBSRef<obs_output_t*, ___output_dummy_addref, obs_output_release>; OBSRef<obs_output_t*, ___output_dummy_addref, obs_output_release>;
#define PROP_AUTHENTICATED "wsclient_authenticated" #define PROP_AUTHENTICATED "wsclient_authenticated"
#define OBS_WEBSOCKET_VERSION "4.3.1" #define OBS_WEBSOCKET_VERSION "4.5.1"
#define blog(level, msg, ...) blog(level, "[obs-websocket] " msg, ##__VA_ARGS__) #define blog(level, msg, ...) blog(level, "[obs-websocket] " msg, ##__VA_ARGS__)