mirror of
https://github.com/Palakis/obs-websocket.git
synced 2024-08-30 18:12:16 +00:00
Merge branch '4.x-current' into fix/obs-shutdown-crash
This commit is contained in:
commit
60e2f0183e
4
.github/workflows/pr_push.yml
vendored
4
.github/workflows/pr_push.yml
vendored
@ -18,8 +18,8 @@ jobs:
|
||||
runs-on: [windows-latest]
|
||||
if: contains(github.event.head_commit.message, '[skip ci]') != true
|
||||
env:
|
||||
QT_VERSION: '5.10.1'
|
||||
WINDOWS_DEPS_VERSION: '2017'
|
||||
QT_VERSION: '5.15.2'
|
||||
WINDOWS_DEPS_VERSION: '2019'
|
||||
CMAKE_GENERATOR: "Visual Studio 16 2019"
|
||||
CMAKE_SYSTEM_VERSION: "10.0"
|
||||
steps:
|
||||
|
4
.github/workflows/tag_release.yml
vendored
4
.github/workflows/tag_release.yml
vendored
@ -12,8 +12,8 @@ jobs:
|
||||
name: 'Windows 32+64bit'
|
||||
runs-on: [windows-latest]
|
||||
env:
|
||||
QT_VERSION: '5.10.1'
|
||||
WINDOWS_DEPS_VERSION: '2017'
|
||||
QT_VERSION: '5.15.2'
|
||||
WINDOWS_DEPS_VERSION: '2019'
|
||||
CMAKE_GENERATOR: "Visual Studio 16 2019"
|
||||
CMAKE_SYSTEM_VERSION: "10.0"
|
||||
steps:
|
||||
|
10
BUILDING.md
10
BUILDING.md
@ -2,7 +2,7 @@
|
||||
|
||||
## Prerequisites
|
||||
|
||||
You'll need [Qt 5.10.x](https://download.qt.io/official_releases/qt/5.10/),
|
||||
You'll need [Qt 5.15.2](https://download.qt.io/official_releases/qt/5.15/5.15.2/),
|
||||
[CMake](https://cmake.org/download/) and a working [OBS Studio development environment](https://obsproject.com/wiki/install-instructions) installed on your
|
||||
computer.
|
||||
|
||||
@ -53,10 +53,10 @@ look for issues or specificities.
|
||||
```shell
|
||||
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
|
||||
./CI/macos/install-dependencies-macos.sh
|
||||
./CI/macos/install-build-obs-macos.sh
|
||||
./CI/macos/build-plugin-macos.sh
|
||||
./CI/macos/package-plugin-macos.sh
|
||||
```
|
||||
|
||||
This will result in a ready-to-use `obs-websocket.pkg` installer in the `release` subfolder.
|
||||
|
@ -1,6 +0,0 @@
|
||||
if not exist %DepsBasePath% (
|
||||
curl -o %DepsBasePath%.zip -kLO https://obsproject.com/downloads/dependencies2017.zip -f --retry 5 -C -
|
||||
7z x %DepsBasePath%.zip -o%DepsBasePath%
|
||||
) else (
|
||||
echo "OBS dependencies are already there. Download skipped."
|
||||
)
|
@ -1,42 +0,0 @@
|
||||
#!/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 \
|
||||
-DENABLE_SCRIPTING=0 \
|
||||
-DDepsPath=/tmp/obsdeps \
|
||||
-DCMAKE_PREFIX_PATH=/usr/local/opt/qt/lib/cmake \
|
||||
&& make -j4
|
@ -1,56 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
|
||||
|
||||
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
|
||||
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
|
||||
echo "[obs-websocket] Installing obs-websocket dependency 'QT 5.10.1'.."
|
||||
|
||||
brew install ./CI/macos/qt.rb
|
||||
|
||||
# Pin this version of QT5 to avoid `brew upgrade`
|
||||
# upgrading it to incompatible version
|
||||
brew pin qt
|
||||
|
||||
# Fetch and install Packages app
|
||||
# =!= NOTICE =!=
|
||||
# Installs a LaunchDaemon under /Library/LaunchDaemons/fr.whitebox.packages.build.dispatcher.plist
|
||||
# =!= NOTICE =!=
|
||||
|
||||
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
|
@ -1,8 +0,0 @@
|
||||
if not exist %QtBaseDir% (
|
||||
curl -kLO https://cdn-fastly.obsproject.com/downloads/Qt_5.10.1.7z -f --retry 5 -z Qt_5.10.1.7z
|
||||
7z x Qt_5.10.1.7z -o%QtBaseDir%
|
||||
) else (
|
||||
echo "Qt is already installed. Download skipped."
|
||||
)
|
||||
|
||||
dir %QtBaseDir%
|
@ -1,6 +1,9 @@
|
||||
#!/bin/sh
|
||||
set -ex
|
||||
|
||||
echo "[obs-websocket] Running CMake.."
|
||||
mkdir build && cd build
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/usr -DUSE_UBUNTU_FIX=true ..
|
||||
|
||||
echo "[obs-websocket] Building plugin.."
|
||||
make -j4
|
@ -1,9 +1,11 @@
|
||||
#!/bin/sh
|
||||
set -ex
|
||||
|
||||
echo "[obs-websocket] Installing obs-studio PPA and updates.."
|
||||
sudo add-apt-repository -y ppa:obsproject/obs-studio
|
||||
sudo apt-get -qq update
|
||||
|
||||
echo "[obs-websocket] Installing obs-studio and dependencies.."
|
||||
sudo apt-get install -y \
|
||||
libc-dev-bin \
|
||||
libc6-dev git \
|
||||
@ -13,7 +15,12 @@ sudo apt-get install -y \
|
||||
obs-studio \
|
||||
qtbase5-dev
|
||||
|
||||
echo "[obs-websocket] Installed OBS Version: $(obs --version)"
|
||||
|
||||
ls /usr/include/
|
||||
ls /usr/include/obs/
|
||||
|
||||
# Dirty hack
|
||||
sudo wget -O /usr/include/obs/obs-frontend-api.h https://raw.githubusercontent.com/obsproject/obs-studio/26.0.0/UI/obs-frontend-api/obs-frontend-api.h
|
||||
sudo wget -O /usr/include/obs/obs-frontend-api.h https://raw.githubusercontent.com/obsproject/obs-studio/26.1.2/UI/obs-frontend-api/obs-frontend-api.h
|
||||
|
||||
sudo ldconfig
|
@ -7,7 +7,7 @@ export PKG_VERSION="1-$GIT_HASH-$BRANCH_SHORT_NAME-git"
|
||||
|
||||
if [[ $BRANCH_FULL_NAME =~ ^refs/tags/ ]]; then
|
||||
export PKG_VERSION="$BRANCH_SHORT_NAME"
|
||||
echo "[obs-websocket] Branch is a tag. Setting version to $PKG_VERSION."
|
||||
echo "[obs-websocket] Branch is a tag. Setting version to $PKG_VERSION."
|
||||
fi
|
||||
|
||||
cd ./build
|
||||
@ -18,7 +18,7 @@ PAGER="cat" sudo checkinstall -y --type=debian --fstrans=no --nodoc \
|
||||
--pkglicense="GPLv2.0" --maintainer="stephane.lepin@gmail.com" \
|
||||
--pkggroup="video" \
|
||||
--pkgsource="https://github.com/Palakis/obs-websocket" \
|
||||
--requires="obs-studio \(\>= 25.0.7\), libqt5core5a, libqt5widgets5, qt5-image-formats-plugins" \
|
||||
--requires="obs-studio \(\>= 26.1.0\), libqt5core5a, libqt5widgets5, qt5-image-formats-plugins" \
|
||||
--pakdir="../package"
|
||||
|
||||
sudo chmod ao+r ../package/*
|
@ -1,10 +1,5 @@
|
||||
tap "akeru-inc/tap"
|
||||
brew "jack"
|
||||
brew "speexdsp"
|
||||
brew "cmake"
|
||||
brew "freetype"
|
||||
brew "fdk-aac"
|
||||
brew "https://gist.githubusercontent.com/DDRBoxman/9c7a2b08933166f4b61ed9a44b242609/raw/ef4de6c587c6bd7f50210eccd5bd51ff08e6de13/qt.rb"
|
||||
brew "swig", link: false
|
||||
brew "https://gist.githubusercontent.com/DDRBoxman/4cada55c51803a2f963fa40ce55c9d3e/raw/572c67e908bfbc1bcb8c476ea77ea3935133f5b5/swig.rb"
|
||||
brew "akeru-inc/tap/xcnotary"
|
@ -3,23 +3,21 @@
|
||||
OSTYPE=$(uname)
|
||||
|
||||
if [ "${OSTYPE}" != "Darwin" ]; then
|
||||
echo "[obs-websocket - Error] macOS build script can be run on Darwin-type OS only."
|
||||
exit 1
|
||||
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
|
||||
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)"
|
||||
|
||||
echo "[obs-websocket] Building 'obs-websocket' for macOS."
|
||||
mkdir -p build && cd build
|
||||
cmake .. \
|
||||
-DQTDIR=/usr/local/opt/qt \
|
||||
-DQTDIR=/tmp/obsdeps \
|
||||
-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" \
|
39
CI/macos/install-build-obs-macos.sh
Executable file
39
CI/macos/install-build-obs-macos.sh
Executable file
@ -0,0 +1,39 @@
|
||||
#!/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
|
||||
|
||||
# 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 .. \
|
||||
-DQTDIR=/tmp/obsdeps \
|
||||
-DDepsPath=/tmp/obsdeps \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 \
|
||||
-DDISABLE_PLUGINS=true \
|
||||
-DENABLE_SCRIPTING=0 \
|
||||
-DCMAKE_PREFIX_PATH=/tmp/obsdeps/lib/cmake \
|
||||
&& make -j4
|
57
CI/macos/install-dependencies-macos.sh
Executable file
57
CI/macos/install-dependencies-macos.sh
Executable file
@ -0,0 +1,57 @@
|
||||
#!/bin/sh
|
||||
|
||||
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 Brew Deps
|
||||
echo "[obs-websocket] Updating Homebrew.."
|
||||
brew update >/dev/null
|
||||
echo "[obs-websocket] Checking installed Homebrew formulas.."
|
||||
|
||||
if [ -d /usr/local/opt/openssl@1.0.2t ]; then
|
||||
brew uninstall openssl@1.0.2t
|
||||
brew untap local/openssl
|
||||
fi
|
||||
|
||||
if [ -d /usr/local/opt/python@2.7.17 ]; then
|
||||
brew uninstall python@2.7.17
|
||||
brew untap local/python2
|
||||
fi
|
||||
|
||||
brew bundle --file ./CI/macos/Brewfile
|
||||
|
||||
# Fetch and install Packages app
|
||||
# =!= NOTICE =!=
|
||||
# Installs a LaunchDaemon under /Library/LaunchDaemons/fr.whitebox.packages.build.dispatcher.plist
|
||||
# =!= NOTICE =!=
|
||||
|
||||
HAS_PACKAGES=$(type packagesbuild 2>/dev/null)
|
||||
|
||||
if [ "${HAS_PACKAGES}" = "" ]; then
|
||||
echo "[obs-websocket] Installing Packaging app (might require password due to 'sudo').."
|
||||
curl -L -O http://s.sudre.free.fr/Software/files/Packages.dmg
|
||||
sudo hdiutil attach ./Packages.dmg
|
||||
sudo installer -pkg /Volumes/Packages\ 1.2.9/Install\ Packages.pkg -target /
|
||||
fi
|
||||
|
||||
# OBS Deps
|
||||
echo "[obs-websocket] Installing obs-websocket dependency 'OBS Deps ${OBS_DEPS_VERSION}'.."
|
||||
wget --quiet --retry-connrefused --waitretry=1 https://github.com/obsproject/obs-deps/releases/download/${OBS_DEPS_VERSION}/macos-deps-${OBS_DEPS_VERSION}.tar.gz
|
||||
tar -xf ./macos-deps-${OBS_DEPS_VERSION}.tar.gz -C /tmp
|
||||
|
||||
# Qt deps
|
||||
echo "[obs-websocket] Installing obs-websocket dependency 'Qt ${QT_VERSION}'.."
|
||||
curl -L -O https://github.com/obsproject/obs-deps/releases/download/${OBS_DEPS_VERSION}/macos-qt-${QT_VERSION}-${OBS_DEPS_VERSION}.tar.gz
|
||||
tar -xf ./macos-qt-${QT_VERSION}-${OBS_DEPS_VERSION}.tar.gz -C "/tmp"
|
||||
xattr -r -d com.apple.quarantine /tmp/obsdeps
|
@ -5,12 +5,11 @@ set -e
|
||||
OSTYPE=$(uname)
|
||||
|
||||
if [ "${OSTYPE}" != "Darwin" ]; then
|
||||
echo "[obs-websocket - Error] macOS package script can be run on Darwin-type OS only."
|
||||
exit 1
|
||||
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)"
|
||||
|
||||
GIT_HASH=$(git rev-parse --short HEAD)
|
||||
GIT_BRANCH_OR_TAG=$(git name-rev --name-only HEAD | awk -F/ '{print $NF}')
|
||||
@ -20,13 +19,13 @@ VERSION="$GIT_HASH-$GIT_BRANCH_OR_TAG"
|
||||
FILENAME_UNSIGNED="obs-websocket-$VERSION-Unsigned.pkg"
|
||||
FILENAME="obs-websocket-$VERSION.pkg"
|
||||
|
||||
echo "[obs-websocket] Modifying obs-websocket.so"
|
||||
echo "[obs-websocket] Modifying obs-websocket.so linking"
|
||||
install_name_tool \
|
||||
-change /usr/local/opt/qt/lib/QtWidgets.framework/Versions/5/QtWidgets \
|
||||
-change /tmp/obsdeps/lib/QtWidgets.framework/Versions/5/QtWidgets \
|
||||
@executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets \
|
||||
-change /usr/local/opt/qt/lib/QtGui.framework/Versions/5/QtGui \
|
||||
-change /tmp/obsdeps/lib/QtGui.framework/Versions/5/QtGui \
|
||||
@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui \
|
||||
-change /usr/local/opt/qt/lib/QtCore.framework/Versions/5/QtCore \
|
||||
-change /tmp/obsdeps/lib/QtCore.framework/Versions/5/QtCore \
|
||||
@executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore \
|
||||
./build/obs-websocket.so
|
||||
|
145
CI/macos/qt.rb
145
CI/macos/qt.rb
@ -1,145 +0,0 @@
|
||||
# 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/official_releases/qt/5.10/5.10.1/single/qt-everywhere-src-5.10.1.tar.xz"
|
||||
mirror "https://www.mirrorservice.org/sites/download.qt-project.org/official_releases/qt/5.10/5.10.1/single/qt-everywhere-src-5.10.1.tar.xz"
|
||||
sha256 "05ffba7b811b854ed558abf2be2ddbd3bb6ddd0b60ea4b5da75d277ac15e740a"
|
||||
head "https://code.qt.io/qt/qt5.git", :branch => "5.10", :shallow => false
|
||||
|
||||
bottle do
|
||||
sha256 "8b4bad005596a5f8790150fe455db998ac2406f4e0f04140d6656205d844d266" => :high_sierra
|
||||
sha256 "9c488554935fb573554a4e36d36d3c81e47245b7fefc4b61edef894e67ba1740" => :sierra
|
||||
sha256 "c0407afba5951df6cc4c6f6c1c315972bd41c99cecb4e029919c4c15ab6f7bdc" => :el_capitan
|
||||
end
|
||||
|
||||
keg_only "Qt 5 has CMake issues when linked"
|
||||
|
||||
option "with-docs", "Build documentation"
|
||||
option "with-examples", "Build examples"
|
||||
option "without-proprietary-codecs", "Don't build with proprietary codecs (e.g. mp3)"
|
||||
|
||||
# OS X 10.7 Lion is still supported in Qt 5.5, but is no longer a reference
|
||||
# configuration and thus untested in practice. Builds on OS X 10.7 have been
|
||||
# reported to fail: <https://github.com/Homebrew/homebrew/issues/45284>.
|
||||
# depends_on :macos => :mountain_lion
|
||||
|
||||
depends_on "pkg-config" => :build
|
||||
depends_on :xcode => :build
|
||||
depends_on "mysql" => :optional
|
||||
depends_on "postgresql" => :optional
|
||||
|
||||
# Restore `.pc` files for framework-based build of Qt 5 on OS X. This
|
||||
# partially reverts <https://codereview.qt-project.org/#/c/140954/> merged
|
||||
# between the 5.5.1 and 5.6.0 releases. (Remove this as soon as feasible!)
|
||||
#
|
||||
# Core formulae known to fail without this patch (as of 2016-10-15):
|
||||
# * gnuplot (with `--with-qt` option)
|
||||
# * mkvtoolnix (with `--with-qt` option, silent build failure)
|
||||
# * poppler (with `--with-qt` option)
|
||||
patch do
|
||||
url "https://raw.githubusercontent.com/Homebrew/formula-patches/e8fe6567/qt5/restore-pc-files.patch"
|
||||
sha256 "48ff18be2f4050de7288bddbae7f47e949512ac4bcd126c2f504be2ac701158b"
|
||||
end
|
||||
|
||||
def install
|
||||
args = %W[
|
||||
-verbose
|
||||
-prefix #{prefix}
|
||||
-release
|
||||
-opensource -confirm-license
|
||||
-system-zlib
|
||||
-qt-libpng
|
||||
-qt-libjpeg
|
||||
-qt-freetype
|
||||
-qt-pcre
|
||||
-nomake tests
|
||||
-no-rpath
|
||||
-pkg-config
|
||||
-dbus-runtime
|
||||
]
|
||||
|
||||
args << "-nomake" << "examples" if build.without? "examples"
|
||||
|
||||
if build.with? "mysql"
|
||||
args << "-plugin-sql-mysql"
|
||||
(buildpath/"brew_shim/mysql_config").write <<~EOS
|
||||
#!/bin/sh
|
||||
if [ x"$1" = x"--libs" ]; then
|
||||
mysql_config --libs | sed "s/-lssl -lcrypto//"
|
||||
else
|
||||
exec mysql_config "$@"
|
||||
fi
|
||||
EOS
|
||||
chmod 0755, "brew_shim/mysql_config"
|
||||
args << "-mysql_config" << buildpath/"brew_shim/mysql_config"
|
||||
end
|
||||
|
||||
args << "-plugin-sql-psql" if build.with? "postgresql"
|
||||
args << "-proprietary-codecs" if build.with? "proprietary-codecs"
|
||||
|
||||
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
|
@ -1,37 +0,0 @@
|
||||
|
||||
@echo off
|
||||
SETLOCAL EnableDelayedExpansion
|
||||
|
||||
REM If obs-studio directory does not exist, clone the git repo
|
||||
if not exist %OBSPath% (
|
||||
echo obs-studio directory does not exist
|
||||
git clone https://github.com/obsproject/obs-studio %OBSPath%
|
||||
cd /D %OBSPath%\
|
||||
git describe --tags --abbrev=0 --exclude="*-rc*" > "%OBSPath%\obs-studio-latest-tag.txt"
|
||||
set /p OBSLatestTag=<"%OBSPath%\obs-studio-latest-tag.txt"
|
||||
)
|
||||
|
||||
REM Prepare OBS Studio builds
|
||||
|
||||
echo Running CMake...
|
||||
cd /D %OBSPath%
|
||||
echo git checkout %OBSLatestTag%
|
||||
git checkout %OBSLatestTag%
|
||||
echo:
|
||||
|
||||
if not exist build32 mkdir build32
|
||||
if not exist build64 mkdir build64
|
||||
|
||||
echo Running cmake for obs-studio %OBSLatestTag% 32-bit...
|
||||
cd build32
|
||||
cmake -G "Visual Studio 16 2019" -A Win32 -DCMAKE_SYSTEM_VERSION=10.0 -DQTDIR="%QTDIR32%" -DDepsPath="%DepsPath32%" -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 16 2019" -A x64 -DCMAKE_SYSTEM_VERSION=10.0 -DQTDIR="%QTDIR64%" -DDepsPath="%DepsPath64%" -DDISABLE_PLUGINS=true -DCOPIED_DEPENDENCIES=false -DCOPY_DEPENDENCIES=true ..
|
||||
echo:
|
||||
echo:
|
||||
|
||||
dir "%OBSPath%\libobs"
|
@ -1,7 +0,0 @@
|
||||
mkdir build32
|
||||
mkdir build64
|
||||
|
||||
cd build32
|
||||
cmake -G "Visual Studio 16 2019" -A Win32 -DCMAKE_SYSTEM_VERSION=10.0 -DQTDIR="%QTDIR32%" -DLibObs_DIR="%OBSPath%\build32\libobs" -DLIBOBS_INCLUDE_DIR="%OBSPath%\libobs" -DLIBOBS_LIB="%OBSPath%\build32\libobs\%build_config%\obs.lib" -DOBS_FRONTEND_LIB="%OBSPath%\build32\UI\obs-frontend-api\%build_config%\obs-frontend-api.lib" ..
|
||||
cd ..\build64
|
||||
cmake -G "Visual Studio 16 2019" -A x64 -DCMAKE_SYSTEM_VERSION=10.0 -DQTDIR="%QTDIR64%" -DLibObs_DIR="%OBSPath%\build64\libobs" -DLIBOBS_INCLUDE_DIR="%OBSPath%\libobs" -DLIBOBS_LIB="%OBSPath%\build64\libobs\%build_config%\obs.lib" -DOBS_FRONTEND_LIB="%OBSPath%\build64\UI\obs-frontend-api\%build_config%\obs-frontend-api.lib" ..
|
7
CI/windows/download-obs-deps.cmd
Normal file
7
CI/windows/download-obs-deps.cmd
Normal file
@ -0,0 +1,7 @@
|
||||
if exist %DEPS_BASE_PATH% (
|
||||
echo "OBS dependencies found. Download skipped."
|
||||
) else (
|
||||
echo "OBS dependencies not found. Downloading..."
|
||||
curl -o %DEPS_BASE_PATH%.zip -kLO https://cdn-fastly.obsproject.com/downloads/dependencies2019.zip -f --retry 5 -C -
|
||||
7z x %DEPS_BASE_PATH%.zip -o%DEPS_BASE_PATH%
|
||||
)
|
8
CI/windows/install-qt-win.cmd
Normal file
8
CI/windows/install-qt-win.cmd
Normal file
@ -0,0 +1,8 @@
|
||||
if exist %QT_BASE_DIR% (
|
||||
echo "Qt directory found. Download skipped."
|
||||
) else (
|
||||
echo "Qt directory not found. Downloading..."
|
||||
curl -kLO https://tt2468.net/dl/Qt_5.15.2.7z -f --retry 5 -C -
|
||||
7z x Qt_5.15.2.7z -o%QT_BASE_DIR%
|
||||
)
|
||||
dir %QT_BASE_DIR%
|
37
CI/windows/prepare-obs-windows.cmd
Normal file
37
CI/windows/prepare-obs-windows.cmd
Normal file
@ -0,0 +1,37 @@
|
||||
|
||||
@echo off
|
||||
SETLOCAL EnableDelayedExpansion
|
||||
|
||||
REM If obs-studio directory does not exist, clone the git repo
|
||||
if not exist %OBS_PATH% (
|
||||
echo obs-studio directory does not exist
|
||||
git clone https://github.com/obsproject/obs-studio %OBS_PATH%
|
||||
cd /D %OBS_PATH%\
|
||||
git describe --tags --abbrev=0 --exclude="*-rc*" > "%OBS_PATH%\obs-studio-latest-tag.txt"
|
||||
set /p OBS_LATEST_TAG=<"%OBS_PATH%\obs-studio-latest-tag.txt"
|
||||
)
|
||||
|
||||
REM Prepare OBS Studio builds
|
||||
|
||||
echo Running CMake...
|
||||
cd /D %OBS_PATH%
|
||||
echo git checkout %OBS_LATEST_TAG%
|
||||
git checkout %OBS_LATEST_TAG%
|
||||
echo:
|
||||
|
||||
if not exist build32 mkdir build32
|
||||
if not exist build64 mkdir build64
|
||||
|
||||
echo Running cmake for obs-studio %OBS_LATEST_TAG% 32-bit...
|
||||
cd build32
|
||||
cmake -G "Visual Studio 16 2019" -A Win32 -DCMAKE_SYSTEM_VERSION=10.0 -DQTDIR="%QTDIR32%" -DDepsPath="%DEPS_PATH_32%" -DDISABLE_PLUGINS=true -DCOPIED_DEPENDENCIES=false -DCOPY_DEPENDENCIES=true ..
|
||||
echo:
|
||||
echo:
|
||||
|
||||
echo Running cmake for obs-studio %OBS_LATEST_TAG% 64-bit...
|
||||
cd ..\build64
|
||||
cmake -G "Visual Studio 16 2019" -A x64 -DCMAKE_SYSTEM_VERSION=10.0 -DQTDIR="%QTDIR64%" -DDepsPath="%DEPS_PATH_64%" -DDISABLE_PLUGINS=true -DCOPIED_DEPENDENCIES=false -DCOPY_DEPENDENCIES=true ..
|
||||
echo:
|
||||
echo:
|
||||
|
||||
dir "%OBS_PATH%\libobs"
|
7
CI/windows/prepare-plugin-windows.cmd
Normal file
7
CI/windows/prepare-plugin-windows.cmd
Normal file
@ -0,0 +1,7 @@
|
||||
mkdir build32
|
||||
mkdir build64
|
||||
|
||||
cd build32
|
||||
cmake -G "Visual Studio 16 2019" -A Win32 -DCMAKE_SYSTEM_VERSION=10.0 -DQTDIR="%QTDIR32%" -DLibObs_DIR="%OBS_PATH%\build32\libobs" -DLIBOBS_INCLUDE_DIR="%OBS_PATH%\libobs" -DLIBOBS_LIB="%OBS_PATH%\build32\libobs\%build_config%\obs.lib" -DOBS_FRONTEND_LIB="%OBS_PATH%\build32\UI\obs-frontend-api\%build_config%\obs-frontend-api.lib" ..
|
||||
cd ..\build64
|
||||
cmake -G "Visual Studio 16 2019" -A x64 -DCMAKE_SYSTEM_VERSION=10.0 -DQTDIR="%QTDIR64%" -DLibObs_DIR="%OBS_PATH%\build64\libobs" -DLIBOBS_INCLUDE_DIR="%OBS_PATH%\libobs" -DLIBOBS_LIB="%OBS_PATH%\build64\libobs\%build_config%\obs.lib" -DOBS_FRONTEND_LIB="%OBS_PATH%\build64\UI\obs-frontend-api\%build_config%\obs-frontend-api.lib" ..
|
@ -36,6 +36,7 @@ set(obs-websocket_SOURCES
|
||||
src/WSRequestHandler_SceneItems.cpp
|
||||
src/WSRequestHandler_Sources.cpp
|
||||
src/WSRequestHandler_Streaming.cpp
|
||||
src/WSRequestHandler_VirtualCam.cpp
|
||||
src/WSRequestHandler_StudioMode.cpp
|
||||
src/WSRequestHandler_Transitions.cpp
|
||||
src/WSRequestHandler_Outputs.cpp
|
||||
@ -72,8 +73,8 @@ include_directories(
|
||||
"${LIBOBS_INCLUDE_DIR}/../UI/obs-frontend-api"
|
||||
${Qt5Core_INCLUDES}
|
||||
${Qt5Widgets_INCLUDES}
|
||||
"${CMAKE_SOURCE_DIR}/deps/asio/asio/include"
|
||||
"${CMAKE_SOURCE_DIR}/deps/websocketpp")
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/deps/asio/asio/include"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/deps/websocketpp")
|
||||
|
||||
target_link_libraries(obs-websocket
|
||||
libobs
|
||||
@ -84,9 +85,9 @@ target_link_libraries(obs-websocket
|
||||
|
||||
# --- Windows-specific build settings and tasks ---
|
||||
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 !")
|
||||
set(OBS_FRONTEND_LIB "NOTFOUND" CACHE FILEPATH "OBS frontend library")
|
||||
if(OBS_FRONTEND_LIB STREQUAL "NOTFOUND")
|
||||
message(FATAL_ERROR "OBS Frontend API library not found!")
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
@ -116,67 +117,70 @@ if(WIN32)
|
||||
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 (
|
||||
# If config is Release or RelWithDebInfo, package release files
|
||||
COMMAND if $<OR:$<CONFIG:Release>,$<CONFIG:RelWithDebInfo>>==1 (
|
||||
"${CMAKE_COMMAND}" -E make_directory
|
||||
"${RELEASE_DIR}/data/obs-plugins/obs-websocket"
|
||||
"${RELEASE_DIR}/obs-plugins/${ARCH_NAME}")
|
||||
"${RELEASE_DIR}/obs-plugins/${ARCH_NAME}"
|
||||
)
|
||||
|
||||
COMMAND if $<CONFIG:Release>==1 ("${CMAKE_COMMAND}" -E copy_directory
|
||||
COMMAND if $<OR:$<CONFIG:Release>,$<CONFIG:RelWithDebInfo>>==1 (
|
||||
"${CMAKE_COMMAND}" -E copy_directory
|
||||
"${PROJECT_SOURCE_DIR}/data"
|
||||
"${RELEASE_DIR}/data/obs-plugins/obs-websocket")
|
||||
"${RELEASE_DIR}/data/obs-plugins/obs-websocket"
|
||||
)
|
||||
|
||||
COMMAND if $<CONFIG:Release>==1 ("${CMAKE_COMMAND}" -E copy
|
||||
"$<TARGET_FILE:obs-websocket>"
|
||||
"${RELEASE_DIR}/obs-plugins/${ARCH_NAME}")
|
||||
|
||||
# In Release mode, copy Qt image format plugins
|
||||
COMMAND if $<CONFIG:Release>==1 (
|
||||
COMMAND if $<OR:$<CONFIG:Release>,$<CONFIG:RelWithDebInfo>>==1 (
|
||||
"${CMAKE_COMMAND}" -E copy
|
||||
"$<TARGET_FILE:obs-websocket>"
|
||||
"${RELEASE_DIR}/obs-plugins/${ARCH_NAME}"
|
||||
)
|
||||
|
||||
# In Release or RelWithDebInfo mode, copy Qt image format plugins
|
||||
COMMAND if $<OR:$<CONFIG:Release>,$<CONFIG:RelWithDebInfo>>==1 (
|
||||
"${CMAKE_COMMAND}" -E make_directory
|
||||
"${RELEASE_DIR}/bin/${ARCH_NAME}/imageformats"
|
||||
)
|
||||
COMMAND if $<OR:$<CONFIG:Release>,$<CONFIG:RelWithDebInfo>>==1 (
|
||||
"${CMAKE_COMMAND}" -E copy
|
||||
"${QTDIR}/plugins/imageformats/qicns.dll"
|
||||
"${QTDIR}/plugins/imageformats/qico.dll"
|
||||
"${QTDIR}/plugins/imageformats/qjpeg.dll"
|
||||
"${RELEASE_DIR}/bin/${ARCH_NAME}/imageformats/qjpeg.dll")
|
||||
"${QTDIR}/plugins/imageformats/qtiff.dll"
|
||||
"${QTDIR}/plugins/imageformats/qwbmp.dll"
|
||||
"${QTDIR}/plugins/imageformats/qwebp.dll"
|
||||
"${RELEASE_DIR}/bin/${ARCH_NAME}/imageformats"
|
||||
)
|
||||
|
||||
# If config is RelWithDebInfo, package PDB file for target
|
||||
COMMAND if $<CONFIG:RelWithDebInfo>==1 (
|
||||
"${CMAKE_COMMAND}" -E copy
|
||||
"${QTDIR}/plugins/imageformats/qjpeg.dll"
|
||||
"${RELEASE_DIR}/bin/${ARCH_NAME}/imageformats/qjpeg.dll")
|
||||
|
||||
# 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>"
|
||||
"${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}")
|
||||
"${RELEASE_DIR}/obs-plugins/${ARCH_NAME}"
|
||||
)
|
||||
|
||||
# Copy to obs-studio dev environment for immediate testing
|
||||
# In the Debug configuration, copy to obs-studio dev environment for immediate testing
|
||||
COMMAND if $<CONFIG:Debug>==1 (
|
||||
"${CMAKE_COMMAND}" -E copy
|
||||
"$<TARGET_FILE:obs-websocket>"
|
||||
"${LIBOBS_INCLUDE_DIR}/../${OBS_BUILDDIR_ARCH}/rundir/$<CONFIG>/obs-plugins/${ARCH_NAME}")
|
||||
"${LIBOBS_INCLUDE_DIR}/../${OBS_BUILDDIR_ARCH}/rundir/$<CONFIG>/obs-plugins/${ARCH_NAME}"
|
||||
)
|
||||
|
||||
COMMAND if $<CONFIG:Debug>==1 (
|
||||
"${CMAKE_COMMAND}" -E copy
|
||||
"$<TARGET_PDB_FILE:obs-websocket>"
|
||||
"${LIBOBS_INCLUDE_DIR}/../${OBS_BUILDDIR_ARCH}/rundir/$<CONFIG>/obs-plugins/${ARCH_NAME}")
|
||||
"$<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")
|
||||
"${LIBOBS_INCLUDE_DIR}/../${OBS_BUILDDIR_ARCH}/rundir/$<CONFIG>/data/obs-plugins/obs-websocket"
|
||||
)
|
||||
|
||||
COMMAND if $<CONFIG:Debug>==1 (
|
||||
"${CMAKE_COMMAND}" -E copy_directory
|
||||
"${PROJECT_SOURCE_DIR}/data"
|
||||
"${LIBOBS_INCLUDE_DIR}/../${OBS_BUILDDIR_ARCH}/rundir/$<CONFIG>/data/obs-plugins/obs-websocket")
|
||||
"${PROJECT_SOURCE_DIR}/data"
|
||||
"${LIBOBS_INCLUDE_DIR}/../${OBS_BUILDDIR_ARCH}/rundir/$<CONFIG>/data/obs-plugins/obs-websocket"
|
||||
)
|
||||
)
|
||||
# --- End of sub-section ---
|
||||
|
||||
@ -192,8 +196,11 @@ if(UNIX AND NOT APPLE)
|
||||
|
||||
file(GLOB locale_files data/locale/*.ini)
|
||||
|
||||
set(CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS
|
||||
OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_WRITE GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
set(CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS
|
||||
OWNER_READ OWNER_WRITE OWNER_EXECUTE
|
||||
GROUP_READ GROUP_WRITE GROUP_EXECUTE
|
||||
WORLD_READ WORLD_EXECUTE
|
||||
)
|
||||
|
||||
if(${USE_UBUNTU_FIX})
|
||||
install(TARGETS obs-websocket LIBRARY
|
||||
|
@ -54,6 +54,7 @@ Here's a list of available language APIs for obs-websocket :
|
||||
- Java 11+: [obs-java-client](https://github.com/harm27/obs-java-client) by harm27
|
||||
- Golang: [go-obs-websocket](https://github.com/christopher-dG/go-obs-websocket) by Chris de Graaf
|
||||
- Rust: [obws](https://github.com/dnaka91/obws) by dnaka91
|
||||
- Dart: [obs_websocket](https://pub.dev/packages/obs_websocket) by faithoflifedev
|
||||
- HTTP API: [obs-websocket-http](https://github.com/IRLToolkit/obs-websocket-http) by tt2468
|
||||
- CLI: [obs-cli](https://github.com/leafac/obs-cli) by leafac
|
||||
|
||||
|
@ -33,31 +33,41 @@ jobs:
|
||||
vmImage: 'windows-2019'
|
||||
variables:
|
||||
build_config: RelWithDebInfo
|
||||
DepsBasePath: 'D:\obsdependencies'
|
||||
DepsPath32: '$(DepsBasePath)\win32'
|
||||
DepsPath64: '$(DepsBasePath)\win64'
|
||||
QtBaseDir: 'D:\QtDep'
|
||||
QTDIR32: '$(QtBaseDir)\5.10.1\msvc2017'
|
||||
QTDIR64: '$(QtBaseDir)\5.10.1\msvc2017_64'
|
||||
OBSPath: 'D:\obs-studio'
|
||||
DEPS_CACHE_VERSION: '1' # Change whenever updating OBS dependencies URL, in order to force a cache reset
|
||||
DEPS_BASE_PATH: 'D:\obsdependencies'
|
||||
DEPS_PATH_32: '$(DEPS_BASE_PATH)\win32'
|
||||
DEPS_PATH_64: '$(DEPS_BASE_PATH)\win64'
|
||||
QT_CACHE_VERSION: '1' # Change whenever updating Qt dependency URL, in order to force a cache reset
|
||||
QT_BASE_DIR: 'D:\QtDep'
|
||||
QTDIR32: '$(QT_BASE_DIR)\5.15.2\msvc2019'
|
||||
QTDIR64: '$(QT_BASE_DIR)\5.15.2\msvc2019_64'
|
||||
OBS_PATH: 'D:\obs-studio'
|
||||
steps:
|
||||
- checkout: self
|
||||
submodules: true
|
||||
|
||||
- script: ./CI/install-qt-win.cmd
|
||||
- task: Cache@2
|
||||
displayName: Restore cached Qt archive file
|
||||
inputs:
|
||||
key: 'qtdep-"$(QT_CACHE_VERSION)" | "$(Agent.OS)"'
|
||||
restoreKeys: |
|
||||
qtdep-"$(QT_CACHE_VERSION)" | "$(Agent.OS)"
|
||||
path: $(QT_BASE_DIR)
|
||||
|
||||
- script: ./CI/windows/install-qt-win.cmd
|
||||
displayName: 'Install Qt'
|
||||
env:
|
||||
QtBaseDir: $(QtBaseDir)
|
||||
QT_BASE_DIR: $(QT_BASE_DIR)
|
||||
|
||||
- task: Cache@2
|
||||
displayName: Restore cached OBS Studio dependencies
|
||||
inputs:
|
||||
key: 'obsdeps | "$(Agent.OS)"'
|
||||
key: 'obsdeps-"$(DEPS_CACHE_VERSION)" | "$(Agent.OS)"'
|
||||
restoreKeys: |
|
||||
obsdeps | "$(Agent.OS)"
|
||||
path: $(DepsBasePath)
|
||||
obsdeps-"$(DEPS_CACHE_VERSION)" | "$(Agent.OS)"
|
||||
path: $(DEPS_BASE_PATH)
|
||||
|
||||
- script: ./CI/download-obs-deps.cmd
|
||||
- script: ./CI/windows/download-obs-deps.cmd
|
||||
displayName: 'Download OBS Studio dependencies'
|
||||
|
||||
- task: Cache@2
|
||||
@ -66,37 +76,37 @@ jobs:
|
||||
key: 'obs | "$(Agent.OS)"'
|
||||
restoreKeys: |
|
||||
obs | "$(Agent.OS)"
|
||||
path: $(OBSPath)
|
||||
path: $(OBS_PATH)
|
||||
|
||||
- script: ./CI/prepare-obs-windows.cmd
|
||||
- script: ./CI/windows/prepare-obs-windows.cmd
|
||||
displayName: 'Checkout & CMake OBS Studio'
|
||||
env:
|
||||
build_config: $(build_config)
|
||||
DepsPath32: $(DepsPath32)
|
||||
DepsPath64: $(DepsPath64)
|
||||
DEPS_PATH_32: $(DEPS_PATH_32)
|
||||
DEPS_PATH_64: $(DEPS_PATH_64)
|
||||
QTDIR32: $(QTDIR32)
|
||||
QTDIR64: $(QTDIR64)
|
||||
OBSPath: $(OBSPath)
|
||||
OBS_PATH: $(OBS_PATH)
|
||||
|
||||
- task: MSBuild@1
|
||||
displayName: 'Build OBS Studio 32-bit'
|
||||
inputs:
|
||||
msbuildArguments: '/m /p:Configuration=$(build_config)'
|
||||
solution: '$(OBSPath)\build32\obs-studio.sln'
|
||||
solution: '$(OBS_PATH)\build32\obs-studio.sln'
|
||||
|
||||
- task: MSBuild@1
|
||||
displayName: 'Build OBS Studio 64-bit'
|
||||
inputs:
|
||||
msbuildArguments: '/m /p:Configuration=$(build_config)'
|
||||
solution: '$(OBSPath)\build64\obs-studio.sln'
|
||||
solution: '$(OBS_PATH)\build64\obs-studio.sln'
|
||||
|
||||
- script: ./CI/prepare-windows.cmd
|
||||
- script: ./CI/windows/prepare-plugin-windows.cmd
|
||||
displayName: 'CMake obs-websocket'
|
||||
env:
|
||||
build_config: $(build_config)
|
||||
QTDIR32: $(QTDIR32)
|
||||
QTDIR64: $(QTDIR64)
|
||||
OBSPath: $(OBSPath)
|
||||
OBS_PATH: $(OBS_PATH)
|
||||
|
||||
- task: MSBuild@1
|
||||
displayName: 'Build obs-websocket 32-bit'
|
||||
@ -110,7 +120,7 @@ jobs:
|
||||
msbuildArguments: '/m /p:Configuration=$(build_config)'
|
||||
solution: '.\build64\obs-websocket.sln'
|
||||
|
||||
- script: ./CI/package-windows.cmd
|
||||
- script: ./CI/windows/package-plugin-windows.cmd
|
||||
displayName: 'Package obs-websocket'
|
||||
|
||||
- task: PublishBuildArtifacts@1
|
||||
@ -121,22 +131,21 @@ jobs:
|
||||
|
||||
- job: 'Build_Linux'
|
||||
pool:
|
||||
vmImage: 'ubuntu-18.04'
|
||||
vmImage: 'ubuntu-20.04'
|
||||
variables:
|
||||
BUILD_REASON: $(Build.Reason)
|
||||
BRANCH_SHORT_NAME: $(Build.SourceBranchName)
|
||||
BRANCH_FULL_NAME: $(Build.SourceBranch)
|
||||
steps:
|
||||
- checkout: self
|
||||
submodules: true
|
||||
|
||||
- script: ./CI/install-dependencies-ubuntu.sh
|
||||
- script: ./CI/linux/install-dependencies-ubuntu.sh
|
||||
displayName: 'Install dependencies'
|
||||
|
||||
- script: ./CI/build-ubuntu.sh
|
||||
- script: ./CI/linux/build-plugin-ubuntu.sh
|
||||
displayName: 'Build obs-websocket'
|
||||
|
||||
- script: ./CI/package-ubuntu.sh
|
||||
- script: ./CI/linux/package-plugin-ubuntu.sh
|
||||
displayName: 'Package obs-websocket'
|
||||
|
||||
- task: PublishBuildArtifacts@1
|
||||
@ -146,18 +155,24 @@ jobs:
|
||||
|
||||
- job: 'Build_macOS'
|
||||
pool:
|
||||
vmImage: 'macos-10.14'
|
||||
vmImage: 'macOS-10.15'
|
||||
variables:
|
||||
OBS_DEPS_VERSION: '2020-12-22'
|
||||
QT_VERSION: '5.15.2'
|
||||
steps:
|
||||
- checkout: self
|
||||
submodules: true
|
||||
|
||||
- script: ./CI/install-dependencies-macos.sh
|
||||
- script: ./CI/macos/install-dependencies-macos.sh
|
||||
displayName: 'Install dependencies'
|
||||
env:
|
||||
OBS_DEPS_VERSION: $(OBS_DEPS_VERSION)
|
||||
QT_VERSION: $(QT_VERSION)
|
||||
|
||||
- script: ./CI/install-build-obs-macos.sh
|
||||
- script: ./CI/macos/install-build-obs-macos.sh
|
||||
displayName: 'Build OBS'
|
||||
|
||||
- script: ./CI/build-macos.sh
|
||||
- script: ./CI/macos/build-plugin-macos.sh
|
||||
displayName: 'Build obs-websocket'
|
||||
|
||||
- task: InstallAppleCertificate@2
|
||||
@ -167,7 +182,7 @@ jobs:
|
||||
certSecureFile: 'Certificates.p12'
|
||||
certPwd: $(secrets.macOS.certificatesImportPassword)
|
||||
|
||||
- script: ./CI/package-macos.sh
|
||||
- script: ./CI/macos/package-plugin-macos.sh
|
||||
displayName: 'Package obs-websocket'
|
||||
env:
|
||||
RELEASE_MODE: $(isReleaseMode)
|
||||
|
@ -366,7 +366,7 @@
|
||||
"{boolean} `flags.encoded` Output is encoded",
|
||||
"{boolean} `flags.multiTrack` Output uses several audio tracks",
|
||||
"{boolean} `flags.service` Output uses a service",
|
||||
"{Object} `settings` Output name",
|
||||
"{Object} `settings` Output settings",
|
||||
"{boolean} `active` Output status (active or not)",
|
||||
"{boolean} `reconnecting` Output reconnection status (reconnecting or not)",
|
||||
"{double} `congestion` Output congestion",
|
||||
@ -433,7 +433,7 @@
|
||||
{
|
||||
"type": "Object",
|
||||
"name": "settings",
|
||||
"description": "Output name"
|
||||
"description": "Output settings"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
@ -861,7 +861,7 @@
|
||||
"{String} `name` Transition name.",
|
||||
"{String} `type` Transition type.",
|
||||
"{int} `duration` Transition duration (in milliseconds). Will be -1 for any transition with a fixed duration, such as a Stinger, due to limitations of the OBS API.",
|
||||
"{String} `from-scene` Source scene of the transition",
|
||||
"{String (optional)} `from-scene` Source scene of the transition",
|
||||
"{String} `to-scene` Destination scene of the transition"
|
||||
],
|
||||
"api": "events",
|
||||
@ -885,7 +885,7 @@
|
||||
"description": "Transition duration (in milliseconds). Will be -1 for any transition with a fixed duration, such as a Stinger, due to limitations of the OBS API."
|
||||
},
|
||||
{
|
||||
"type": "String",
|
||||
"type": "String (optional)",
|
||||
"name": "from-scene",
|
||||
"description": "Source scene of the transition"
|
||||
},
|
||||
@ -989,7 +989,7 @@
|
||||
"{String} `name` Transition name.",
|
||||
"{String} `type` Transition type.",
|
||||
"{int} `duration` Transition duration (in milliseconds).",
|
||||
"{String} `from-scene` Source scene of the transition",
|
||||
"{String (optional)} `from-scene` Source scene of the transition",
|
||||
"{String} `to-scene` Destination scene of the transition"
|
||||
],
|
||||
"api": "events",
|
||||
@ -1013,7 +1013,7 @@
|
||||
"description": "Transition duration (in milliseconds)."
|
||||
},
|
||||
{
|
||||
"type": "String",
|
||||
"type": "String (optional)",
|
||||
"name": "from-scene",
|
||||
"description": "Source scene of the transition"
|
||||
},
|
||||
@ -1667,6 +1667,74 @@
|
||||
"examples": []
|
||||
}
|
||||
],
|
||||
"virtual cam": [
|
||||
{
|
||||
"subheads": [],
|
||||
"description": "Virtual cam started successfully.",
|
||||
"api": "events",
|
||||
"name": "VirtualCamStarted",
|
||||
"category": "virtual cam",
|
||||
"since": "unreleased",
|
||||
"names": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "VirtualCamStarted"
|
||||
}
|
||||
],
|
||||
"categories": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "virtual cam"
|
||||
}
|
||||
],
|
||||
"sinces": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "unreleased"
|
||||
}
|
||||
],
|
||||
"heading": {
|
||||
"level": 2,
|
||||
"text": "VirtualCamStarted"
|
||||
},
|
||||
"lead": "",
|
||||
"type": "class",
|
||||
"examples": []
|
||||
},
|
||||
{
|
||||
"subheads": [],
|
||||
"description": "Virtual cam stopped successfully.",
|
||||
"api": "events",
|
||||
"name": "VirtualCamStopped",
|
||||
"category": "virtual cam",
|
||||
"since": "unreleased",
|
||||
"names": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "VirtualCamStopped"
|
||||
}
|
||||
],
|
||||
"categories": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "virtual cam"
|
||||
}
|
||||
],
|
||||
"sinces": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "unreleased"
|
||||
}
|
||||
],
|
||||
"heading": {
|
||||
"level": 2,
|
||||
"text": "VirtualCamStopped"
|
||||
},
|
||||
"lead": "",
|
||||
"type": "class",
|
||||
"examples": []
|
||||
}
|
||||
],
|
||||
"replay buffer": [
|
||||
{
|
||||
"subheads": [],
|
||||
@ -2118,7 +2186,8 @@
|
||||
"description": "The volume of a source has changed.",
|
||||
"return": [
|
||||
"{String} `sourceName` Source name",
|
||||
"{float} `volume` Source volume"
|
||||
"{float} `volume` Source volume",
|
||||
"{float} `volumeDb` Source volume in Decibel"
|
||||
],
|
||||
"api": "events",
|
||||
"name": "SourceVolumeChanged",
|
||||
@ -2134,6 +2203,11 @@
|
||||
"type": "float",
|
||||
"name": "volume",
|
||||
"description": "Source volume"
|
||||
},
|
||||
{
|
||||
"type": "float",
|
||||
"name": "volumeDb",
|
||||
"description": "Source volume in Decibel"
|
||||
}
|
||||
],
|
||||
"names": [
|
||||
@ -4441,10 +4515,10 @@
|
||||
"media control": [
|
||||
{
|
||||
"subheads": [],
|
||||
"description": "Pause or play a media source. Supports ffmpeg and vlc media sources (as of OBS v25.0.8)",
|
||||
"description": "Pause or play a media source. Supports ffmpeg and vlc media sources (as of OBS v25.0.8)\nNote :Leaving out `playPause` toggles the current pause state",
|
||||
"param": [
|
||||
"{String} `sourceName` Source name.",
|
||||
"{boolean} `playPause` Whether to pause or play the source. `false` for play, `true` for pause."
|
||||
"{boolean} `playPause` (optional) Whether to pause or play the source. `false` for play, `true` for pause."
|
||||
],
|
||||
"api": "requests",
|
||||
"name": "PlayPauseMedia",
|
||||
@ -4459,7 +4533,7 @@
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "playPause",
|
||||
"description": "Whether to pause or play the source. `false` for play, `true` for pause."
|
||||
"description": "(optional) Whether to pause or play the source. `false` for play, `true` for pause."
|
||||
}
|
||||
],
|
||||
"names": [
|
||||
@ -5337,6 +5411,142 @@
|
||||
"type": "class",
|
||||
"examples": []
|
||||
},
|
||||
{
|
||||
"subheads": [],
|
||||
"description": "Changes whether an audio track is active for a source.",
|
||||
"param": [
|
||||
"{String} `sourceName` Source name.",
|
||||
"{int} `track` Audio tracks 1-6.",
|
||||
"{boolean} `active` Whether audio track is active or not."
|
||||
],
|
||||
"api": "requests",
|
||||
"name": "SetTracks",
|
||||
"category": "sources",
|
||||
"since": "unreleased",
|
||||
"params": [
|
||||
{
|
||||
"type": "String",
|
||||
"name": "sourceName",
|
||||
"description": "Source name."
|
||||
},
|
||||
{
|
||||
"type": "int",
|
||||
"name": "track",
|
||||
"description": "Audio tracks 1-6."
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "active",
|
||||
"description": "Whether audio track is active or not."
|
||||
}
|
||||
],
|
||||
"names": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "SetTracks"
|
||||
}
|
||||
],
|
||||
"categories": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "sources"
|
||||
}
|
||||
],
|
||||
"sinces": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "unreleased"
|
||||
}
|
||||
],
|
||||
"heading": {
|
||||
"level": 2,
|
||||
"text": "SetTracks"
|
||||
},
|
||||
"lead": "",
|
||||
"type": "class",
|
||||
"examples": []
|
||||
},
|
||||
{
|
||||
"subheads": [],
|
||||
"description": "Gets whether an audio track is active for a source.",
|
||||
"param": "{String} `sourceName` Source name.",
|
||||
"return": [
|
||||
"{boolean} `track1`",
|
||||
"{boolean} `track2`",
|
||||
"{boolean} `track3`",
|
||||
"{boolean} `track4`",
|
||||
"{boolean} `track5`",
|
||||
"{boolean} `track6`"
|
||||
],
|
||||
"api": "requests",
|
||||
"name": "GetTracks",
|
||||
"category": "sources",
|
||||
"since": "unreleased",
|
||||
"returns": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "track1",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "track2",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "track3",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "track4",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "track5",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "track6",
|
||||
"description": ""
|
||||
}
|
||||
],
|
||||
"params": [
|
||||
{
|
||||
"type": "String",
|
||||
"name": "sourceName",
|
||||
"description": "Source name."
|
||||
}
|
||||
],
|
||||
"names": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "GetTracks"
|
||||
}
|
||||
],
|
||||
"categories": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "sources"
|
||||
}
|
||||
],
|
||||
"sinces": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "unreleased"
|
||||
}
|
||||
],
|
||||
"heading": {
|
||||
"level": 2,
|
||||
"text": "GetTracks"
|
||||
},
|
||||
"lead": "",
|
||||
"type": "class",
|
||||
"examples": []
|
||||
},
|
||||
{
|
||||
"subheads": [],
|
||||
"description": "Get the mute status of a specified source.",
|
||||
@ -5484,6 +5694,55 @@
|
||||
"type": "class",
|
||||
"examples": []
|
||||
},
|
||||
{
|
||||
"subheads": [],
|
||||
"description": "Get the source's active status of a specified source (if it is showing in the final mix).",
|
||||
"param": "{String} `sourceName` Source name.",
|
||||
"return": "{boolean} `sourceActive` Source active status of the source.",
|
||||
"api": "requests",
|
||||
"name": "GetSourceActive",
|
||||
"category": "sources",
|
||||
"since": "unreleased",
|
||||
"returns": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "sourceActive",
|
||||
"description": "Source active status of the source."
|
||||
}
|
||||
],
|
||||
"params": [
|
||||
{
|
||||
"type": "String",
|
||||
"name": "sourceName",
|
||||
"description": "Source name."
|
||||
}
|
||||
],
|
||||
"names": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "GetSourceActive"
|
||||
}
|
||||
],
|
||||
"categories": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "sources"
|
||||
}
|
||||
],
|
||||
"sinces": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "unreleased"
|
||||
}
|
||||
],
|
||||
"heading": {
|
||||
"level": 2,
|
||||
"text": "GetSourceActive"
|
||||
},
|
||||
"lead": "",
|
||||
"type": "class",
|
||||
"examples": []
|
||||
},
|
||||
{
|
||||
"subheads": [],
|
||||
"description": "Get the audio's active status of a specified source.",
|
||||
@ -9393,7 +9652,7 @@
|
||||
"param": [
|
||||
"{String} `sceneName` Name of the scene to create the scene item in",
|
||||
"{String} `sourceName` Name of the source to be added",
|
||||
"{boolean} `setVisible` Whether to make the sceneitem visible on creation or not. Default `true`"
|
||||
"{boolean (optional)} `setVisible` Whether to make the sceneitem visible on creation or not. Default `true`"
|
||||
],
|
||||
"return": "{int} `itemId` Numerical ID of the created scene item",
|
||||
"api": "requests",
|
||||
@ -9419,7 +9678,7 @@
|
||||
"description": "Name of the source to be added"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"type": "boolean (optional)",
|
||||
"name": "setVisible",
|
||||
"description": "Whether to make the sceneitem visible on creation or not. Default `true`"
|
||||
}
|
||||
@ -9732,7 +9991,7 @@
|
||||
"description": "Changes the order of scene items in the requested scene.",
|
||||
"param": [
|
||||
"{String (optional)} `scene` Name of the scene to reorder (defaults to current).",
|
||||
"{Array<Scene>} `items` Ordered list of objects with name and/or id specified. Id preferred due to uniqueness per scene",
|
||||
"{Array<Object>} `items` Ordered list of objects with name and/or id specified. Id preferred due to uniqueness per scene",
|
||||
"{int (optional)} `items.*.id` Id of a specific scene item. Unique on a scene by scene basis.",
|
||||
"{String (optional)} `items.*.name` Name of a scene item. Sufficiently unique if no scene items share sources within the scene."
|
||||
],
|
||||
@ -9747,7 +10006,7 @@
|
||||
"description": "Name of the scene to reorder (defaults to current)."
|
||||
},
|
||||
{
|
||||
"type": "Array<Scene>",
|
||||
"type": "Array<Object>",
|
||||
"name": "items",
|
||||
"description": "Ordered list of objects with name and/or id specified. Id preferred due to uniqueness per scene"
|
||||
},
|
||||
@ -9950,9 +10209,11 @@
|
||||
"{boolean} `streaming` Current streaming status.",
|
||||
"{boolean} `recording` Current recording status.",
|
||||
"{boolean} `recording-paused` If recording is paused.",
|
||||
"{boolean} `virtualcam` Current virtual cam status.",
|
||||
"{boolean} `preview-only` Always false. Retrocompatibility with OBSRemote.",
|
||||
"{String (optional)} `stream-timecode` Time elapsed since streaming started (only present if currently streaming).",
|
||||
"{String (optional)} `rec-timecode` Time elapsed since recording started (only present if currently recording)."
|
||||
"{String (optional)} `rec-timecode` Time elapsed since recording started (only present if currently recording).",
|
||||
"{String (optional)} `virtualcam-timecode` Time elapsed since virtual cam started (only present if virtual cam currently active)."
|
||||
],
|
||||
"api": "requests",
|
||||
"name": "GetStreamingStatus",
|
||||
@ -9974,6 +10235,11 @@
|
||||
"name": "recording-paused",
|
||||
"description": "If recording is paused."
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "virtualcam",
|
||||
"description": "Current virtual cam status."
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "preview-only",
|
||||
@ -9988,6 +10254,11 @@
|
||||
"type": "String (optional)",
|
||||
"name": "rec-timecode",
|
||||
"description": "Time elapsed since recording started (only present if currently recording)."
|
||||
},
|
||||
{
|
||||
"type": "String (optional)",
|
||||
"name": "virtualcam-timecode",
|
||||
"description": "Time elapsed since virtual cam started (only present if virtual cam currently active)."
|
||||
}
|
||||
],
|
||||
"names": [
|
||||
@ -11156,6 +11427,156 @@
|
||||
"type": "class",
|
||||
"examples": []
|
||||
}
|
||||
],
|
||||
"virtual cam": [
|
||||
{
|
||||
"subheads": [],
|
||||
"description": "Get current virtual cam status.",
|
||||
"return": [
|
||||
"{boolean} `isVirtualCam` Current virtual camera status.",
|
||||
"{String (optional)} `virtualCamTimecode` Time elapsed since virtual cam started (only present if virtual cam currently active)."
|
||||
],
|
||||
"api": "requests",
|
||||
"name": "GetVirtualCamStatus",
|
||||
"category": "virtual cam",
|
||||
"since": "unreleased",
|
||||
"returns": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "isVirtualCam",
|
||||
"description": "Current virtual camera status."
|
||||
},
|
||||
{
|
||||
"type": "String (optional)",
|
||||
"name": "virtualCamTimecode",
|
||||
"description": "Time elapsed since virtual cam started (only present if virtual cam currently active)."
|
||||
}
|
||||
],
|
||||
"names": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "GetVirtualCamStatus"
|
||||
}
|
||||
],
|
||||
"categories": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "virtual cam"
|
||||
}
|
||||
],
|
||||
"sinces": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "unreleased"
|
||||
}
|
||||
],
|
||||
"heading": {
|
||||
"level": 2,
|
||||
"text": "GetVirtualCamStatus"
|
||||
},
|
||||
"lead": "",
|
||||
"type": "class",
|
||||
"examples": []
|
||||
},
|
||||
{
|
||||
"subheads": [],
|
||||
"description": "Toggle virtual cam on or off (depending on the current virtual cam state).",
|
||||
"api": "requests",
|
||||
"name": "StartStopVirtualCam",
|
||||
"category": "virtual cam",
|
||||
"since": "unreleased",
|
||||
"names": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "StartStopVirtualCam"
|
||||
}
|
||||
],
|
||||
"categories": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "virtual cam"
|
||||
}
|
||||
],
|
||||
"sinces": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "unreleased"
|
||||
}
|
||||
],
|
||||
"heading": {
|
||||
"level": 2,
|
||||
"text": "StartStopVirtualCam"
|
||||
},
|
||||
"lead": "",
|
||||
"type": "class",
|
||||
"examples": []
|
||||
},
|
||||
{
|
||||
"subheads": [],
|
||||
"description": "Start virtual cam.\nWill return an `error` if virtual cam is already active.",
|
||||
"api": "requests",
|
||||
"name": "StartVirtualCam",
|
||||
"category": "virtual cam",
|
||||
"since": "unreleased",
|
||||
"names": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "StartVirtualCam"
|
||||
}
|
||||
],
|
||||
"categories": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "virtual cam"
|
||||
}
|
||||
],
|
||||
"sinces": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "unreleased"
|
||||
}
|
||||
],
|
||||
"heading": {
|
||||
"level": 2,
|
||||
"text": "StartVirtualCam"
|
||||
},
|
||||
"lead": "",
|
||||
"type": "class",
|
||||
"examples": []
|
||||
},
|
||||
{
|
||||
"subheads": [],
|
||||
"description": "Stop virtual cam.\nWill return an `error` if virtual cam is not active.",
|
||||
"api": "requests",
|
||||
"name": "StopVirtualCam",
|
||||
"category": "virtual cam",
|
||||
"since": "unreleased",
|
||||
"names": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "StopVirtualCam"
|
||||
}
|
||||
],
|
||||
"categories": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "virtual cam"
|
||||
}
|
||||
],
|
||||
"sinces": [
|
||||
{
|
||||
"name": "",
|
||||
"description": "unreleased"
|
||||
}
|
||||
],
|
||||
"heading": {
|
||||
"level": 2,
|
||||
"text": "StopVirtualCam"
|
||||
},
|
||||
"lead": "",
|
||||
"type": "class",
|
||||
"examples": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -37,7 +37,7 @@ auth_response_hash = binary_sha256(auth_response_string)
|
||||
auth_response = base64_encode(auth_response_hash)
|
||||
```
|
||||
|
||||
You can also refer to any of the client libraries listed on the [README](README.md) for examples of how to authenticate.
|
||||
You can also refer to any of the [client libraries](https://github.com/Palakis/obs-websocket#for-developers) listed on the README for examples of how to authenticate.
|
||||
|
||||
|
||||
|
||||
@ -82,6 +82,9 @@ You can also refer to any of the client libraries listed on the [README](README.
|
||||
+ [RecordingStopped](#recordingstopped)
|
||||
+ [RecordingPaused](#recordingpaused)
|
||||
+ [RecordingResumed](#recordingresumed)
|
||||
* [Virtual Cam](#virtual-cam)
|
||||
+ [VirtualCamStarted](#virtualcamstarted)
|
||||
+ [VirtualCamStopped](#virtualcamstopped)
|
||||
* [Replay Buffer](#replay-buffer)
|
||||
+ [ReplayStarting](#replaystarting)
|
||||
+ [ReplayStarted](#replaystarted)
|
||||
@ -161,9 +164,12 @@ You can also refer to any of the client libraries listed on the [README](README.
|
||||
+ [GetSourceTypesList](#getsourcetypeslist)
|
||||
+ [GetVolume](#getvolume)
|
||||
+ [SetVolume](#setvolume)
|
||||
+ [SetTracks](#settracks)
|
||||
+ [GetTracks](#gettracks)
|
||||
+ [GetMute](#getmute)
|
||||
+ [SetMute](#setmute)
|
||||
+ [ToggleMute](#togglemute)
|
||||
+ [GetSourceActive](#getsourceactive)
|
||||
+ [GetAudioActive](#getaudioactive)
|
||||
+ [SetSourceName](#setsourcename)
|
||||
+ [SetSyncOffset](#setsyncoffset)
|
||||
@ -267,6 +273,11 @@ You can also refer to any of the client libraries listed on the [README](README.
|
||||
+ [SetTransitionSettings](#settransitionsettings)
|
||||
+ [ReleaseTBar](#releasetbar)
|
||||
+ [SetTBarPosition](#settbarposition)
|
||||
* [Virtual Cam](#virtual-cam-1)
|
||||
+ [GetVirtualCamStatus](#getvirtualcamstatus)
|
||||
+ [StartStopVirtualCam](#startstopvirtualcam)
|
||||
+ [StartVirtualCam](#startvirtualcam)
|
||||
+ [StopVirtualCam](#stopvirtualcam)
|
||||
|
||||
<!-- tocstop -->
|
||||
|
||||
@ -345,7 +356,7 @@ These are complex types, such as `Source` and `Scene`, which are used as argumen
|
||||
| `flags.encoded` | _boolean_ | Output is encoded |
|
||||
| `flags.multiTrack` | _boolean_ | Output uses several audio tracks |
|
||||
| `flags.service` | _boolean_ | Output uses a service |
|
||||
| `settings` | _Object_ | Output name |
|
||||
| `settings` | _Object_ | Output settings |
|
||||
| `active` | _boolean_ | Output status (active or not) |
|
||||
| `reconnecting` | _boolean_ | Output reconnection status (reconnecting or not) |
|
||||
| `congestion` | _double_ | Output congestion |
|
||||
@ -513,7 +524,7 @@ A transition (other than "cut") has begun.
|
||||
| `name` | _String_ | Transition name. |
|
||||
| `type` | _String_ | Transition type. |
|
||||
| `duration` | _int_ | Transition duration (in milliseconds). Will be -1 for any transition with a fixed duration, such as a Stinger, due to limitations of the OBS API. |
|
||||
| `from-scene` | _String_ | Source scene of the transition |
|
||||
| `from-scene` | _String (optional)_ | Source scene of the transition |
|
||||
| `to-scene` | _String_ | Destination scene of the transition |
|
||||
|
||||
|
||||
@ -553,7 +564,7 @@ A stinger transition has finished playing its video.
|
||||
| `name` | _String_ | Transition name. |
|
||||
| `type` | _String_ | Transition type. |
|
||||
| `duration` | _int_ | Transition duration (in milliseconds). |
|
||||
| `from-scene` | _String_ | Source scene of the transition |
|
||||
| `from-scene` | _String (optional)_ | Source scene of the transition |
|
||||
| `to-scene` | _String_ | Destination scene of the transition |
|
||||
|
||||
|
||||
@ -780,6 +791,34 @@ _No additional response items._
|
||||
|
||||
---
|
||||
|
||||
## Virtual Cam
|
||||
|
||||
### VirtualCamStarted
|
||||
|
||||
|
||||
- Unreleased
|
||||
|
||||
Virtual cam started successfully.
|
||||
|
||||
**Response Items:**
|
||||
|
||||
_No additional response items._
|
||||
|
||||
---
|
||||
|
||||
### VirtualCamStopped
|
||||
|
||||
|
||||
- Unreleased
|
||||
|
||||
Virtual cam stopped successfully.
|
||||
|
||||
**Response Items:**
|
||||
|
||||
_No additional response items._
|
||||
|
||||
---
|
||||
|
||||
## Replay Buffer
|
||||
|
||||
### ReplayStarting
|
||||
@ -947,6 +986,7 @@ The volume of a source has changed.
|
||||
| ---- | :---: | ------------|
|
||||
| `sourceName` | _String_ | Source name |
|
||||
| `volume` | _float_ | Source volume |
|
||||
| `volumeDb` | _float_ | Source volume in Decibel |
|
||||
|
||||
|
||||
---
|
||||
@ -1809,13 +1849,14 @@ _No additional response items._
|
||||
- Added in v4.9.0
|
||||
|
||||
Pause or play a media source. Supports ffmpeg and vlc media sources (as of OBS v25.0.8)
|
||||
Note :Leaving out `playPause` toggles the current pause state
|
||||
|
||||
**Request Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ------------|
|
||||
| `sourceName` | _String_ | Source name. |
|
||||
| `playPause` | _boolean_ | Whether to pause or play the source. `false` for play, `true` for pause. |
|
||||
| `playPause` | _boolean_ | (optional) Whether to pause or play the source. `false` for play, `true` for pause. |
|
||||
|
||||
|
||||
**Response Items:**
|
||||
@ -2170,6 +2211,56 @@ Set the volume of the specified source. Default request format uses mul, NOT SLI
|
||||
|
||||
_No additional response items._
|
||||
|
||||
---
|
||||
|
||||
### SetTracks
|
||||
|
||||
|
||||
- Unreleased
|
||||
|
||||
Changes whether an audio track is active for a source.
|
||||
|
||||
**Request Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ------------|
|
||||
| `sourceName` | _String_ | Source name. |
|
||||
| `track` | _int_ | Audio tracks 1-6. |
|
||||
| `active` | _boolean_ | Whether audio track is active or not. |
|
||||
|
||||
|
||||
**Response Items:**
|
||||
|
||||
_No additional response items._
|
||||
|
||||
---
|
||||
|
||||
### GetTracks
|
||||
|
||||
|
||||
- Unreleased
|
||||
|
||||
Gets whether an audio track is active for a source.
|
||||
|
||||
**Request Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ------------|
|
||||
| `sourceName` | _String_ | Source name. |
|
||||
|
||||
|
||||
**Response Items:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ------------|
|
||||
| `track1` | _boolean_ | |
|
||||
| `track2` | _boolean_ | |
|
||||
| `track3` | _boolean_ | |
|
||||
| `track4` | _boolean_ | |
|
||||
| `track5` | _boolean_ | |
|
||||
| `track6` | _boolean_ | |
|
||||
|
||||
|
||||
---
|
||||
|
||||
### GetMute
|
||||
@ -2235,6 +2326,29 @@ Inverts the mute status of a specified source.
|
||||
|
||||
_No additional response items._
|
||||
|
||||
---
|
||||
|
||||
### GetSourceActive
|
||||
|
||||
|
||||
- Unreleased
|
||||
|
||||
Get the source's active status of a specified source (if it is showing in the final mix).
|
||||
|
||||
**Request Fields:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ------------|
|
||||
| `sourceName` | _String_ | Source name. |
|
||||
|
||||
|
||||
**Response Items:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ------------|
|
||||
| `sourceActive` | _boolean_ | Source active status of the source. |
|
||||
|
||||
|
||||
---
|
||||
|
||||
### GetAudioActive
|
||||
@ -3698,7 +3812,7 @@ Creates a scene item in a scene. In other words, this is how you add a source in
|
||||
| ---- | :---: | ------------|
|
||||
| `sceneName` | _String_ | Name of the scene to create the scene item in |
|
||||
| `sourceName` | _String_ | Name of the source to be added |
|
||||
| `setVisible` | _boolean_ | Whether to make the sceneitem visible on creation or not. Default `true` |
|
||||
| `setVisible` | _boolean (optional)_ | Whether to make the sceneitem visible on creation or not. Default `true` |
|
||||
|
||||
|
||||
**Response Items:**
|
||||
@ -3836,7 +3950,7 @@ Changes the order of scene items in the requested scene.
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ------------|
|
||||
| `scene` | _String (optional)_ | Name of the scene to reorder (defaults to current). |
|
||||
| `items` | _Array<Scene>_ | Ordered list of objects with name and/or id specified. Id preferred due to uniqueness per scene |
|
||||
| `items` | _Array<Object>_ | 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. |
|
||||
|
||||
@ -3933,9 +4047,11 @@ _No specified parameters._
|
||||
| `streaming` | _boolean_ | Current streaming status. |
|
||||
| `recording` | _boolean_ | Current recording status. |
|
||||
| `recording-paused` | _boolean_ | If recording is paused. |
|
||||
| `virtualcam` | _boolean_ | Current virtual cam status. |
|
||||
| `preview-only` | _boolean_ | Always false. Retrocompatibility with OBSRemote. |
|
||||
| `stream-timecode` | _String (optional)_ | Time elapsed since streaming started (only present if currently streaming). |
|
||||
| `rec-timecode` | _String (optional)_ | Time elapsed since recording started (only present if currently recording). |
|
||||
| `virtualcam-timecode` | _String (optional)_ | Time elapsed since virtual cam started (only present if virtual cam currently active). |
|
||||
|
||||
|
||||
---
|
||||
@ -4446,3 +4562,79 @@ _No additional response items._
|
||||
|
||||
---
|
||||
|
||||
## Virtual Cam
|
||||
|
||||
### GetVirtualCamStatus
|
||||
|
||||
|
||||
- Unreleased
|
||||
|
||||
Get current virtual cam status.
|
||||
|
||||
**Request Fields:**
|
||||
|
||||
_No specified parameters._
|
||||
|
||||
**Response Items:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | :---: | ------------|
|
||||
| `isVirtualCam` | _boolean_ | Current virtual camera status. |
|
||||
| `virtualCamTimecode` | _String (optional)_ | Time elapsed since virtual cam started (only present if virtual cam currently active). |
|
||||
|
||||
|
||||
---
|
||||
|
||||
### StartStopVirtualCam
|
||||
|
||||
|
||||
- Unreleased
|
||||
|
||||
Toggle virtual cam on or off (depending on the current virtual cam state).
|
||||
|
||||
**Request Fields:**
|
||||
|
||||
_No specified parameters._
|
||||
|
||||
**Response Items:**
|
||||
|
||||
_No additional response items._
|
||||
|
||||
---
|
||||
|
||||
### StartVirtualCam
|
||||
|
||||
|
||||
- Unreleased
|
||||
|
||||
Start virtual cam.
|
||||
Will return an `error` if virtual cam is already active.
|
||||
|
||||
**Request Fields:**
|
||||
|
||||
_No specified parameters._
|
||||
|
||||
**Response Items:**
|
||||
|
||||
_No additional response items._
|
||||
|
||||
---
|
||||
|
||||
### StopVirtualCam
|
||||
|
||||
|
||||
- Unreleased
|
||||
|
||||
Stop virtual cam.
|
||||
Will return an `error` if virtual cam is not active.
|
||||
|
||||
**Request Fields:**
|
||||
|
||||
_No specified parameters._
|
||||
|
||||
**Response Items:**
|
||||
|
||||
_No additional response items._
|
||||
|
||||
---
|
||||
|
||||
|
@ -35,4 +35,4 @@ auth_response_hash = binary_sha256(auth_response_string)
|
||||
auth_response = base64_encode(auth_response_hash)
|
||||
```
|
||||
|
||||
You can also refer to any of the client libraries listed on the [README](README.md) for examples of how to authenticate.
|
||||
You can also refer to any of the [client libraries](https://github.com/Palakis/obs-websocket#for-developers) listed on the README for examples of how to authenticate.
|
||||
|
@ -124,7 +124,7 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void* private
|
||||
case OBS_FRONTEND_EVENT_FINISHED_LOADING:
|
||||
owner->hookTransitionPlaybackEvents();
|
||||
break;
|
||||
|
||||
|
||||
case OBS_FRONTEND_EVENT_SCENE_CHANGED:
|
||||
owner->OnSceneChange();
|
||||
break;
|
||||
@ -202,6 +202,14 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void* private
|
||||
owner->OnRecordingResumed();
|
||||
break;
|
||||
|
||||
case OBS_FRONTEND_EVENT_VIRTUALCAM_STARTED:
|
||||
owner->OnVirtualCamStarted();
|
||||
break;
|
||||
|
||||
case OBS_FRONTEND_EVENT_VIRTUALCAM_STOPPED:
|
||||
owner->OnVirtualCamStopped();
|
||||
break;
|
||||
|
||||
case OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTING:
|
||||
owner->OnReplayStarting();
|
||||
break;
|
||||
@ -281,7 +289,7 @@ void WSEvents::connectSourceSignals(obs_source_t* source) {
|
||||
signal_handler_connect(sh, "filter_add", OnSourceFilterAdded, this);
|
||||
signal_handler_connect(sh, "filter_remove", OnSourceFilterRemoved, this);
|
||||
signal_handler_connect(sh, "reorder_filters", OnSourceFilterOrderChanged, this);
|
||||
|
||||
|
||||
signal_handler_connect(sh, "media_play", OnMediaPlaying, this);
|
||||
signal_handler_connect(sh, "media_pause", OnMediaPaused, this);
|
||||
signal_handler_connect(sh, "media_restart", OnMediaRestarted, this);
|
||||
@ -339,7 +347,7 @@ void WSEvents::disconnectSourceSignals(obs_source_t* source) {
|
||||
signal_handler_disconnect(sh, "transition_start", OnTransitionBegin, this);
|
||||
signal_handler_disconnect(sh, "transition_stop", OnTransitionEnd, this);
|
||||
signal_handler_disconnect(sh, "transition_video_stop", OnTransitionVideoEnd, this);
|
||||
|
||||
|
||||
signal_handler_disconnect(sh, "media_play", OnMediaPlaying, this);
|
||||
signal_handler_disconnect(sh, "media_pause", OnMediaPaused, this);
|
||||
signal_handler_disconnect(sh, "media_restart", OnMediaRestarted, this);
|
||||
@ -425,6 +433,11 @@ uint64_t WSEvents::getRecordingTime() {
|
||||
return getOutputRunningTime(recordingOutput);
|
||||
}
|
||||
|
||||
uint64_t WSEvents::getVirtualCamTime() {
|
||||
OBSOutputAutoRelease virtualCamOutput = obs_frontend_get_virtualcam_output();
|
||||
return getOutputRunningTime(virtualCamOutput);
|
||||
}
|
||||
|
||||
QString WSEvents::getStreamingTimecode() {
|
||||
return Utils::nsToTimestamp(getStreamingTime());
|
||||
}
|
||||
@ -433,6 +446,10 @@ QString WSEvents::getRecordingTimecode() {
|
||||
return Utils::nsToTimestamp(getRecordingTime());
|
||||
}
|
||||
|
||||
QString WSEvents::getVirtualCamTimecode() {
|
||||
return Utils::nsToTimestamp(getVirtualCamTime());
|
||||
}
|
||||
|
||||
OBSDataAutoRelease getMediaSourceData(calldata_t* data) {
|
||||
OBSDataAutoRelease fields = obs_data_create();
|
||||
OBSSource source = calldata_get_pointer<obs_source_t>(data, "source");
|
||||
@ -472,7 +489,7 @@ void WSEvents::OnSceneChange() {
|
||||
* Note: This event is not fired when the scenes are reordered.
|
||||
*
|
||||
* @return {Array<Scene>} `scenes` Scenes list.
|
||||
*
|
||||
*
|
||||
* @api events
|
||||
* @name ScenesChanged
|
||||
* @category scenes
|
||||
@ -490,7 +507,7 @@ void WSEvents::OnSceneListChange() {
|
||||
* Triggered when switching to another scene collection or when renaming the current scene collection.
|
||||
*
|
||||
* @return {String} `sceneCollection` Name of the new current scene collection.
|
||||
*
|
||||
*
|
||||
* @api events
|
||||
* @name SceneCollectionChanged
|
||||
* @category scenes
|
||||
@ -513,7 +530,7 @@ void WSEvents::OnSceneCollectionChange() {
|
||||
*
|
||||
* @return {Array<Object>} `sceneCollections` Scene collections list.
|
||||
* @return {String} `sceneCollections.*.name` Scene collection name.
|
||||
*
|
||||
*
|
||||
* @api events
|
||||
* @name SceneCollectionListChanged
|
||||
* @category scenes
|
||||
@ -556,7 +573,7 @@ void WSEvents::OnTransitionChange() {
|
||||
*
|
||||
* @return {Array<Object>} `transitions` Transitions list.
|
||||
* @return {String} `transitions.*.name` Transition name.
|
||||
*
|
||||
*
|
||||
* @api events
|
||||
* @name TransitionListChanged
|
||||
* @category transitions
|
||||
@ -585,7 +602,7 @@ void WSEvents::OnTransitionListChange() {
|
||||
* Triggered when switching to another profile or when renaming the current profile.
|
||||
*
|
||||
* @return {String} `profile` Name of the new current profile.
|
||||
*
|
||||
*
|
||||
* @api events
|
||||
* @name ProfileChanged
|
||||
* @category profiles
|
||||
@ -602,7 +619,7 @@ void WSEvents::OnProfileChange() {
|
||||
*
|
||||
* @return {Array<Object>} `profiles` Profiles list.
|
||||
* @return {String} `profiles.*.name` Profile name.
|
||||
*
|
||||
*
|
||||
* @api events
|
||||
* @name ProfileListChanged
|
||||
* @category profiles
|
||||
@ -682,10 +699,10 @@ void WSEvents::OnStreamStopped() {
|
||||
|
||||
/**
|
||||
* A request to start recording has been issued.
|
||||
*
|
||||
*
|
||||
* Note: `recordingFilename` is not provided in this event because this information
|
||||
* is not available at the time this event is emitted.
|
||||
*
|
||||
*
|
||||
* @api events
|
||||
* @name RecordingStarting
|
||||
* @category recording
|
||||
@ -699,7 +716,7 @@ void WSEvents::OnRecordingStarting() {
|
||||
* Recording started successfully.
|
||||
*
|
||||
* @return {String} `recordingFilename` Absolute path to the file of the current recording.
|
||||
*
|
||||
*
|
||||
* @api events
|
||||
* @name RecordingStarted
|
||||
* @category recording
|
||||
@ -715,7 +732,7 @@ void WSEvents::OnRecordingStarted() {
|
||||
* A request to stop recording has been issued.
|
||||
*
|
||||
* @return {String} `recordingFilename` Absolute path to the file of the current recording.
|
||||
*
|
||||
*
|
||||
* @api events
|
||||
* @name RecordingStopping
|
||||
* @category recording
|
||||
@ -731,7 +748,7 @@ void WSEvents::OnRecordingStopping() {
|
||||
* Recording stopped successfully.
|
||||
*
|
||||
* @return {String} `recordingFilename` Absolute path to the file of the current recording.
|
||||
*
|
||||
*
|
||||
* @api events
|
||||
* @name RecordingStopped
|
||||
* @category recording
|
||||
@ -767,6 +784,30 @@ void WSEvents::OnRecordingResumed() {
|
||||
broadcastUpdate("RecordingResumed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Virtual cam started successfully.
|
||||
*
|
||||
* @api events
|
||||
* @name VirtualCamStarted
|
||||
* @category virtual cam
|
||||
* @since unreleased
|
||||
*/
|
||||
void WSEvents::OnVirtualCamStarted() {
|
||||
broadcastUpdate("VirtualCamStarted");
|
||||
}
|
||||
|
||||
/**
|
||||
* Virtual cam stopped successfully.
|
||||
*
|
||||
* @api events
|
||||
* @name VirtualCamStopped
|
||||
* @category virtual cam
|
||||
* @since unreleased
|
||||
*/
|
||||
void WSEvents::OnVirtualCamStopped() {
|
||||
broadcastUpdate("VirtualCamStopped");
|
||||
}
|
||||
|
||||
/**
|
||||
* A request to start the replay buffer has been issued.
|
||||
*
|
||||
@ -1002,10 +1043,10 @@ void WSEvents::TransitionDurationChanged(int ms) {
|
||||
*
|
||||
* @return {String} `name` Transition name.
|
||||
* @return {String} `type` Transition type.
|
||||
* @return {int} `duration` Transition duration (in milliseconds).
|
||||
* Will be -1 for any transition with a fixed duration,
|
||||
* @return {int} `duration` Transition duration (in milliseconds).
|
||||
* Will be -1 for any transition with a fixed duration,
|
||||
* such as a Stinger, due to limitations of the OBS API.
|
||||
* @return {String} `from-scene` Source scene of the transition
|
||||
* @return {String (optional)} `from-scene` Source scene of the transition
|
||||
* @return {String} `to-scene` Destination scene of the transition
|
||||
*
|
||||
* @api events
|
||||
@ -1057,7 +1098,7 @@ void WSEvents::OnTransitionEnd(void* param, calldata_t* data) {
|
||||
* @return {String} `name` Transition name.
|
||||
* @return {String} `type` Transition type.
|
||||
* @return {int} `duration` Transition duration (in milliseconds).
|
||||
* @return {String} `from-scene` Source scene of the transition
|
||||
* @return {String (optional)} `from-scene` Source scene of the transition
|
||||
* @return {String} `to-scene` Destination scene of the transition
|
||||
*
|
||||
* @api events
|
||||
@ -1148,6 +1189,7 @@ void WSEvents::OnSourceDestroy(void* param, calldata_t* data) {
|
||||
*
|
||||
* @return {String} `sourceName` Source name
|
||||
* @return {float} `volume` Source volume
|
||||
* @return {float} `volumeDb` Source volume in Decibel
|
||||
*
|
||||
* @api events
|
||||
* @name SourceVolumeChanged
|
||||
@ -1167,9 +1209,15 @@ void WSEvents::OnSourceVolumeChange(void* param, calldata_t* data) {
|
||||
return;
|
||||
}
|
||||
|
||||
double volumeDb = obs_mul_to_db(volume);
|
||||
if (volumeDb == -INFINITY) {
|
||||
volumeDb = -100.0;
|
||||
}
|
||||
|
||||
OBSDataAutoRelease fields = obs_data_create();
|
||||
obs_data_set_string(fields, "sourceName", obs_source_get_name(source));
|
||||
obs_data_set_double(fields, "volume", volume);
|
||||
obs_data_set_double(fields, "volumeDb", volumeDb);
|
||||
self->broadcastUpdate("SourceVolumeChanged", fields);
|
||||
}
|
||||
|
||||
@ -1383,7 +1431,7 @@ void WSEvents::OnSourceFilterAdded(void* param, calldata_t* data) {
|
||||
if (!filter) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
self->connectFilterSignals(filter);
|
||||
|
||||
OBSDataAutoRelease filterSettings = obs_source_get_settings(filter);
|
||||
|
@ -48,9 +48,11 @@ public:
|
||||
|
||||
uint64_t getStreamingTime();
|
||||
uint64_t getRecordingTime();
|
||||
uint64_t getVirtualCamTime();
|
||||
|
||||
QString getStreamingTimecode();
|
||||
QString getRecordingTimecode();
|
||||
QString getVirtualCamTimecode();
|
||||
|
||||
obs_data_t* GetStats();
|
||||
|
||||
@ -101,6 +103,9 @@ private:
|
||||
void OnRecordingStopped();
|
||||
void OnRecordingPaused();
|
||||
void OnRecordingResumed();
|
||||
|
||||
void OnVirtualCamStarted();
|
||||
void OnVirtualCamStopped();
|
||||
|
||||
void OnReplayStarting();
|
||||
void OnReplayStarted();
|
||||
|
@ -121,9 +121,12 @@ const QHash<QString, RpcMethodHandler> WSRequestHandler::messageMap{
|
||||
{ "GetSourceTypesList", &WSRequestHandler::GetSourceTypesList },
|
||||
{ "GetVolume", &WSRequestHandler::GetVolume },
|
||||
{ "SetVolume", &WSRequestHandler::SetVolume },
|
||||
{ "SetAudioTracks", &WSRequestHandler::SetAudioTracks },
|
||||
{ "GetAudioTracks", &WSRequestHandler::GetAudioTracks },
|
||||
{ "GetMute", &WSRequestHandler::GetMute },
|
||||
{ "SetMute", &WSRequestHandler::SetMute },
|
||||
{ "ToggleMute", &WSRequestHandler::ToggleMute },
|
||||
{ "GetSourceActive", &WSRequestHandler::GetSourceActive },
|
||||
{ "GetAudioActive", &WSRequestHandler::GetAudioActive },
|
||||
{ "SetSourceName", &WSRequestHandler::SetSourceName },
|
||||
{ "SetSyncOffset", &WSRequestHandler::SetSyncOffset },
|
||||
@ -160,6 +163,12 @@ const QHash<QString, RpcMethodHandler> WSRequestHandler::messageMap{
|
||||
{ "GetStreamSettings", &WSRequestHandler::GetStreamSettings },
|
||||
{ "SaveStreamSettings", &WSRequestHandler::SaveStreamSettings },
|
||||
{ "SendCaptions", &WSRequestHandler::SendCaptions },
|
||||
|
||||
// Category: VirtualCam
|
||||
{ "GetVirtualCamStatus", &WSRequestHandler::GetVirtualCamStatus },
|
||||
{ "StartStopVirtualCam", &WSRequestHandler::StartStopVirtualCam },
|
||||
{ "StartVirtualCam", &WSRequestHandler::StartVirtualCam },
|
||||
{ "StopVirtualCam", &WSRequestHandler::StopVirtualCam },
|
||||
|
||||
// Category: Studio Mode
|
||||
{ "GetStudioModeStatus", &WSRequestHandler::GetStudioModeStatus },
|
||||
|
@ -138,9 +138,12 @@ class WSRequestHandler {
|
||||
RpcResponse GetSourceTypesList(const RpcRequest&);
|
||||
RpcResponse GetVolume(const RpcRequest&);
|
||||
RpcResponse SetVolume(const RpcRequest&);
|
||||
RpcResponse SetAudioTracks(const RpcRequest&);
|
||||
RpcResponse GetAudioTracks(const RpcRequest&);
|
||||
RpcResponse GetMute(const RpcRequest&);
|
||||
RpcResponse SetMute(const RpcRequest&);
|
||||
RpcResponse ToggleMute(const RpcRequest&);
|
||||
RpcResponse GetSourceActive(const RpcRequest&);
|
||||
RpcResponse GetAudioActive(const RpcRequest&);
|
||||
RpcResponse SetSourceName(const RpcRequest&);
|
||||
RpcResponse SetSyncOffset(const RpcRequest&);
|
||||
@ -177,6 +180,12 @@ class WSRequestHandler {
|
||||
RpcResponse GetStreamSettings(const RpcRequest&);
|
||||
RpcResponse SaveStreamSettings(const RpcRequest&);
|
||||
RpcResponse SendCaptions(const RpcRequest&);
|
||||
|
||||
// Category: Virtual Cam
|
||||
RpcResponse GetVirtualCamStatus(const RpcRequest&);
|
||||
RpcResponse StartStopVirtualCam(const RpcRequest&);
|
||||
RpcResponse StartVirtualCam(const RpcRequest&);
|
||||
RpcResponse StopVirtualCam(const RpcRequest&);
|
||||
|
||||
// Category: Studio Mode
|
||||
RpcResponse GetStudioModeStatus(const RpcRequest&);
|
||||
|
@ -44,9 +44,10 @@ QString getSourceMediaState(obs_source_t *source)
|
||||
|
||||
/**
|
||||
* Pause or play a media source. Supports ffmpeg and vlc media sources (as of OBS v25.0.8)
|
||||
* Note :Leaving out `playPause` toggles the current pause state
|
||||
*
|
||||
* @param {String} `sourceName` Source name.
|
||||
* @param {boolean} `playPause` Whether to pause or play the source. `false` for play, `true` for pause.
|
||||
* @param {boolean} `playPause` (optional) Whether to pause or play the source. `false` for play, `true` for pause.
|
||||
*
|
||||
* @api requests
|
||||
* @name PlayPauseMedia
|
||||
@ -54,7 +55,7 @@ QString getSourceMediaState(obs_source_t *source)
|
||||
* @since 4.9.0
|
||||
*/
|
||||
RpcResponse WSRequestHandler::PlayPauseMedia(const RpcRequest& request) {
|
||||
if ((!request.hasField("sourceName")) || (!request.hasField("playPause"))) {
|
||||
if (!request.hasField("sourceName")) {
|
||||
return request.failed("missing request parameters");
|
||||
}
|
||||
|
||||
@ -68,8 +69,16 @@ RpcResponse WSRequestHandler::PlayPauseMedia(const RpcRequest& request) {
|
||||
if (!source) {
|
||||
return request.failed("specified source doesn't exist");
|
||||
}
|
||||
|
||||
obs_source_media_play_pause(source, playPause);
|
||||
if (!request.hasField("playPause")) {
|
||||
if (obs_source_media_get_state(source) == obs_media_state::OBS_MEDIA_STATE_PLAYING) {
|
||||
obs_source_media_play_pause(source, true);
|
||||
} else {
|
||||
obs_source_media_play_pause(source, false);
|
||||
}
|
||||
} else {
|
||||
bool playPause = obs_data_get_bool(request.parameters(), "playPause");
|
||||
obs_source_media_play_pause(source, playPause);
|
||||
}
|
||||
return request.success();
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
* @property {boolean} `flags.encoded` Output is encoded
|
||||
* @property {boolean} `flags.multiTrack` Output uses several audio tracks
|
||||
* @property {boolean} `flags.service` Output uses a service
|
||||
* @property {Object} `settings` Output name
|
||||
* @property {Object} `settings` Output settings
|
||||
* @property {boolean} `active` Output status (active or not)
|
||||
* @property {boolean} `reconnecting` Output reconnection status (reconnecting or not)
|
||||
* @property {double} `congestion` Output congestion
|
||||
|
@ -652,7 +652,7 @@ RpcResponse WSRequestHandler::DeleteSceneItem(const RpcRequest& request) {
|
||||
*
|
||||
* @param {String} `sceneName` Name of the scene to create the scene item in
|
||||
* @param {String} `sourceName` Name of the source to be added
|
||||
* @param {boolean} `setVisible` Whether to make the sceneitem visible on creation or not. Default `true`
|
||||
* @param {boolean (optional)} `setVisible` Whether to make the sceneitem visible on creation or not. Default `true`
|
||||
*
|
||||
* @return {int} `itemId` Numerical ID of the created scene item
|
||||
*
|
||||
|
@ -100,7 +100,8 @@ RpcResponse WSRequestHandler::CreateScene(const RpcRequest& request) {
|
||||
if (source) {
|
||||
return request.failed("scene with this name already exists");
|
||||
}
|
||||
obs_scene_create(sceneName);
|
||||
obs_scene_t *createdScene = obs_scene_create(sceneName);
|
||||
obs_scene_release(createdScene);
|
||||
return request.success();
|
||||
}
|
||||
|
||||
@ -108,7 +109,7 @@ RpcResponse WSRequestHandler::CreateScene(const RpcRequest& request) {
|
||||
* 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 {Array<Object>} `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.
|
||||
*
|
||||
|
@ -315,6 +315,96 @@ RpcResponse WSRequestHandler::SetVolume(const RpcRequest& request)
|
||||
return request.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes whether an audio track is active for a source.
|
||||
*
|
||||
* @param {String} `sourceName` Source name.
|
||||
* @param {int} `track` Audio tracks 1-6.
|
||||
* @param {boolean} `active` Whether audio track is active or not.
|
||||
*
|
||||
* @api requests
|
||||
* @name SetTracks
|
||||
* @category sources
|
||||
* @since unreleased
|
||||
*/
|
||||
RpcResponse WSRequestHandler::SetAudioTracks(const RpcRequest& request)
|
||||
{
|
||||
if (!request.hasField("sourceName") || !request.hasField("track") || !request.hasField("active")) {
|
||||
return request.failed("missing request parameters");
|
||||
}
|
||||
|
||||
QString sourceName = obs_data_get_string(request.parameters(), "sourceName");
|
||||
bool active = obs_data_get_bool(request.parameters(), "active");
|
||||
int track = obs_data_get_int(request.parameters(), "track")-1;
|
||||
|
||||
if (sourceName.isEmpty() || track > 5 || track < 0) {
|
||||
return request.failed("invalid request parameters");
|
||||
}
|
||||
|
||||
OBSSourceAutoRelease source = obs_get_source_by_name(sourceName.toUtf8());
|
||||
if (!source) {
|
||||
return request.failed("specified source doesn't exist");
|
||||
}
|
||||
|
||||
uint32_t mixers = obs_source_get_audio_mixers(source);
|
||||
|
||||
if (active && !(mixers & (1 << track)))
|
||||
mixers |= (1 << track);
|
||||
else if (mixers & (1 << track))
|
||||
mixers &= ~(1 << track);
|
||||
|
||||
obs_source_set_audio_mixers(source, mixers);
|
||||
|
||||
return request.success();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets whether an audio track is active for a source.
|
||||
*
|
||||
* @param {String} `sourceName` Source name.
|
||||
*
|
||||
* @return {boolean} `track1`
|
||||
* @return {boolean} `track2`
|
||||
* @return {boolean} `track3`
|
||||
* @return {boolean} `track4`
|
||||
* @return {boolean} `track5`
|
||||
* @return {boolean} `track6`
|
||||
*
|
||||
* @api requests
|
||||
* @name GetTracks
|
||||
* @category sources
|
||||
* @since unreleased
|
||||
*/
|
||||
RpcResponse WSRequestHandler::GetAudioTracks(const RpcRequest& request)
|
||||
{
|
||||
if (!request.hasField("sourceName")) {
|
||||
return request.failed("missing request parameters");
|
||||
}
|
||||
|
||||
QString sourceName = obs_data_get_string(request.parameters(), "sourceName");
|
||||
if (sourceName.isEmpty()) {
|
||||
return request.failed("invalid request parameters");
|
||||
}
|
||||
|
||||
OBSSourceAutoRelease source = obs_get_source_by_name(sourceName.toUtf8());
|
||||
if (!source) {
|
||||
return request.failed("specified source doesn't exist");
|
||||
}
|
||||
|
||||
uint32_t mixers = obs_source_get_audio_mixers(source);
|
||||
|
||||
OBSDataAutoRelease response = obs_data_create();
|
||||
obs_data_set_string(response, "name", obs_source_get_name(source));
|
||||
obs_data_set_bool(response, "track1", mixers & (1 << 0));
|
||||
obs_data_set_bool(response, "track2", mixers & (1 << 1));
|
||||
obs_data_set_bool(response, "track3", mixers & (1 << 2));
|
||||
obs_data_set_bool(response, "track4", mixers & (1 << 3));
|
||||
obs_data_set_bool(response, "track5", mixers & (1 << 4));
|
||||
obs_data_set_bool(response, "track6", mixers & (1 << 5));
|
||||
return request.success(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mute status of a specified source.
|
||||
*
|
||||
@ -414,6 +504,40 @@ RpcResponse WSRequestHandler::ToggleMute(const RpcRequest& request)
|
||||
return request.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source's active status of a specified source (if it is showing in the final mix).
|
||||
*
|
||||
* @param {String} `sourceName` Source name.
|
||||
*
|
||||
* @return {boolean} `sourceActive` Source active status of the source.
|
||||
*
|
||||
* @api requests
|
||||
* @name GetSourceActive
|
||||
* @category sources
|
||||
* @since unreleased
|
||||
*/
|
||||
RpcResponse WSRequestHandler::GetSourceActive(const RpcRequest& request)
|
||||
{
|
||||
if (!request.hasField("sourceName")) {
|
||||
return request.failed("missing request parameters");
|
||||
}
|
||||
|
||||
QString sourceName = obs_data_get_string(request.parameters(), "sourceName");
|
||||
if (sourceName.isEmpty()) {
|
||||
return request.failed("invalid request parameters");
|
||||
}
|
||||
|
||||
OBSSourceAutoRelease source = obs_get_source_by_name(sourceName.toUtf8());
|
||||
if (!source) {
|
||||
return request.failed("specified source doesn't exist");
|
||||
}
|
||||
|
||||
OBSDataAutoRelease response = obs_data_create();
|
||||
obs_data_set_bool(response, "sourceActive", obs_source_active(source));
|
||||
|
||||
return request.success(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the audio's active status of a specified source.
|
||||
*
|
||||
|
@ -12,9 +12,11 @@
|
||||
* @return {boolean} `streaming` Current streaming status.
|
||||
* @return {boolean} `recording` Current recording status.
|
||||
* @return {boolean} `recording-paused` If recording is paused.
|
||||
* @return {boolean} `virtualcam` Current virtual cam status.
|
||||
* @return {boolean} `preview-only` Always false. Retrocompatibility with OBSRemote.
|
||||
* @return {String (optional)} `stream-timecode` Time elapsed since streaming started (only present if currently streaming).
|
||||
* @return {String (optional)} `rec-timecode` Time elapsed since recording started (only present if currently recording).
|
||||
* @return {String (optional)} `virtualcam-timecode` Time elapsed since virtual cam started (only present if virtual cam currently active).
|
||||
*
|
||||
* @api requests
|
||||
* @name GetStreamingStatus
|
||||
@ -28,6 +30,7 @@ RpcResponse WSRequestHandler::GetStreamingStatus(const RpcRequest& request) {
|
||||
obs_data_set_bool(data, "streaming", obs_frontend_streaming_active());
|
||||
obs_data_set_bool(data, "recording", obs_frontend_recording_active());
|
||||
obs_data_set_bool(data, "recording-paused", obs_frontend_recording_paused());
|
||||
obs_data_set_bool(data, "virtualcam", obs_frontend_virtualcam_active());
|
||||
obs_data_set_bool(data, "preview-only", false);
|
||||
|
||||
if (obs_frontend_streaming_active()) {
|
||||
@ -40,6 +43,11 @@ RpcResponse WSRequestHandler::GetStreamingStatus(const RpcRequest& request) {
|
||||
obs_data_set_string(data, "rec-timecode", recordingTimecode.toUtf8().constData());
|
||||
}
|
||||
|
||||
if (obs_frontend_virtualcam_active()) {
|
||||
QString virtualCamTimecode = events->getVirtualCamTimecode();
|
||||
obs_data_set_string(data, "virtualcam-timecode", virtualCamTimecode.toUtf8().constData());
|
||||
}
|
||||
|
||||
return request.success(data);
|
||||
}
|
||||
|
||||
|
79
src/WSRequestHandler_VirtualCam.cpp
Normal file
79
src/WSRequestHandler_VirtualCam.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
#include "obs-websocket.h"
|
||||
#include "Utils.h"
|
||||
#include "WSEvents.h"
|
||||
|
||||
#include "WSRequestHandler.h"
|
||||
|
||||
/**
|
||||
* Get current virtual cam status.
|
||||
*
|
||||
* @return {boolean} `isVirtualCam` Current virtual camera status.
|
||||
* @return {String (optional)} `virtualCamTimecode` Time elapsed since virtual cam started (only present if virtual cam currently active).
|
||||
*
|
||||
* @api requests
|
||||
* @name GetVirtualCamStatus
|
||||
* @category virtual cam
|
||||
* @since unreleased
|
||||
*/
|
||||
RpcResponse WSRequestHandler::GetVirtualCamStatus(const RpcRequest& request) {
|
||||
auto events = GetEventsSystem();
|
||||
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
obs_data_set_bool(data, "isVirtualCam", obs_frontend_virtualcam_active());
|
||||
|
||||
if (obs_frontend_virtualcam_active()) {
|
||||
QString virtualCamTimecode = events->getVirtualCamTimecode();
|
||||
obs_data_set_string(data, "virtualCamTimecode", virtualCamTimecode.toUtf8().constData());
|
||||
}
|
||||
|
||||
return request.success(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle virtual cam on or off (depending on the current virtual cam state).
|
||||
*
|
||||
* @api requests
|
||||
* @name StartStopVirtualCam
|
||||
* @category virtual cam
|
||||
* @since unreleased
|
||||
*/
|
||||
RpcResponse WSRequestHandler::StartStopVirtualCam(const RpcRequest& request) {
|
||||
(obs_frontend_virtualcam_active() ? obs_frontend_stop_virtualcam() : obs_frontend_start_virtualcam());
|
||||
return request.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start virtual cam.
|
||||
* Will return an `error` if virtual cam is already active.
|
||||
*
|
||||
* @api requests
|
||||
* @name StartVirtualCam
|
||||
* @category virtual cam
|
||||
* @since unreleased
|
||||
*/
|
||||
RpcResponse WSRequestHandler::StartVirtualCam(const RpcRequest& request) {
|
||||
if (obs_frontend_virtualcam_active()) {
|
||||
return request.failed("virtual cam already active");
|
||||
}
|
||||
|
||||
obs_frontend_start_virtualcam();
|
||||
return request.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop virtual cam.
|
||||
* Will return an `error` if virtual cam is not active.
|
||||
*
|
||||
* @api requests
|
||||
* @name StopVirtualCam
|
||||
* @category virtual cam
|
||||
* @since unreleased
|
||||
*/
|
||||
RpcResponse WSRequestHandler::StopVirtualCam(const RpcRequest& request) {
|
||||
if (!obs_frontend_virtualcam_active()) {
|
||||
return request.failed("virtual cam not active");
|
||||
}
|
||||
|
||||
obs_frontend_stop_virtualcam();
|
||||
return request.success();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user