Compare commits

...

112 Commits
4.3.0 ... 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
beadb56b05 general: update version to 4.3.1 2018-01-22 23:13:27 +01:00
745fb5ea29 Merge branch 'scenecol-crash-fix' 2018-01-22 23:11:24 +01:00
58434cac3b events: fix crash on exit 2018-01-22 23:10:33 +01:00
c34dff17ff events: fix crash when switching between scene collections 2018-01-22 23:03:20 +01:00
52 changed files with 5210 additions and 3006 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:
- 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:
- provider: s3
region: eu-central-1
@ -55,15 +47,3 @@ deploy:
- "$TRAVIS_OS_NAME = linux"
- "-d /home/travis/package"
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
## 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
In cmake-gui, you'll have to set the following variables :
@ -22,17 +25,31 @@ sudo make install
```
## 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.
Of course, you're encouraged to dig through the contents of these scripts to look for issues or specificities.
As a prerequisite, you will need Xcode for your current OSX version, the command line tools, and [Homebrew](https://brew.sh/).
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
cd obs-websocket
./CI/install-dependencies-macos.sh
./CI/install-build-obs-macos.sh
./CI/build-macos.sh
./CI/package-macos.sh
```
This will result in a ready-to-use `obs-websocket.pkg` installer in the `release` subfolder.
## 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)
- 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)
- 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: [![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
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)"
mkdir build && cd build
echo "[obs-websocket] Building 'obs-websocket' for macOS."
mkdir -p build && cd build
cmake .. \
-DQTDIR=/usr/local/opt/qt \
-DLIBOBS_INCLUDE_DIR=../../obs-studio/libobs \
-DLIBOBS_LIB=../../obs-studio/libobs \
-DOBS_FRONTEND_LIB="$(pwd)/../../obs-studio/build/UI/obs-frontend-api/libobs-frontend-api.dylib" \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_INSTALL_PREFIX=/usr \
&& make -j4

View File

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

View File

@ -15,7 +15,7 @@ if git diff --quiet; then
exit 0
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."
exit 0
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.
if not exist C:\projects\obs-studio (
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\
git describe --tags --abbrev=0 > C:\projects\obs-studio-latest-tag.txt
set /p OBSLatestTag=<C:\projects\obs-studio-latest-tag.txt
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
echo:
echo Latest tag pre-pull: %OBSLatestTagPrePull%
@ -97,12 +108,12 @@ if defined BuildOBS (
mkdir build64
echo Running cmake for obs-studio %OBSLatestTag% 32-bit...
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 Running cmake for obs-studio %OBSLatestTag% 64-bit...
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 Building obs-studio %OBSLatestTag% 32-bit ^(Build Config: %build_config%^)...

View File

@ -1,32 +1,61 @@
#!/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
brew update
brew install ffmpeg
brew install libav
echo "[obs-websocket] Updating Homebrew.."
brew update >/dev/null
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
# qt latest
#brew install qt5
echo "[obs-websocket] Installing obs-websocket dependency 'QT 5.10.1'.."
# =!= NOTICE =!=
# When building QT5 from sources on macOS 10.13+, use local qt5 formula:
# brew install ./CI/macos/qt.rb
# Pouring from the bottle is much quicker though, so use bottle for now.
# =!= NOTICE =!=
# qt 5.9.2
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/2b121c9a96e58a5da14228630cb71d5bead7137e/Formula/qt.rb
brew install https://gist.githubusercontent.com/DDRBoxman/b3956fab6073335a4bf151db0dcbd4ad/raw/ed1342a8a86793ea8c10d8b4d712a654da121ace/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
cd ..
git clone --recursive https://github.com/jp9000/obs-studio
cd obs-studio
git checkout 20.1.0
mkdir build && cd build
cmake .. \
-DCMAKE_PREFIX_PATH=/usr/local/opt/qt/lib/cmake \
&& make -j4
# Fetch and install Packages app
# =!= NOTICE =!=
# Installs a LaunchDaemon under /Library/LaunchDaemons/fr.whitebox.packages.build.dispatcher.plist
# =!= NOTICE =!=
# Packages app
cd ..
curl -L -O http://s.sudre.free.fr/Software/files/Packages.dmg -f --retry 5 -C -
hdiutil attach ./Packages.dmg
sudo installer -pkg /Volumes/Packages\ 1.2.2/packages/Packages.pkg -target /
HAS_PACKAGES=$(type packagesbuild 2>/dev/null)
if [ "${HAS_PACKAGES}" = "" ]; then
echo "[obs-websocket] Installing Packaging app (might require password due to 'sudo').."
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
set -ex
# OBS Studio deps
add-apt-repository -y ppa:obsproject/obs-studio
apt-get -qq update
apt-get install -y \
libc-dev-bin libc6-dev \
git \
build-essential
apt-get install -y \
libc-dev-bin \
libc6-dev git \
build-essential \
checkinstall \
cmake \
libasound2-dev \
libavcodec-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-studio \
libqt5websockets5-dev
# obs-websocket deps
apt-get install -y libqt5websockets5-dev
# 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
# Dirty hack
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
ldconfig

View File

@ -1,20 +1,6 @@
@echo off
REM Set default values to use AppVeyor's built-in Qt.
set QTDIR32=C:\Qt\5.7\msvc2013
set QTDIR64=C:\Qt\5.7\msvc2013_64
set QTCompileVersion=5.7.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
)
set QTDIR32=C:\Qt\5.10.1\msvc2015
set QTDIR64=C:\Qt\5.10.1\msvc2015_64
set QTCompileVersion=5.10.1

View File

@ -635,7 +635,7 @@
<key>OVERWRITE_PERMISSIONS</key>
<false/>
<key>VERSION</key>
<string>4.3.0</string>
<string>4.5.1</string>
</dict>
<key>PROJECT_COMMENTS</key>
<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
echo "-- Preparing package build"
export QT_CELLAR_PREFIX="$(find /usr/local/Cellar/qt -d 1 | tail -n 1)"
OSTYPE=$(uname)
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 NET_LIB="/usr/local/opt/qt/lib/QtNetwork.framework/QtNetwork"
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 LATEST_VERSION="$TRAVIS_BRANCH"
if [ -n "${TRAVIS_TAG}" ]; then
export VERSION="$TRAVIS_TAG"
export LATEST_VERSION="$TRAVIS_TAG"
fi
export VERSION="$GIT_HASH-$GIT_BRANCH_OR_TAG"
export LATEST_VERSION="$GIT_BRANCH_OR_TAG"
export FILENAME="obs-websocket-$VERSION.pkg"
export LATEST_FILENAME="obs-websocket-latest-$LATEST_VERSION.pkg"
echo "-- Copying Qt dependencies"
cp $WS_LIB ./build
cp $NET_LIB ./build
echo "[obs-websocket] Copying Qt dependencies"
if [ ! -f ./build/$(basename $WS_LIB) ]; then cp $WS_LIB ./build; fi
if [ ! -f ./build/$(basename $NET_LIB) ]; then cp $NET_LIB ./build; fi
chmod +rw ./build/QtWebSockets ./build/QtNetwork
echo "-- Modifying QtNetwork"
echo "[obs-websocket] Modifying QtNetwork"
install_name_tool \
-id @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 \
./build/QtNetwork
echo "-- Modifying QtWebSockets"
echo "[obs-websocket] Modifying QtWebSockets"
install_name_tool \
-id @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/QtCore.framework/Versions/5/QtCore @rpath/QtCore \
./build/QtWebSockets
echo "-- Modifying obs-websocket.so"
echo "[obs-websocket] Modifying obs-websocket.so"
install_name_tool \
-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 \
@ -49,18 +55,18 @@ install_name_tool \
./build/obs-websocket.so
# Check if replacement worked
echo "-- Dependencies for QtNetwork"
echo "[obs-websocket] Dependencies for QtNetwork"
otool -L ./build/QtNetwork
echo "-- Dependencies for QtWebSockets"
echo "[obs-websocket] Dependencies for QtWebSockets"
otool -L ./build/QtWebSockets
echo "-- Dependencies for obs-websocket"
echo "[obs-websocket] Dependencies for obs-websocket"
otool -L ./build/obs-websocket.so
chmod -w ./build/QtWebSockets ./build/QtNetwork
echo "-- Actual package build"
echo "[obs-websocket] Actual package build"
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
cp ./release/$FILENAME ./release/$LATEST_FILENAME

View File

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

View File

@ -4,20 +4,20 @@ environment:
install:
- git submodule update --init --recursive
- cd C:\projects\
- if not exist dependencies2013.zip curl -kLO https://obsproject.com/downloads/dependencies2013.zip -f --retry 5 -C -
- 7z x dependencies2013.zip -odependencies2013
- set DepsPath32=%CD%\dependencies2013\win32
- set DepsPath64=%CD%\dependencies2013\win64
- if not exist dependencies2015.zip curl -kLO https://obsproject.com/downloads/dependencies2015.zip -f --retry 5 -C -
- 7z x dependencies2015.zip -odependencies2015
- set DepsPath32=%CD%\dependencies2015\win32
- set DepsPath64=%CD%\dependencies2015\win64
- 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
- cd C:\projects\obs-websocket\
- mkdir build32
- mkdir build64
- 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
- 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:
- 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:
- 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:
- 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
cache:
- C:\projects\dependencies2013.zip
- C:\projects\qt570.7z
- C:\projects\dependencies2015.zip
- C:\projects\obs-studio-last-tag-built.txt
- 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 = [];
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;
let validationFailures = validateComment(comment);
@ -84,9 +92,7 @@ const validateComment = comment => {
fullContext: Object.assign({}, comment)
};
}
return;
}
};
const files = glob.sync(config.srcGlob);
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! -->
# obs-websocket 4.2.1 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)
# obs-websocket 4.5.0 protocol reference
# General Introduction
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.
# Authentication
OBSWebSocket uses SHA256 to transmit credentials.
`obs-websocket` uses SHA256 to transmit credentials.
A request for [`GetAuthRequired`](#getauthrequired) returns two elements:
- 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 -->
- [Typedefs](#typedefs)
* [Scene](#scene)
* [Source](#source)
- [Events](#events)
* [Scenes](#scenes)
+ [SwitchScenes](#switchscenes)
@ -125,10 +122,13 @@ auth_response = base64_encode(auth_response_hash)
+ [SetSceneItemPosition](#setsceneitemposition)
+ [SetSceneItemTransform](#setsceneitemtransform)
+ [SetSceneItemCrop](#setsceneitemcrop)
+ [DeleteSceneItem](#deletesceneitem)
+ [DuplicateSceneItem](#duplicatesceneitem)
* [Scenes](#scenes-1)
+ [SetCurrentScene](#setcurrentscene)
+ [GetCurrentScene](#getcurrentscene)
+ [GetSceneList](#getscenelist)
+ [ReorderSceneItems](#reordersceneitems)
* [Sources](#sources-1)
+ [GetSourcesList](#getsourceslist)
+ [GetSourcesTypesList](#getsourcestypeslist)
@ -143,9 +143,17 @@ auth_response = base64_encode(auth_response_hash)
+ [SetSourceSettings](#setsourcesettings)
+ [GetTextGDIPlusProperties](#gettextgdiplusproperties)
+ [SetTextGDIPlusProperties](#settextgdiplusproperties)
+ [GetTextFreetype2Properties](#gettextfreetype2properties)
+ [SetTextFreetype2Properties](#settextfreetype2properties)
+ [GetBrowserSourceProperties](#getbrowsersourceproperties)
+ [SetBrowserSourceProperties](#setbrowsersourceproperties)
+ [GetSpecialSources](#getspecialsources)
+ [GetSourceFilters](#getsourcefilters)
+ [AddFilterToSource](#addfiltertosource)
+ [RemoveFilterFromSource](#removefilterfromsource)
+ [ReorderSourceFilter](#reordersourcefilter)
+ [MoveSourceFilter](#movesourcefilter)
+ [SetSourceFilterSettings](#setsourcefiltersettings)
* [Streaming](#streaming-1)
+ [GetStreamingStatus](#getstreamingstatus)
+ [StartStopStreaming](#startstopstreaming)
@ -171,6 +179,31 @@ auth_response = base64_encode(auth_response_hash)
<!-- 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 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 |
| ---- | :---: | ------------|
| `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. |
| `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
A request to start the replay buffer has been issued.
A request to stop the replay buffer has been issued.
**Response Items:**
@ -557,7 +592,7 @@ Emitted every 2 seconds after enabling it by calling SetHeartbeat.
| 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-scene` | _string (optional)_ | Current active scene. |
| `streaming` | _boolean (optional)_ | Current streaming state. |
@ -656,7 +691,7 @@ The selected preview scene has changed (only available in Studio Mode).
| Name | Type | Description |
| ---- | :---: | ------------|
| `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 |
| ---- | :---: | ------------|
| `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 |
| ---- | :---: | ------------|
| `scene-collections` | _Object\|Array_ | Scene collections list |
| `scene-collections.*.` | _String_ | |
| `scene-collections` | _Array&lt;String&gt;_ | Scene collections list |
---
@ -1206,7 +1240,7 @@ Reset a scene item.
| 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. |
@ -1312,6 +1346,59 @@ Sets the crop coordinates of the specified source item.
_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
@ -1352,7 +1439,7 @@ _No specified parameters._
| Name | Type | Description |
| ---- | :---: | ------------|
| `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 |
| ---- | :---: | ------------|
| `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
@ -1395,7 +1505,7 @@ _No specified parameters._
| 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.*.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" |
@ -1418,7 +1528,7 @@ _No specified parameters._
| 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.*.displayName` | _String_ | Display name of the source type |
| `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 |
| ---- | :---: | ------------|
| `source` | _String_ | Name of the source. |
| `source` | _String_ | Source name. |
**Response Items:**
| 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`. |
| `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 |
| ---- | :---: | ------------|
| `source` | _String_ | Name of the source. |
| `source` | _String_ | Source name. |
| `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 |
| ---- | :---: | ------------|
| `source` | _String_ | The name of the source. |
| `source` | _String_ | Source name. |
**Response Items:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `name` | _String_ | The name of the source. |
| `name` | _String_ | Source name. |
| `muted` | _boolean_ | Mute status of the source. |
@ -1516,7 +1626,7 @@ Sets the mute status of a specified source.
| Name | Type | Description |
| ---- | :---: | ------------|
| `source` | _String_ | The name of the source. |
| `source` | _String_ | Source name. |
| `mute` | _boolean_ | Desired mute status. |
@ -1537,7 +1647,7 @@ Inverts the mute status of a specified source.
| Name | Type | Description |
| ---- | :---: | ------------|
| `source` | _String_ | The name of the source. |
| `source` | _String_ | Source name. |
**Response Items:**
@ -1557,7 +1667,7 @@ Set the audio sync offset of a specified source.
| Name | Type | Description |
| ---- | :---: | ------------|
| `source` | _String_ | The name of the source. |
| `source` | _String_ | Source name. |
| `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 |
| ---- | :---: | ------------|
| `source` | _String_ | The name of the source. |
| `source` | _String_ | Source name. |
**Response Items:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `name` | _String_ | The name of the source. |
| `name` | _String_ | Source name. |
| `offset` | _int_ | The audio sync offset (in nanoseconds). |
@ -1602,7 +1712,7 @@ Get settings of the specified source
| 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. |
@ -1612,7 +1722,7 @@ Get settings of the specified source
| ---- | :---: | ------------|
| `sourceName` | _String_ | Source name |
| `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 |
| ---- | :---: | ------------|
| `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. |
| `sourceSettings` | _Object_ | Source settings. Varying between source types. |
| `sourceSettings` | _Object_ | Source settings (varies between source types, may require some probing around). |
**Response Items:**
@ -1639,7 +1749,7 @@ Set settings of the specified source.
| ---- | :---: | ------------|
| `sourceName` | _String_ | Source name |
| `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 |
| ---- | :---: | ------------|
| `scene-name` | _String (optional)_ | Name of the scene to retrieve. Defaults to the current scene. |
| `source` | _String_ | Name of the source. |
| `source` | _String_ | Source name. |
**Response Items:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `source` | _String_ | Source name. |
| `align` | _String_ | Text Alignment ("left", "center", "right"). |
| `bk-color` | _int_ | Background color. |
| `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. |
| `valign` | _String_ | Text vertical alignment ("top", "center", "bottom"). |
| `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
Get the current properties of a Text GDI Plus source.
Set the current properties of a Text GDI Plus source.
**Request Fields:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `scene-name` | _String (optional)_ | Name of the scene to retrieve. Defaults to the current scene. |
| `source` | _String_ | Name of the source. |
| `align` | _String (optional)_ | Text Alignment ("left", "center", "right"). |
| `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. |
**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:**
_No additional response items._
@ -1755,14 +1936,14 @@ Get current properties for a Browser Source.
| 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_ | Source name. |
**Response Items:**
| Name | Type | Description |
| ---- | :---: | ------------|
| `source` | _String_ | Source name. |
| `is_local_file` | _boolean_ | Indicates that a local file is in use. |
| `local_file` | _String_ | file path. |
| `url` | _String_ | Url. |
@ -1771,7 +1952,6 @@ Get current properties for a Browser Source.
| `height` | _int_ | Height. |
| `fps` | _int_ | Framerate. |
| `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 |
| ---- | :---: | ------------|
| `scene-name` | _String (optional)_ | Name of the scene that the source belongs to. Defaults to the current scene. |
| `source` | _String_ | Name of the source. |
| `is_local_file` | _boolean (optional)_ | Indicates that a local file is in use. |
| `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. |
---
### 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
@ -1966,7 +2281,7 @@ _No specified parameters._
| `settings` | _Object_ | Stream settings object. |
| `settings.server` | _String_ | The publish URL. |
| `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.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` | _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 |
| ---- | :---: | ------------|
| `current-transition` | _String_ | Name of the currently active transition. |
| `transitions` | _Object\|Array_ | List of transitions. |
| `transitions[].name` | _String_ | Name of the transition. |
| `transitions` | _Array&lt;Object&gt;_ | List of transitions. |
| `transitions.*.name` | _String_ | Name of the transition. |
---

View File

@ -1,17 +1,11 @@
# obs-websocket 4.2.1 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)
# obs-websocket 4.5.0 protocol reference
# General Introduction
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.
# Authentication
OBSWebSocket uses SHA256 to transmit credentials.
`obs-websocket` uses SHA256 to transmit credentials.
A request for [`GetAuthRequired`](#getauthrequired) returns two elements:
- 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}}
{{#each events}}

View File

@ -2,8 +2,8 @@
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "obs-websocket"
#define MyAppVersion "4.3.0"
#define MyAppPublisher "St<EFBFBD>phane Lepin"
#define MyAppVersion "4.5.1"
#define MyAppPublisher "Stephane Lepin"
#define MyAppURL "http://github.com/Palakis/obs-websocket"
[Setup]
@ -20,7 +20,7 @@ AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={code:GetDirName}
DefaultGroupName={#MyAppName}
OutputBaseFilename=obs-websocket-{#MyAppVersion}-Windows-Installer
OutputBaseFilename=obs-websocket-Windows-Installer
Compression=lzma
SolidCompression=yes
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/>
*/
#include <mbedtls/base64.h>
#include <mbedtls/sha256.h>
#include <obs-frontend-api.h>
#include <util/config-file.h>
#include <string>
#include <QCryptographicHash>
#include <QTime>
#define SECTION_NAME "WebsocketAPI"
#define PARAM_ENABLE "ServerEnabled"
@ -34,6 +34,8 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#include "Config.h"
#include "Utils.h"
#define QT_TO_UTF8(str) str.toUtf8().constData()
Config* Config::_instance = new Config();
Config::Config() :
@ -46,6 +48,8 @@ Config::Config() :
Salt(""),
SettingsLoaded(false)
{
qsrand(QTime::currentTime().msec());
// OBS Config defaults
config_t* obsConfig = obs_frontend_get_global_config();
if (obsConfig) {
@ -62,24 +66,20 @@ Config::Config() :
config_set_default_bool(obsConfig,
SECTION_NAME, PARAM_AUTHREQUIRED, AuthRequired);
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,
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();
}
Config::~Config() {
mbedtls_ctr_drbg_free(&rng);
mbedtls_entropy_free(&entropy);
Config::~Config()
{
}
void Config::Load() {
void Config::Load()
{
config_t* obsConfig = obs_frontend_get_global_config();
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);
}
void Config::Save() {
void Config::Save()
{
config_t* obsConfig = obs_frontend_get_global_config();
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_string(obsConfig, SECTION_NAME, PARAM_SECRET,
qstring_data_copy(Secret));
QT_TO_UTF8(Secret));
config_set_string(obsConfig, SECTION_NAME, PARAM_SALT,
qstring_data_copy(Salt));
QT_TO_UTF8(Salt));
config_save(obsConfig);
}
QString Config::GenerateSalt() {
QString Config::GenerateSalt()
{
// Generate 32 random chars
unsigned char* randomChars = (unsigned char*)bzalloc(32);
mbedtls_ctr_drbg_random(&rng, randomChars, 32);
const size_t randomCount = 32;
QByteArray randomChars;
for (size_t i = 0; i < randomCount; i++) {
randomChars.append((char)qrand());
}
// Convert the 32 random chars to a base64 string
char* salt = (char*)bzalloc(64);
size_t saltBytes;
mbedtls_base64_encode(
(unsigned char*)salt, 64, &saltBytes,
randomChars, 32);
QString salt = randomChars.toBase64();
bfree(randomChars);
return salt;
}
QString Config::GenerateSecret(QString password, QString salt) {
QString Config::GenerateSecret(QString password, QString salt)
{
// Concatenate the password and the salt
QString passAndSalt = "";
passAndSalt += password;
passAndSalt += salt;
// Generate a SHA256 hash of the password
unsigned char* challengeHash = (unsigned char*)bzalloc(32);
mbedtls_sha256(
(unsigned char*)passAndSalt.toUtf8().constData(), passAndSalt.length(),
challengeHash, 0);
// Generate a SHA256 hash of the password and salt
auto challengeHash = QCryptographicHash::hash(
passAndSalt.toUtf8(),
QCryptographicHash::Algorithm::Sha256
);
// Encode SHA256 hash to Base64
char* challenge = (char*)bzalloc(64);
size_t challengeBytes = 0;
mbedtls_base64_encode(
(unsigned char*)challenge, 64, &challengeBytes,
challengeHash, 32);
QString challenge = challengeHash.toBase64();
bfree(challengeHash);
return challenge;
}
void Config::SetPassword(QString password) {
void Config::SetPassword(QString password)
{
QString newSalt = GenerateSalt();
QString newChallenge = GenerateSecret(password, newSalt);
@ -158,37 +155,32 @@ void Config::SetPassword(QString password) {
this->Secret = newChallenge;
}
bool Config::CheckAuth(QString response) {
bool Config::CheckAuth(QString response)
{
// Concatenate auth secret with the challenge sent to the user
QString challengeAndResponse = "";
challengeAndResponse += Secret;
challengeAndResponse += SessionChallenge;
// Generate a SHA256 hash of challengeAndResponse
unsigned char* hash = (unsigned char*)bzalloc(32);
mbedtls_sha256(
(unsigned char*)challengeAndResponse.toUtf8().constData(),
challengeAndResponse.length(),
hash, 0);
auto hash = QCryptographicHash::hash(
challengeAndResponse.toUtf8(),
QCryptographicHash::Algorithm::Sha256
);
// Encode the SHA256 hash to Base64
char* expectedResponse = (char*)bzalloc(64);
size_t base64_size = 0;
mbedtls_base64_encode(
(unsigned char*)expectedResponse, 64, &base64_size,
hash, 32);
QString expectedResponse = hash.toBase64();
bool authSuccess = false;
if (response == QString(expectedResponse)) {
if (response == expectedResponse) {
SessionChallenge = GenerateSalt();
authSuccess = true;
}
bfree(hash);
bfree(expectedResponse);
return authSuccess;
}
Config* Config::Current() {
Config* Config::Current()
{
return _instance;
}

View File

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

View File

@ -28,13 +28,6 @@ with this program. If not, see <https://www.gnu.org/licenses/>
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) {
if (!strings)
return obs_data_array_create();
@ -110,6 +103,22 @@ obs_data_t* Utils::GetSceneItemData(obs_sceneitem_t* item) {
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) {
struct current_search {
QString query;
@ -146,6 +155,39 @@ obs_sceneitem_t* Utils::GetSceneItemFromName(obs_source_t* source, QString name)
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) {
switch (alignment) {
case OBS_ALIGN_CENTER:
@ -315,13 +357,19 @@ QString Utils::OBSVersionString() {
QSystemTrayIcon* Utils::GetTrayIcon() {
QMainWindow* main = (QMainWindow*)obs_frontend_get_main_window();
if (!main) return nullptr;
return main->findChildren<QSystemTrayIcon*>().first();
}
void Utils::SysTrayNotify(QString &text,
QSystemTrayIcon::MessageIcon icon, QString title) {
if (!Config::Current()->AlertsEnabled || !QSystemTrayIcon::supportsMessages())
if (!Config::Current()->AlertsEnabled ||
!QSystemTrayIcon::isSystemTrayAvailable() ||
!QSystemTrayIcon::supportsMessages())
{
return;
}
QSystemTrayIcon* trayIcon = GetTrayIcon();
if (trayIcon)

View File

@ -32,8 +32,6 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#include <obs-module.h>
#include <util/config-file.h>
const char* qstring_data_copy(QString value);
class Utils {
public:
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_sceneitem_t* GetSceneItemFromName(
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* GetSceneFromNameOrCurrent(QString sceneName);
@ -49,8 +49,6 @@ class Utils {
static obs_data_array_t* GetScenes();
static obs_data_t* GetSceneData(obs_source_t* source);
static obs_data_array_t* GetProfiles();
static QSpinBox* GetTransitionDurationControl();
static int GetTransitionDuration();
static void SetTransitionDuration(int ms);

View File

@ -80,12 +80,7 @@ WSEvents::WSEvents(WSServer* srv) {
this, SLOT(Heartbeat()));
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*)));
transitionHandler = nullptr;
sceneHandler = nullptr;
currentScene = nullptr;
QTimer::singleShot(1000, this, SLOT(deferredInitOperations()));
@ -103,8 +98,7 @@ WSEvents::~WSEvents() {
}
void WSEvents::deferredInitOperations() {
OBSSourceAutoRelease transition = obs_frontend_get_current_transition();
connectTransitionSignals(transition);
hookTransitionBeginEvent();
OBSSourceAutoRelease scene = obs_frontend_get_current_scene();
connectSceneSignals(scene);
@ -123,6 +117,7 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void* private
owner->OnSceneListChange();
}
else if (event == OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED) {
owner->hookTransitionBeginEvent();
owner->OnSceneCollectionChange();
}
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();
}
else if (event == OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED) {
owner->hookTransitionBeginEvent();
owner->OnTransitionListChange();
}
else if (event == OBS_FRONTEND_EVENT_PROFILE_CHANGED) {
@ -186,7 +182,11 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void* private
else if (event == OBS_FRONTEND_EVENT_STUDIO_MODE_DISABLED) {
owner->OnStudioModeSwitched(false);
}
else if (event == OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED) {
owner->OnPreviewSceneChanged();
}
else if (event == OBS_FRONTEND_EVENT_EXIT) {
owner->connectSceneSignals(nullptr);
owner->OnExit();
}
}
@ -220,43 +220,50 @@ void WSEvents::broadcastUpdate(const char* updateType,
blog(LOG_DEBUG, "Update << '%s'", json.toUtf8().constData());
}
void WSEvents::connectTransitionSignals(obs_source_t* transition) {
if (transitionHandler) {
signal_handler_disconnect(transitionHandler,
"transition_start", OnTransitionBegin, this);
void WSEvents::hookTransitionBeginEvent() {
obs_frontend_source_list transitions = {};
obs_frontend_get_transitions(&transitions);
for (int i = 0; i < transitions.sources.num; i++) {
obs_source_t* transition = transitions.sources.array[i];
signal_handler_t* sh = obs_source_get_signal_handler(transition);
signal_handler_disconnect(sh, "transition_start", OnTransitionBegin, this);
signal_handler_connect(sh, "transition_start", OnTransitionBegin, this);
}
if (!transitionIsCut(transition)) {
transitionHandler = obs_source_get_signal_handler(transition);
signal_handler_connect(transitionHandler,
"transition_start", OnTransitionBegin, this);
} else {
transitionHandler = nullptr;
}
obs_frontend_source_list_free(&transitions);
}
void WSEvents::connectSceneSignals(obs_source_t* scene) {
if (sceneHandler) {
signal_handler_disconnect(sceneHandler,
signal_handler_t* sh = nullptr;
if (currentScene) {
sh = obs_source_get_signal_handler(currentScene);
signal_handler_disconnect(sh,
"reorder", OnSceneReordered, this);
signal_handler_disconnect(sceneHandler,
signal_handler_disconnect(sh,
"item_add", OnSceneItemAdd, this);
signal_handler_disconnect(sceneHandler,
signal_handler_disconnect(sh,
"item_remove", OnSceneItemDelete, this);
signal_handler_disconnect(sceneHandler,
signal_handler_disconnect(sh,
"item_visible", OnSceneItemVisibilityChanged, this);
}
currentScene = scene;
if (currentScene) {
// TODO : connect to all scenes, not just the current one.
sceneHandler = obs_source_get_signal_handler(scene);
signal_handler_connect(sceneHandler,
sh = obs_source_get_signal_handler(currentScene);
signal_handler_connect(sh,
"reorder", OnSceneReordered, this);
signal_handler_connect(sceneHandler,
signal_handler_connect(sh,
"item_add", OnSceneItemAdd, this);
signal_handler_connect(sceneHandler,
signal_handler_connect(sh,
"item_remove", OnSceneItemDelete, this);
signal_handler_connect(sceneHandler,
signal_handler_connect(sh,
"item_visible", OnSceneItemVisibilityChanged, this);
}
}
uint64_t WSEvents::GetStreamingTime() {
@ -285,7 +292,7 @@ const char* WSEvents::GetRecordingTimecode() {
* Indicates a scene change.
*
* @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
* @name SwitchScenes
@ -302,13 +309,6 @@ void WSEvents::OnSceneChange() {
obs_data_set_array(data, "sources", sceneItems);
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);
}
}
/**
@ -335,8 +335,7 @@ void WSEvents::OnSceneListChange() {
void WSEvents::OnSceneCollectionChange() {
broadcastUpdate("SceneCollectionChanged");
sceneHandler = nullptr;
transitionHandler = nullptr;
currentScene = nullptr;
OnTransitionListChange();
OnTransitionChange();
@ -369,7 +368,6 @@ void WSEvents::OnSceneCollectionListChange() {
*/
void WSEvents::OnTransitionChange() {
OBSSourceAutoRelease currentTransition = obs_frontend_get_current_transition();
connectTransitionSignals(currentTransition);
OBSDataAutoRelease data = obs_data_create();
obs_data_set_string(data, "transition-name",
@ -551,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
* @name ReplayStopping
@ -659,7 +657,7 @@ void WSEvents::StreamStatus() {
/**
* 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-scene` Current active scene.
* @return {boolean (optional)} `streaming` Current streaming state.
@ -735,6 +733,8 @@ void WSEvents::TransitionDurationChanged(int ms) {
*
* @return {String} `name` Transition name.
* @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
* @name TransitionBegin
@ -742,14 +742,39 @@ void WSEvents::TransitionDurationChanged(int ms) {
* @since 4.0.0
*/
void WSEvents::OnTransitionBegin(void* param, calldata_t* data) {
UNUSED_PARAMETER(data);
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();
obs_data_set_string(fields, "name", obs_source_get_name(currentTransition));
obs_data_set_int(fields, "duration", Utils::GetTransitionDuration());
obs_data_set_string(fields, "name", obs_source_get_name(transition));
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);
}
@ -882,24 +907,23 @@ void WSEvents::OnSceneItemVisibilityChanged(void* param, calldata_t* data) {
* The selected preview scene has changed (only available in Studio Mode).
*
* @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
* @name PreviewSceneChanged
* @category studio mode
* @since 4.1.0
*/
void WSEvents::SelectedSceneChanged(QListWidgetItem* current, QListWidgetItem* prev) {
void WSEvents::OnPreviewSceneChanged() {
if (obs_frontend_preview_program_mode_active()) {
OBSScene scene = Utils::SceneListItemToScene(current);
OBSSourceAutoRelease scene = obs_frontend_get_current_preview_scene();
if (!scene)
return;
OBSSource sceneSource = obs_scene_get_source(scene);
OBSDataArrayAutoRelease sceneItems = Utils::GetSceneItems(sceneSource);
OBSDataArrayAutoRelease sceneItems = Utils::GetSceneItems(scene);
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);
broadcastUpdate("PreviewSceneChanged", data);

View File

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

View File

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

View File

@ -73,6 +73,9 @@ class WSRequestHandler : public QObject {
static void HandleGetSceneItemProperties(WSRequestHandler* req);
static void HandleSetSceneItemProperties(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 HandleStartStopStreaming(WSRequestHandler* req);
@ -107,6 +110,13 @@ class WSRequestHandler : public QObject {
static void HandleGetSourceSettings(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 HandleGetCurrentSceneCollection(WSRequestHandler* req);
static void HandleListSceneCollections(WSRequestHandler* req);
@ -132,6 +142,10 @@ class WSRequestHandler : public QObject {
static void HandleSetTextGDIPlusProperties(WSRequestHandler* req);
static void HandleGetTextGDIPlusProperties(WSRequestHandler* req);
static void HandleSetTextFreetype2Properties(WSRequestHandler* req);
static void HandleGetTextFreetype2Properties(WSRequestHandler* req);
static void HandleSetBrowserSourceProperties(WSRequestHandler* req);
static void HandleGetBrowserSourceProperties(WSRequestHandler* req);
};

View File

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

View File

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

View File

@ -322,7 +322,7 @@ void WSRequestHandler::HandleSetSceneItemProperties(WSRequestHandler* req) {
/**
* 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.
*
* @api requests
@ -566,3 +566,124 @@ void WSRequestHandler::HandleSetSceneItemCrop(WSRequestHandler* req) {
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"
/**
* @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.
*
@ -34,7 +40,7 @@
* Get the current scene's name and source items.
*
* @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
* @name GetCurrentScene
@ -56,7 +62,7 @@ void WSRequestHandler::HandleGetCurrentScene(WSRequestHandler* req) {
* Get a list of scenes in the currently active profile.
*
* @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
* @name GetSceneList
@ -74,3 +80,69 @@ void WSRequestHandler::HandleGetSceneList(WSRequestHandler* req) {
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 {String} `settings.server` The publish URL.
* @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.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.
*
* @return {String} `name` The name of the active preview scene.
* @return {Source|Array} `sources`
* @return {Array<Source>} `sources`
*
* @api requests
* @name GetPreviewScene

View File

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

View File

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

View File

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

View File

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