mirror of
https://github.com/Palakis/obs-websocket.git
synced 2024-08-30 18:12:16 +00:00
Merge branch 'master' into docs-formatting
This commit is contained in:
commit
d7de347b37
2
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@ -69,8 +69,8 @@ body:
|
||||
label: obs-websocket Version
|
||||
description: What version of obs-websocket are you using?
|
||||
options:
|
||||
- 5.0.0-alpha3
|
||||
- 5.0.0-alpha2
|
||||
- 5.0.0-alpha1
|
||||
- 4.9.1
|
||||
- 4.9.0
|
||||
- Git
|
||||
|
264
.github/workflows/main.yml
vendored
264
.github/workflows/main.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: "CI Multiplatform Build"
|
||||
name: 'CI Multiplatform Build'
|
||||
|
||||
on:
|
||||
push:
|
||||
@ -18,15 +18,15 @@ on:
|
||||
jobs:
|
||||
windows:
|
||||
name: 'Windows 32/64-bit'
|
||||
runs-on: [windows-latest]
|
||||
runs-on: [windows-2019]
|
||||
if: contains(github.event.head_commit.message, '[skip ci]') != true
|
||||
env:
|
||||
QT_CACHE_VERSION: '2' # Change whenever updating OBS dependencies URL, in order to force a cache reset
|
||||
QT_VERSION: '5.15.2'
|
||||
WINDOWS_DEPS_CACHE_VERSION: '1' # Change whenever updating Qt dependency URL, in order to force a cache reset
|
||||
WINDOWS_DEPS_VERSION: '2019'
|
||||
CMAKE_GENERATOR: "Visual Studio 16 2019"
|
||||
CMAKE_SYSTEM_VERSION: "10.0"
|
||||
CMAKE_GENERATOR: 'Visual Studio 16 2019'
|
||||
CMAKE_SYSTEM_VERSION: '10.0'
|
||||
steps:
|
||||
- name: 'Add msbuild to PATH'
|
||||
uses: microsoft/setup-msbuild@v1.0.2
|
||||
@ -35,20 +35,20 @@ jobs:
|
||||
with:
|
||||
path: ${{ github.workspace }}/obs-websocket
|
||||
submodules: 'recursive'
|
||||
- name: 'Checkout OBS-Studio'
|
||||
- name: 'Checkout OBS Studio'
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: obsproject/obs-studio
|
||||
path: ${{ github.workspace }}/obs-studio
|
||||
submodules: 'recursive'
|
||||
- name: 'Get OBS-Studio Git Info'
|
||||
- name: 'Get OBS Studio Git Info'
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/obs-studio
|
||||
run: |
|
||||
git fetch --prune --unshallow
|
||||
echo "OBS_GIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
||||
echo "OBS_GIT_TAG=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV
|
||||
- name: 'Checkout last OBS-Studio release (${{ env.OBS_GIT_TAG }})'
|
||||
- name: 'Checkout last OBS Studio release (${{ env.OBS_GIT_TAG }})'
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/obs-studio
|
||||
run: |
|
||||
@ -78,8 +78,6 @@ jobs:
|
||||
with:
|
||||
path: Qt_${{ env.QT_VERSION }}.7z
|
||||
key: 'qtdep-${{ env.QT_CACHE_VERSION }} | ${{ runner.os }}'
|
||||
restore-keys: |
|
||||
qtdep-${{ env.QT_CACHE_VERSION }} | ${{ runner.os }}
|
||||
- name: 'Download Prerequisite: Qt'
|
||||
if: steps.qtcache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
@ -87,20 +85,18 @@ jobs:
|
||||
- name: 'Extract Prerequisite: Qt'
|
||||
run: |
|
||||
7z x Qt_${{ env.QT_VERSION }}.7z -o"${{ github.workspace }}\cmbuild\QT"
|
||||
- name: 'Restore Cached OBS-Studio Dependencies'
|
||||
- name: 'Restore Cached OBS Studio Dependencies'
|
||||
id: obscache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ github.workspace }}\cmbuild\deps\**
|
||||
key: 'obsdep-${{ env.WINDOWS_DEPS_CACHE_VERSION }} | ${{ runner.os }}'
|
||||
restore-keys: |
|
||||
obsdep-${{ env.WINDOWS_DEPS_CACHE_VERSION }} | ${{ runner.os }}
|
||||
- name: 'Install Prerequisite: Pre-built OBS-Studio dependencies'
|
||||
- name: 'Install Prerequisite: Pre-built OBS Studio dependencies'
|
||||
if: steps.obscache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
curl -kLO https://cdn-fastly.obsproject.com/downloads/dependencies${{ env.WINDOWS_DEPS_VERSION }}.zip -f --retry 5 -C -
|
||||
7z x dependencies${{ env.WINDOWS_DEPS_VERSION }}.zip -o"${{ github.workspace }}\cmbuild\deps"
|
||||
- name: 'Restore OBS-Studio 32-bit Build v${{ env.OBS_GIT_TAG }} from Cache'
|
||||
- name: 'Restore OBS Studio 32-bit Build v${{ env.OBS_GIT_TAG }} from Cache'
|
||||
id: build-cache-obs-32
|
||||
uses: actions/cache@v2
|
||||
env:
|
||||
@ -108,22 +104,20 @@ jobs:
|
||||
with:
|
||||
path: ${{ github.workspace }}/obs-studio/build32
|
||||
key: ${{ runner.os }}-${{ env.CACHE_NAME }}-${{ env.OBS_GIT_TAG }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ env.CACHE_NAME }}-
|
||||
- name: 'Configure OBS-Studio 32-bit'
|
||||
- name: 'Configure OBS Studio 32-bit'
|
||||
if: steps.build-cache-obs-32.outputs.cache-hit != 'true'
|
||||
working-directory: ${{ github.workspace }}/obs-studio
|
||||
run: |
|
||||
if(!(Test-Path -Path ".\build32")){New-Item -ItemType directory -Path .\build32}
|
||||
cd .\build32
|
||||
cmake -G "${{ env.CMAKE_GENERATOR }}" -A Win32 -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DQTDIR="${{ github.workspace }}\cmbuild\QT\${{ env.QT_VERSION }}\msvc2019" -DDepsPath="${{ github.workspace }}\cmbuild\deps\win32" -DCOPIED_DEPENDENCIES=NO -DCOPY_DEPENDENCIES=YES -DBUILD_BROWSER=OFF ..
|
||||
- name: 'Build OBS-Studio 32-bit'
|
||||
- name: 'Build OBS Studio 32-bit'
|
||||
if: steps.build-cache-obs-32.outputs.cache-hit != 'true'
|
||||
working-directory: ${{ github.workspace }}/obs-studio
|
||||
run: |
|
||||
msbuild /m /p:Configuration=RelWithDebInfo .\build32\libobs\libobs.vcxproj
|
||||
msbuild /m /p:Configuration=RelWithDebInfo .\build32\UI\obs-frontend-api\obs-frontend-api.vcxproj
|
||||
- name: 'Restore OBS-Studio 64-bit Build v${{ env.OBS_GIT_TAG }} from Cache'
|
||||
- name: 'Restore OBS Studio 64-bit Build v${{ env.OBS_GIT_TAG }} from Cache'
|
||||
id: build-cache-obs-64
|
||||
uses: actions/cache@v1
|
||||
env:
|
||||
@ -131,16 +125,14 @@ jobs:
|
||||
with:
|
||||
path: ${{ github.workspace }}/obs-studio/build64
|
||||
key: ${{ runner.os }}-${{ env.CACHE_NAME }}-${{ env.OBS_GIT_TAG }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ env.CACHE_NAME }}-
|
||||
- name: 'Configure OBS-Studio 64-bit'
|
||||
- name: 'Configure OBS Studio 64-bit'
|
||||
if: steps.build-cache-obs-64.outputs.cache-hit != 'true'
|
||||
working-directory: ${{ github.workspace }}/obs-studio
|
||||
run: |
|
||||
if(!(Test-Path -Path ".\build64")){New-Item -ItemType directory -Path .\build64}
|
||||
cd .\build64
|
||||
cmake -G "${{ env.CMAKE_GENERATOR }}" -A x64 -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DQTDIR="${{ github.workspace }}\cmbuild\QT\${{ env.QT_VERSION }}\msvc2019_64" -DDepsPath="${{ github.workspace }}\cmbuild\deps\win64" -DCOPIED_DEPENDENCIES=NO -DCOPY_DEPENDENCIES=YES -DBUILD_BROWSER=OFF ..
|
||||
- name: 'Build OBS-Studio 64-bit'
|
||||
- name: 'Build OBS Studio 64-bit'
|
||||
if: steps.build-cache-obs-64.outputs.cache-hit != 'true'
|
||||
working-directory: ${{ github.workspace }}/obs-studio
|
||||
run: |
|
||||
@ -188,7 +180,7 @@ jobs:
|
||||
name: 'obs-websocket-${{ env.PACKAGE_VERSION }}-Windows-Installer'
|
||||
path: ${{ github.workspace }}/obs-websocket/package/*.exe
|
||||
ubuntu64:
|
||||
name: "Linux/Ubuntu 64-bit"
|
||||
name: 'Linux/Ubuntu 64-bit'
|
||||
runs-on: [ubuntu-latest]
|
||||
if: contains(github.event.head_commit.message, '[skip ci]') != true
|
||||
steps:
|
||||
@ -197,20 +189,20 @@ jobs:
|
||||
with:
|
||||
path: ${{ github.workspace }}/obs-websocket
|
||||
submodules: 'recursive'
|
||||
- name: 'Checkout OBS-Studio'
|
||||
- name: 'Checkout OBS Studio'
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: obsproject/obs-studio
|
||||
path: ${{ github.workspace }}/obs-studio
|
||||
submodules: 'recursive'
|
||||
- name: 'Get OBS-Studio Git Info'
|
||||
- name: 'Get OBS Studio Git Info'
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/obs-studio
|
||||
run: |
|
||||
git fetch --prune --unshallow
|
||||
echo "OBS_GIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
||||
echo "OBS_GIT_TAG=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV
|
||||
- name: 'Checkout last OBS-Studio release (${{ env.OBS_GIT_TAG }})'
|
||||
- name: 'Checkout last OBS Studio release (${{ env.OBS_GIT_TAG }})'
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/obs-studio
|
||||
run: |
|
||||
@ -284,21 +276,21 @@ jobs:
|
||||
libx11-xcb-dev \
|
||||
libxcb1-dev \
|
||||
libxss-dev \
|
||||
- name: 'Configure OBS-Studio'
|
||||
- name: 'Configure OBS Studio'
|
||||
working-directory: ${{ github.workspace }}/obs-studio
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir ./build
|
||||
cd ./build
|
||||
cmake -DDISABLE_PLUGINS=YES -DENABLE_SCRIPTING=NO -DUNIX_STRUCTURE=YES -DCMAKE_INSTALL_PREFIX=/usr ..
|
||||
- name: 'Build OBS-Studio'
|
||||
- name: 'Build OBS Studio'
|
||||
working-directory: ${{ github.workspace }}/obs-studio
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
cd ./build
|
||||
make -j4 libobs obs-frontend-api
|
||||
- name: 'Install OBS-Studio'
|
||||
- name: 'Install OBS Studio'
|
||||
working-directory: ${{ github.workspace }}/obs-studio
|
||||
shell: bash
|
||||
run: |
|
||||
@ -316,7 +308,7 @@ jobs:
|
||||
if [ "${{ env.GIT_TAG }}" ] ; then \
|
||||
cmake -DLIBOBS_INCLUDE_DIR=${{ github.workspace }}/obs-studio/libobs -DCMAKE_INSTALL_PREFIX=/usr -DUSE_UBUNTU_FIX=TRUE -DOBS_WEBSOCKET_VERSION_SUFFIX="${{ env.CMAKE_VERSION_SUFFIX }}" -DCMAKE_BUILD_TYPE=Release .. ; \
|
||||
else \
|
||||
cmake -DLIBOBS_INCLUDE_DIR=${{ github.workspace }}/obs-studio/libobs -DCMAKE_INSTALL_PREFIX=/usr -DUSE_UBUNTU_FIX=TRUE -DOBS_WEBSOCKET_VERSION_SUFFIX="${{ env.CMAKE_VERSION_SUFFIX }}" .. ; \
|
||||
cmake -DLIBOBS_INCLUDE_DIR=${{ github.workspace }}/obs-studio/libobs -DCMAKE_INSTALL_PREFIX=/usr -DUSE_UBUNTU_FIX=TRUE -DOBS_WEBSOCKET_VERSION_SUFFIX="${{ env.CMAKE_VERSION_SUFFIX }}" -DPLUGIN_TESTS=TRUE .. ; \
|
||||
fi
|
||||
- name: 'Build obs-websocket'
|
||||
working-directory: ${{ github.workspace }}/obs-websocket
|
||||
@ -355,3 +347,213 @@ jobs:
|
||||
with:
|
||||
name: 'obs-websocket-${{ env.PACKAGE_VERSION }}-Ubuntu64'
|
||||
path: '${{ github.workspace }}/obs-websocket/package/*.deb'
|
||||
macOS:
|
||||
name: 'macOS 64-bit'
|
||||
runs-on: [macos-latest]
|
||||
if: contains(github.event.head_commit.message, '[skip ci]') != true
|
||||
env:
|
||||
MACOS_DEPS_VERSION: '2022-01-01'
|
||||
MACOS_DEPS_CACHE_VERSION: '2' # Change whenever updating dependencies version, in order to force a cache reset
|
||||
steps:
|
||||
- name: 'Checkout obs-websocket'
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: ${{ github.workspace }}/obs-websocket
|
||||
submodules: 'recursive'
|
||||
- name: 'Checkout OBS Studio'
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: obsproject/obs-studio
|
||||
path: ${{ github.workspace }}/obs-studio
|
||||
submodules: 'recursive'
|
||||
- name: 'Install Prerequisite: Binary Signing Certificate'
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: apple-actions/import-codesign-certs@v1
|
||||
with:
|
||||
p12-file-base64: ${{ secrets.MACOS_SIGNING_CERT }}
|
||||
p12-password: ${{ secrets.MACOS_SIGNING_CERT_PASSWORD }}
|
||||
create-keychain: true
|
||||
keychain-password: ${{ secrets.MACOS_TEMP_CI_KEYCHAIN_PASSWORD }}
|
||||
- name: 'Install Prerequisite: Installer Signing Certificate'
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: apple-actions/import-codesign-certs@v1
|
||||
with:
|
||||
p12-file-base64: ${{ secrets.MACOS_INSTALLER_CERT }}
|
||||
p12-password: ${{ secrets.MACOS_INSTALLER_CERT_PASSWORD }}
|
||||
create-keychain: false
|
||||
keychain-password: ${{ secrets.MACOS_TEMP_CI_KEYCHAIN_PASSWORD }}
|
||||
- name: 'Get OBS Studio Git Info'
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/obs-studio
|
||||
run: |
|
||||
git fetch --prune --unshallow
|
||||
echo "OBS_GIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
||||
echo "OBS_GIT_TAG=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV
|
||||
- name: 'Checkout last OBS Studio release (${{ env.OBS_GIT_TAG }})'
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/obs-studio
|
||||
run: |
|
||||
git checkout ${{ env.OBS_GIT_TAG }}
|
||||
git submodule update
|
||||
- name: 'Get obs-websocket git info'
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/obs-websocket
|
||||
run: |
|
||||
git fetch --prune --unshallow
|
||||
GIT_HASH=$(git rev-parse --short HEAD)
|
||||
echo "GIT_HASH=$GIT_HASH" >> $GITHUB_ENV
|
||||
GIT_TAG=$(git describe --exact-match --tags --abbrev=0) || GIT_TAG=""
|
||||
echo "GIT_TAG=$GIT_TAG" >> $GITHUB_ENV
|
||||
if [ "$GIT_TAG" ] ; then \
|
||||
VERSION="$GIT_TAG" \
|
||||
VERSION_SUFFIX=$(echo "$GIT_TAG" | cut -c6-20) ; \
|
||||
else \
|
||||
VERSION="$GIT_HASH-git" \
|
||||
VERSION_SUFFIX="-$GIT_HASH-git" ; \
|
||||
fi
|
||||
echo "PACKAGE_VERSION=$VERSION" >> $GITHUB_ENV
|
||||
echo "CMAKE_VERSION_SUFFIX=$VERSION_SUFFIX" >> $GITHUB_ENV
|
||||
- name: 'Install Packages'
|
||||
shell: bash
|
||||
run: |
|
||||
curl -L -O http://s.sudre.free.fr/Software/files/Packages.dmg
|
||||
sudo hdiutil attach ./Packages.dmg
|
||||
sudo installer -pkg /Volumes/Packages\ 1.2.10/Install\ Packages.pkg -target /
|
||||
- name: 'Restore Cached Qt & OBS Studio dependencies'
|
||||
id: deps-cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ github.workspace }}/obsdeps/**
|
||||
key: 'deps-cache-${{ env.MACOS_DEPS_CACHE_VERSION }} | ${{ runner.os }}'
|
||||
- name: 'Install Prerequisite: Qt + OBS Studio dependencies'
|
||||
if: steps.deps-cache.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p obsdeps
|
||||
curl -L -O https://github.com/obsproject/obs-deps/releases/download/${{ env.MACOS_DEPS_VERSION }}/macos-deps-qt-${{ env.MACOS_DEPS_VERSION }}-universal.tar.xz
|
||||
tar -xf macos-deps-qt-${{ env.MACOS_DEPS_VERSION }}-universal.tar.xz -C "./obsdeps"
|
||||
curl -L -O https://github.com/obsproject/obs-deps/releases/download/${{ env.MACOS_DEPS_VERSION }}/macos-deps-${{ env.MACOS_DEPS_VERSION }}-universal.tar.xz
|
||||
tar -xf macos-deps-${{ env.MACOS_DEPS_VERSION }}-universal.tar.xz -C "./obsdeps"
|
||||
- run: xattr -r -d com.apple.quarantine ./obsdeps
|
||||
shell: bash
|
||||
- name: 'Configue OBS Studio'
|
||||
if: steps.cache-obs-build.outputs.cache-hit != 'true'
|
||||
working-directory: ${{ github.workspace }}/obs-studio
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p ./build
|
||||
cd ./build
|
||||
cmake .. \
|
||||
-DQTDIR=${{ github.workspace }}/obsdeps \
|
||||
-DDepsPath=${{ github.workspace }}/obsdeps \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 \
|
||||
-DDISABLE_PLUGINS=true \
|
||||
-DENABLE_SCRIPTING=0 \
|
||||
-DCMAKE_PREFIX_PATH=${{ github.workspace }}/obsdeps/lib/cmake
|
||||
- name: 'Build OBS Studio'
|
||||
if: steps.cache-obs-build.outputs.cache-hit != 'true'
|
||||
working-directory: ${{ github.workspace }}/obs-studio/build
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
make -j4 libobs obs-frontend-api
|
||||
- name: 'Configure obs-websocket'
|
||||
working-directory: ${{ github.workspace }}/obs-websocket
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake .. \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 \
|
||||
-DQTDIR=${{ github.workspace }}/obsdeps \
|
||||
-DLIBOBS_INCLUDE_DIR=${{ github.workspace }}/obs-studio/libobs \
|
||||
-DLIBOBS_LIB=${{ github.workspace }}/obs-studio/libobs \
|
||||
-DOBS_FRONTEND_LIB="${{ github.workspace }}/obs-studio/build/UI/obs-frontend-api/libobs-frontend-api.dylib" \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr
|
||||
- name: 'Build obs-websocket'
|
||||
working-directory: ${{ github.workspace }}/obs-websocket/build
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
make -j4
|
||||
- name: 'Relink Qt'
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/obs-websocket/build
|
||||
run: |
|
||||
install_name_tool \
|
||||
-change /tmp/obsdeps/lib/QtWidgets.framework/Versions/5/QtWidgets \
|
||||
@executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets \
|
||||
-change /tmp/obsdeps/lib/QtGui.framework/Versions/5/QtGui \
|
||||
@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui \
|
||||
-change /tmp/obsdeps/lib/QtCore.framework/Versions/5/QtCore \
|
||||
@executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore \
|
||||
-change /tmp/obsdeps/lib/QtNetwork.framework/Versions/5/QtNetwork \
|
||||
@executable_path/../Frameworks/QtNetwork.framework/Versions/5/QtNetwork \
|
||||
-change /tmp/obsdeps/lib/QtSvg.framework/Versions/5/QtSvg \
|
||||
@executable_path/../Frameworks/QtSvg.framework/Versions/5/QtSvg \
|
||||
./obs-websocket.so
|
||||
- name: 'Sign plugin binary'
|
||||
if: github.event_name != 'pull_request'
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/obs-websocket/build
|
||||
run: |
|
||||
codesign --sign "${{ secrets.MACOS_SIGNING_IDENTITY }}" ./obs-websocket.so
|
||||
- name: 'Set PR Artifact Filename'
|
||||
shell: bash
|
||||
run: |
|
||||
echo "MACOS_FILENAME=obs-websocket-${{ env.PACKAGE_VERSION }}-macOS.pkg" >> $GITHUB_ENV
|
||||
echo "MACOS_FILENAME_UNSIGNED=obs-websocket-${{ env.PACKAGE_VERSION }}-macOS-Unsigned.pkg" >> $GITHUB_ENV
|
||||
- name: 'Package ${{ env.MACOS_FILENAME_UNSIGNED }}'
|
||||
if: success()
|
||||
working-directory: ${{ github.workspace }}/obs-websocket
|
||||
shell: bash
|
||||
run: |
|
||||
packagesbuild ./CI/macos/obs-websocket.pkgproj
|
||||
mv ./release/obs-websocket.pkg ./release/${{ env.MACOS_FILENAME_UNSIGNED }}
|
||||
- name: 'Sign plugin package'
|
||||
if: ${{ env.GIT_TAG != '' }}
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/obs-websocket
|
||||
run: |
|
||||
productsign \
|
||||
--sign "${{ secrets.MACOS_INSTALLER_IDENTITY }}" \
|
||||
./release/${{ env.MACOS_FILENAME_UNSIGNED }} \
|
||||
./release/${{ env.MACOS_FILENAME }}
|
||||
rm ./release/${{ env.MACOS_FILENAME_UNSIGNED }}
|
||||
- name: 'Notarize package'
|
||||
if: ${{ env.GIT_TAG != '' }}
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/obs-websocket
|
||||
run: |
|
||||
zip -r ./release/${{ env.MACOS_FILENAME }}.zip ./release/${{ env.MACOS_FILENAME }}
|
||||
UPLOAD_RESULT=$(xcrun altool --notarize-app \
|
||||
--primary-bundle-id "com.obsproject.obs-websocket" \
|
||||
--username "${{ secrets.MACOS_NOTARIZATION_USERNAME }}" \
|
||||
--password "${{ secrets.MACOS_NOTARIZATION_PASSWORD }}" \
|
||||
--asc-provider "${{ secrets.ASC_PROVIDER_SHORTNAME }}" \
|
||||
--file "./release/${{ env.MACOS_FILENAME }}.zip")
|
||||
|
||||
rm ./release/${{ env.MACOS_FILENAME }}.zip
|
||||
|
||||
REQUEST_UUID=$(echo $UPLOAD_RESULT | awk -F ' = ' '/RequestUUID/ {print $2}')
|
||||
|
||||
# Pieces of code borrowed from rednoah/notarized-app
|
||||
while sleep 30 && date; do
|
||||
CHECK_RESULT=$(xcrun altool \
|
||||
--notarization-info "$REQUEST_UUID" \
|
||||
--username "${{ secrets.MACOS_NOTARIZATION_USERNAME }}" \
|
||||
--password "${{ secrets.MACOS_NOTARIZATION_PASSWORD }}" \
|
||||
--asc-provider "${{ secrets.ASC_PROVIDER_SHORTNAME }}")
|
||||
|
||||
if ! grep -q "Status: in progress" <<< "$CHECK_RESULT"; then
|
||||
xcrun stapler staple ./release/${{ env.MACOS_FILENAME }}
|
||||
break
|
||||
fi
|
||||
done
|
||||
- name: 'Publish Packages'
|
||||
if: success()
|
||||
uses: actions/upload-artifact@v2-preview
|
||||
with:
|
||||
name: 'obs-websocket-${{ env.PACKAGE_VERSION }}-macOS'
|
||||
path: '${{ github.workspace }}/obs-websocket/release/*.pkg'
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -11,3 +11,4 @@
|
||||
/docs/node_modules/
|
||||
/src/plugin-macros.generated.h
|
||||
/installer/installer-windows.generated.iss
|
||||
/cmake-build-debug/
|
||||
|
@ -1,5 +0,0 @@
|
||||
brew "jack"
|
||||
brew "speexdsp"
|
||||
brew "cmake"
|
||||
brew "freetype"
|
||||
brew "fdk-aac"
|
@ -1,26 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
OSTYPE=$(uname)
|
||||
|
||||
if [ "${OSTYPE}" != "Darwin" ]; then
|
||||
echo "[obs-websocket - Error] macOS build script can be run on Darwin-type OS only."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
HAS_CMAKE=$(type cmake 2>/dev/null)
|
||||
|
||||
if [ "${HAS_CMAKE}" = "" ]; then
|
||||
echo "[obs-websocket - Error] CMake not installed - please run 'install-dependencies-macos.sh' first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[obs-websocket] Building 'obs-websocket' for macOS."
|
||||
mkdir -p build && cd build
|
||||
cmake .. \
|
||||
-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" \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||
&& make -j4
|
@ -1,39 +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
|
||||
|
||||
# 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
|
@ -1,57 +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 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
|
@ -514,7 +514,7 @@
|
||||
<key>CONCLUSION_ACTION</key>
|
||||
<integer>0</integer>
|
||||
<key>IDENTIFIER</key>
|
||||
<string>fr.palakis.obs-websocket</string>
|
||||
<string>com.obsproject.obs-websocket</string>
|
||||
<key>OVERWRITE_PERMISSIONS</key>
|
||||
<false/>
|
||||
<key>VERSION</key>
|
||||
|
@ -1,93 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
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
|
||||
fi
|
||||
|
||||
echo "[obs-websocket] Preparing package build"
|
||||
|
||||
GIT_HASH=$(git rev-parse --short HEAD)
|
||||
GIT_BRANCH_OR_TAG=$(git name-rev --name-only HEAD | awk -F/ '{print $NF}')
|
||||
|
||||
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 linking"
|
||||
install_name_tool \
|
||||
-change /tmp/obsdeps/lib/QtWidgets.framework/Versions/5/QtWidgets \
|
||||
@executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets \
|
||||
-change /tmp/obsdeps/lib/QtGui.framework/Versions/5/QtGui \
|
||||
@executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui \
|
||||
-change /tmp/obsdeps/lib/QtCore.framework/Versions/5/QtCore \
|
||||
@executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore \
|
||||
-change /tmp/obsdeps/lib/QtNetwork.framework/Versions/5/QtNetwork \
|
||||
@executable_path/../Frameworks/QtNetwork.framework/Versions/5/QtNetwork \
|
||||
-change /tmp/obsdeps/lib/QtSvg.framework/Versions/5/QtSvg \
|
||||
@executable_path/../Frameworks/QtSvg.framework/Versions/5/QtSvg \
|
||||
./build/obs-websocket.so
|
||||
|
||||
# Check if replacement worked
|
||||
echo "[obs-websocket] Dependencies for obs-websocket"
|
||||
otool -L ./build/obs-websocket.so
|
||||
|
||||
if [[ "$RELEASE_MODE" == "True" ]]; then
|
||||
echo "[obs-websocket] Signing plugin binary: obs-websocket.so"
|
||||
codesign --sign "$CODE_SIGNING_IDENTITY" ./build/obs-websocket.so
|
||||
else
|
||||
echo "[obs-websocket] Skipped plugin codesigning"
|
||||
fi
|
||||
|
||||
echo "[obs-websocket] Actual package build"
|
||||
packagesbuild ./CI/macos/obs-websocket.pkgproj
|
||||
|
||||
echo "[obs-websocket] Renaming obs-websocket.pkg to $FILENAME"
|
||||
mv ./release/obs-websocket.pkg ./release/$FILENAME_UNSIGNED
|
||||
|
||||
if [[ "$RELEASE_MODE" == "True" ]]; then
|
||||
echo "[obs-websocket] Signing installer: $FILENAME"
|
||||
productsign \
|
||||
--sign "$INSTALLER_SIGNING_IDENTITY" \
|
||||
./release/$FILENAME_UNSIGNED \
|
||||
./release/$FILENAME
|
||||
rm ./release/$FILENAME_UNSIGNED
|
||||
|
||||
echo "[obs-websocket] Submitting installer $FILENAME for notarization"
|
||||
zip -r ./release/$FILENAME.zip ./release/$FILENAME
|
||||
UPLOAD_RESULT=$(xcrun altool \
|
||||
--notarize-app \
|
||||
--primary-bundle-id "fr.palakis.obs-websocket" \
|
||||
--username "$AC_USERNAME" \
|
||||
--password "$AC_PASSWORD" \
|
||||
--asc-provider "$AC_PROVIDER_SHORTNAME" \
|
||||
--file "./release/$FILENAME.zip")
|
||||
rm ./release/$FILENAME.zip
|
||||
|
||||
REQUEST_UUID=$(echo $UPLOAD_RESULT | awk -F ' = ' '/RequestUUID/ {print $2}')
|
||||
echo "Request UUID: $REQUEST_UUID"
|
||||
|
||||
echo "[obs-websocket] Wait for notarization result"
|
||||
# Pieces of code borrowed from rednoah/notarized-app
|
||||
while sleep 30 && date; do
|
||||
CHECK_RESULT=$(xcrun altool \
|
||||
--notarization-info "$REQUEST_UUID" \
|
||||
--username "$AC_USERNAME" \
|
||||
--password "$AC_PASSWORD" \
|
||||
--asc-provider "$AC_PROVIDER_SHORTNAME")
|
||||
echo $CHECK_RESULT
|
||||
|
||||
if ! grep -q "Status: in progress" <<< "$CHECK_RESULT"; then
|
||||
echo "[obs-websocket] Staple ticket to installer: $FILENAME"
|
||||
xcrun stapler staple ./release/$FILENAME
|
||||
break
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "[obs-websocket] Skipped installer codesigning and notarization"
|
||||
fi
|
@ -103,6 +103,7 @@ set(obs-websocket_SOURCES
|
||||
src/eventhandler/EventHandler_Outputs.cpp
|
||||
src/eventhandler/EventHandler_SceneItems.cpp
|
||||
src/eventhandler/EventHandler_MediaInputs.cpp
|
||||
src/eventhandler/EventHandler_Ui.cpp
|
||||
src/requesthandler/RequestHandler.cpp
|
||||
src/requesthandler/RequestBatchHandler.cpp
|
||||
src/requesthandler/RequestHandler_General.cpp
|
||||
@ -110,10 +111,14 @@ set(obs-websocket_SOURCES
|
||||
src/requesthandler/RequestHandler_Sources.cpp
|
||||
src/requesthandler/RequestHandler_Scenes.cpp
|
||||
src/requesthandler/RequestHandler_Inputs.cpp
|
||||
src/requesthandler/RequestHandler_Transitions.cpp
|
||||
src/requesthandler/RequestHandler_Filters.cpp
|
||||
src/requesthandler/RequestHandler_SceneItems.cpp
|
||||
src/requesthandler/RequestHandler_Outputs.cpp
|
||||
src/requesthandler/RequestHandler_Stream.cpp
|
||||
src/requesthandler/RequestHandler_Record.cpp
|
||||
src/requesthandler/RequestHandler_MediaInputs.cpp
|
||||
src/requesthandler/RequestHandler_Ui.cpp
|
||||
src/requesthandler/rpc/Request.cpp
|
||||
src/requesthandler/rpc/RequestBatchRequest.cpp
|
||||
src/requesthandler/rpc/RequestResult.cpp
|
||||
@ -123,7 +128,14 @@ set(obs-websocket_SOURCES
|
||||
src/utils/Crypto.cpp
|
||||
src/utils/Json.cpp
|
||||
src/utils/Obs.cpp
|
||||
src/utils/ObsVolumeMeter.cpp
|
||||
src/utils/Obs_StringHelper.cpp
|
||||
src/utils/Obs_EnumHelper.cpp
|
||||
src/utils/Obs_NumberHelper.cpp
|
||||
src/utils/Obs_ArrayHelper.cpp
|
||||
src/utils/Obs_ObjectHelper.cpp
|
||||
src/utils/Obs_SearchHelper.cpp
|
||||
src/utils/Obs_ActionHelper.cpp
|
||||
src/utils/Obs_VolumeMeter.cpp
|
||||
src/utils/Platform.cpp
|
||||
src/utils/Compat.cpp
|
||||
deps/qr/cpp/QrCode.cpp)
|
||||
@ -150,8 +162,8 @@ set(obs-websocket_HEADERS
|
||||
src/utils/Crypto.h
|
||||
src/utils/Json.h
|
||||
src/utils/Obs.h
|
||||
src/utils/ObsVolumeMeter.h
|
||||
src/utils/ObsVolumeMeter_Helpers.h
|
||||
src/utils/Obs_VolumeMeter.h
|
||||
src/utils/Obs_VolumeMeter_Helpers.h
|
||||
src/utils/Platform.h
|
||||
src/utils/Compat.h
|
||||
src/utils/Utils.h
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
WebSocket API for OBS Studio.
|
||||
|
||||
[](https://github.com/obs-websocket/obs-websocket/actions/workflows/main.yml)
|
||||
[](https://github.com/obsproject/obs-websocket/actions/workflows/main.yml)
|
||||
[](https://discord.gg/WBaSQ3A)
|
||||
[](https://opencollective.com/obs-websocket-dev)
|
||||
|
||||
@ -30,7 +30,7 @@ It is **highly recommended** to protect obs-websocket with a password against un
|
||||
|
||||
### Client software
|
||||
|
||||
- (No known clients supporting 5.0.0 at the moment. Send a message in Discord if you have one!)
|
||||
- (No known clients supporting 5.0.0 at the moment. Ping us in the Discord if you have one!)
|
||||
|
||||
### Client libraries (for developers)
|
||||
|
||||
@ -39,10 +39,10 @@ Here's a list of available language APIs for obs-websocket:
|
||||
- Python 3.7+ (Asyncio): [simpleobsws](https://github.com/IRLToolkit/simpleobsws/tree/master) by IRLToolkit
|
||||
- Rust: [obws](https://github.com/dnaka91/obws/tree/v5-api) by dnaka91
|
||||
|
||||
The server is a typical Websockets server running by default on port 4444 (the port number can be changed in the Settings dialog under `Tools`).
|
||||
The 5.x server is a typical WebSocket server running by default on port 4455 (the port number can be changed in the Settings dialog under `Tools`).
|
||||
The protocol we use is documented in [PROTOCOL.md](docs/generated/protocol.md).
|
||||
|
||||
We'd like to know what you're building with or for obs-websocket. If you do something in this fashion, feel free to drop a message in `#project-showoff` in the [discord server!](https://discord.gg/WBaSQ3A)
|
||||
We'd like to know what you're building with obs-websocket! If you do something in this fashion, feel free to drop a message in `#project-showoff` in the [discord server!](https://discord.gg/WBaSQ3A)
|
||||
|
||||
## Contributors
|
||||
|
||||
|
2
deps/asio
vendored
2
deps/asio
vendored
@ -1 +1 @@
|
||||
Subproject commit b84e6c16b2ea907dbad94206b7510d85aafc0b42
|
||||
Subproject commit b73dc1d2c0ecb9452a87c26544d7f71e24342df6
|
@ -25,6 +25,7 @@ categoryOrder = [
|
||||
'Stream',
|
||||
'Record',
|
||||
'Media Inputs',
|
||||
'Ui',
|
||||
'High-Volume'
|
||||
]
|
||||
|
||||
|
@ -122,7 +122,7 @@ for comment in comments_raw:
|
||||
enumValue = field_to_string(comment['enumValue'])
|
||||
enum['enumValue'] = int(enumValue) if enumValue.isdigit() else enumValue
|
||||
else:
|
||||
enum['enumValue'] = None
|
||||
enum['enumValue'] = enum['enumIdentifier']
|
||||
|
||||
if enumType not in enums_raw:
|
||||
enums_raw[enumType] = {'enumIdentifiers': [enum]}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -22,6 +22,8 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
#include <obs.h>
|
||||
|
||||
#define OBS_WEBSOCKET_API_VERSION 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -41,7 +41,7 @@ Config::Config() :
|
||||
PasswordOverridden(false),
|
||||
FirstLoad(true),
|
||||
ServerEnabled(true),
|
||||
ServerPort(4444),
|
||||
ServerPort(4455),
|
||||
DebugEnabled(false),
|
||||
AlertsEnabled(false),
|
||||
AuthRequired(true),
|
||||
@ -70,7 +70,7 @@ void Config::Load()
|
||||
// future loads use the override flag.
|
||||
if (FirstLoad) {
|
||||
FirstLoad = false;
|
||||
if (!ServerPassword.isEmpty()) {
|
||||
if (ServerPassword.isEmpty()) {
|
||||
blog(LOG_INFO, "[Config::Load] (FirstLoad) Generating new server password.");
|
||||
ServerPassword = QString::fromStdString(Utils::Crypto::GeneratePassword());
|
||||
} else {
|
||||
|
@ -16,8 +16,7 @@ WebSocketApi::Vendor *get_vendor(calldata_t *cd)
|
||||
return static_cast<WebSocketApi::Vendor*>(voidVendor);
|
||||
}
|
||||
|
||||
WebSocketApi::WebSocketApi(EventCallback cb) :
|
||||
_eventCallback(cb)
|
||||
WebSocketApi::WebSocketApi()
|
||||
{
|
||||
blog_debug("[WebSocketApi::WebSocketApi] Setting up...");
|
||||
|
||||
@ -50,6 +49,11 @@ WebSocketApi::~WebSocketApi()
|
||||
blog_debug("[WebSocketApi::~WebSocketApi] Finished.");
|
||||
}
|
||||
|
||||
void WebSocketApi::SetEventCallback(EventCallback cb)
|
||||
{
|
||||
_eventCallback = cb;
|
||||
}
|
||||
|
||||
enum WebSocketApi::RequestReturnCode WebSocketApi::PerformVendorRequest(std::string vendorName, std::string requestType, obs_data_t *requestData, obs_data_t *responseData)
|
||||
{
|
||||
std::shared_lock l(_mutex);
|
||||
@ -196,6 +200,9 @@ void WebSocketApi::vendor_event_emit_cb(void *priv_data, calldata_t *cd)
|
||||
|
||||
auto eventData = static_cast<obs_data_t*>(voidEventData);
|
||||
|
||||
if (!c->_eventCallback)
|
||||
RETURN_FAILURE();
|
||||
|
||||
c->_eventCallback(v->_name, eventType, eventData);
|
||||
|
||||
RETURN_SUCCESS();
|
||||
|
@ -25,9 +25,11 @@ class WebSocketApi {
|
||||
std::map<std::string, obs_websocket_request_callback> _requests;
|
||||
};
|
||||
|
||||
WebSocketApi(EventCallback cb);
|
||||
WebSocketApi();
|
||||
~WebSocketApi();
|
||||
|
||||
void SetEventCallback(EventCallback cb);
|
||||
|
||||
enum RequestReturnCode PerformVendorRequest(std::string vendorName, std::string requestName, obs_data_t *requestData, obs_data_t *responseData);
|
||||
|
||||
static void get_ph_cb(void *priv_data, calldata_t *cd);
|
||||
|
@ -134,9 +134,13 @@ void EventHandler::ConnectSourceSignals(obs_source_t *source) // Applies to inpu
|
||||
signal_handler_connect(sh, "hide", HandleInputShowStateChanged, this);
|
||||
signal_handler_connect(sh, "mute", HandleInputMuteStateChanged, this);
|
||||
signal_handler_connect(sh, "volume", HandleInputVolumeChanged, this);
|
||||
signal_handler_connect(sh, "audio_balance", HandleInputAudioBalanceChanged, this);
|
||||
signal_handler_connect(sh, "audio_sync", HandleInputAudioSyncOffsetChanged, this);
|
||||
signal_handler_connect(sh, "audio_mixers", HandleInputAudioTracksChanged, this);
|
||||
//signal_handler_connect(sh, "audio_monitoring", HandleInputAudioMonitorTypeChanged, this);
|
||||
signal_handler_connect(sh, "audio_monitoring", HandleInputAudioMonitorTypeChanged, this);
|
||||
signal_handler_connect(sh, "filter_add", HandleSourceFilterCreated, this);
|
||||
signal_handler_connect(sh, "filter_remove", HandleSourceFilterRemoved, this);
|
||||
signal_handler_connect(sh, "reorder_filters", HandleSourceFilterListReindexed, this);
|
||||
|
||||
if (sourceType == OBS_SOURCE_TYPE_INPUT) {
|
||||
signal_handler_connect(sh, "media_started", HandleMediaInputPlaybackStarted, this);
|
||||
@ -156,6 +160,7 @@ void EventHandler::ConnectSourceSignals(obs_source_t *source) // Applies to inpu
|
||||
signal_handler_connect(sh, "reorder", HandleSceneItemListReindexed, this);
|
||||
signal_handler_connect(sh, "item_visible", HandleSceneItemEnableStateChanged, this);
|
||||
signal_handler_connect(sh, "item_locked", HandleSceneItemLockStateChanged, this);
|
||||
signal_handler_connect(sh, "item_select", HandleSceneItemSelected, this);
|
||||
signal_handler_connect(sh, "item_transform", HandleSceneItemTransformChanged, this);
|
||||
}
|
||||
}
|
||||
@ -174,9 +179,10 @@ void EventHandler::DisconnectSourceSignals(obs_source_t *source)
|
||||
signal_handler_disconnect(sh, "hide", HandleInputShowStateChanged, this);
|
||||
signal_handler_disconnect(sh, "mute", HandleInputMuteStateChanged, this);
|
||||
signal_handler_disconnect(sh, "volume", HandleInputVolumeChanged, this);
|
||||
signal_handler_disconnect(sh, "audio_balance", HandleInputAudioBalanceChanged, this);
|
||||
signal_handler_disconnect(sh, "audio_sync", HandleInputAudioSyncOffsetChanged, this);
|
||||
signal_handler_disconnect(sh, "audio_mixers", HandleInputAudioTracksChanged, this);
|
||||
//signal_handler_disconnect(sh, "audio_monitoring", HandleInputAudioMonitorTypeChanged, this);
|
||||
signal_handler_disconnect(sh, "audio_monitoring", HandleInputAudioMonitorTypeChanged, this);
|
||||
signal_handler_disconnect(sh, "media_started", HandleMediaInputPlaybackStarted, this);
|
||||
signal_handler_disconnect(sh, "media_ended", HandleMediaInputPlaybackEnded, this);
|
||||
signal_handler_disconnect(sh, "media_pause", SourceMediaPauseMultiHandler, this);
|
||||
@ -185,6 +191,9 @@ void EventHandler::DisconnectSourceSignals(obs_source_t *source)
|
||||
signal_handler_disconnect(sh, "media_stopped", SourceMediaStopMultiHandler, this);
|
||||
signal_handler_disconnect(sh, "media_next", SourceMediaNextMultiHandler, this);
|
||||
signal_handler_disconnect(sh, "media_previous", SourceMediaPreviousMultiHandler, this);
|
||||
signal_handler_disconnect(sh, "filter_add", HandleSourceFilterCreated, this);
|
||||
signal_handler_disconnect(sh, "filter_remove", HandleSourceFilterRemoved, this);
|
||||
signal_handler_disconnect(sh, "reorder_filters", HandleSourceFilterListReindexed, this);
|
||||
|
||||
// Scenes
|
||||
signal_handler_disconnect(sh, "item_add", HandleSceneItemCreated, this);
|
||||
@ -192,12 +201,37 @@ void EventHandler::DisconnectSourceSignals(obs_source_t *source)
|
||||
signal_handler_disconnect(sh, "reorder", HandleSceneItemListReindexed, this);
|
||||
signal_handler_disconnect(sh, "item_visible", HandleSceneItemEnableStateChanged, this);
|
||||
signal_handler_disconnect(sh, "item_locked", HandleSceneItemLockStateChanged, this);
|
||||
signal_handler_disconnect(sh, "item_select", HandleSceneItemSelected, this);
|
||||
signal_handler_disconnect(sh, "item_transform", HandleSceneItemTransformChanged, this);
|
||||
}
|
||||
|
||||
void EventHandler::ConnectFilterSignals(obs_source_t *filter)
|
||||
{
|
||||
if (!filter || obs_source_removed(filter))
|
||||
return;
|
||||
|
||||
DisconnectFilterSignals(filter);
|
||||
|
||||
signal_handler_t* sh = obs_source_get_signal_handler(filter);
|
||||
|
||||
signal_handler_connect(sh, "enable", HandleSourceFilterEnableStateChanged, this);
|
||||
signal_handler_connect(sh, "rename", HandleSourceFilterNameChanged, this);
|
||||
}
|
||||
|
||||
void EventHandler::DisconnectFilterSignals(obs_source_t *filter)
|
||||
{
|
||||
if (!filter)
|
||||
return;
|
||||
|
||||
signal_handler_t* sh = obs_source_get_signal_handler(filter);
|
||||
|
||||
signal_handler_disconnect(sh, "enable", HandleSourceFilterEnableStateChanged, this);
|
||||
signal_handler_disconnect(sh, "rename", HandleSourceFilterNameChanged, this);
|
||||
}
|
||||
|
||||
void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(private_data);
|
||||
auto eventHandler = static_cast<EventHandler*>(private_data);
|
||||
|
||||
if (!eventHandler->_obsLoaded.load()) {
|
||||
if (event == OBS_FRONTEND_EVENT_FINISHED_LOADING) {
|
||||
@ -207,18 +241,38 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_
|
||||
|
||||
// In the case that plugins become hotloadable, this will have to go back into `EventHandler::EventHandler()`
|
||||
// Enumerate inputs and connect each one
|
||||
obs_enum_sources([](void* param, obs_source_t* source) {
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
{
|
||||
auto enumInputs = [](void *param, obs_source_t *source) {
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
eventHandler->ConnectSourceSignals(source);
|
||||
|
||||
auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *param){
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
eventHandler->ConnectFilterSignals(filter);
|
||||
};
|
||||
obs_source_enum_filters(source, enumFilters, param);
|
||||
|
||||
return true;
|
||||
}, private_data);
|
||||
};
|
||||
obs_enum_sources(enumInputs, private_data);
|
||||
}
|
||||
|
||||
// Enumerate scenes and connect each one
|
||||
obs_enum_scenes([](void* param, obs_source_t* source) {
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
{
|
||||
auto enumScenes = [](void *param, obs_source_t *source) {
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
eventHandler->ConnectSourceSignals(source);
|
||||
|
||||
auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *param){
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
eventHandler->ConnectFilterSignals(filter);
|
||||
};
|
||||
obs_source_enum_filters(source, enumFilters, param);
|
||||
|
||||
return true;
|
||||
}, private_data);
|
||||
};
|
||||
obs_enum_scenes(enumScenes, private_data);
|
||||
}
|
||||
|
||||
blog_debug("[EventHandler::OnFrontendEvent] Finished.");
|
||||
|
||||
@ -240,18 +294,38 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_
|
||||
|
||||
// In the case that plugins become hotloadable, this will have to go back into `EventHandler::~EventHandler()`
|
||||
// Enumerate inputs and disconnect each one
|
||||
obs_enum_sources([](void* param, obs_source_t* source) {
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
{
|
||||
auto enumInputs = [](void *param, obs_source_t *source) {
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
eventHandler->DisconnectSourceSignals(source);
|
||||
|
||||
auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *param){
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
eventHandler->ConnectFilterSignals(filter);
|
||||
};
|
||||
obs_source_enum_filters(source, enumFilters, param);
|
||||
|
||||
return true;
|
||||
}, private_data);
|
||||
};
|
||||
obs_enum_sources(enumInputs, private_data);
|
||||
}
|
||||
|
||||
// Enumerate scenes and disconnect each one
|
||||
obs_enum_scenes([](void* param, obs_source_t* source) {
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
{
|
||||
auto enumScenes = [](void *param, obs_source_t *source) {
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
eventHandler->DisconnectSourceSignals(source);
|
||||
|
||||
auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *param){
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
eventHandler->ConnectFilterSignals(filter);
|
||||
};
|
||||
obs_source_enum_filters(source, enumFilters, param);
|
||||
|
||||
return true;
|
||||
}, private_data);
|
||||
};
|
||||
obs_enum_scenes(enumScenes, private_data);
|
||||
}
|
||||
|
||||
blog_debug("[EventHandler::OnFrontendEvent] Finished.");
|
||||
|
||||
@ -264,18 +338,18 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_
|
||||
break;
|
||||
|
||||
// Config
|
||||
//case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGING:
|
||||
// eventHandler->HandleCurrentSceneCollectionChanging();
|
||||
// break;
|
||||
case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGING:
|
||||
eventHandler->HandleCurrentSceneCollectionChanging();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED:
|
||||
eventHandler->HandleCurrentSceneCollectionChanged();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED:
|
||||
eventHandler->HandleSceneCollectionListChanged();
|
||||
break;
|
||||
//case OBS_FRONTEND_EVENT_PROFILE_CHANGING:
|
||||
// eventHandler->HandleCurrentProfileChanging();
|
||||
// break;
|
||||
case OBS_FRONTEND_EVENT_PROFILE_CHANGING:
|
||||
eventHandler->HandleCurrentProfileChanging();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_PROFILE_CHANGED:
|
||||
eventHandler->HandleCurrentProfileChanged();
|
||||
break;
|
||||
@ -285,7 +359,7 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_
|
||||
|
||||
// Scenes
|
||||
case OBS_FRONTEND_EVENT_SCENE_CHANGED:
|
||||
eventHandler->HandleCurrentSceneChanged();
|
||||
eventHandler->HandleCurrentProgramSceneChanged();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED:
|
||||
eventHandler->HandleCurrentPreviewSceneChanged();
|
||||
@ -296,10 +370,12 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_
|
||||
|
||||
// Transitions
|
||||
case OBS_FRONTEND_EVENT_TRANSITION_CHANGED:
|
||||
eventHandler->HandleCurrentSceneTransitionChanged();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED:
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_TRANSITION_DURATION_CHANGED:
|
||||
eventHandler->HandleCurrentSceneTransitionDurationChanged();
|
||||
break;
|
||||
|
||||
// Outputs
|
||||
@ -363,7 +439,7 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_
|
||||
// Only called for creation of a public source
|
||||
void EventHandler::SourceCreatedMultiHandler(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
// Don't react to signals until OBS has finished loading
|
||||
if (!eventHandler->_obsLoaded.load())
|
||||
@ -379,10 +455,6 @@ void EventHandler::SourceCreatedMultiHandler(void *param, calldata_t *data)
|
||||
case OBS_SOURCE_TYPE_INPUT:
|
||||
eventHandler->HandleInputCreated(source);
|
||||
break;
|
||||
case OBS_SOURCE_TYPE_FILTER:
|
||||
break;
|
||||
case OBS_SOURCE_TYPE_TRANSITION:
|
||||
break;
|
||||
case OBS_SOURCE_TYPE_SCENE:
|
||||
eventHandler->HandleSceneCreated(source);
|
||||
break;
|
||||
@ -394,7 +466,7 @@ void EventHandler::SourceCreatedMultiHandler(void *param, calldata_t *data)
|
||||
// Only called for destruction of a public source
|
||||
void EventHandler::SourceDestroyedMultiHandler(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
// We can't use any smart types here because releasing the source will cause infinite recursion
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
@ -413,10 +485,6 @@ void EventHandler::SourceDestroyedMultiHandler(void *param, calldata_t *data)
|
||||
// We have to call `InputRemoved` with source_destroy because source_removed is not called when an input's last scene item is removed
|
||||
eventHandler->HandleInputRemoved(source);
|
||||
break;
|
||||
case OBS_SOURCE_TYPE_FILTER:
|
||||
break;
|
||||
case OBS_SOURCE_TYPE_TRANSITION:
|
||||
break;
|
||||
case OBS_SOURCE_TYPE_SCENE:
|
||||
break;
|
||||
default:
|
||||
@ -426,7 +494,7 @@ void EventHandler::SourceDestroyedMultiHandler(void *param, calldata_t *data)
|
||||
|
||||
void EventHandler::SourceRemovedMultiHandler(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
if (!eventHandler->_obsLoaded.load())
|
||||
return;
|
||||
@ -438,10 +506,6 @@ void EventHandler::SourceRemovedMultiHandler(void *param, calldata_t *data)
|
||||
switch (obs_source_get_type(source)) {
|
||||
case OBS_SOURCE_TYPE_INPUT:
|
||||
break;
|
||||
case OBS_SOURCE_TYPE_FILTER:
|
||||
break;
|
||||
case OBS_SOURCE_TYPE_TRANSITION:
|
||||
break;
|
||||
case OBS_SOURCE_TYPE_SCENE:
|
||||
// Scenes emit the `removed` signal when they are removed from OBS, as expected
|
||||
eventHandler->HandleSceneRemoved(source);
|
||||
@ -453,7 +517,7 @@ void EventHandler::SourceRemovedMultiHandler(void *param, calldata_t *data)
|
||||
|
||||
void EventHandler::SourceRenamedMultiHandler(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
if (!eventHandler->_obsLoaded.load())
|
||||
return;
|
||||
@ -471,8 +535,6 @@ void EventHandler::SourceRenamedMultiHandler(void *param, calldata_t *data)
|
||||
case OBS_SOURCE_TYPE_INPUT:
|
||||
eventHandler->HandleInputNameChanged(source, oldSourceName, sourceName);
|
||||
break;
|
||||
case OBS_SOURCE_TYPE_FILTER:
|
||||
break;
|
||||
case OBS_SOURCE_TYPE_TRANSITION:
|
||||
break;
|
||||
case OBS_SOURCE_TYPE_SCENE:
|
||||
|
@ -22,12 +22,11 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
#include <atomic>
|
||||
#include <obs.hpp>
|
||||
#include <obs-frontend-api.h>
|
||||
#include <util/platform.h>
|
||||
|
||||
#include "types/EventSubscription.h"
|
||||
#include "../obs-websocket.h"
|
||||
#include "../utils/Obs.h"
|
||||
#include "../utils/ObsVolumeMeter.h"
|
||||
#include "../utils/Obs_VolumeMeter.h"
|
||||
#include "../plugin-macros.generated.h"
|
||||
|
||||
class EventHandler
|
||||
@ -59,6 +58,9 @@ class EventHandler
|
||||
void ConnectSourceSignals(obs_source_t *source);
|
||||
void DisconnectSourceSignals(obs_source_t *source);
|
||||
|
||||
void ConnectFilterSignals(obs_source_t *filter);
|
||||
void DisconnectFilterSignals(obs_source_t *filter);
|
||||
|
||||
void BroadcastEvent(uint64_t requiredIntent, std::string eventType, json eventData = nullptr, uint8_t rpcVersion = 0);
|
||||
|
||||
// Signal handler: frontend
|
||||
@ -95,7 +97,7 @@ class EventHandler
|
||||
void HandleSceneCreated(obs_source_t *source);
|
||||
void HandleSceneRemoved(obs_source_t *source);
|
||||
void HandleSceneNameChanged(obs_source_t *source, std::string oldSceneName, std::string sceneName);
|
||||
void HandleCurrentSceneChanged();
|
||||
void HandleCurrentProgramSceneChanged();
|
||||
void HandleCurrentPreviewSceneChanged();
|
||||
void HandleSceneListChanged();
|
||||
|
||||
@ -108,14 +110,14 @@ class EventHandler
|
||||
static void HandleInputShowStateChanged(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleInputMuteStateChanged(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleInputVolumeChanged(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleInputAudioBalanceChanged(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleInputAudioSyncOffsetChanged(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleInputAudioTracksChanged(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleInputAudioMonitorTypeChanged(void *param, calldata_t *data); // Direct callback
|
||||
|
||||
// Transitions
|
||||
void HandleTransitionCreated(obs_source_t *source);
|
||||
void HandleTransitionRemoved(obs_source_t *source);
|
||||
void HandleTransitionNameChanged(obs_source_t *source, std::string oldTransitionName, std::string transitionName);
|
||||
void HandleCurrentSceneTransitionChanged();
|
||||
void HandleCurrentSceneTransitionDurationChanged();
|
||||
|
||||
// Outputs
|
||||
void HandleStreamStateChanged(ObsOutputState state);
|
||||
@ -130,10 +132,18 @@ class EventHandler
|
||||
static void HandleSceneItemListReindexed(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleSceneItemEnableStateChanged(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleSceneItemLockStateChanged(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleSceneItemSelected(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleSceneItemTransformChanged(void *param, calldata_t *data); // Direct callback
|
||||
|
||||
// Media Inputs
|
||||
static void HandleMediaInputPlaybackStarted(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleMediaInputPlaybackEnded(void *param, calldata_t *data); // Direct callback
|
||||
void HandleMediaInputActionTriggered(obs_source_t *source, ObsMediaInputAction action);
|
||||
|
||||
// Filters
|
||||
static void HandleSourceFilterNameChanged(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleSourceFilterCreated(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleSourceFilterRemoved(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleSourceFilterListReindexed(void *param, calldata_t *data); // Direct callback
|
||||
static void HandleSourceFilterEnableStateChanged(void *param, calldata_t *data); // Direct callback
|
||||
};
|
||||
|
@ -80,7 +80,7 @@ void EventHandler::HandleCurrentSceneCollectionChanged()
|
||||
void EventHandler::HandleSceneCollectionListChanged()
|
||||
{
|
||||
json eventData;
|
||||
eventData["sceneCollections"] = Utils::Obs::ListHelper::GetSceneCollectionList();
|
||||
eventData["sceneCollections"] = Utils::Obs::ArrayHelper::GetSceneCollectionList();
|
||||
BroadcastEvent(EventSubscription::Config, "SceneCollectionListChanged", eventData);
|
||||
}
|
||||
|
||||
@ -140,6 +140,6 @@ void EventHandler::HandleCurrentProfileChanged()
|
||||
void EventHandler::HandleProfileListChanged()
|
||||
{
|
||||
json eventData;
|
||||
eventData["profiles"] = Utils::Obs::ListHelper::GetProfileList();
|
||||
eventData["profiles"] = Utils::Obs::ArrayHelper::GetProfileList();
|
||||
BroadcastEvent(EventSubscription::Config, "ProfileListChanged", eventData);
|
||||
}
|
||||
|
@ -18,3 +18,174 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "EventHandler.h"
|
||||
|
||||
/**
|
||||
* A filter has been added to a source.
|
||||
*
|
||||
* @dataField sourceName | String | Name of the source the filter was added to
|
||||
* @dataField filterName | String | Name of the filter
|
||||
* @dataField filterKind | String | The kind of the filter
|
||||
* @dataField filterIndex | Number | Index position of the filter
|
||||
* @dataField filterSettings | Object | The settings configured to the filter when it was created
|
||||
* @dataField defaultFilterSettings | Object | The default settings for the filter
|
||||
*
|
||||
* @eventType SourceFilterCreated
|
||||
* @eventSubscription Filters
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category filters
|
||||
*/
|
||||
void EventHandler::HandleSourceFilterCreated(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
obs_source_t *filter = GetCalldataPointer<obs_source_t>(data, "filter");
|
||||
|
||||
if (!(source && filter))
|
||||
return;
|
||||
|
||||
eventHandler->ConnectFilterSignals(filter);
|
||||
|
||||
std::string filterKind = obs_source_get_id(filter);
|
||||
OBSDataAutoRelease filterSettings = obs_source_get_settings(filter);
|
||||
OBSDataAutoRelease defaultFilterSettings = obs_get_source_defaults(filterKind.c_str());
|
||||
|
||||
json eventData;
|
||||
eventData["sourceName"] = obs_source_get_name(source);
|
||||
eventData["filterName"] = obs_source_get_name(filter);
|
||||
eventData["filterKind"] = filterKind;
|
||||
eventData["filterIndex"] = Utils::Obs::NumberHelper::GetSourceFilterIndex(source, filter);
|
||||
eventData["filterSettings"] = Utils::Json::ObsDataToJson(filterSettings);
|
||||
eventData["defaultFilterSettings"] = Utils::Json::ObsDataToJson(defaultFilterSettings, true);
|
||||
eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterCreated", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filter has been removed from a source.
|
||||
*
|
||||
* @dataField sourceName | String | Name of the source the filter was on
|
||||
* @dataField filterName | String | Name of the filter
|
||||
*
|
||||
* @eventType SourceFilterRemoved
|
||||
* @eventSubscription Filters
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category filters
|
||||
*/
|
||||
void EventHandler::HandleSourceFilterRemoved(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
obs_source_t *filter = GetCalldataPointer<obs_source_t>(data, "filter");
|
||||
|
||||
if (!(source && filter))
|
||||
return;
|
||||
|
||||
eventHandler->DisconnectFilterSignals(filter);
|
||||
|
||||
json eventData;
|
||||
eventData["sourceName"] = obs_source_get_name(source);
|
||||
eventData["filterName"] = obs_source_get_name(filter);
|
||||
eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterRemoved", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* A source's filter list has been reindexed.
|
||||
*
|
||||
* @dataField sourceName | String | Name of the source
|
||||
* @dataField filters | Array<Object> | Array of filter objects
|
||||
*
|
||||
* @eventType SourceFilterListReindexed
|
||||
* @eventSubscription Filters
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category filters
|
||||
*/
|
||||
void EventHandler::HandleSourceFilterListReindexed(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!source)
|
||||
return;
|
||||
|
||||
json eventData;
|
||||
eventData["sourceName"] = obs_source_get_name(source);
|
||||
eventData["filters"] = Utils::Obs::ArrayHelper::GetSourceFilterList(source);
|
||||
eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterListReindexed", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* A source filter's enable state has changed.
|
||||
*
|
||||
* @dataField sourceName | String | Name of the source the filter is on
|
||||
* @dataField filterName | String | Name of the filter
|
||||
* @dataField filterEnabled | Boolean | Whether the filter is enabled
|
||||
*
|
||||
* @eventType SourceFilterEnableStateChanged
|
||||
* @eventSubscription Filters
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category filters
|
||||
*/
|
||||
void EventHandler::HandleSourceFilterEnableStateChanged(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *filter = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!filter)
|
||||
return;
|
||||
|
||||
// Not OBSSourceAutoRelease as get_parent doesn't increment refcount
|
||||
obs_source_t *source = obs_filter_get_parent(filter);
|
||||
if (!source)
|
||||
return;
|
||||
|
||||
bool filterEnabled = calldata_bool(data, "enabled");
|
||||
|
||||
json eventData;
|
||||
eventData["sourceName"] = obs_source_get_name(source);
|
||||
eventData["filterName"] = obs_source_get_name(filter);
|
||||
eventData["filterEnabled"] = filterEnabled;
|
||||
eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterEnableStateChanged", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of a source filter has changed.
|
||||
*
|
||||
* @dataField sourceName | String | The source the filter is on
|
||||
* @dataField oldFilterName | String | Old name of the filter
|
||||
* @dataField filterName | String | New name of the filter
|
||||
*
|
||||
* @eventType SourceFilterNameChanged
|
||||
* @eventSubscription Filters
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category filters
|
||||
*/
|
||||
void EventHandler::HandleSourceFilterNameChanged(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *filter = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!filter)
|
||||
return;
|
||||
|
||||
json eventData;
|
||||
eventData["sourceName"] = obs_source_get_name(obs_filter_get_parent(filter));
|
||||
eventData["oldFilterName"] = calldata_string(data, "prev_name");
|
||||
eventData["filterName"] = calldata_string(data, "new_name");
|
||||
eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterNameChanged", eventData);
|
||||
}
|
||||
|
@ -34,23 +34,3 @@ void EventHandler::HandleExitStarted()
|
||||
{
|
||||
BroadcastEvent(EventSubscription::General, "ExitStarted");
|
||||
}
|
||||
|
||||
/**
|
||||
* Studio mode has been enabled or disabled.
|
||||
*
|
||||
* @dataField studioModeEnabled | Boolean | True == Enabled, False == Disabled
|
||||
*
|
||||
* @eventType StudioModeStateChanged
|
||||
* @eventSubscription General
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @category general
|
||||
* @api events
|
||||
*/
|
||||
void EventHandler::HandleStudioModeStateChanged(bool enabled)
|
||||
{
|
||||
json eventData;
|
||||
eventData["studioModeEnabled"] = enabled;
|
||||
BroadcastEvent(EventSubscription::General, "StudioModeStateChanged", eventData);
|
||||
}
|
||||
|
@ -19,6 +19,23 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
#include "EventHandler.h"
|
||||
|
||||
/**
|
||||
* An input has been created.
|
||||
*
|
||||
* @dataField inputName | String | Name of the input
|
||||
* @dataField inputKind | String | The kind of the input
|
||||
* @dataField unversionedInputKind | String | The unversioned kind of input (aka no `_v2` stuff)
|
||||
* @dataField inputSettings | Object | The settings configured to the input when it was created
|
||||
* @dataField defaultInputSettings | Object | The default settings for the input
|
||||
*
|
||||
* @eventType InputCreated
|
||||
* @eventSubscription Inputs
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category inputs
|
||||
*/
|
||||
void EventHandler::HandleInputCreated(obs_source_t *source)
|
||||
{
|
||||
std::string inputKind = obs_source_get_id(source);
|
||||
@ -34,6 +51,19 @@ void EventHandler::HandleInputCreated(obs_source_t *source)
|
||||
BroadcastEvent(EventSubscription::Inputs, "InputCreated", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* An input has been removed.
|
||||
*
|
||||
* @dataField inputName | String | Name of the input
|
||||
*
|
||||
* @eventType InputRemoved
|
||||
* @eventSubscription Inputs
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category inputs
|
||||
*/
|
||||
void EventHandler::HandleInputRemoved(obs_source_t *source)
|
||||
{
|
||||
json eventData;
|
||||
@ -41,6 +71,20 @@ void EventHandler::HandleInputRemoved(obs_source_t *source)
|
||||
BroadcastEvent(EventSubscription::Inputs, "InputRemoved", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of an input has changed.
|
||||
*
|
||||
* @dataField oldInputName | String | Old name of the input
|
||||
* @dataField inputName | String | New name of the input
|
||||
*
|
||||
* @eventType InputNameChanged
|
||||
* @eventSubscription Inputs
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category inputs
|
||||
*/
|
||||
void EventHandler::HandleInputNameChanged(obs_source_t *, std::string oldInputName, std::string inputName)
|
||||
{
|
||||
json eventData;
|
||||
@ -49,16 +93,25 @@ void EventHandler::HandleInputNameChanged(obs_source_t *, std::string oldInputNa
|
||||
BroadcastEvent(EventSubscription::Inputs, "InputNameChanged", eventData);
|
||||
}
|
||||
|
||||
void EventHandler::HandleInputVolumeMeters(std::vector<json> inputs)
|
||||
{
|
||||
json eventData;
|
||||
eventData["inputs"] = inputs;
|
||||
BroadcastEvent(EventSubscription::InputVolumeMeters, "InputVolumeMeters", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* An input's active state has changed.
|
||||
*
|
||||
* When an input is active, it means it's being shown by the program feed.
|
||||
*
|
||||
* @dataField inputName | String | Name of the input
|
||||
* @dataField videoActive | Boolean | Whether the input is active
|
||||
*
|
||||
* @eventType InputActiveStateChanged
|
||||
* @eventSubscription InputActiveStateChanged
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category inputs
|
||||
*/
|
||||
void EventHandler::HandleInputActiveStateChanged(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
if (!eventHandler->_inputActiveStateChangedRef.load())
|
||||
return;
|
||||
@ -76,9 +129,25 @@ void EventHandler::HandleInputActiveStateChanged(void *param, calldata_t *data)
|
||||
eventHandler->BroadcastEvent(EventSubscription::InputActiveStateChanged, "InputActiveStateChanged", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* An input's show state has changed.
|
||||
*
|
||||
* When an input is showing, it means it's being shown by the preview or a dialog.
|
||||
*
|
||||
* @dataField inputName | String | Name of the input
|
||||
* @dataField videoShowing | Boolean | Whether the input is showing
|
||||
*
|
||||
* @eventType InputShowStateChanged
|
||||
* @eventSubscription InputShowStateChanged
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category inputs
|
||||
*/
|
||||
void EventHandler::HandleInputShowStateChanged(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
if (!eventHandler->_inputShowStateChangedRef.load())
|
||||
return;
|
||||
@ -96,9 +165,23 @@ void EventHandler::HandleInputShowStateChanged(void *param, calldata_t *data)
|
||||
eventHandler->BroadcastEvent(EventSubscription::InputShowStateChanged, "InputShowStateChanged", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* An input's mute state has changed.
|
||||
*
|
||||
* @dataField inputName | String | Name of the input
|
||||
* @dataField inputMuted | Boolean | Whether the input is muted
|
||||
*
|
||||
* @eventType InputMuteStateChanged
|
||||
* @eventSubscription Inputs
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category inputs
|
||||
*/
|
||||
void EventHandler::HandleInputMuteStateChanged(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!source)
|
||||
@ -113,9 +196,24 @@ void EventHandler::HandleInputMuteStateChanged(void *param, calldata_t *data)
|
||||
eventHandler->BroadcastEvent(EventSubscription::Inputs, "InputMuteStateChanged", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* An input's volume level has changed.
|
||||
*
|
||||
* @dataField inputName | String | Name of the input
|
||||
* @dataField inputVolumeMul | Number | New volume level in multimap
|
||||
* @dataField inputVolumeDb | Number | New volume level in dB
|
||||
*
|
||||
* @eventType InputVolumeChanged
|
||||
* @eventSubscription Inputs
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category inputs
|
||||
*/
|
||||
void EventHandler::HandleInputVolumeChanged(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!source)
|
||||
@ -138,9 +236,56 @@ void EventHandler::HandleInputVolumeChanged(void *param, calldata_t *data)
|
||||
eventHandler->BroadcastEvent(EventSubscription::Inputs, "InputVolumeChanged", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* The audio balance value of an input has changed.
|
||||
*
|
||||
* @dataField inputName | String | Name of the affected input
|
||||
* @dataField inputAudioBalance | Number | New audio balance value of the input
|
||||
*
|
||||
* @eventType InputAudioBalanceChanged
|
||||
* @eventSubscription Inputs
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @category inputs
|
||||
* @api events
|
||||
*/
|
||||
void EventHandler::HandleInputAudioBalanceChanged(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!source)
|
||||
return;
|
||||
|
||||
if (obs_source_get_type(source) != OBS_SOURCE_TYPE_INPUT)
|
||||
return;
|
||||
|
||||
float inputAudioBalance = (float)calldata_float(data, "balance");
|
||||
|
||||
json eventData;
|
||||
eventData["inputName"] = obs_source_get_name(source);
|
||||
eventData["inputAudioBalance"] = inputAudioBalance;
|
||||
eventHandler->BroadcastEvent(EventSubscription::Inputs, "InputAudioBalanceChanged", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* The sync offset of an input has changed.
|
||||
*
|
||||
* @dataField inputName | String | Name of the input
|
||||
* @dataField inputAudioSyncOffset | Number | New sync offset in milliseconds
|
||||
*
|
||||
* @eventType InputAudioSyncOffsetChanged
|
||||
* @eventSubscription Inputs
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category inputs
|
||||
*/
|
||||
void EventHandler::HandleInputAudioSyncOffsetChanged(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!source)
|
||||
@ -157,9 +302,23 @@ void EventHandler::HandleInputAudioSyncOffsetChanged(void *param, calldata_t *da
|
||||
eventHandler->BroadcastEvent(EventSubscription::Inputs, "InputAudioSyncOffsetChanged", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* The audio tracks of an input have changed.
|
||||
*
|
||||
* @dataField inputName | String | Name of the input
|
||||
* @dataField inputAudioTracks | Object | Object of audio tracks along with their associated enable states
|
||||
*
|
||||
* @eventType InputAudioTracksChanged
|
||||
* @eventSubscription Inputs
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category inputs
|
||||
*/
|
||||
void EventHandler::HandleInputAudioTracksChanged(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!source)
|
||||
@ -181,9 +340,28 @@ void EventHandler::HandleInputAudioTracksChanged(void *param, calldata_t *data)
|
||||
eventHandler->BroadcastEvent(EventSubscription::Inputs, "InputAudioTracksChanged", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* The monitor type of an input has changed.
|
||||
*
|
||||
* Available types are:
|
||||
* - `OBS_MONITORING_TYPE_NONE`
|
||||
* - `OBS_MONITORING_TYPE_MONITOR_ONLY`
|
||||
* - `OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT`
|
||||
*
|
||||
* @dataField inputName | String | Name of the input
|
||||
* @dataField monitorType | String | New monitor type of the input
|
||||
*
|
||||
* @eventType InputAudioMonitorTypeChanged
|
||||
* @eventSubscription Inputs
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category inputs
|
||||
*/
|
||||
void EventHandler::HandleInputAudioMonitorTypeChanged(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!source)
|
||||
@ -194,22 +372,30 @@ void EventHandler::HandleInputAudioMonitorTypeChanged(void *param, calldata_t *d
|
||||
|
||||
enum obs_monitoring_type monitorType = (obs_monitoring_type)calldata_int(data, "type");
|
||||
|
||||
std::string monitorTypeString;
|
||||
switch (monitorType) {
|
||||
default:
|
||||
case OBS_MONITORING_TYPE_NONE:
|
||||
monitorTypeString = "OBS_WEBSOCKET_MONITOR_TYPE_NONE";
|
||||
break;
|
||||
case OBS_MONITORING_TYPE_MONITOR_ONLY:
|
||||
monitorTypeString = "OBS_WEBSOCKET_MONITOR_TYPE_MONITOR_ONLY";
|
||||
break;
|
||||
case OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT:
|
||||
monitorTypeString = "OBS_WEBSOCKET_MONITOR_TYPE_MONITOR_AND_OUTPUT";
|
||||
break;
|
||||
}
|
||||
std::string monitorTypeString = Utils::Obs::StringHelper::GetInputMonitorType(monitorType);
|
||||
|
||||
json eventData;
|
||||
eventData["inputName"] = obs_source_get_name(source);
|
||||
eventData["monitorType"] = monitorTypeString;
|
||||
eventHandler->BroadcastEvent(EventSubscription::Inputs, "InputAudioMonitorTypeChanged", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* A high-volume event providing volume levels of all active inputs every 50 milliseconds.
|
||||
*
|
||||
* @dataField inputs | Array<Object> | Array of active inputs with their associated volume levels
|
||||
*
|
||||
* @eventType InputVolumeMeters
|
||||
* @eventSubscription InputVolumeMeters
|
||||
* @complexity 4
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category inputs
|
||||
*/
|
||||
void EventHandler::HandleInputVolumeMeters(std::vector<json> inputs)
|
||||
{
|
||||
json eventData;
|
||||
eventData["inputs"] = inputs;
|
||||
BroadcastEvent(EventSubscription::InputVolumeMeters, "InputVolumeMeters", eventData);
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ std::string GetMediaInputActionString(ObsMediaInputAction action) {
|
||||
|
||||
void EventHandler::SourceMediaPauseMultiHandler(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!source)
|
||||
@ -49,7 +49,7 @@ void EventHandler::SourceMediaPauseMultiHandler(void *param, calldata_t *data)
|
||||
|
||||
void EventHandler::SourceMediaPlayMultiHandler(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!source)
|
||||
@ -63,7 +63,7 @@ void EventHandler::SourceMediaPlayMultiHandler(void *param, calldata_t *data)
|
||||
|
||||
void EventHandler::SourceMediaRestartMultiHandler(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!source)
|
||||
@ -77,7 +77,7 @@ void EventHandler::SourceMediaRestartMultiHandler(void *param, calldata_t *data)
|
||||
|
||||
void EventHandler::SourceMediaStopMultiHandler(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!source)
|
||||
@ -91,7 +91,7 @@ void EventHandler::SourceMediaStopMultiHandler(void *param, calldata_t *data)
|
||||
|
||||
void EventHandler::SourceMediaNextMultiHandler(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!source)
|
||||
@ -105,7 +105,7 @@ void EventHandler::SourceMediaNextMultiHandler(void *param, calldata_t *data)
|
||||
|
||||
void EventHandler::SourceMediaPreviousMultiHandler(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!source)
|
||||
@ -117,9 +117,22 @@ void EventHandler::SourceMediaPreviousMultiHandler(void *param, calldata_t *data
|
||||
eventHandler->HandleMediaInputActionTriggered(source, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS);
|
||||
}
|
||||
|
||||
/**
|
||||
* A media input has started playing.
|
||||
*
|
||||
* @dataField inputName | String | Name of the input
|
||||
*
|
||||
* @eventType MediaInputPlaybackStarted
|
||||
* @eventSubscription MediaInputs
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category media inputs
|
||||
*/
|
||||
void EventHandler::HandleMediaInputPlaybackStarted(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!source)
|
||||
@ -133,9 +146,22 @@ void EventHandler::HandleMediaInputPlaybackStarted(void *param, calldata_t *data
|
||||
eventHandler->BroadcastEvent(EventSubscription::MediaInputs, "MediaInputPlaybackStarted", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* A media input has finished playing.
|
||||
*
|
||||
* @dataField inputName | String | Name of the input
|
||||
*
|
||||
* @eventType MediaInputPlaybackEnded
|
||||
* @eventSubscription MediaInputs
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category media inputs
|
||||
*/
|
||||
void EventHandler::HandleMediaInputPlaybackEnded(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_source_t *source = GetCalldataPointer<obs_source_t>(data, "source");
|
||||
if (!source)
|
||||
@ -149,6 +175,20 @@ void EventHandler::HandleMediaInputPlaybackEnded(void *param, calldata_t *data)
|
||||
eventHandler->BroadcastEvent(EventSubscription::MediaInputs, "MediaInputPlaybackEnded", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* An action has been performed on an input.
|
||||
*
|
||||
* @dataField inputName | String | Name of the input
|
||||
* @dataField mediaAction | String | Action performed on the input. See `ObsMediaInputAction` enum
|
||||
*
|
||||
* @eventType MediaInputActionTriggered
|
||||
* @eventSubscription MediaInputs
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category media inputs
|
||||
*/
|
||||
void EventHandler::HandleMediaInputActionTriggered(obs_source_t *source, ObsMediaInputAction action)
|
||||
{
|
||||
json eventData;
|
||||
|
@ -19,21 +19,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
#include "EventHandler.h"
|
||||
|
||||
#define CASE(x) case x: return #x;
|
||||
|
||||
std::string GetOutputStateString(ObsOutputState state) {
|
||||
switch (state) {
|
||||
default:
|
||||
CASE(OBS_WEBSOCKET_OUTPUT_STARTING)
|
||||
CASE(OBS_WEBSOCKET_OUTPUT_STARTED)
|
||||
CASE(OBS_WEBSOCKET_OUTPUT_STOPPING)
|
||||
CASE(OBS_WEBSOCKET_OUTPUT_STOPPED)
|
||||
CASE(OBS_WEBSOCKET_OUTPUT_PAUSED)
|
||||
CASE(OBS_WEBSOCKET_OUTPUT_RESUMED)
|
||||
}
|
||||
}
|
||||
|
||||
bool GetOutputStateActive(ObsOutputState state) {
|
||||
static bool GetOutputStateActive(ObsOutputState state) {
|
||||
switch(state) {
|
||||
case OBS_WEBSOCKET_OUTPUT_STARTED:
|
||||
case OBS_WEBSOCKET_OUTPUT_RESUMED:
|
||||
@ -48,38 +34,107 @@ bool GetOutputStateActive(ObsOutputState state) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The state of the stream output has changed.
|
||||
*
|
||||
* @dataField outputActive | Boolean | Whether the output is active
|
||||
* @dataField outputState | String | The specific state of the output
|
||||
*
|
||||
* @eventType StreamStateChanged
|
||||
* @eventSubscription Outputs
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category outputs
|
||||
*/
|
||||
void EventHandler::HandleStreamStateChanged(ObsOutputState state)
|
||||
{
|
||||
json eventData;
|
||||
eventData["outputActive"] = GetOutputStateActive(state);
|
||||
eventData["outputState"] = GetOutputStateString(state);
|
||||
eventData["outputState"] = Utils::Obs::StringHelper::GetOutputState(state);
|
||||
BroadcastEvent(EventSubscription::Outputs, "StreamStateChanged", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* The state of the record output has changed.
|
||||
*
|
||||
* @dataField outputActive | Boolean | Whether the output is active
|
||||
* @dataField outputState | String | The specific state of the output
|
||||
*
|
||||
* @eventType RecordStateChanged
|
||||
* @eventSubscription Outputs
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category outputs
|
||||
*/
|
||||
void EventHandler::HandleRecordStateChanged(ObsOutputState state)
|
||||
{
|
||||
json eventData;
|
||||
eventData["outputActive"] = GetOutputStateActive(state);
|
||||
eventData["outputState"] = GetOutputStateString(state);
|
||||
eventData["outputState"] = Utils::Obs::StringHelper::GetOutputState(state);
|
||||
BroadcastEvent(EventSubscription::Outputs, "RecordStateChanged", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* The state of the replay buffer output has changed.
|
||||
*
|
||||
* @dataField outputActive | Boolean | Whether the output is active
|
||||
* @dataField outputState | String | The specific state of the output
|
||||
*
|
||||
* @eventType ReplayBufferStateChanged
|
||||
* @eventSubscription Outputs
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category outputs
|
||||
*/
|
||||
void EventHandler::HandleReplayBufferStateChanged(ObsOutputState state)
|
||||
{
|
||||
json eventData;
|
||||
eventData["outputActive"] = GetOutputStateActive(state);
|
||||
eventData["outputState"] = GetOutputStateString(state);
|
||||
eventData["outputState"] = Utils::Obs::StringHelper::GetOutputState(state);
|
||||
BroadcastEvent(EventSubscription::Outputs, "ReplayBufferStateChanged", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* The state of the virtualcam output has changed.
|
||||
*
|
||||
* @dataField outputActive | Boolean | Whether the output is active
|
||||
* @dataField outputState | String | The specific state of the output
|
||||
*
|
||||
* @eventType VirtualcamStateChanged
|
||||
* @eventSubscription Outputs
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category outputs
|
||||
*/
|
||||
void EventHandler::HandleVirtualcamStateChanged(ObsOutputState state)
|
||||
{
|
||||
json eventData;
|
||||
eventData["outputActive"] = GetOutputStateActive(state);
|
||||
eventData["outputState"] = GetOutputStateString(state);
|
||||
eventData["outputState"] = Utils::Obs::StringHelper::GetOutputState(state);
|
||||
BroadcastEvent(EventSubscription::Outputs, "VirtualcamStateChanged", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* The replay buffer has been saved.
|
||||
*
|
||||
* @dataField savedReplayPath | String | Path of the saved replay file
|
||||
*
|
||||
* @eventType ReplayBufferSaved
|
||||
* @eventSubscription Outputs
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category outputs
|
||||
*/
|
||||
void EventHandler::HandleReplayBufferSaved()
|
||||
{
|
||||
json eventData;
|
||||
|
@ -19,9 +19,25 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
#include "EventHandler.h"
|
||||
|
||||
/**
|
||||
* A scene item has been created.
|
||||
*
|
||||
* @dataField sceneName | String | Name of the scene the item was added to
|
||||
* @dataField sourceName | String | Name of the underlying source (input/scene)
|
||||
* @dataField sceneItemId | Number | Numeric ID of the scene item
|
||||
* @dataField sceneItemIndex | Number | Index position of the item
|
||||
*
|
||||
* @eventType SceneItemCreated
|
||||
* @eventSubscription SceneItems
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category scene items
|
||||
*/
|
||||
void EventHandler::HandleSceneItemCreated(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_scene_t *scene = GetCalldataPointer<obs_scene_t>(data, "scene");
|
||||
if (!scene)
|
||||
@ -33,16 +49,32 @@ void EventHandler::HandleSceneItemCreated(void *param, calldata_t *data)
|
||||
|
||||
json eventData;
|
||||
eventData["sceneName"] = obs_source_get_name(obs_scene_get_source(scene));
|
||||
eventData["inputName"] = obs_source_get_name(obs_sceneitem_get_source(sceneItem));
|
||||
eventData["sourceName"] = obs_source_get_name(obs_sceneitem_get_source(sceneItem));
|
||||
eventData["sceneItemId"] = obs_sceneitem_get_id(sceneItem);
|
||||
eventData["sceneItemIndex"] = obs_sceneitem_get_order_position(sceneItem);
|
||||
eventHandler->BroadcastEvent(EventSubscription::SceneItems, "SceneItemCreated", eventData);
|
||||
}
|
||||
|
||||
// Will not be emitted if an item is removed due to the parent scene being removed.
|
||||
/**
|
||||
* A scene item has been removed.
|
||||
*
|
||||
* This event is not emitted when the scene the item is in is removed.
|
||||
*
|
||||
* @dataField sceneName | String | Name of the scene the item was removed from
|
||||
* @dataField sourceName | String | Name of the underlying source (input/scene)
|
||||
* @dataField sceneItemId | Number | Numeric ID of the scene item
|
||||
*
|
||||
* @eventType SceneItemRemoved
|
||||
* @eventSubscription SceneItems
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category scene items
|
||||
*/
|
||||
void EventHandler::HandleSceneItemRemoved(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_scene_t *scene = GetCalldataPointer<obs_scene_t>(data, "scene");
|
||||
if (!scene)
|
||||
@ -54,15 +86,28 @@ void EventHandler::HandleSceneItemRemoved(void *param, calldata_t *data)
|
||||
|
||||
json eventData;
|
||||
eventData["sceneName"] = obs_source_get_name(obs_scene_get_source(scene));
|
||||
eventData["inputName"] = obs_source_get_name(obs_sceneitem_get_source(sceneItem));
|
||||
eventData["sourceName"] = obs_source_get_name(obs_sceneitem_get_source(sceneItem));
|
||||
eventData["sceneItemId"] = obs_sceneitem_get_id(sceneItem);
|
||||
eventData["sceneItemIndex"] = obs_sceneitem_get_order_position(sceneItem);
|
||||
eventHandler->BroadcastEvent(EventSubscription::SceneItems, "SceneItemRemoved", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* A scene's item list has been reindexed.
|
||||
*
|
||||
* @dataField sceneName | String | Name of the scene
|
||||
* @dataField sceneItems | Array<Object> | Array of scene item objects
|
||||
*
|
||||
* @eventType SceneItemListReindexed
|
||||
* @eventSubscription SceneItems
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category scene items
|
||||
*/
|
||||
void EventHandler::HandleSceneItemListReindexed(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_scene_t *scene = GetCalldataPointer<obs_scene_t>(data, "scene");
|
||||
if (!scene)
|
||||
@ -70,13 +115,28 @@ void EventHandler::HandleSceneItemListReindexed(void *param, calldata_t *data)
|
||||
|
||||
json eventData;
|
||||
eventData["sceneName"] = obs_source_get_name(obs_scene_get_source(scene));
|
||||
eventData["sceneItems"] = Utils::Obs::ListHelper::GetSceneItemList(scene, true);
|
||||
eventData["sceneItems"] = Utils::Obs::ArrayHelper::GetSceneItemList(scene, true);
|
||||
eventHandler->BroadcastEvent(EventSubscription::SceneItems, "SceneItemListReindexed", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* A scene item's enable state has changed.
|
||||
*
|
||||
* @dataField sceneName | String | Name of the scene the item is in
|
||||
* @dataField sceneItemId | Number | Numeric ID of the scene item
|
||||
* @dataField sceneItemEnabled | Boolean | Whether the scene item is enabled (visible)
|
||||
*
|
||||
* @eventType SceneItemEnableStateChanged
|
||||
* @eventSubscription SceneItems
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category scene items
|
||||
*/
|
||||
void EventHandler::HandleSceneItemEnableStateChanged(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_scene_t *scene = GetCalldataPointer<obs_scene_t>(data, "scene");
|
||||
if (!scene)
|
||||
@ -95,9 +155,24 @@ void EventHandler::HandleSceneItemEnableStateChanged(void *param, calldata_t *da
|
||||
eventHandler->BroadcastEvent(EventSubscription::SceneItems, "SceneItemEnableStateChanged", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* A scene item's lock state has changed.
|
||||
*
|
||||
* @dataField sceneName | String | Name of the scene the item is in
|
||||
* @dataField sceneItemId | Number | Numeric ID of the scene item
|
||||
* @dataField sceneItemLocked | Boolean | Whether the scene item is locked
|
||||
*
|
||||
* @eventType SceneItemLockStateChanged
|
||||
* @eventSubscription SceneItems
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category scene items
|
||||
*/
|
||||
void EventHandler::HandleSceneItemLockStateChanged(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_scene_t *scene = GetCalldataPointer<obs_scene_t>(data, "scene");
|
||||
if (!scene)
|
||||
@ -116,9 +191,56 @@ void EventHandler::HandleSceneItemLockStateChanged(void *param, calldata_t *data
|
||||
eventHandler->BroadcastEvent(EventSubscription::SceneItems, "SceneItemLockStateChanged", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* A scene item has been selected in the Ui.
|
||||
*
|
||||
* @dataField sceneName | String | Name of the scene the item is in
|
||||
* @dataField sceneItemId | Number | Numeric ID of the scene item
|
||||
*
|
||||
* @eventType SceneItemSelected
|
||||
* @eventSubscription SceneItems
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category scene items
|
||||
*/
|
||||
void EventHandler::HandleSceneItemSelected(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
obs_scene_t *scene = GetCalldataPointer<obs_scene_t>(data, "scene");
|
||||
if (!scene)
|
||||
return;
|
||||
|
||||
obs_sceneitem_t *sceneItem = GetCalldataPointer<obs_sceneitem_t>(data, "item");
|
||||
if (!sceneItem)
|
||||
return;
|
||||
|
||||
json eventData;
|
||||
eventData["sceneName"] = obs_source_get_name(obs_scene_get_source(scene));
|
||||
eventData["sceneItemId"] = obs_sceneitem_get_id(sceneItem);
|
||||
eventHandler->BroadcastEvent(EventSubscription::SceneItems, "SceneItemSelected", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* The transform/crop of a scene item has changed.
|
||||
*
|
||||
* @dataField sceneName | String | The name of the scene the item is in
|
||||
* @dataField sceneItemId | Number | Numeric ID of the scene item
|
||||
* @dataField sceneItemTransform | Object | New transform/crop info of the scene item
|
||||
*
|
||||
* @eventType SceneItemTransformChanged
|
||||
* @eventSubscription SceneItemTransformChanged
|
||||
* @complexity 4
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category scene items
|
||||
*/
|
||||
void EventHandler::HandleSceneItemTransformChanged(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
||||
auto eventHandler = static_cast<EventHandler*>(param);
|
||||
|
||||
if (!eventHandler->_sceneItemTransformChangedRef.load())
|
||||
return;
|
||||
@ -134,6 +256,6 @@ void EventHandler::HandleSceneItemTransformChanged(void *param, calldata_t *data
|
||||
json eventData;
|
||||
eventData["sceneName"] = obs_source_get_name(obs_scene_get_source(scene));
|
||||
eventData["sceneItemId"] = obs_sceneitem_get_id(sceneItem);
|
||||
eventData["sceneItemTransform"] = Utils::Obs::DataHelper::GetSceneItemTransform(sceneItem);
|
||||
eventData["sceneItemTransform"] = Utils::Obs::ObjectHelper::GetSceneItemTransform(sceneItem);
|
||||
eventHandler->BroadcastEvent(EventSubscription::SceneItemTransformChanged, "SceneItemTransformChanged", eventData);
|
||||
}
|
||||
|
@ -19,6 +19,20 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
#include "EventHandler.h"
|
||||
|
||||
/**
|
||||
* A new scene has been created.
|
||||
*
|
||||
* @dataField sceneName | String | Name of the new scene
|
||||
* @dataField isGroup | Boolean | Whether the new scene is a group
|
||||
*
|
||||
* @eventType SceneCreated
|
||||
* @eventSubscription Scenes
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category scenes
|
||||
*/
|
||||
void EventHandler::HandleSceneCreated(obs_source_t *source)
|
||||
{
|
||||
json eventData;
|
||||
@ -27,6 +41,20 @@ void EventHandler::HandleSceneCreated(obs_source_t *source)
|
||||
BroadcastEvent(EventSubscription::Scenes, "SceneCreated", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* A scene has been removed.
|
||||
*
|
||||
* @dataField sceneName | String | Name of the removed scene
|
||||
* @dataField isGroup | Boolean | Whether the scene was a group
|
||||
*
|
||||
* @eventType SceneRemoved
|
||||
* @eventSubscription Scenes
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category scenes
|
||||
*/
|
||||
void EventHandler::HandleSceneRemoved(obs_source_t *source)
|
||||
{
|
||||
json eventData;
|
||||
@ -35,6 +63,20 @@ void EventHandler::HandleSceneRemoved(obs_source_t *source)
|
||||
BroadcastEvent(EventSubscription::Scenes, "SceneRemoved", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of a scene has changed.
|
||||
*
|
||||
* @dataField oldSceneName | String | Old name of the scene
|
||||
* @dataField sceneName | String | New name of the scene
|
||||
*
|
||||
* @eventType SceneNameChanged
|
||||
* @eventSubscription Scenes
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category scenes
|
||||
*/
|
||||
void EventHandler::HandleSceneNameChanged(obs_source_t *, std::string oldSceneName, std::string sceneName)
|
||||
{
|
||||
json eventData;
|
||||
@ -43,15 +85,41 @@ void EventHandler::HandleSceneNameChanged(obs_source_t *, std::string oldSceneNa
|
||||
BroadcastEvent(EventSubscription::Scenes, "SceneNameChanged", eventData);
|
||||
}
|
||||
|
||||
void EventHandler::HandleCurrentSceneChanged()
|
||||
/**
|
||||
* The current program scene has changed.
|
||||
*
|
||||
* @dataField sceneName | String | Name of the scene that was switched to
|
||||
*
|
||||
* @eventType CurrentProgramSceneChanged
|
||||
* @eventSubscription Scenes
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category scenes
|
||||
*/
|
||||
void EventHandler::HandleCurrentProgramSceneChanged()
|
||||
{
|
||||
OBSSourceAutoRelease currentScene = obs_frontend_get_current_scene();
|
||||
|
||||
json eventData;
|
||||
eventData["sceneName"] = obs_source_get_name(currentScene);
|
||||
BroadcastEvent(EventSubscription::Scenes, "CurrentSceneChanged", eventData);
|
||||
BroadcastEvent(EventSubscription::Scenes, "CurrentProgramSceneChanged", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* The current preview scene has changed.
|
||||
*
|
||||
* @dataField sceneName | String | Name of the scene that was switched to
|
||||
*
|
||||
* @eventType CurrentPreviewSceneChanged
|
||||
* @eventSubscription Scenes
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category scenes
|
||||
*/
|
||||
void EventHandler::HandleCurrentPreviewSceneChanged()
|
||||
{
|
||||
OBSSourceAutoRelease currentPreviewScene = obs_frontend_get_current_preview_scene();
|
||||
@ -65,9 +133,24 @@ void EventHandler::HandleCurrentPreviewSceneChanged()
|
||||
BroadcastEvent(EventSubscription::Scenes, "CurrentPreviewSceneChanged", eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* The list of scenes has changed.
|
||||
*
|
||||
* TODO: Make OBS fire this event when scenes are reordered.
|
||||
*
|
||||
* @dataField scenes | Array<Object> | Updated array of scenes
|
||||
*
|
||||
* @eventType SceneListChanged
|
||||
* @eventSubscription Scenes
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category scenes
|
||||
*/
|
||||
void EventHandler::HandleSceneListChanged()
|
||||
{
|
||||
json eventData;
|
||||
eventData["scenes"] = Utils::Obs::ListHelper::GetSceneList();
|
||||
eventData["scenes"] = Utils::Obs::ArrayHelper::GetSceneList();
|
||||
BroadcastEvent(EventSubscription::Scenes, "SceneListChanged", eventData);
|
||||
}
|
||||
|
@ -19,26 +19,44 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
#include "EventHandler.h"
|
||||
|
||||
void EventHandler::HandleTransitionCreated(obs_source_t *source)
|
||||
/**
|
||||
* The current scene transition has changed.
|
||||
*
|
||||
* @dataField transitionName | String | Name of the new transition
|
||||
*
|
||||
* @eventType CurrentSceneTransitionChanged
|
||||
* @eventSubscription Transitions
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category transitions
|
||||
*/
|
||||
void EventHandler::HandleCurrentSceneTransitionChanged()
|
||||
{
|
||||
OBSSourceAutoRelease transition = obs_frontend_get_current_transition();
|
||||
|
||||
json eventData;
|
||||
eventData["transitionName"] = obs_source_get_name(source);
|
||||
eventData["transitionKind"] = obs_source_get_id(source);
|
||||
eventData["transitionFixed"] = obs_transition_fixed(source);
|
||||
BroadcastEvent(EventSubscription::Transitions, "TransitionCreated", eventData);
|
||||
eventData["transitionName"] = obs_source_get_name(transition);
|
||||
BroadcastEvent(EventSubscription::Transitions, "CurrentSceneTransitionChanged", eventData);
|
||||
}
|
||||
|
||||
void EventHandler::HandleTransitionRemoved(obs_source_t *source)
|
||||
/**
|
||||
* The current scene transition duration has changed.
|
||||
*
|
||||
* @dataField transitionDuration | Number | Transition duration in milliseconds
|
||||
*
|
||||
* @eventType CurrentSceneTransitionDurationChanged
|
||||
* @eventSubscription Transitions
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api events
|
||||
* @category transitions
|
||||
*/
|
||||
void EventHandler::HandleCurrentSceneTransitionDurationChanged()
|
||||
{
|
||||
json eventData;
|
||||
eventData["transitionName"] = obs_source_get_name(source);
|
||||
BroadcastEvent(EventSubscription::Transitions, "TransitionRemoved", eventData);
|
||||
}
|
||||
|
||||
void EventHandler::HandleTransitionNameChanged(obs_source_t *, std::string oldTransitionName, std::string transitionName)
|
||||
{
|
||||
json eventData;
|
||||
eventData["oldTransitionName"] = oldTransitionName;
|
||||
eventData["transitionName"] = transitionName;
|
||||
BroadcastEvent(EventSubscription::Transitions, "TransitionNameChanged", eventData);
|
||||
eventData["transitionDuration"] = obs_frontend_get_transition_duration();
|
||||
BroadcastEvent(EventSubscription::Transitions, "CurrentSceneTransitionDurationChanged", eventData);
|
||||
}
|
||||
|
@ -19,3 +19,22 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
#include "EventHandler.h"
|
||||
|
||||
/**
|
||||
* Studio mode has been enabled or disabled.
|
||||
*
|
||||
* @dataField studioModeEnabled | Boolean | True == Enabled, False == Disabled
|
||||
*
|
||||
* @eventType StudioModeStateChanged
|
||||
* @eventSubscription Ui
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @category ui
|
||||
* @api events
|
||||
*/
|
||||
void EventHandler::HandleStudioModeStateChanged(bool enabled)
|
||||
{
|
||||
json eventData;
|
||||
eventData["studioModeEnabled"] = enabled;
|
||||
BroadcastEvent(EventSubscription::Ui, "StudioModeStateChanged", eventData);
|
||||
}
|
@ -130,7 +130,6 @@ namespace EventSubscription {
|
||||
* @initialVersion 5.0.0
|
||||
* @api enums
|
||||
*/
|
||||
// Receive events in the `MediaInputs` category
|
||||
MediaInputs = (1 << 8),
|
||||
/**
|
||||
* Subscription value to receive the `VendorEvent` event.
|
||||
@ -142,9 +141,19 @@ namespace EventSubscription {
|
||||
* @initialVersion 5.0.0
|
||||
* @api enums
|
||||
*/
|
||||
// Receive events from external OBS plugins and scripts
|
||||
Vendors = (1 << 9),
|
||||
/**
|
||||
* Subscription value to receive events in the `Ui` category.
|
||||
*
|
||||
* @enumIdentifier Ui
|
||||
* @enumValue (1 << 10)
|
||||
* @enumType EventSubscription
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api enums
|
||||
*/
|
||||
Ui = (1 << 10),
|
||||
/**
|
||||
* Helper to receive all non-high-volume events.
|
||||
*
|
||||
* @enumIdentifier All
|
||||
@ -154,8 +163,7 @@ namespace EventSubscription {
|
||||
* @initialVersion 5.0.0
|
||||
* @api enums
|
||||
*/
|
||||
// Receive all event categories (exclude high-volume)
|
||||
All = (General | Config | Scenes | Inputs | Transitions | Filters | Outputs | SceneItems | MediaInputs | Vendors),
|
||||
All = (General | Config | Scenes | Inputs | Transitions | Filters | Outputs | SceneItems | MediaInputs | Ui | Vendors),
|
||||
/**
|
||||
* Subscription value to receive the `InputVolumeMeters` high-volume event.
|
||||
*
|
||||
@ -166,7 +174,6 @@ namespace EventSubscription {
|
||||
* @initialVersion 5.0.0
|
||||
* @api enums
|
||||
*/
|
||||
// InputVolumeMeters event (high-volume)
|
||||
InputVolumeMeters = (1 << 16),
|
||||
/**
|
||||
* Subscription value to receive the `InputActiveStateChanged` high-volume event.
|
||||
@ -178,7 +185,6 @@ namespace EventSubscription {
|
||||
* @initialVersion 5.0.0
|
||||
* @api enums
|
||||
*/
|
||||
// InputActiveStateChanged event (high-volume)
|
||||
InputActiveStateChanged = (1 << 17),
|
||||
/**
|
||||
* Subscription value to receive the `InputShowStateChanged` high-volume event.
|
||||
@ -190,7 +196,6 @@ namespace EventSubscription {
|
||||
* @initialVersion 5.0.0
|
||||
* @api enums
|
||||
*/
|
||||
// InputShowStateChanged event (high-volume)
|
||||
InputShowStateChanged = (1 << 18),
|
||||
/**
|
||||
* Subscription value to receive the `SceneItemTransformChanged` high-volume event.
|
||||
@ -202,7 +207,6 @@ namespace EventSubscription {
|
||||
* @initialVersion 5.0.0
|
||||
* @api enums
|
||||
*/
|
||||
// SceneItemTransformChanged event (high-volume)
|
||||
SceneItemTransformChanged = (1 << 19),
|
||||
};
|
||||
}
|
||||
|
@ -151,7 +151,7 @@
|
||||
<number>65534</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>4444</number>
|
||||
<number>4455</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -35,12 +35,12 @@ OBS_MODULE_AUTHOR("OBSProject")
|
||||
const char *obs_module_name(void) { return "obs-websocket"; }
|
||||
const char *obs_module_description(void) { return obs_module_text("OBSWebSocket.Plugin.Description"); }
|
||||
|
||||
os_cpu_usage_info_t* _cpuUsageInfo;
|
||||
ConfigPtr _config;
|
||||
EventHandlerPtr _eventHandler;
|
||||
WebSocketApiPtr _webSocketApi;
|
||||
WebSocketServerPtr _webSocketServer;
|
||||
EventHandlerPtr _eventHandler;
|
||||
SettingsDialog *_settingsDialog = nullptr;
|
||||
os_cpu_usage_info_t* _cpuUsageInfo;
|
||||
|
||||
void WebSocketApiEventCallback(std::string vendorName, std::string eventType, obs_data_t *obsEventData);
|
||||
|
||||
@ -48,32 +48,37 @@ bool obs_module_load(void)
|
||||
{
|
||||
blog(LOG_INFO, "[obs_module_load] you can haz websockets (Version: %s | RPC Version: %d)", OBS_WEBSOCKET_VERSION, OBS_WEBSOCKET_RPC_VERSION);
|
||||
blog(LOG_INFO, "[obs_module_load] Qt version (compile-time): %s | Qt version (run-time): %s", QT_VERSION_STR, qVersion());
|
||||
blog(LOG_INFO, "[obs_module_load] Linked ASIO Version: %d", ASIO_VERSION);
|
||||
|
||||
// Create the config object then load the parameters from storage
|
||||
// Initialize the cpu stats
|
||||
_cpuUsageInfo = os_cpu_usage_info_start();
|
||||
|
||||
// Create the config manager then load the parameters from storage
|
||||
_config = ConfigPtr(new Config());
|
||||
_config->Load();
|
||||
|
||||
// Initialize event handler before server, as the server configures the event handler.
|
||||
// Initialize the event handler
|
||||
_eventHandler = EventHandlerPtr(new EventHandler());
|
||||
|
||||
_webSocketApi = WebSocketApiPtr(new WebSocketApi(WebSocketApiEventCallback));
|
||||
// Initialize the plugin/script API
|
||||
_webSocketApi = WebSocketApiPtr(new WebSocketApi());
|
||||
_webSocketApi->SetEventCallback(WebSocketApiEventCallback);
|
||||
|
||||
// Initialize the WebSocket server
|
||||
_webSocketServer = WebSocketServerPtr(new WebSocketServer());
|
||||
|
||||
// Initialize the settings dialog
|
||||
obs_frontend_push_ui_translation(obs_module_get_string);
|
||||
QMainWindow* mainWindow = reinterpret_cast<QMainWindow*>(obs_frontend_get_main_window());
|
||||
QMainWindow* mainWindow = static_cast<QMainWindow*>(obs_frontend_get_main_window());
|
||||
_settingsDialog = new SettingsDialog(mainWindow);
|
||||
obs_frontend_pop_ui_translation();
|
||||
|
||||
// Add the settings dialog to the tools menu
|
||||
const char* menuActionText = obs_module_text("OBSWebSocket.Settings.DialogTitle");
|
||||
QAction* menuAction = (QAction*)obs_frontend_add_tools_menu_qaction(menuActionText);
|
||||
QObject::connect(menuAction, &QAction::triggered, [] { _settingsDialog->ToggleShowHide(); });
|
||||
|
||||
_cpuUsageInfo = os_cpu_usage_info_start();
|
||||
|
||||
// Loading finished
|
||||
blog(LOG_INFO, "[obs_module_load] Module loaded.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -81,29 +86,46 @@ void obs_module_unload()
|
||||
{
|
||||
blog(LOG_INFO, "[obs_module_unload] Shutting down...");
|
||||
|
||||
// Shutdown the WebSocket server if it is running
|
||||
if (_webSocketServer->IsListening()) {
|
||||
blog_debug("[obs_module_unload] WebSocket server is running. Stopping...");
|
||||
_webSocketServer->Stop();
|
||||
}
|
||||
|
||||
// Destroy the WebSocket server
|
||||
_webSocketServer.reset();
|
||||
|
||||
_eventHandler.reset();
|
||||
|
||||
// Destroy the plugin/script api
|
||||
_webSocketApi.reset();
|
||||
|
||||
// Destroy the event handler
|
||||
_eventHandler.reset();
|
||||
|
||||
// Save and destroy the config manager
|
||||
_config->Save();
|
||||
_config.reset();
|
||||
|
||||
// Destroy the cpu stats
|
||||
os_cpu_usage_info_destroy(_cpuUsageInfo);
|
||||
|
||||
blog(LOG_INFO, "[obs_module_unload] Finished shutting down.");
|
||||
}
|
||||
|
||||
os_cpu_usage_info_t* GetCpuUsageInfo()
|
||||
{
|
||||
return _cpuUsageInfo;
|
||||
}
|
||||
|
||||
ConfigPtr GetConfig()
|
||||
{
|
||||
return _config;
|
||||
}
|
||||
|
||||
EventHandlerPtr GetEventHandler()
|
||||
{
|
||||
return _eventHandler;
|
||||
}
|
||||
|
||||
WebSocketApiPtr GetWebSocketApi()
|
||||
{
|
||||
return _webSocketApi;
|
||||
@ -114,32 +136,11 @@ WebSocketServerPtr GetWebSocketServer()
|
||||
return _webSocketServer;
|
||||
}
|
||||
|
||||
EventHandlerPtr GetEventHandler()
|
||||
{
|
||||
return _eventHandler;
|
||||
}
|
||||
|
||||
os_cpu_usage_info_t* GetCpuUsageInfo()
|
||||
{
|
||||
return _cpuUsageInfo;
|
||||
}
|
||||
|
||||
bool IsDebugEnabled()
|
||||
{
|
||||
return !_config || _config->DebugEnabled;
|
||||
}
|
||||
|
||||
void ___source_dummy_addref(obs_source_t*) {}
|
||||
void ___weak_source_dummy_addref(obs_weak_source_t*) {}
|
||||
void ___scene_dummy_addref(obs_scene_t*) {}
|
||||
void ___sceneitem_dummy_addref(obs_sceneitem_t*) {}
|
||||
void ___data_dummy_addref(obs_data_t*) {}
|
||||
void ___data_array_dummy_addref(obs_data_array_t*) {}
|
||||
void ___output_dummy_addref(obs_output_t*) {}
|
||||
void ___data_item_dummy_addref(obs_data_item_t*) {}
|
||||
void ___data_item_release(obs_data_item_t* dataItem){ obs_data_item_release(&dataItem); }
|
||||
void ___properties_dummy_addref(obs_properties_t*) {}
|
||||
|
||||
/**
|
||||
* An event has been emitted from a vendor.
|
||||
*
|
||||
|
@ -21,58 +21,31 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
#include <memory>
|
||||
#include <obs.hpp>
|
||||
#ifdef _MSC_VER
|
||||
#pragma push_macro("strtoll")
|
||||
#endif
|
||||
#include <util/platform.h>
|
||||
#ifdef _MSC_VER
|
||||
#pragma pop_macro("strtoll")
|
||||
#endif
|
||||
|
||||
#include "utils/Obs.h"
|
||||
#include "plugin-macros.generated.h"
|
||||
|
||||
// Autorelease object definitions
|
||||
void ___source_dummy_addref(obs_source_t*);
|
||||
void ___weak_source_dummy_addref(obs_weak_source_t*);
|
||||
void ___scene_dummy_addref(obs_scene_t*);
|
||||
void ___sceneitem_dummy_addref(obs_sceneitem_t*);
|
||||
void ___data_dummy_addref(obs_data_t*);
|
||||
void ___data_array_dummy_addref(obs_data_array_t*);
|
||||
void ___output_dummy_addref(obs_output_t*);
|
||||
void ___data_item_dummy_addref(obs_data_item_t*);
|
||||
void ___data_item_release(obs_data_item_t*);
|
||||
void ___properties_dummy_addref(obs_properties_t*);
|
||||
|
||||
using OBSSourceAutoRelease = OBSRef<obs_source_t*, ___source_dummy_addref, obs_source_release>;
|
||||
using OBSWeakSourceAutoRelease = OBSRef<obs_weak_source_t*, ___weak_source_dummy_addref, obs_weak_source_release>;
|
||||
using OBSSceneAutoRelease = OBSRef<obs_scene_t*, ___scene_dummy_addref, obs_scene_release>;
|
||||
using OBSSceneItemAutoRelease = OBSRef<obs_sceneitem_t*, ___sceneitem_dummy_addref, obs_sceneitem_release>;
|
||||
using OBSDataAutoRelease = OBSRef<obs_data_t*, ___data_dummy_addref, obs_data_release>;
|
||||
using OBSDataArrayAutoRelease = OBSRef<obs_data_array_t*, ___data_array_dummy_addref, obs_data_array_release>;
|
||||
using OBSOutputAutoRelease = OBSRef<obs_output_t*, ___output_dummy_addref, obs_output_release>;
|
||||
using OBSDataItemAutoRelease = OBSRef<obs_data_item_t*, ___data_item_dummy_addref, ___data_item_release>;
|
||||
using OBSPropertiesAutoDestroy = OBSRef<obs_properties_t*, ___properties_dummy_addref, obs_properties_destroy>;
|
||||
|
||||
class Config;
|
||||
typedef std::shared_ptr<Config> ConfigPtr;
|
||||
|
||||
class EventHandler;
|
||||
typedef std::shared_ptr<EventHandler> EventHandlerPtr;
|
||||
|
||||
class WebSocketApi;
|
||||
typedef std::shared_ptr<WebSocketApi> WebSocketApiPtr;
|
||||
|
||||
class WebSocketServer;
|
||||
typedef std::shared_ptr<WebSocketServer> WebSocketServerPtr;
|
||||
|
||||
class EventHandler;
|
||||
typedef std::shared_ptr<EventHandler> EventHandlerPtr;
|
||||
os_cpu_usage_info_t* GetCpuUsageInfo();
|
||||
|
||||
ConfigPtr GetConfig();
|
||||
|
||||
EventHandlerPtr GetEventHandler();
|
||||
|
||||
WebSocketApiPtr GetWebSocketApi();
|
||||
|
||||
WebSocketServerPtr GetWebSocketServer();
|
||||
|
||||
EventHandlerPtr GetEventHandler();
|
||||
|
||||
os_cpu_usage_info_t* GetCpuUsageInfo();
|
||||
|
||||
bool IsDebugEnabled();
|
||||
|
@ -109,7 +109,7 @@ static void ObsTickCallback(void *param, float)
|
||||
{
|
||||
ScopeProfiler prof{"obs_websocket_request_batch_frame_tick"};
|
||||
|
||||
auto serialFrameBatch = reinterpret_cast<SerialFrameBatch*>(param);
|
||||
auto serialFrameBatch = static_cast<SerialFrameBatch*>(param);
|
||||
|
||||
// Increment frame count
|
||||
serialFrameBatch->frameCount++;
|
||||
|
@ -17,9 +17,13 @@ You should have received a copy of the GNU General Public License along
|
||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#ifdef PLUGIN_TESTS
|
||||
#include <util/profiler.hpp>
|
||||
#endif
|
||||
|
||||
#include "RequestHandler.h"
|
||||
|
||||
const std::map<std::string, RequestMethodHandler> RequestHandler::_handlerMap
|
||||
const std::unordered_map<std::string, RequestMethodHandler> RequestHandler::_handlerMap
|
||||
{
|
||||
// General
|
||||
{"GetVersion", &RequestHandler::GetVersion},
|
||||
@ -29,8 +33,6 @@ const std::map<std::string, RequestMethodHandler> RequestHandler::_handlerMap
|
||||
{"GetHotkeyList", &RequestHandler::GetHotkeyList},
|
||||
{"TriggerHotkeyByName", &RequestHandler::TriggerHotkeyByName},
|
||||
{"TriggerHotkeyByKeySequence", &RequestHandler::TriggerHotkeyByKeySequence},
|
||||
{"GetStudioModeEnabled", &RequestHandler::GetStudioModeEnabled},
|
||||
{"SetStudioModeEnabled", &RequestHandler::SetStudioModeEnabled},
|
||||
{"Sleep", &RequestHandler::Sleep},
|
||||
|
||||
// Config
|
||||
@ -49,14 +51,18 @@ const std::map<std::string, RequestMethodHandler> RequestHandler::_handlerMap
|
||||
{"SetVideoSettings", &RequestHandler::SetVideoSettings},
|
||||
{"GetStreamServiceSettings", &RequestHandler::GetStreamServiceSettings},
|
||||
{"SetStreamServiceSettings", &RequestHandler::SetStreamServiceSettings},
|
||||
{"GetRecordDirectory", &RequestHandler::GetRecordDirectory},
|
||||
|
||||
// Sources
|
||||
{"GetSourceActive", &RequestHandler::GetSourceActive},
|
||||
{"GetSourceScreenshot", &RequestHandler::GetSourceScreenshot},
|
||||
{"SaveSourceScreenshot", &RequestHandler::SaveSourceScreenshot},
|
||||
{"GetSourcePrivateSettings", &RequestHandler::GetSourcePrivateSettings},
|
||||
{"SetSourcePrivateSettings", &RequestHandler::SetSourcePrivateSettings},
|
||||
|
||||
// Scenes
|
||||
{"GetSceneList", &RequestHandler::GetSceneList},
|
||||
{"GetGroupList", &RequestHandler::GetGroupList},
|
||||
{"GetCurrentProgramScene", &RequestHandler::GetCurrentProgramScene},
|
||||
{"SetCurrentProgramScene", &RequestHandler::SetCurrentProgramScene},
|
||||
{"GetCurrentPreviewScene", &RequestHandler::GetCurrentPreviewScene},
|
||||
@ -64,12 +70,15 @@ const std::map<std::string, RequestMethodHandler> RequestHandler::_handlerMap
|
||||
{"CreateScene", &RequestHandler::CreateScene},
|
||||
{"RemoveScene", &RequestHandler::RemoveScene},
|
||||
{"SetSceneName", &RequestHandler::SetSceneName},
|
||||
{"GetSceneSceneTransitionOverride", &RequestHandler::GetSceneSceneTransitionOverride},
|
||||
{"SetSceneSceneTransitionOverride", &RequestHandler::SetSceneSceneTransitionOverride},
|
||||
|
||||
// Inputs
|
||||
{"GetInputList", &RequestHandler::GetInputList},
|
||||
{"GetInputKindList", &RequestHandler::GetInputKindList},
|
||||
{"GetSpecialInputs", &RequestHandler::GetSpecialInputs},
|
||||
{"CreateInput", &RequestHandler::CreateInput},
|
||||
//{"RemoveInput", &RequestHandler::RemoveInput}, // Disabled for now. Pending obs-studio#5276
|
||||
{"RemoveInput", &RequestHandler::RemoveInput},
|
||||
{"SetInputName", &RequestHandler::SetInputName},
|
||||
{"GetInputDefaultSettings", &RequestHandler::GetInputDefaultSettings},
|
||||
{"GetInputSettings", &RequestHandler::GetInputSettings},
|
||||
@ -79,13 +88,39 @@ const std::map<std::string, RequestMethodHandler> RequestHandler::_handlerMap
|
||||
{"ToggleInputMute", &RequestHandler::ToggleInputMute},
|
||||
{"GetInputVolume", &RequestHandler::GetInputVolume},
|
||||
{"SetInputVolume", &RequestHandler::SetInputVolume},
|
||||
{"GetInputAudioBalance", &RequestHandler::GetInputAudioBalance},
|
||||
{"SetInputAudioBalance", &RequestHandler::SetInputAudioBalance},
|
||||
{"GetInputAudioSyncOffset", &RequestHandler::GetInputAudioSyncOffset},
|
||||
{"SetInputAudioSyncOffset", &RequestHandler::SetInputAudioSyncOffset},
|
||||
{"GetInputAudioMonitorType", &RequestHandler::GetInputAudioMonitorType},
|
||||
{"SetInputAudioMonitorType", &RequestHandler::SetInputAudioMonitorType},
|
||||
{"GetInputAudioTracks", &RequestHandler::GetInputAudioTracks},
|
||||
{"SetInputAudioTracks", &RequestHandler::SetInputAudioTracks},
|
||||
{"GetInputPropertiesListPropertyItems", &RequestHandler::GetInputPropertiesListPropertyItems},
|
||||
{"PressInputPropertiesButton", &RequestHandler::PressInputPropertiesButton},
|
||||
|
||||
// Transitions
|
||||
{"GetTransitionKindList", &RequestHandler::GetTransitionKindList},
|
||||
{"GetSceneTransitionList", &RequestHandler::GetSceneTransitionList},
|
||||
{"GetCurrentSceneTransition", &RequestHandler::GetCurrentSceneTransition},
|
||||
{"SetCurrentSceneTransition", &RequestHandler::SetCurrentSceneTransition},
|
||||
{"SetCurrentSceneTransitionDuration", &RequestHandler::SetCurrentSceneTransitionDuration},
|
||||
{"SetCurrentSceneTransitionSettings", &RequestHandler::SetCurrentSceneTransitionSettings},
|
||||
{"GetCurrentSceneTransitionCursor", &RequestHandler::GetCurrentSceneTransitionCursor},
|
||||
{"TriggerStudioModeTransition", &RequestHandler::TriggerStudioModeTransition},
|
||||
{"SetTBarPosition", &RequestHandler::SetTBarPosition},
|
||||
|
||||
// Filters
|
||||
{"GetSourceFilterList", &RequestHandler::GetSourceFilterList},
|
||||
{"GetSourceFilterDefaultSettings", &RequestHandler::GetSourceFilterDefaultSettings},
|
||||
{"CreateSourceFilter", &RequestHandler::CreateSourceFilter},
|
||||
{"RemoveSourceFilter", &RequestHandler::RemoveSourceFilter},
|
||||
{"SetSourceFilterName", &RequestHandler::SetSourceFilterName},
|
||||
{"GetSourceFilter", &RequestHandler::GetSourceFilter},
|
||||
{"SetSourceFilterIndex", &RequestHandler::SetSourceFilterIndex},
|
||||
{"SetSourceFilterSettings", &RequestHandler::SetSourceFilterSettings},
|
||||
{"SetSourceFilterEnabled", &RequestHandler::SetSourceFilterEnabled},
|
||||
|
||||
// Scene Items
|
||||
{"GetSceneItemList", &RequestHandler::GetSceneItemList},
|
||||
{"GetGroupSceneItemList", &RequestHandler::GetGroupSceneItemList},
|
||||
@ -101,12 +136,27 @@ const std::map<std::string, RequestMethodHandler> RequestHandler::_handlerMap
|
||||
{"SetSceneItemLocked", &RequestHandler::SetSceneItemLocked},
|
||||
{"GetSceneItemIndex", &RequestHandler::GetSceneItemIndex},
|
||||
{"SetSceneItemIndex", &RequestHandler::SetSceneItemIndex},
|
||||
{"GetSceneItemBlendMode", &RequestHandler::GetSceneItemBlendMode},
|
||||
{"SetSceneItemBlendMode", &RequestHandler::SetSceneItemBlendMode},
|
||||
|
||||
// Outputs
|
||||
{"GetVirtualCamStatus", &RequestHandler::GetVirtualCamStatus},
|
||||
{"ToggleVirtualCam", &RequestHandler::ToggleVirtualCam},
|
||||
{"StartVirtualCam", &RequestHandler::StartVirtualCam},
|
||||
{"StopVirtualCam", &RequestHandler::StopVirtualCam},
|
||||
{"GetReplayBufferStatus", &RequestHandler::GetReplayBufferStatus},
|
||||
{"ToggleReplayBuffer", &RequestHandler::ToggleReplayBuffer},
|
||||
{"StartReplayBuffer", &RequestHandler::StartReplayBuffer},
|
||||
{"StopReplayBuffer", &RequestHandler::StopReplayBuffer},
|
||||
{"SaveReplayBuffer", &RequestHandler::SaveReplayBuffer},
|
||||
{"GetLastReplayBufferReplay", &RequestHandler::GetLastReplayBufferReplay},
|
||||
|
||||
// Stream
|
||||
{"GetStreamStatus", &RequestHandler::GetStreamStatus},
|
||||
{"ToggleStream", &RequestHandler::ToggleStream},
|
||||
{"StartStream", &RequestHandler::StartStream},
|
||||
{"StopStream", &RequestHandler::StopStream},
|
||||
{"SendStreamCaption", &RequestHandler::SendStreamCaption},
|
||||
|
||||
// Record
|
||||
{"GetRecordStatus", &RequestHandler::GetRecordStatus},
|
||||
@ -116,13 +166,19 @@ const std::map<std::string, RequestMethodHandler> RequestHandler::_handlerMap
|
||||
{"ToggleRecordPause", &RequestHandler::ToggleRecordPause},
|
||||
{"PauseRecord", &RequestHandler::PauseRecord},
|
||||
{"ResumeRecord", &RequestHandler::ResumeRecord},
|
||||
//{"GetRecordDirectory", &RequestHandler::GetRecordDirectory},
|
||||
|
||||
// Media Inputs
|
||||
{"GetMediaInputStatus", &RequestHandler::GetMediaInputStatus},
|
||||
{"SetMediaInputCursor", &RequestHandler::SetMediaInputCursor},
|
||||
{"OffsetMediaInputCursor", &RequestHandler::OffsetMediaInputCursor},
|
||||
{"TriggerMediaInputAction", &RequestHandler::TriggerMediaInputAction},
|
||||
|
||||
// Ui
|
||||
{"GetStudioModeEnabled", &RequestHandler::GetStudioModeEnabled},
|
||||
{"SetStudioModeEnabled", &RequestHandler::SetStudioModeEnabled},
|
||||
{"OpenInputPropertiesDialog", &RequestHandler::OpenInputPropertiesDialog},
|
||||
{"OpenInputFiltersDialog", &RequestHandler::OpenInputFiltersDialog},
|
||||
{"OpenInputInteractDialog", &RequestHandler::OpenInputInteractDialog},
|
||||
};
|
||||
|
||||
RequestHandler::RequestHandler(SessionPtr session) :
|
||||
@ -132,6 +188,10 @@ RequestHandler::RequestHandler(SessionPtr session) :
|
||||
|
||||
RequestResult RequestHandler::ProcessRequest(const Request& request)
|
||||
{
|
||||
#ifdef PLUGIN_TESTS
|
||||
ScopeProfiler prof{"obs_websocket_request_processing"};
|
||||
#endif
|
||||
|
||||
if (!request.RequestData.is_object() && !request.RequestData.is_null())
|
||||
return RequestResult::Error(RequestStatus::InvalidRequestFieldType, "Your request data is not an object.");
|
||||
|
||||
|
@ -19,7 +19,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <obs.hpp>
|
||||
#include <obs-frontend-api.h>
|
||||
|
||||
@ -51,8 +51,6 @@ class RequestHandler {
|
||||
RequestResult GetHotkeyList(const Request&);
|
||||
RequestResult TriggerHotkeyByName(const Request&);
|
||||
RequestResult TriggerHotkeyByKeySequence(const Request&);
|
||||
RequestResult GetStudioModeEnabled(const Request&);
|
||||
RequestResult SetStudioModeEnabled(const Request&);
|
||||
RequestResult Sleep(const Request&);
|
||||
|
||||
// Config
|
||||
@ -71,14 +69,18 @@ class RequestHandler {
|
||||
RequestResult SetVideoSettings(const Request&);
|
||||
RequestResult GetStreamServiceSettings(const Request&);
|
||||
RequestResult SetStreamServiceSettings(const Request&);
|
||||
RequestResult GetRecordDirectory(const Request&);
|
||||
|
||||
// Sources
|
||||
RequestResult GetSourceActive(const Request&);
|
||||
RequestResult GetSourceScreenshot(const Request&);
|
||||
RequestResult SaveSourceScreenshot(const Request&);
|
||||
RequestResult GetSourcePrivateSettings(const Request&);
|
||||
RequestResult SetSourcePrivateSettings(const Request&);
|
||||
|
||||
// Scenes
|
||||
RequestResult GetSceneList(const Request&);
|
||||
RequestResult GetGroupList(const Request&);
|
||||
RequestResult GetCurrentProgramScene(const Request&);
|
||||
RequestResult SetCurrentProgramScene(const Request&);
|
||||
RequestResult GetCurrentPreviewScene(const Request&);
|
||||
@ -86,10 +88,13 @@ class RequestHandler {
|
||||
RequestResult CreateScene(const Request&);
|
||||
RequestResult RemoveScene(const Request&);
|
||||
RequestResult SetSceneName(const Request&);
|
||||
RequestResult GetSceneSceneTransitionOverride(const Request&);
|
||||
RequestResult SetSceneSceneTransitionOverride(const Request&);
|
||||
|
||||
// Inputs
|
||||
RequestResult GetInputList(const Request&);
|
||||
RequestResult GetInputKindList(const Request&);
|
||||
RequestResult GetSpecialInputs(const Request&);
|
||||
RequestResult CreateInput(const Request&);
|
||||
RequestResult RemoveInput(const Request&);
|
||||
RequestResult SetInputName(const Request&);
|
||||
@ -101,13 +106,39 @@ class RequestHandler {
|
||||
RequestResult ToggleInputMute(const Request&);
|
||||
RequestResult GetInputVolume(const Request&);
|
||||
RequestResult SetInputVolume(const Request&);
|
||||
RequestResult GetInputAudioBalance(const Request&);
|
||||
RequestResult SetInputAudioBalance(const Request&);
|
||||
RequestResult GetInputAudioSyncOffset(const Request&);
|
||||
RequestResult SetInputAudioSyncOffset(const Request&);
|
||||
RequestResult GetInputAudioMonitorType(const Request&);
|
||||
RequestResult SetInputAudioMonitorType(const Request&);
|
||||
RequestResult GetInputAudioTracks(const Request&);
|
||||
RequestResult SetInputAudioTracks(const Request&);
|
||||
RequestResult GetInputPropertiesListPropertyItems(const Request&);
|
||||
RequestResult PressInputPropertiesButton(const Request&);
|
||||
|
||||
// Transitions
|
||||
RequestResult GetTransitionKindList(const Request&);
|
||||
RequestResult GetSceneTransitionList(const Request&);
|
||||
RequestResult GetCurrentSceneTransition(const Request&);
|
||||
RequestResult SetCurrentSceneTransition(const Request&);
|
||||
RequestResult SetCurrentSceneTransitionDuration(const Request&);
|
||||
RequestResult SetCurrentSceneTransitionSettings(const Request&);
|
||||
RequestResult GetCurrentSceneTransitionCursor(const Request&);
|
||||
RequestResult TriggerStudioModeTransition(const Request&);
|
||||
RequestResult SetTBarPosition(const Request&);
|
||||
|
||||
// Filters
|
||||
RequestResult GetSourceFilterList(const Request&);
|
||||
RequestResult GetSourceFilterDefaultSettings(const Request&);
|
||||
RequestResult CreateSourceFilter(const Request&);
|
||||
RequestResult RemoveSourceFilter(const Request&);
|
||||
RequestResult SetSourceFilterName(const Request&);
|
||||
RequestResult GetSourceFilter(const Request&);
|
||||
RequestResult SetSourceFilterIndex(const Request&);
|
||||
RequestResult SetSourceFilterSettings(const Request&);
|
||||
RequestResult SetSourceFilterEnabled(const Request&);
|
||||
|
||||
// Scene Items
|
||||
RequestResult GetSceneItemList(const Request&);
|
||||
RequestResult GetGroupSceneItemList(const Request&);
|
||||
@ -123,12 +154,27 @@ class RequestHandler {
|
||||
RequestResult SetSceneItemLocked(const Request&);
|
||||
RequestResult GetSceneItemIndex(const Request&);
|
||||
RequestResult SetSceneItemIndex(const Request&);
|
||||
RequestResult GetSceneItemBlendMode(const Request&);
|
||||
RequestResult SetSceneItemBlendMode(const Request&);
|
||||
|
||||
// Outputs
|
||||
RequestResult GetVirtualCamStatus(const Request&);
|
||||
RequestResult ToggleVirtualCam(const Request&);
|
||||
RequestResult StartVirtualCam(const Request&);
|
||||
RequestResult StopVirtualCam(const Request&);
|
||||
RequestResult GetReplayBufferStatus(const Request&);
|
||||
RequestResult ToggleReplayBuffer(const Request&);
|
||||
RequestResult StartReplayBuffer(const Request&);
|
||||
RequestResult StopReplayBuffer(const Request&);
|
||||
RequestResult SaveReplayBuffer(const Request&);
|
||||
RequestResult GetLastReplayBufferReplay(const Request&);
|
||||
|
||||
// Stream
|
||||
RequestResult GetStreamStatus(const Request&);
|
||||
RequestResult ToggleStream(const Request&);
|
||||
RequestResult StartStream(const Request&);
|
||||
RequestResult StopStream(const Request&);
|
||||
RequestResult SendStreamCaption(const Request&);
|
||||
|
||||
// Record
|
||||
RequestResult GetRecordStatus(const Request&);
|
||||
@ -138,7 +184,6 @@ class RequestHandler {
|
||||
RequestResult ToggleRecordPause(const Request&);
|
||||
RequestResult PauseRecord(const Request&);
|
||||
RequestResult ResumeRecord(const Request&);
|
||||
RequestResult GetRecordDirectory(const Request&);
|
||||
|
||||
// Media Inputs
|
||||
RequestResult GetMediaInputStatus(const Request&);
|
||||
@ -146,6 +191,13 @@ class RequestHandler {
|
||||
RequestResult OffsetMediaInputCursor(const Request&);
|
||||
RequestResult TriggerMediaInputAction(const Request&);
|
||||
|
||||
// Ui
|
||||
RequestResult GetStudioModeEnabled(const Request&);
|
||||
RequestResult SetStudioModeEnabled(const Request&);
|
||||
RequestResult OpenInputPropertiesDialog(const Request&);
|
||||
RequestResult OpenInputFiltersDialog(const Request&);
|
||||
RequestResult OpenInputInteractDialog(const Request&);
|
||||
|
||||
SessionPtr _session;
|
||||
static const std::map<std::string, RequestMethodHandler> _handlerMap;
|
||||
static const std::unordered_map<std::string, RequestMethodHandler> _handlerMap;
|
||||
};
|
||||
|
@ -124,7 +124,7 @@ RequestResult RequestHandler::GetSceneCollectionList(const Request&)
|
||||
{
|
||||
json responseData;
|
||||
responseData["currentSceneCollectionName"] = Utils::Obs::StringHelper::GetCurrentSceneCollection();
|
||||
responseData["sceneCollections"] = Utils::Obs::ListHelper::GetSceneCollectionList();
|
||||
responseData["sceneCollections"] = Utils::Obs::ArrayHelper::GetSceneCollectionList();
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
@ -151,7 +151,7 @@ RequestResult RequestHandler::SetCurrentSceneCollection(const Request& request)
|
||||
|
||||
std::string sceneCollectionName = request.RequestData["sceneCollectionName"];
|
||||
|
||||
auto sceneCollections = Utils::Obs::ListHelper::GetSceneCollectionList();
|
||||
auto sceneCollections = Utils::Obs::ArrayHelper::GetSceneCollectionList();
|
||||
if (std::find(sceneCollections.begin(), sceneCollections.end(), sceneCollectionName) == sceneCollections.end())
|
||||
return RequestResult::Error(RequestStatus::ResourceNotFound);
|
||||
|
||||
@ -159,7 +159,7 @@ RequestResult RequestHandler::SetCurrentSceneCollection(const Request& request)
|
||||
// Avoid queueing tasks if nothing will change
|
||||
if (currentSceneCollectionName != sceneCollectionName) {
|
||||
obs_queue_task(OBS_TASK_UI, [](void* param) {
|
||||
obs_frontend_set_current_scene_collection(reinterpret_cast<const char*>(param));
|
||||
obs_frontend_set_current_scene_collection(static_cast<const char*>(param));
|
||||
}, (void*)sceneCollectionName.c_str(), true);
|
||||
}
|
||||
|
||||
@ -189,11 +189,11 @@ RequestResult RequestHandler::CreateSceneCollection(const Request& request)
|
||||
|
||||
std::string sceneCollectionName = request.RequestData["sceneCollectionName"];
|
||||
|
||||
auto sceneCollections = Utils::Obs::ListHelper::GetSceneCollectionList();
|
||||
auto sceneCollections = Utils::Obs::ArrayHelper::GetSceneCollectionList();
|
||||
if (std::find(sceneCollections.begin(), sceneCollections.end(), sceneCollectionName) != sceneCollections.end())
|
||||
return RequestResult::Error(RequestStatus::ResourceAlreadyExists);
|
||||
|
||||
QMainWindow* mainWindow = reinterpret_cast<QMainWindow*>(obs_frontend_get_main_window());
|
||||
QMainWindow* mainWindow = static_cast<QMainWindow*>(obs_frontend_get_main_window());
|
||||
bool success = false;
|
||||
QMetaObject::invokeMethod(mainWindow, "AddSceneCollection", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, success), Q_ARG(bool, true), Q_ARG(QString, QString::fromStdString(sceneCollectionName)));
|
||||
if (!success)
|
||||
@ -219,7 +219,7 @@ RequestResult RequestHandler::GetProfileList(const Request&)
|
||||
{
|
||||
json responseData;
|
||||
responseData["currentProfileName"] = Utils::Obs::StringHelper::GetCurrentProfile();
|
||||
responseData["profiles"] = Utils::Obs::ListHelper::GetProfileList();
|
||||
responseData["profiles"] = Utils::Obs::ArrayHelper::GetProfileList();
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
@ -244,7 +244,7 @@ RequestResult RequestHandler::SetCurrentProfile(const Request& request)
|
||||
|
||||
std::string profileName = request.RequestData["profileName"];
|
||||
|
||||
auto profiles = Utils::Obs::ListHelper::GetProfileList();
|
||||
auto profiles = Utils::Obs::ArrayHelper::GetProfileList();
|
||||
if (std::find(profiles.begin(), profiles.end(), profileName) == profiles.end())
|
||||
return RequestResult::Error(RequestStatus::ResourceNotFound);
|
||||
|
||||
@ -252,7 +252,7 @@ RequestResult RequestHandler::SetCurrentProfile(const Request& request)
|
||||
// Avoid queueing tasks if nothing will change
|
||||
if (currentProfileName != profileName) {
|
||||
obs_queue_task(OBS_TASK_UI, [](void* param) {
|
||||
obs_frontend_set_current_profile(reinterpret_cast<const char*>(param));
|
||||
obs_frontend_set_current_profile(static_cast<const char*>(param));
|
||||
}, (void*)profileName.c_str(), true);
|
||||
}
|
||||
|
||||
@ -280,11 +280,11 @@ RequestResult RequestHandler::CreateProfile(const Request& request)
|
||||
|
||||
std::string profileName = request.RequestData["profileName"];
|
||||
|
||||
auto profiles = Utils::Obs::ListHelper::GetProfileList();
|
||||
auto profiles = Utils::Obs::ArrayHelper::GetProfileList();
|
||||
if (std::find(profiles.begin(), profiles.end(), profileName) != profiles.end())
|
||||
return RequestResult::Error(RequestStatus::ResourceAlreadyExists);
|
||||
|
||||
QMainWindow* mainWindow = reinterpret_cast<QMainWindow*>(obs_frontend_get_main_window());
|
||||
QMainWindow* mainWindow = static_cast<QMainWindow*>(obs_frontend_get_main_window());
|
||||
QMetaObject::invokeMethod(mainWindow, "NewProfile", Qt::BlockingQueuedConnection, Q_ARG(QString, QString::fromStdString(profileName)));
|
||||
|
||||
return RequestResult::Success();
|
||||
@ -311,14 +311,14 @@ RequestResult RequestHandler::RemoveProfile(const Request& request)
|
||||
|
||||
std::string profileName = request.RequestData["profileName"];
|
||||
|
||||
auto profiles = Utils::Obs::ListHelper::GetProfileList();
|
||||
auto profiles = Utils::Obs::ArrayHelper::GetProfileList();
|
||||
if (std::find(profiles.begin(), profiles.end(), profileName) == profiles.end())
|
||||
return RequestResult::Error(RequestStatus::ResourceNotFound);
|
||||
|
||||
if (profiles.size() < 2)
|
||||
return RequestResult::Error(RequestStatus::NotEnoughResources);
|
||||
|
||||
QMainWindow* mainWindow = reinterpret_cast<QMainWindow*>(obs_frontend_get_main_window());
|
||||
QMainWindow* mainWindow = static_cast<QMainWindow*>(obs_frontend_get_main_window());
|
||||
QMetaObject::invokeMethod(mainWindow, "DeleteProfile", Qt::BlockingQueuedConnection, Q_ARG(QString, QString::fromStdString(profileName)));
|
||||
|
||||
return RequestResult::Success();
|
||||
@ -334,7 +334,7 @@ RequestResult RequestHandler::RemoveProfile(const Request& request)
|
||||
* @responseField defaultParameterValue | String | Default value associated with the parameter. `null` if no default
|
||||
*
|
||||
* @requestType GetProfileParameter
|
||||
* @complexity 3
|
||||
* @complexity 4
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @category config
|
||||
@ -378,7 +378,7 @@ RequestResult RequestHandler::GetProfileParameter(const Request& request)
|
||||
* @requestField parameterValue | String | Value of the parameter to set. Use `null` to delete
|
||||
*
|
||||
* @requestType SetProfileParameter
|
||||
* @complexity 3
|
||||
* @complexity 4
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @category config
|
||||
@ -408,6 +408,8 @@ RequestResult RequestHandler::SetProfileParameter(const Request& request)
|
||||
return RequestResult::Error(RequestStatus::InvalidRequestFieldType, "The field `parameterValue` must be a string.");
|
||||
}
|
||||
|
||||
config_save(profile);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
@ -592,3 +594,23 @@ RequestResult RequestHandler::SetStreamServiceSettings(const Request& request)
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current directory that the record output is set to.
|
||||
*
|
||||
* @responseField recordDirectory | String | Output directory
|
||||
*
|
||||
* @requestType GetRecordDirectory
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category rconfig
|
||||
*/
|
||||
RequestResult RequestHandler::GetRecordDirectory(const Request&)
|
||||
{
|
||||
json responseData;
|
||||
responseData["recordDirectory"] = Utils::Obs::StringHelper::GetCurrentRecordOutputPath();
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
334
src/requesthandler/RequestHandler_Filters.cpp
Normal file
334
src/requesthandler/RequestHandler_Filters.cpp
Normal file
@ -0,0 +1,334 @@
|
||||
/*
|
||||
obs-websocket
|
||||
Copyright (C) 2016-2021 Stephane Lepin <stephane.lepin@gmail.com>
|
||||
Copyright (C) 2020-2021 Kyle Manning <tt2468@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "RequestHandler.h"
|
||||
|
||||
/**
|
||||
* Gets an array of all of a source's filters.
|
||||
*
|
||||
* @requestField sourceName | String | Name of the source
|
||||
*
|
||||
* @responseField filters | Array<Object> | Array of filters
|
||||
*
|
||||
* @requestType GetSourceFilterList
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category filters
|
||||
*/
|
||||
RequestResult RequestHandler::GetSourceFilterList(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease source = request.ValidateSource("sourceName", statusCode, comment);
|
||||
if(!source)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
json responseData;
|
||||
responseData["filters"] = Utils::Obs::ArrayHelper::GetSourceFilterList(source);
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default settings for a filter kind.
|
||||
*
|
||||
* @requestField filterKind | String | Filter kind to get the default settings for
|
||||
*
|
||||
* @responseField defaultFilterSettings | Object | Object of default settings for the filter kind
|
||||
*
|
||||
* @requestType GetSourceFilterDefaultSettings
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category filters
|
||||
*/
|
||||
RequestResult RequestHandler::GetSourceFilterDefaultSettings(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
if (!request.ValidateString("filterKind", statusCode, comment))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
std::string filterKind = request.RequestData["filterKind"];
|
||||
auto kinds = Utils::Obs::ArrayHelper::GetFilterKindList();
|
||||
if (std::find(kinds.begin(), kinds.end(), filterKind) == kinds.end())
|
||||
return RequestResult::Error(RequestStatus::InvalidFilterKind);
|
||||
|
||||
OBSDataAutoRelease defaultSettings = obs_get_source_defaults(filterKind.c_str());
|
||||
if (!defaultSettings)
|
||||
return RequestResult::Error(RequestStatus::InvalidFilterKind);
|
||||
|
||||
json responseData;
|
||||
responseData["defaultFilterSettings"] = Utils::Json::ObsDataToJson(defaultSettings, true);
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new filter, adding it to the specified source.
|
||||
*
|
||||
* @requestField sourceName | String | Name of the source to add the filter to
|
||||
* @requestField filterName | String | Name of the new filter to be created
|
||||
* @requestField filterKind | String | The kind of filter to be created
|
||||
* @requestField ?filterSettings | Object | Settings object to initialize the filter with | Default settings used
|
||||
*
|
||||
* @requestType CreateSourceFilter
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category filters
|
||||
*/
|
||||
RequestResult RequestHandler::CreateSourceFilter(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
|
||||
OBSSourceAutoRelease source = request.ValidateSource("sourceName", statusCode, comment);
|
||||
if (!(source && request.ValidateString("filterName", statusCode, comment) && request.ValidateString("filterKind", statusCode, comment)))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
std::string filterName = request.RequestData["filterName"];
|
||||
OBSSourceAutoRelease existingFilter = obs_source_get_filter_by_name(source, filterName.c_str());
|
||||
if (existingFilter)
|
||||
return RequestResult::Error(RequestStatus::ResourceAlreadyExists, "A filter already exists by that name.");
|
||||
|
||||
std::string filterKind = request.RequestData["filterKind"];
|
||||
auto kinds = Utils::Obs::ArrayHelper::GetFilterKindList();
|
||||
if (std::find(kinds.begin(), kinds.end(), filterKind) == kinds.end())
|
||||
return RequestResult::Error(RequestStatus::InvalidFilterKind, "Your specified filter kind is not supported by OBS. Check that any necessary plugins are loaded.");
|
||||
|
||||
OBSDataAutoRelease filterSettings = nullptr;
|
||||
if (request.Contains("filterSettings")) {
|
||||
if (!request.ValidateOptionalObject("filterSettings", statusCode, comment, true))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
filterSettings = Utils::Json::JsonToObsData(request.RequestData["filterSettings"]);
|
||||
}
|
||||
|
||||
OBSSourceAutoRelease filter = Utils::Obs::ActionHelper::CreateSourceFilter(source, filterName, filterKind, filterSettings);
|
||||
|
||||
if(!filter)
|
||||
return RequestResult::Error(RequestStatus::ResourceCreationFailed, "Creation of the filter failed.");
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a filter from a source.
|
||||
*
|
||||
* @requestField sourceName | String | Name of the source the filter is on
|
||||
* @requestField filterName | String | Name of the filter to remove
|
||||
*
|
||||
* @requestType RemoveSourceFilter
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category filters
|
||||
*/
|
||||
RequestResult RequestHandler::RemoveSourceFilter(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment);
|
||||
if (!pair.filter)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
obs_source_filter_remove(pair.source, pair.filter);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of a source filter (rename).
|
||||
*
|
||||
* @requestField sourceName | String | Name of the source the filter is on
|
||||
* @requestField filterName | String | Current name of the filter
|
||||
* @requestField newFilterName | String | New name for the filter
|
||||
*
|
||||
* @requestType SetSourceFilterName
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category filters
|
||||
*/
|
||||
RequestResult RequestHandler::SetSourceFilterName(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment);
|
||||
if (!pair.filter || !request.ValidateString("newFilterName", statusCode, comment))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
std::string newFilterName = request.RequestData["newFilterName"];
|
||||
|
||||
OBSSourceAutoRelease existingFilter = obs_source_get_filter_by_name(pair.source, newFilterName.c_str());
|
||||
if (existingFilter)
|
||||
return RequestResult::Error(RequestStatus::ResourceAlreadyExists, "A filter already exists by that new name.");
|
||||
|
||||
obs_source_set_name(pair.filter, newFilterName.c_str());
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the info for a specific source filter.
|
||||
*
|
||||
* @requestField sourceName | String | Name of the source
|
||||
* @requestField filterName | String | Name of the filter
|
||||
*
|
||||
* @responseField filterEnabled | Boolean | Whether the filter is enabled
|
||||
* @responseField filterIndex | Number | Index of the filter in the list, beginning at 0
|
||||
* @responseField filterKind | String | The kind of filter
|
||||
* @responseField filterSettings | Object | Settings object associated with the filter
|
||||
*
|
||||
* @requestType GetSourceFilter
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category filters
|
||||
*/
|
||||
RequestResult RequestHandler::GetSourceFilter(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment);
|
||||
if (!pair.filter)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
json responseData;
|
||||
responseData["filterEnabled"] = obs_source_enabled(pair.filter);
|
||||
responseData["filterIndex"] = Utils::Obs::NumberHelper::GetSourceFilterIndex(pair.source, pair.filter); // Todo: Use `GetSourceFilterlist` to select this filter maybe
|
||||
responseData["filterKind"] = obs_source_get_id(pair.filter);
|
||||
|
||||
OBSDataAutoRelease filterSettings = obs_source_get_settings(pair.filter);
|
||||
responseData["filterSettings"] = Utils::Json::ObsDataToJson(filterSettings);
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the index position of a filter on a source.
|
||||
*
|
||||
* @requestField sourceName | String | Name of the source the filter is on
|
||||
* @requestField filterName | String | Name of the filter
|
||||
* @requestField filterIndex | Number | New index position of the filter | >= 0
|
||||
*
|
||||
* @requestType SetSourceFilterIndex
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category filters
|
||||
*/
|
||||
RequestResult RequestHandler::SetSourceFilterIndex(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment);
|
||||
if (!(pair.filter && request.ValidateNumber("filterIndex", statusCode, comment, 0, 8192)))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
int filterIndex = request.RequestData["filterIndex"];
|
||||
|
||||
Utils::Obs::ActionHelper::SetSourceFilterIndex(pair.source, pair.filter, filterIndex);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the settings of a source filter.
|
||||
*
|
||||
* @requestField sourceName | String | Name of the source the filter is on
|
||||
* @requestField filterName | String | Name of the filter to set the settings of
|
||||
* @requestField filterSettings | Object | Object of settings to apply
|
||||
* @requestField ?overlay | Boolean | True == apply the settings on top of existing ones, False == reset the input to its defaults, then apply settings. | true
|
||||
*
|
||||
* @requestType SetSourceFilterSettings
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category filters
|
||||
*/
|
||||
RequestResult RequestHandler::SetSourceFilterSettings(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment);
|
||||
if (!(pair.filter && request.ValidateObject("filterSettings", statusCode, comment, true)))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
// Almost identical to SetInputSettings
|
||||
|
||||
bool overlay = true;
|
||||
if (request.Contains("overlay")) {
|
||||
if (!request.ValidateOptionalBoolean("overlay", statusCode, comment))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
overlay = request.RequestData["overlay"];
|
||||
}
|
||||
|
||||
OBSDataAutoRelease newSettings = Utils::Json::JsonToObsData(request.RequestData["filterSettings"]);
|
||||
if (!newSettings)
|
||||
return RequestResult::Error(RequestStatus::RequestProcessingFailed, "An internal data conversion operation failed. Please report this!");
|
||||
|
||||
if (overlay)
|
||||
obs_source_update(pair.filter, newSettings);
|
||||
else
|
||||
obs_source_reset_settings(pair.filter, newSettings);
|
||||
|
||||
obs_source_update_properties(pair.filter);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the enable state of a source filter.
|
||||
*
|
||||
* @requestField sourceName | String | Name of the source the filter is on
|
||||
* @requestField filterName | Number | Name of the filter
|
||||
* @requestField filterEnabled | Boolean | New enable state of the filter
|
||||
*
|
||||
* @requestType SetSourceFilterEnabled
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category filters
|
||||
*/
|
||||
RequestResult RequestHandler::SetSourceFilterEnabled(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment);
|
||||
if (!(pair.filter && request.ValidateBoolean("filterEnabled", statusCode, comment)))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
bool filterEnabled = request.RequestData["filterEnabled"];
|
||||
|
||||
obs_source_set_enabled(pair.filter, filterEnabled);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
@ -84,7 +84,7 @@ RequestResult RequestHandler::GetVersion(const Request&)
|
||||
*/
|
||||
RequestResult RequestHandler::GetStats(const Request&)
|
||||
{
|
||||
json responseData = Utils::Obs::DataHelper::GetStats();
|
||||
json responseData = Utils::Obs::ObjectHelper::GetStats();
|
||||
|
||||
responseData["webSocketSessionIncomingMessages"] = _session->IncomingMessages();
|
||||
responseData["webSocketSessionOutgoingMessages"] = _session->OutgoingMessages();
|
||||
@ -195,7 +195,7 @@ RequestResult RequestHandler::CallVendorRequest(const Request& request)
|
||||
RequestResult RequestHandler::GetHotkeyList(const Request&)
|
||||
{
|
||||
json responseData;
|
||||
responseData["hotkeys"] = Utils::Obs::ListHelper::GetHotkeyNameList();
|
||||
responseData["hotkeys"] = Utils::Obs::ArrayHelper::GetHotkeyNameList();
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
@ -288,58 +288,6 @@ RequestResult RequestHandler::TriggerHotkeyByKeySequence(const Request& request)
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether studio is enabled.
|
||||
*
|
||||
* @responseField studioModeEnabled | Boolean | Whether studio mode is enabled
|
||||
*
|
||||
* @requestType GetStudioModeEnabled
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @category general
|
||||
* @api requests
|
||||
*/
|
||||
RequestResult RequestHandler::GetStudioModeEnabled(const Request&)
|
||||
{
|
||||
json responseData;
|
||||
responseData["studioModeEnabled"] = obs_frontend_preview_program_mode_active();
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables studio mode
|
||||
*
|
||||
* @requestField studioModeEnabled | Boolean | True == Enabled, False == Disabled
|
||||
*
|
||||
* @requestType SetStudioModeEnabled
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @category general
|
||||
* @api requests
|
||||
*/
|
||||
RequestResult RequestHandler::SetStudioModeEnabled(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
if (!request.ValidateBoolean("studioModeEnabled", statusCode, comment))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
// Avoid queueing tasks if nothing will change
|
||||
if (obs_frontend_preview_program_mode_active() != request.RequestData["studioModeEnabled"]) {
|
||||
// (Bad) Create a boolean then pass it as a reference to the task. Requires `wait` in obs_queue_task() to be true, else undefined behavior
|
||||
bool studioModeEnabled = request.RequestData["studioModeEnabled"];
|
||||
// Queue the task inside of the UI thread to prevent race conditions
|
||||
obs_queue_task(OBS_TASK_UI, [](void* param) {
|
||||
auto studioModeEnabled = (bool*)param;
|
||||
obs_frontend_set_preview_program_mode(*studioModeEnabled);
|
||||
}, &studioModeEnabled, true);
|
||||
}
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sleeps for a time duration or number of frames. Only available in request batches with types `SERIAL_REALTIME` or `SERIAL_FRAME`.
|
||||
*
|
||||
|
@ -47,7 +47,7 @@ RequestResult RequestHandler::GetInputList(const Request& request)
|
||||
}
|
||||
|
||||
json responseData;
|
||||
responseData["inputs"] = Utils::Obs::ListHelper::GetInputList(inputKind);
|
||||
responseData["inputs"] = Utils::Obs::ArrayHelper::GetInputList(inputKind);
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
@ -79,7 +79,44 @@ RequestResult RequestHandler::GetInputKindList(const Request& request)
|
||||
}
|
||||
|
||||
json responseData;
|
||||
responseData["inputKinds"] = Utils::Obs::ListHelper::GetInputKindList(unversioned);
|
||||
responseData["inputKinds"] = Utils::Obs::ArrayHelper::GetInputKindList(unversioned);
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the names of all special inputs.
|
||||
*
|
||||
* @responseField desktop1 | String | Name of the Desktop Audio input
|
||||
* @responseField desktop2 | String | Name of the Desktop Audio 2 input
|
||||
* @responseField mic1 | String | Name of the Mic/Auxiliary Audio input
|
||||
* @responseField mic2 | String | Name of the Mic/Auxiliary Audio 2 input
|
||||
* @responseField mic3 | String | Name of the Mic/Auxiliary Audio 3 input
|
||||
* @responseField mic4 | String | Name of the Mic/Auxiliary Audio 4 input
|
||||
*
|
||||
* @requestType GetSpecialInputs
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category inputs
|
||||
*/
|
||||
RequestResult RequestHandler::GetSpecialInputs(const Request&)
|
||||
{
|
||||
json responseData;
|
||||
|
||||
std::vector<std::string> channels = {"desktop1", "desktop2", "mic1", "mic2", "mic3", "mic4"};
|
||||
|
||||
size_t channelId = 1;
|
||||
for (auto &channel : channels) {
|
||||
OBSSourceAutoRelease input = obs_get_output_source(channelId);
|
||||
if (!input)
|
||||
responseData[channel] = nullptr;
|
||||
else
|
||||
responseData[channel] = obs_source_get_name(input);
|
||||
|
||||
channelId++;
|
||||
}
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
@ -115,7 +152,7 @@ RequestResult RequestHandler::CreateInput(const Request& request)
|
||||
return RequestResult::Error(RequestStatus::ResourceAlreadyExists, "A source already exists by that input name.");
|
||||
|
||||
std::string inputKind = request.RequestData["inputKind"];
|
||||
auto kinds = Utils::Obs::ListHelper::GetInputKindList();
|
||||
auto kinds = Utils::Obs::ArrayHelper::GetInputKindList();
|
||||
if (std::find(kinds.begin(), kinds.end(), inputKind) == kinds.end())
|
||||
return RequestResult::Error(RequestStatus::InvalidInputKind, "Your specified input kind is not supported by OBS. Check that your specified kind is properly versioned and that any necessary plugins are loaded.");
|
||||
|
||||
@ -232,6 +269,9 @@ RequestResult RequestHandler::GetInputDefaultSettings(const Request& request)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
std::string inputKind = request.RequestData["inputKind"];
|
||||
auto kinds = Utils::Obs::ArrayHelper::GetInputKindList();
|
||||
if (std::find(kinds.begin(), kinds.end(), inputKind) == kinds.end())
|
||||
return RequestResult::Error(RequestStatus::InvalidInputKind);
|
||||
|
||||
OBSDataAutoRelease defaultSettings = obs_get_source_defaults(inputKind.c_str());
|
||||
if (!defaultSettings)
|
||||
@ -280,6 +320,7 @@ RequestResult RequestHandler::GetInputSettings(const Request& request)
|
||||
*
|
||||
* @requestField inputName | String | Name of the input to set the settings of
|
||||
* @requestField inputSettings | Object | Object of settings to apply
|
||||
* @requestField ?overlay | Boolean | True == apply the settings on top of existing ones, False == reset the input to its defaults, then apply settings. | true
|
||||
*
|
||||
* @requestType SetInputSettings
|
||||
* @complexity 3
|
||||
@ -345,6 +386,9 @@ RequestResult RequestHandler::GetInputMute(const Request& request)
|
||||
if (!input)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO))
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio.");
|
||||
|
||||
json responseData;
|
||||
responseData["inputMuted"] = obs_source_muted(input);
|
||||
return RequestResult::Success(responseData);
|
||||
@ -371,6 +415,9 @@ RequestResult RequestHandler::SetInputMute(const Request& request)
|
||||
if (!(input && request.ValidateBoolean("inputMuted", statusCode, comment)))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO))
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio.");
|
||||
|
||||
obs_source_set_muted(input, request.RequestData["inputMuted"]);
|
||||
|
||||
return RequestResult::Success();
|
||||
@ -398,6 +445,9 @@ RequestResult RequestHandler::ToggleInputMute(const Request& request)
|
||||
if (!input)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO))
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio.");
|
||||
|
||||
bool inputMuted = !obs_source_muted(input);
|
||||
obs_source_set_muted(input, inputMuted);
|
||||
|
||||
@ -429,6 +479,9 @@ RequestResult RequestHandler::GetInputVolume(const Request& request)
|
||||
if (!input)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO))
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio.");
|
||||
|
||||
float inputVolumeMul = obs_source_get_volume(input);
|
||||
float inputVolumeDb = obs_mul_to_db(inputVolumeMul);
|
||||
if (inputVolumeDb == -INFINITY)
|
||||
@ -445,7 +498,7 @@ RequestResult RequestHandler::GetInputVolume(const Request& request)
|
||||
*
|
||||
* @requestField inputName | String | Name of the input to set the volume of
|
||||
* @requestField ?inputVolumeMul | Number | Volume setting in mul | >= 0, <= 20 | `inputVolumeDb` should be specified
|
||||
* @requestField ?inputVolumeDb | Number | Volume setting in dB | >= -100, <= -26 | `inputVolumeMul` should be specified
|
||||
* @requestField ?inputVolumeDb | Number | Volume setting in dB | >= -100, <= 26 | `inputVolumeMul` should be specified
|
||||
*
|
||||
* @requestType SetInputVolume
|
||||
* @complexity 3
|
||||
@ -462,6 +515,9 @@ RequestResult RequestHandler::SetInputVolume(const Request& request)
|
||||
if (!input)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO))
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio.");
|
||||
|
||||
bool hasMul = request.Contains("inputVolumeMul");
|
||||
if (hasMul && !request.ValidateOptionalNumber("inputVolumeMul", statusCode, comment, 0, 20))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
@ -487,6 +543,67 @@ RequestResult RequestHandler::SetInputVolume(const Request& request)
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the audio balance of an input.
|
||||
*
|
||||
* @requestField inputName | String | Name of the input to get the audio balance of
|
||||
*
|
||||
* @responseField inputAudioBalance | Number | Audio balance value from 0.0-1.0
|
||||
*
|
||||
* @requestType GetInputAudioBalance
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category inputs
|
||||
*/
|
||||
RequestResult RequestHandler::GetInputAudioBalance(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
|
||||
if (!input)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO))
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio.");
|
||||
|
||||
json responseData;
|
||||
responseData["inputAudioBalance"] = obs_source_get_balance_value(input);
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the audio balance of an input.
|
||||
*
|
||||
* @requestField inputName | String | Name of the input to set the audio balance of
|
||||
* @requestField inputAudioBalance | Number | New audio balance value | >= 0.0, <= 1.0
|
||||
*
|
||||
* @requestType SetInputAudioBalance
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category inputs
|
||||
*/
|
||||
RequestResult RequestHandler::SetInputAudioBalance(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
|
||||
if (!(input && request.ValidateNumber("inputAudioBalance", statusCode, comment, 0.0, 1.0)))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO))
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio.");
|
||||
|
||||
float inputAudioBalance = request.RequestData["inputAudioBalance"];
|
||||
obs_source_set_balance_value(input, inputAudioBalance);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the audio sync offset of an input.
|
||||
*
|
||||
@ -511,6 +628,9 @@ RequestResult RequestHandler::GetInputAudioSyncOffset(const Request& request)
|
||||
if (!input)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO))
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio.");
|
||||
|
||||
json responseData;
|
||||
// Offset is stored in nanoseconds in OBS.
|
||||
responseData["inputAudioSyncOffset"] = obs_source_get_sync_offset(input) / 1000000;
|
||||
@ -539,6 +659,9 @@ RequestResult RequestHandler::SetInputAudioSyncOffset(const Request& request)
|
||||
if (!(input && request.ValidateNumber("inputAudioSyncOffset", statusCode, comment, -950, 20000)))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO))
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio.");
|
||||
|
||||
int64_t syncOffset = request.RequestData["inputAudioSyncOffset"];
|
||||
obs_source_set_sync_offset(input, syncOffset * 1000000);
|
||||
|
||||
@ -573,6 +696,9 @@ RequestResult RequestHandler::GetInputAudioMonitorType(const Request& request)
|
||||
if (!input)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO))
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio.");
|
||||
|
||||
json responseData;
|
||||
responseData["monitorType"] = Utils::Obs::StringHelper::GetInputMonitorType(input);
|
||||
|
||||
@ -600,6 +726,12 @@ RequestResult RequestHandler::SetInputAudioMonitorType(const Request& request)
|
||||
if (!(input && request.ValidateString("monitorType", statusCode, comment)))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO))
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio.");
|
||||
|
||||
if (!obs_audio_monitoring_available())
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "Audio monitoring is not available on this platform.");
|
||||
|
||||
enum obs_monitoring_type monitorType;
|
||||
std::string monitorTypeString = request.RequestData["monitorType"];
|
||||
if (monitorTypeString == "OBS_MONITORING_TYPE_NONE")
|
||||
@ -616,30 +748,93 @@ RequestResult RequestHandler::SetInputAudioMonitorType(const Request& request)
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
std::vector<json> GetListPropertyItems(obs_property_t *property)
|
||||
/**
|
||||
* Gets the enable state of all audio tracks of an input.
|
||||
*
|
||||
* @requestField inputName | String | Name of the input
|
||||
*
|
||||
* @responseField inputAudioTracks | Object | Object of audio tracks and associated enable states
|
||||
*
|
||||
* @requestType GetInputAudioTracks
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category inputs
|
||||
*/
|
||||
RequestResult RequestHandler::GetInputAudioTracks(const Request& request)
|
||||
{
|
||||
std::vector<json> ret;
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
|
||||
if (!input)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
enum obs_combo_format itemFormat = obs_property_list_format(property);
|
||||
size_t itemCount = obs_property_list_item_count(property);
|
||||
if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO))
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio.");
|
||||
|
||||
for (size_t i = 0; i < itemCount; i++) {
|
||||
json itemData;
|
||||
itemData["itemName"] = obs_property_list_item_name(property, i);
|
||||
itemData["itemEnabled"] = !obs_property_list_item_disabled(property, i);
|
||||
if (itemFormat == OBS_COMBO_FORMAT_INT) {
|
||||
itemData["itemValue"] = obs_property_list_item_int(property, i);
|
||||
} else if (itemFormat == OBS_COMBO_FORMAT_FLOAT) {
|
||||
itemData["itemValue"] = obs_property_list_item_float(property, i);
|
||||
} else if (itemFormat == OBS_COMBO_FORMAT_STRING) {
|
||||
itemData["itemValue"] = obs_property_list_item_string(property, i);
|
||||
} else {
|
||||
itemData["itemValue"] = nullptr;
|
||||
}
|
||||
ret.push_back(itemData);
|
||||
long long tracks = obs_source_get_audio_mixers(input);
|
||||
|
||||
json inputAudioTracks;
|
||||
for (long long i = 0; i < MAX_AUDIO_MIXES; i++) {
|
||||
inputAudioTracks[std::to_string(i + 1)] = (bool)((tracks >> i) & 1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
json responseData;
|
||||
responseData["inputAudioTracks"] = inputAudioTracks;
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the enable state of audio tracks of an input.
|
||||
*
|
||||
* @requestField inputName | String | Name of the input
|
||||
* @requestField inputAudioTracks | Object | Track settings to apply
|
||||
*
|
||||
* @requestType SetInputAudioTracks
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category inputs
|
||||
*/
|
||||
RequestResult RequestHandler::SetInputAudioTracks(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
|
||||
if (!input || !request.ValidateObject("inputAudioTracks", statusCode, comment))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO))
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio.");
|
||||
|
||||
json inputAudioTracks = request.RequestData["inputAudioTracks"];
|
||||
|
||||
long long mixers = obs_source_get_audio_mixers(input);
|
||||
|
||||
for (long long i = 0; i < MAX_AUDIO_MIXES; i++) {
|
||||
std::string track = std::to_string(i + 1);
|
||||
|
||||
if (!Utils::Json::Contains(inputAudioTracks, track))
|
||||
continue;
|
||||
|
||||
if (!inputAudioTracks[track].is_boolean())
|
||||
return RequestResult::Error(RequestStatus::InvalidRequestFieldType, "The value of one of your tracks is not a boolean.");
|
||||
|
||||
bool enabled = inputAudioTracks[track];
|
||||
|
||||
if (enabled)
|
||||
mixers |= (1 << i);
|
||||
else
|
||||
mixers &= ~(1 << i);
|
||||
}
|
||||
|
||||
// Decided that checking if tracks have actually changed is unnecessary
|
||||
obs_source_set_audio_mixers(input, mixers);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -677,7 +872,7 @@ RequestResult RequestHandler::GetInputPropertiesListPropertyItems(const Request&
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceType, "The property found is not a list.");
|
||||
|
||||
json responseData;
|
||||
responseData["propertyItems"] = GetListPropertyItems(property);
|
||||
responseData["propertyItems"] = Utils::Obs::ArrayHelper::GetListPropertyItems(property);
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
@ -25,6 +25,32 @@ bool IsMediaTimeValid(obs_source_t *input)
|
||||
return mediaState == OBS_MEDIA_STATE_PLAYING || mediaState == OBS_MEDIA_STATE_PAUSED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the status of a media input.
|
||||
*
|
||||
* Media States:
|
||||
* - `OBS_MEDIA_STATE_NONE`
|
||||
* - `OBS_MEDIA_STATE_PLAYING`
|
||||
* - `OBS_MEDIA_STATE_OPENING`
|
||||
* - `OBS_MEDIA_STATE_BUFFERING`
|
||||
* - `OBS_MEDIA_STATE_PAUSED`
|
||||
* - `OBS_MEDIA_STATE_STOPPED`
|
||||
* - `OBS_MEDIA_STATE_ENDED`
|
||||
* - `OBS_MEDIA_STATE_ERROR`
|
||||
*
|
||||
* @requestField inputName | String | Name of the media input
|
||||
*
|
||||
* @responseField mediaState | String | State of the media input
|
||||
* @responseField mediaDuration | Number | Total duration of the playing media in milliseconds. `null` if not playing
|
||||
* @responseField mediaCursor | Number | Position of the cursor in milliseconds. `null` if not playing
|
||||
*
|
||||
* @requestType GetMediaInputStatus
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category media inputs
|
||||
*/
|
||||
RequestResult RequestHandler::GetMediaInputStatus(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
@ -47,6 +73,21 @@ RequestResult RequestHandler::GetMediaInputStatus(const Request& request)
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cursor position of a media input.
|
||||
*
|
||||
* This request does not perform bounds checking of the cursor position.
|
||||
*
|
||||
* @requestField inputName | String | Name of the media input
|
||||
* @requestField mediaCursor | Number | New cursor position to set | >= 0
|
||||
*
|
||||
* @requestType SetMediaInputCursor
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category media inputs
|
||||
*/
|
||||
RequestResult RequestHandler::SetMediaInputCursor(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
@ -66,6 +107,21 @@ RequestResult RequestHandler::SetMediaInputCursor(const Request& request)
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Offsets the current cursor position of a media input by the specified value.
|
||||
*
|
||||
* This request does not perform bounds checking of the cursor position.
|
||||
*
|
||||
* @requestField inputName | String | Name of the media input
|
||||
* @requestField mediaCursorOffset | Number | Value to offset the current cursor position by | None
|
||||
*
|
||||
* @requestType OffsetMediaInputCursor
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category media inputs
|
||||
*/
|
||||
RequestResult RequestHandler::OffsetMediaInputCursor(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
@ -88,6 +144,19 @@ RequestResult RequestHandler::OffsetMediaInputCursor(const Request& request)
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers an action on a media input.
|
||||
*
|
||||
* @requestField inputName | String | Name of the media input
|
||||
* @requestField mediaAction | String | Identifier of the `ObsMediaInputAction` enum
|
||||
*
|
||||
* @requestType TriggerMediaInputAction
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category media inputs
|
||||
*/
|
||||
RequestResult RequestHandler::TriggerMediaInputAction(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
|
277
src/requesthandler/RequestHandler_Outputs.cpp
Normal file
277
src/requesthandler/RequestHandler_Outputs.cpp
Normal file
@ -0,0 +1,277 @@
|
||||
/*
|
||||
obs-websocket
|
||||
Copyright (C) 2016-2021 Stephane Lepin <stephane.lepin@gmail.com>
|
||||
Copyright (C) 2020-2021 Kyle Manning <tt2468@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "RequestHandler.h"
|
||||
|
||||
static bool VirtualCamAvailable()
|
||||
{
|
||||
OBSDataAutoRelease privateData = obs_get_private_data();
|
||||
if (!privateData)
|
||||
return false;
|
||||
|
||||
return obs_data_get_bool(privateData, "vcamEnabled");
|
||||
}
|
||||
|
||||
static bool ReplayBufferAvailable()
|
||||
{
|
||||
OBSOutputAutoRelease output = obs_frontend_get_replay_buffer_output();
|
||||
return output != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the status of the virtualcam output.
|
||||
*
|
||||
* @responseField outputActive | Boolean | Whether the output is active
|
||||
*
|
||||
* @requestType GetVirtualCamStatus
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @category outputs
|
||||
* @api requests
|
||||
*/
|
||||
RequestResult RequestHandler::GetVirtualCamStatus(const Request&)
|
||||
{
|
||||
if (!VirtualCamAvailable())
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "VirtualCam is not available.");
|
||||
|
||||
json responseData;
|
||||
responseData["outputActive"] = obs_frontend_virtualcam_active();
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the state of the virtualcam output.
|
||||
*
|
||||
* @responseField outputActive | Boolean | Whether the output is active
|
||||
*
|
||||
* @requestType ToggleVirtualCam
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @category outputs
|
||||
* @api requests
|
||||
*/
|
||||
RequestResult RequestHandler::ToggleVirtualCam(const Request&)
|
||||
{
|
||||
if (!VirtualCamAvailable())
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "VirtualCam is not available.");
|
||||
|
||||
bool outputActive = obs_frontend_virtualcam_active();
|
||||
|
||||
if (outputActive)
|
||||
obs_frontend_stop_virtualcam();
|
||||
else
|
||||
obs_frontend_start_virtualcam();
|
||||
|
||||
json responseData;
|
||||
responseData["outputActive"] = !outputActive;
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the virtualcam output.
|
||||
*
|
||||
* @requestType StartVirtualCam
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category outputs
|
||||
*/
|
||||
RequestResult RequestHandler::StartVirtualCam(const Request&)
|
||||
{
|
||||
if (!VirtualCamAvailable())
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "VirtualCam is not available.");
|
||||
|
||||
if (obs_frontend_virtualcam_active())
|
||||
return RequestResult::Error(RequestStatus::OutputRunning);
|
||||
|
||||
obs_frontend_start_virtualcam();
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the virtualcam output.
|
||||
*
|
||||
* @requestType StopVirtualCam
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category outputs
|
||||
*/
|
||||
RequestResult RequestHandler::StopVirtualCam(const Request&)
|
||||
{
|
||||
if (!VirtualCamAvailable())
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "VirtualCam is not available.");
|
||||
|
||||
if (!obs_frontend_virtualcam_active())
|
||||
return RequestResult::Error(RequestStatus::OutputNotRunning);
|
||||
|
||||
obs_frontend_stop_virtualcam();
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the status of the replay buffer output.
|
||||
*
|
||||
* @responseField outputActive | Boolean | Whether the output is active
|
||||
*
|
||||
* @requestType GetReplayBufferStatus
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @category outputs
|
||||
* @api requests
|
||||
*/
|
||||
RequestResult RequestHandler::GetReplayBufferStatus(const Request&)
|
||||
{
|
||||
if (!ReplayBufferAvailable())
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available.");
|
||||
|
||||
json responseData;
|
||||
responseData["outputActive"] = obs_frontend_replay_buffer_active();
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the state of the replay buffer output.
|
||||
*
|
||||
* @responseField outputActive | Boolean | Whether the output is active
|
||||
*
|
||||
* @requestType ToggleReplayBuffer
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @category outputs
|
||||
* @api requests
|
||||
*/
|
||||
RequestResult RequestHandler::ToggleReplayBuffer(const Request&)
|
||||
{
|
||||
if (!ReplayBufferAvailable())
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available.");
|
||||
|
||||
bool outputActive = obs_frontend_replay_buffer_active();
|
||||
|
||||
if (outputActive)
|
||||
obs_frontend_replay_buffer_stop();
|
||||
else
|
||||
obs_frontend_replay_buffer_start();
|
||||
|
||||
json responseData;
|
||||
responseData["outputActive"] = !outputActive;
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the replay buffer output.
|
||||
*
|
||||
* @requestType StartReplayBuffer
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category outputs
|
||||
*/
|
||||
RequestResult RequestHandler::StartReplayBuffer(const Request&)
|
||||
{
|
||||
if (!ReplayBufferAvailable())
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available.");
|
||||
|
||||
if (obs_frontend_replay_buffer_active())
|
||||
return RequestResult::Error(RequestStatus::OutputRunning);
|
||||
|
||||
obs_frontend_replay_buffer_start();
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the replay buffer output.
|
||||
*
|
||||
* @requestType StopReplayBuffer
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category outputs
|
||||
*/
|
||||
RequestResult RequestHandler::StopReplayBuffer(const Request&)
|
||||
{
|
||||
if (!ReplayBufferAvailable())
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available.");
|
||||
|
||||
if (!obs_frontend_replay_buffer_active())
|
||||
return RequestResult::Error(RequestStatus::OutputNotRunning);
|
||||
|
||||
obs_frontend_replay_buffer_stop();
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the contents of the replay buffer output.
|
||||
*
|
||||
* @requestType SaveReplayBuffer
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category outputs
|
||||
*/
|
||||
RequestResult RequestHandler::SaveReplayBuffer(const Request&)
|
||||
{
|
||||
if (!ReplayBufferAvailable())
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available.");
|
||||
|
||||
if (!obs_frontend_replay_buffer_active())
|
||||
return RequestResult::Error(RequestStatus::OutputNotRunning);
|
||||
|
||||
obs_frontend_replay_buffer_save();
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the filename of the last replay buffer save file.
|
||||
*
|
||||
* @responseField savedReplayPath | String | File path
|
||||
*
|
||||
* @requestType GetLastReplayBufferReplay
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category outputs
|
||||
*/
|
||||
RequestResult RequestHandler::GetLastReplayBufferReplay(const Request&)
|
||||
{
|
||||
if (!ReplayBufferAvailable())
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available.");
|
||||
|
||||
if (!obs_frontend_replay_buffer_active())
|
||||
return RequestResult::Error(RequestStatus::OutputNotRunning);
|
||||
|
||||
json responseData;
|
||||
responseData["savedReplayPath"] = Utils::Obs::StringHelper::GetLastReplayBufferFilePath();
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
@ -19,9 +19,25 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
#include "RequestHandler.h"
|
||||
|
||||
/**
|
||||
* Gets the status of the record output.
|
||||
*
|
||||
* @responseField outputActive | Boolean | Whether the output is active
|
||||
* @responseField ouputPaused | Boolean | Whether the output is paused
|
||||
* @responseField outputTimecode | String | Current formatted timecode string for the output
|
||||
* @responseField outputDuration | Number | Current duration in milliseconds for the output
|
||||
* @responseField outputBytes | Number | Number of bytes sent by the output
|
||||
*
|
||||
* @requestType GetRecordStatus
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category record
|
||||
*/
|
||||
RequestResult RequestHandler::GetRecordStatus(const Request&)
|
||||
{
|
||||
OBSOutputAutoRelease recordOutput = obs_frontend_get_streaming_output();
|
||||
OBSOutputAutoRelease recordOutput = obs_frontend_get_recording_output();
|
||||
|
||||
uint64_t outputDuration = Utils::Obs::NumberHelper::GetOutputDuration(recordOutput);
|
||||
|
||||
@ -35,6 +51,16 @@ RequestResult RequestHandler::GetRecordStatus(const Request&)
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the status of the record output.
|
||||
*
|
||||
* @requestType ToggleRecord
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category record
|
||||
*/
|
||||
RequestResult RequestHandler::ToggleRecord(const Request&)
|
||||
{
|
||||
json responseData;
|
||||
@ -49,6 +75,16 @@ RequestResult RequestHandler::ToggleRecord(const Request&)
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the record output.
|
||||
*
|
||||
* @requestType StartRecord
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category record
|
||||
*/
|
||||
RequestResult RequestHandler::StartRecord(const Request&)
|
||||
{
|
||||
if (obs_frontend_recording_active())
|
||||
@ -60,6 +96,16 @@ RequestResult RequestHandler::StartRecord(const Request&)
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the record output.
|
||||
*
|
||||
* @requestType StopRecord
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category record
|
||||
*/
|
||||
RequestResult RequestHandler::StopRecord(const Request&)
|
||||
{
|
||||
if (!obs_frontend_recording_active())
|
||||
@ -71,6 +117,16 @@ RequestResult RequestHandler::StopRecord(const Request&)
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles pause on the record output.
|
||||
*
|
||||
* @requestType ToggleRecordPause
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category record
|
||||
*/
|
||||
RequestResult RequestHandler::ToggleRecordPause(const Request&)
|
||||
{
|
||||
json responseData;
|
||||
@ -85,6 +141,16 @@ RequestResult RequestHandler::ToggleRecordPause(const Request&)
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses the record output.
|
||||
*
|
||||
* @requestType PauseRecord
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category record
|
||||
*/
|
||||
RequestResult RequestHandler::PauseRecord(const Request&)
|
||||
{
|
||||
if (obs_frontend_recording_paused())
|
||||
@ -96,6 +162,16 @@ RequestResult RequestHandler::PauseRecord(const Request&)
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes the record output.
|
||||
*
|
||||
* @requestType ResumeRecord
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category record
|
||||
*/
|
||||
RequestResult RequestHandler::ResumeRecord(const Request&)
|
||||
{
|
||||
if (!obs_frontend_recording_paused())
|
||||
@ -106,11 +182,3 @@ RequestResult RequestHandler::ResumeRecord(const Request&)
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
RequestResult RequestHandler::GetRecordDirectory(const Request&)
|
||||
{
|
||||
json responseData;
|
||||
responseData["recordDirectory"] = Utils::Obs::StringHelper::GetCurrentRecordOutputPath();
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
@ -19,6 +19,22 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
#include "RequestHandler.h"
|
||||
|
||||
/**
|
||||
* Gets a list of all scene items in a scene.
|
||||
*
|
||||
* Scenes only
|
||||
*
|
||||
* @requestField sceneName | String | Name of the scene to get the items of
|
||||
*
|
||||
* @responseField sceneItems | Array<Object> | Array of scene items in the scene
|
||||
*
|
||||
* @requestType GetSceneItemList
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category scene items
|
||||
*/
|
||||
RequestResult RequestHandler::GetSceneItemList(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
@ -28,11 +44,29 @@ RequestResult RequestHandler::GetSceneItemList(const Request& request)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
json responseData;
|
||||
responseData["sceneItems"] = Utils::Obs::ListHelper::GetSceneItemList(obs_scene_from_source(scene));
|
||||
responseData["sceneItems"] = Utils::Obs::ArrayHelper::GetSceneItemList(obs_scene_from_source(scene));
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Basically GetSceneItemList, but for groups.
|
||||
*
|
||||
* Using groups at all in OBS is discouraged, as they are very broken under the hood.
|
||||
*
|
||||
* Groups only
|
||||
*
|
||||
* @requestField sceneName | String | Name of the group to get the items of
|
||||
*
|
||||
* @responseField sceneItems | Array<Object> | Array of scene items in the group
|
||||
*
|
||||
* @requestType GetGroupItemList
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category scene items
|
||||
*/
|
||||
RequestResult RequestHandler::GetGroupSceneItemList(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
@ -42,26 +76,36 @@ RequestResult RequestHandler::GetGroupSceneItemList(const Request& request)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
json responseData;
|
||||
responseData["sceneItems"] = Utils::Obs::ListHelper::GetSceneItemList(obs_group_from_source(scene));
|
||||
responseData["sceneItems"] = Utils::Obs::ArrayHelper::GetSceneItemList(obs_group_from_source(scene));
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches a scene for a source, and returns its id.
|
||||
*
|
||||
* Scenes and Groups
|
||||
*
|
||||
* @requestField sceneName | String | Name of the scene or group to search in
|
||||
* @requestField sourceName | String | Name of the source to find
|
||||
*
|
||||
* @responseField sceneItemId | Number | Numeric ID of the scene item
|
||||
*
|
||||
* @requestType GetSceneItemId
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category scene items
|
||||
*/
|
||||
RequestResult RequestHandler::GetSceneItemId(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease sceneSource = request.ValidateScene("sceneName", statusCode, comment, OBS_WEBSOCKET_SCENE_FILTER_SCENE_OR_GROUP);
|
||||
if (!(sceneSource && request.ValidateString("sourceName", statusCode, comment)))
|
||||
OBSSceneAutoRelease scene = request.ValidateScene2("sceneName", statusCode, comment, OBS_WEBSOCKET_SCENE_FILTER_SCENE_OR_GROUP);
|
||||
if (!(scene && request.ValidateString("sourceName", statusCode, comment)))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
OBSScene scene = obs_scene_from_source(sceneSource);
|
||||
if (!scene) {
|
||||
scene = obs_group_from_source(sceneSource);
|
||||
if (!scene) // This should never happen
|
||||
return RequestResult::Error(RequestStatus::GenericError, "Somehow the scene was found but the scene object could not be fetched. Please report this to the obs-websocket developers.");
|
||||
}
|
||||
|
||||
std::string sourceName = request.RequestData["sourceName"];
|
||||
|
||||
OBSSceneItemAutoRelease item = Utils::Obs::SearchHelper::GetSceneItemByName(scene, sourceName);
|
||||
@ -74,6 +118,24 @@ RequestResult RequestHandler::GetSceneItemId(const Request& request)
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new scene item using a source.
|
||||
*
|
||||
* Scenes only
|
||||
*
|
||||
* @requestField sceneName | String | Name of the scene to create the new item in
|
||||
* @requestField sourceName | String | Name of the source to add to the scene
|
||||
* @requestField ?sceneItemEnabled | Boolean | Enable state to apply to the scene item on creation | True
|
||||
*
|
||||
* @responseField sceneItemId | Number | Numeric ID of the scene item
|
||||
*
|
||||
* @requestType CreateSceneItem
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category scene items
|
||||
*/
|
||||
RequestResult RequestHandler::CreateSceneItem(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
@ -108,6 +170,21 @@ RequestResult RequestHandler::CreateSceneItem(const Request& request)
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a scene item from a scene.
|
||||
*
|
||||
* Scenes only
|
||||
*
|
||||
* @requestField sceneName | String | Name of the scene the item is in
|
||||
* @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0
|
||||
*
|
||||
* @requestType RemoveSceneItem
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category scene items
|
||||
*/
|
||||
RequestResult RequestHandler::RemoveSceneItem(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
@ -116,11 +193,30 @@ RequestResult RequestHandler::RemoveSceneItem(const Request& request)
|
||||
if (!sceneItem)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
// Makes the UI log `User Removed source '[source]' from scene '(null)'`. This is not a problem, just a side effect.
|
||||
obs_sceneitem_remove(sceneItem);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicates a scene item, copying all transform and crop info.
|
||||
*
|
||||
* Scenes only
|
||||
*
|
||||
* @requestField sceneName | String | Name of the scene the item is in
|
||||
* @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0
|
||||
* @requestField ?destinationSceneName | String | Name of the scene to create the duplicated item in | `sceneName` is assumed
|
||||
*
|
||||
* @responseField sceneItemId | Number | Numeric ID of the duplicated scene item
|
||||
*
|
||||
* @requestType DuplicateSceneItem
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category scene items
|
||||
*/
|
||||
RequestResult RequestHandler::DuplicateSceneItem(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
@ -136,8 +232,9 @@ RequestResult RequestHandler::DuplicateSceneItem(const Request& request)
|
||||
if (!destinationScene)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
} else {
|
||||
destinationScene = obs_sceneitem_get_scene(sceneItem);
|
||||
obs_scene_addref(destinationScene);
|
||||
destinationScene = obs_scene_get_ref(obs_sceneitem_get_scene(sceneItem));
|
||||
if (!destinationScene)
|
||||
return RequestResult::Error(RequestStatus::RequestProcessingFailed, "Internal error: Failed to get ref for scene of scene item.");
|
||||
}
|
||||
|
||||
if (obs_sceneitem_is_group(sceneItem) && obs_sceneitem_get_scene(sceneItem) == destinationScene) {
|
||||
@ -165,6 +262,23 @@ RequestResult RequestHandler::DuplicateSceneItem(const Request& request)
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the transform and crop info of a scene item.
|
||||
*
|
||||
* Scenes and Groups
|
||||
*
|
||||
* @requestField sceneName | String | Name of the scene the item is in
|
||||
* @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0
|
||||
*
|
||||
* @responseField sceneItemTransform | Object | Object containing scene item transform info
|
||||
*
|
||||
* @requestType GetSceneItemTransform
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category scene items
|
||||
*/
|
||||
RequestResult RequestHandler::GetSceneItemTransform(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
@ -174,11 +288,25 @@ RequestResult RequestHandler::GetSceneItemTransform(const Request& request)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
json responseData;
|
||||
responseData["sceneItemTransform"] = Utils::Obs::DataHelper::GetSceneItemTransform(sceneItem);
|
||||
responseData["sceneItemTransform"] = Utils::Obs::ObjectHelper::GetSceneItemTransform(sceneItem);
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the transform and crop info of a scene item.
|
||||
*
|
||||
* @requestField sceneName | String | Name of the scene the item is in
|
||||
* @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0
|
||||
* @requestField sceneItemTransform | Object | Object containing scene item transform info to update
|
||||
*
|
||||
* @requestType SetSceneItemTransform
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category scene items
|
||||
*/
|
||||
RequestResult RequestHandler::SetSceneItemTransform(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
@ -317,6 +445,23 @@ RequestResult RequestHandler::SetSceneItemTransform(const Request& request)
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the enable state of a scene item.
|
||||
*
|
||||
* Scenes and Groups
|
||||
*
|
||||
* @requestField sceneName | String | Name of the scene the item is in
|
||||
* @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0
|
||||
*
|
||||
* @responseField sceneItemEnabled | Boolean | Whether the scene item is enabled. `true` for enabled, `false` for disabled
|
||||
*
|
||||
* @requestType GetSceneItemEnabled
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category scene items
|
||||
*/
|
||||
RequestResult RequestHandler::GetSceneItemEnabled(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
@ -331,6 +476,22 @@ RequestResult RequestHandler::GetSceneItemEnabled(const Request& request)
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the enable state of a scene item.
|
||||
*
|
||||
* Scenes and Groups
|
||||
*
|
||||
* @requestField sceneName | String | Name of the scene the item is in
|
||||
* @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0
|
||||
* @requestField sceneItemEnabled | Boolean | New enable state of the scene item
|
||||
*
|
||||
* @requestType SetSceneItemEnabled
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category scene items
|
||||
*/
|
||||
RequestResult RequestHandler::SetSceneItemEnabled(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
@ -346,6 +507,23 @@ RequestResult RequestHandler::SetSceneItemEnabled(const Request& request)
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the lock state of a scene item.
|
||||
*
|
||||
* Scenes and Groups
|
||||
*
|
||||
* @requestField sceneName | String | Name of the scene the item is in
|
||||
* @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0
|
||||
*
|
||||
* @responseField sceneItemLocked | Boolean | Whether the scene item is locked. `true` for locked, `false` for unlocked
|
||||
*
|
||||
* @requestType GetSceneItemLocked
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category scene items
|
||||
*/
|
||||
RequestResult RequestHandler::GetSceneItemLocked(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
@ -360,6 +538,22 @@ RequestResult RequestHandler::GetSceneItemLocked(const Request& request)
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the lock state of a scene item.
|
||||
*
|
||||
* Scenes and Group
|
||||
*
|
||||
* @requestField sceneName | String | Name of the scene the item is in
|
||||
* @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0
|
||||
* @requestField sceneItemLocked | Boolean | New lock state of the scene item
|
||||
*
|
||||
* @requestType SetSceneItemLocked
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category scene items
|
||||
*/
|
||||
RequestResult RequestHandler::SetSceneItemLocked(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
@ -375,6 +569,25 @@ RequestResult RequestHandler::SetSceneItemLocked(const Request& request)
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index position of a scene item in a scene.
|
||||
*
|
||||
* An index of 0 is at the bottom of the source list in the UI.
|
||||
*
|
||||
* Scenes and Groups
|
||||
*
|
||||
* @requestField sceneName | String | Name of the scene the item is in
|
||||
* @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0
|
||||
*
|
||||
* @responseField sceneItemIndex | Number | Index position of the scene item
|
||||
*
|
||||
* @requestType GetSceneItemIndex
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category scene items
|
||||
*/
|
||||
RequestResult RequestHandler::GetSceneItemIndex(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
@ -389,6 +602,22 @@ RequestResult RequestHandler::GetSceneItemIndex(const Request& request)
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the index position of a scene item in a scene.
|
||||
*
|
||||
* Scenes and Groups
|
||||
*
|
||||
* @requestField sceneName | String | Name of the scene the item is in
|
||||
* @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0
|
||||
* @requestField sceneItemIndex | Number | New index position of the scene item | >= 0
|
||||
*
|
||||
* @requestType SetSceneItemIndex
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category scene items
|
||||
*/
|
||||
RequestResult RequestHandler::SetSceneItemIndex(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
@ -403,3 +632,81 @@ RequestResult RequestHandler::SetSceneItemIndex(const Request& request)
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the blend mode of a scene item.
|
||||
*
|
||||
* Blend modes:
|
||||
*
|
||||
* - `OBS_BLEND_NORMAL`
|
||||
* - `OBS_BLEND_ADDITIVE`
|
||||
* - `OBS_BLEND_SUBTRACT`
|
||||
* - `OBS_BLEND_SCREEN`
|
||||
* - `OBS_BLEND_MULTIPLY`
|
||||
* - `OBS_BLEND_LIGHTEN`
|
||||
* - `OBS_BLEND_DARKEN`
|
||||
*
|
||||
* Scenes and Groups
|
||||
*
|
||||
* @requestField sceneName | String | Name of the scene the item is in
|
||||
* @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0
|
||||
*
|
||||
* @responseField sceneItemBlendMode | String | Current blend mode
|
||||
*
|
||||
* @requestType GetSceneItemBlendMode
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category scene items
|
||||
*/
|
||||
RequestResult RequestHandler::GetSceneItemBlendMode(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSceneItemAutoRelease sceneItem = request.ValidateSceneItem("sceneName", "sceneItemId", statusCode, comment, OBS_WEBSOCKET_SCENE_FILTER_SCENE_OR_GROUP);
|
||||
if (!sceneItem)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
auto blendMode = obs_sceneitem_get_blending_mode(sceneItem);
|
||||
|
||||
json responseData;
|
||||
responseData["sceneItemBlendMode"] = Utils::Obs::StringHelper::GetSceneItemBlendMode(blendMode);
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the blend mode of a scene item.
|
||||
*
|
||||
* Scenes and Groups
|
||||
*
|
||||
* @requestField sceneName | String | Name of the scene the item is in
|
||||
* @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0
|
||||
* @requestField sceneItemBlendMode | String | New blend mode
|
||||
*
|
||||
* @requestType SetSceneItemBlendMode
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category scene items
|
||||
*/
|
||||
RequestResult RequestHandler::SetSceneItemBlendMode(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSceneItemAutoRelease sceneItem = request.ValidateSceneItem("sceneName", "sceneItemId", statusCode, comment, OBS_WEBSOCKET_SCENE_FILTER_SCENE_OR_GROUP);
|
||||
if (!(sceneItem && request.ValidateString("sceneItemBlendMode", statusCode, comment)))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
std::string blendModeString = request.RequestData["sceneItemBlendMode"];
|
||||
|
||||
auto blendMode = Utils::Obs::EnumHelper::GetSceneItemBlendMode(blendModeString);
|
||||
if (blendMode == OBS_BLEND_NORMAL && blendModeString != "OBS_BLEND_NORMAL")
|
||||
return RequestResult::Error(RequestStatus::InvalidRequestField, "The field sceneItemBlendMode has an invalid value.");
|
||||
|
||||
obs_sceneitem_set_blending_mode(sceneItem, blendMode);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
@ -22,9 +22,9 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
/**
|
||||
* Gets an array of all scenes in OBS.
|
||||
*
|
||||
* @responseField scenes | Array<String> | Array of scenes in OBS
|
||||
* @responseField currentProgramSceneName | String | Current program scene
|
||||
* @responseField currentPreviewSceneName | String | Current preview scene. `null` if not in studio mode
|
||||
* @responseField scenes | Array<Object> | Array of scenes
|
||||
*
|
||||
* @requestType GetSceneList
|
||||
* @complexity 2
|
||||
@ -49,7 +49,30 @@ RequestResult RequestHandler::GetSceneList(const Request&)
|
||||
else
|
||||
responseData["currentPreviewSceneName"] = nullptr;
|
||||
|
||||
responseData["scenes"] = Utils::Obs::ListHelper::GetSceneList();
|
||||
responseData["scenes"] = Utils::Obs::ArrayHelper::GetSceneList();
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of all groups in OBS.
|
||||
*
|
||||
* Groups in OBS are actually scenes, but renamed and modified. In obs-websocket, we treat them as scenes where we can.
|
||||
*
|
||||
* @responseField groups | Array<String> | Array of group names
|
||||
*
|
||||
* @requestType GetGroupList
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category scenes
|
||||
*/
|
||||
RequestResult RequestHandler::GetGroupList(const Request&)
|
||||
{
|
||||
json responseData;
|
||||
|
||||
responseData["groups"] = Utils::Obs::ArrayHelper::GetGroupList();
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
@ -250,3 +273,105 @@ RequestResult RequestHandler::SetSceneName(const Request& request)
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scene transition overridden for a scene.
|
||||
*
|
||||
* @requestField sceneName | String | Name of the scene
|
||||
*
|
||||
* @responseField transitionName | String | Name of the overridden scene transition, else `null`
|
||||
* @responseField transitionDuration | Number | Duration of the overridden scene transition, else `null`
|
||||
*
|
||||
* @requestType GetSceneSceneTransitionOverride
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category scenes
|
||||
*/
|
||||
RequestResult RequestHandler::GetSceneSceneTransitionOverride(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease scene = request.ValidateScene("sceneName", statusCode, comment);
|
||||
if (!scene)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
OBSDataAutoRelease privateSettings = obs_source_get_private_settings(scene);
|
||||
|
||||
json responseData;
|
||||
const char *transitionName = obs_data_get_string(privateSettings, "transition");
|
||||
if (transitionName && strlen(transitionName))
|
||||
responseData["transitionName"] = transitionName;
|
||||
else
|
||||
responseData["transitionName"] = nullptr;
|
||||
|
||||
if (obs_data_has_user_value(privateSettings, "transition_duration"))
|
||||
responseData["transitionDuration"] = obs_data_get_int(privateSettings, "transition_duration");
|
||||
else
|
||||
responseData["transitionDuration"] = nullptr;
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scene transition overridden for a scene.
|
||||
*
|
||||
* @requestField sceneName | String | Name of the scene
|
||||
* @requestField ?transitionName | String | Name of the scene transition to use as override. Specify `null` to remove | Unchanged
|
||||
* @requestField ?transitionDuration | Number | Duration to use for any overridden transition. Specify `null` to remove | >= 50, <= 20000 | Unchanged
|
||||
*
|
||||
* @requestType SetSceneSceneTransitionOverride
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category scenes
|
||||
*/
|
||||
RequestResult RequestHandler::SetSceneSceneTransitionOverride(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease scene = request.ValidateScene("sceneName", statusCode, comment);
|
||||
if (!scene)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
OBSDataAutoRelease privateSettings = obs_source_get_private_settings(scene);
|
||||
|
||||
bool hasName = request.RequestData.contains("transitionName");
|
||||
if (hasName && !request.RequestData["transitionName"].is_null()) {
|
||||
if (!request.ValidateOptionalString("transitionName", statusCode, comment))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
OBSSourceAutoRelease transition = Utils::Obs::SearchHelper::GetSceneTransitionByName(request.RequestData["transitionName"]);
|
||||
if (!transition)
|
||||
return RequestResult::Error(RequestStatus::ResourceNotFound, "No scene transition was found by that name.");
|
||||
}
|
||||
|
||||
bool hasDuration = request.RequestData.contains("transitionDuration");
|
||||
if (hasDuration && !request.RequestData["transitionDuration"].is_null()) {
|
||||
if (!request.ValidateOptionalNumber("transitionDuration", statusCode, comment, 50, 20000))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
}
|
||||
|
||||
if (!hasName && !hasDuration)
|
||||
return RequestResult::Error(RequestStatus::MissingRequestField, "Your request data must include either `transitionName` or `transitionDuration`.");
|
||||
|
||||
if (hasName) {
|
||||
if (request.RequestData["transitionName"].is_null()) {
|
||||
obs_data_erase(privateSettings, "transition");
|
||||
} else {
|
||||
std::string transitionName = request.RequestData["transitionName"];
|
||||
obs_data_set_string(privateSettings, "transition", transitionName.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (hasDuration) {
|
||||
if (request.RequestData["transitionDuration"].is_null()) {
|
||||
obs_data_erase(privateSettings, "transition_duration");
|
||||
} else {
|
||||
obs_data_set_int(privateSettings, "transition_duration", request.RequestData["transitionDuration"]);
|
||||
}
|
||||
}
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
@ -312,3 +312,39 @@ RequestResult RequestHandler::SaveSourceScreenshot(const Request& request)
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
// Intentionally undocumented
|
||||
RequestResult RequestHandler::GetSourcePrivateSettings(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease source = request.ValidateSource("sourceName", statusCode, comment);
|
||||
if (!source)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
OBSDataAutoRelease privateSettings = obs_source_get_private_settings(source);
|
||||
|
||||
json responseData;
|
||||
responseData["sourceSettings"] = Utils::Json::ObsDataToJson(privateSettings);
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
// Intentionally undocumented
|
||||
RequestResult RequestHandler::SetSourcePrivateSettings(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease source = request.ValidateSource("sourceName", statusCode, comment);
|
||||
if (!source || !request.ValidateObject("sourceSettings", statusCode, comment))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
OBSDataAutoRelease privateSettings = obs_source_get_private_settings(source);
|
||||
|
||||
OBSDataAutoRelease newSettings = Utils::Json::JsonToObsData(request.RequestData["sourceSettings"]);
|
||||
|
||||
// Always overlays to prevent destroying internal source data unintentionally
|
||||
obs_data_apply(privateSettings, newSettings);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
@ -19,6 +19,24 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
#include "RequestHandler.h"
|
||||
|
||||
/**
|
||||
* Gets the status of the stream output.
|
||||
*
|
||||
* @responseField outputActive | Boolean | Whether the output is active
|
||||
* @responseField outputReconnecting | Boolean | Whether the output is currently reconnecting
|
||||
* @responseField outputTimecode | String | Current formatted timecode string for the output
|
||||
* @responseField outputDuration | Number | Current duration in milliseconds for the output
|
||||
* @responseField outputBytes | Number | Number of bytes sent by the output
|
||||
* @responseField outputSkippedFrames | Number | Number of frames skipped by the output's process
|
||||
* @responseField outputTotalFrames | Number | Total number of frames delivered by the output's process
|
||||
*
|
||||
* @requestType GetStreamStatus
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category stream
|
||||
*/
|
||||
RequestResult RequestHandler::GetStreamStatus(const Request&)
|
||||
{
|
||||
OBSOutputAutoRelease streamOutput = obs_frontend_get_streaming_output();
|
||||
@ -37,6 +55,18 @@ RequestResult RequestHandler::GetStreamStatus(const Request&)
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the status of the stream output.
|
||||
*
|
||||
* @responseField outputActive | Boolean | New state of the stream output
|
||||
*
|
||||
* @requestType ToggleStream
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category stream
|
||||
*/
|
||||
RequestResult RequestHandler::ToggleStream(const Request&)
|
||||
{
|
||||
json responseData;
|
||||
@ -51,6 +81,16 @@ RequestResult RequestHandler::ToggleStream(const Request&)
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the stream output.
|
||||
*
|
||||
* @requestType StartStream
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category stream
|
||||
*/
|
||||
RequestResult RequestHandler::StartStream(const Request&)
|
||||
{
|
||||
if (obs_frontend_streaming_active())
|
||||
@ -62,6 +102,16 @@ RequestResult RequestHandler::StartStream(const Request&)
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the stream output.
|
||||
*
|
||||
* @requestType StopStream
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category stream
|
||||
*/
|
||||
RequestResult RequestHandler::StopStream(const Request&)
|
||||
{
|
||||
if (!obs_frontend_streaming_active())
|
||||
@ -72,3 +122,35 @@ RequestResult RequestHandler::StopStream(const Request&)
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends CEA-608 caption text over the stream output.
|
||||
*
|
||||
* @requestField captionText | String | Caption text
|
||||
*
|
||||
* @requestType SendStreamCaption
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @category stream
|
||||
* @api requests
|
||||
*/
|
||||
RequestResult RequestHandler::SendStreamCaption(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
if (!request.ValidateString("captionText", statusCode, comment, true))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
if (!obs_frontend_streaming_active())
|
||||
return RequestResult::Error(RequestStatus::OutputNotRunning);
|
||||
|
||||
std::string captionText = request.RequestData["captionText"];
|
||||
|
||||
OBSOutputAutoRelease output = obs_frontend_get_streaming_output();
|
||||
|
||||
// 0.0 means no delay until the next caption can be sent
|
||||
obs_output_output_caption_text2(output, captionText.c_str(), 0.0);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
322
src/requesthandler/RequestHandler_Transitions.cpp
Normal file
322
src/requesthandler/RequestHandler_Transitions.cpp
Normal file
@ -0,0 +1,322 @@
|
||||
/*
|
||||
obs-websocket
|
||||
Copyright (C) 2016-2021 Stephane Lepin <stephane.lepin@gmail.com>
|
||||
Copyright (C) 2020-2021 Kyle Manning <tt2468@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "RequestHandler.h"
|
||||
|
||||
/**
|
||||
* Gets an array of all available transition kinds.
|
||||
*
|
||||
* Similar to `GetInputKindList`
|
||||
*
|
||||
* @responseField transitionKinds | Array<String> | Array of transition kinds
|
||||
*
|
||||
* @requestType GetTransitionKindList
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category transitions
|
||||
*/
|
||||
RequestResult RequestHandler::GetTransitionKindList(const Request&)
|
||||
{
|
||||
json responseData;
|
||||
responseData["transitionKinds"] = Utils::Obs::ArrayHelper::GetTransitionKindList();
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of all scene transitions in OBS.
|
||||
*
|
||||
* @responseField currentSceneTransitionName | String | Name of the current scene transition. Can be null
|
||||
* @responseField currentSceneTransitionKind | String | Kind of the current scene transition. Can be null
|
||||
* @responseField transitions | Array<Object> | Array of transitions
|
||||
*
|
||||
* @requestType GetSceneTransitionList
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category transitions
|
||||
*/
|
||||
RequestResult RequestHandler::GetSceneTransitionList(const Request&)
|
||||
{
|
||||
json responseData;
|
||||
|
||||
OBSSourceAutoRelease transition = obs_frontend_get_current_transition();
|
||||
if (transition) {
|
||||
responseData["currentSceneTransitionName"] = obs_source_get_name(transition);
|
||||
responseData["currentSceneTransitionKind"] = obs_source_get_id(transition);
|
||||
} else {
|
||||
responseData["currentSceneTransitionName"] = nullptr;
|
||||
responseData["currentSceneTransitionKind"] = nullptr;
|
||||
}
|
||||
|
||||
responseData["transitions"] = Utils::Obs::ArrayHelper::GetSceneTransitionList();
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets information about the current scene transition.
|
||||
*
|
||||
* @responseField transitionName | String | Name of the transition
|
||||
* @responseField transitionKind | String | Kind of the transition
|
||||
* @responseField transitionFixed | Boolean | Whether the transition uses a fixed (unconfigurable) duration
|
||||
* @responseField transitionDuration | Number | Configured transition duration in milliseconds. `null` if transition is fixed
|
||||
* @responseField transitionConfigurable | Boolean | Whether the transition supports being configured
|
||||
* @responseField transitionSettings | Object | Object of settings for the transition. `null` if transition is not configurable
|
||||
*
|
||||
* @requestType GetCurrentSceneTransition
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category transitions
|
||||
*/
|
||||
RequestResult RequestHandler::GetCurrentSceneTransition(const Request&)
|
||||
{
|
||||
OBSSourceAutoRelease transition = obs_frontend_get_current_transition();
|
||||
if (!transition)
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "OBS does not currently have a scene transition set."); // This should not happen!
|
||||
|
||||
json responseData;
|
||||
responseData["transitionName"] = obs_source_get_name(transition);
|
||||
responseData["transitionKind"] = obs_source_get_id(transition);
|
||||
|
||||
if (obs_transition_fixed(transition)) {
|
||||
responseData["transitionFixed"] = true;
|
||||
responseData["transitionDuration"] = nullptr;
|
||||
} else {
|
||||
responseData["transitionFixed"] = false;
|
||||
responseData["transitionDuration"] = obs_frontend_get_transition_duration();
|
||||
}
|
||||
|
||||
if (obs_source_configurable(transition)) {
|
||||
responseData["transitionConfigurable"] = true;
|
||||
OBSDataAutoRelease transitionSettings = obs_source_get_settings(transition);
|
||||
responseData["transitionSettings"] = Utils::Json::ObsDataToJson(transitionSettings);
|
||||
} else {
|
||||
responseData["transitionConfigurable"] = false;
|
||||
responseData["transitionSettings"] = nullptr;
|
||||
}
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current scene transition.
|
||||
*
|
||||
* Small note: While the namespace of scene transitions is generally unique, that uniqueness is not a guarantee as it is with other resources like inputs.
|
||||
*
|
||||
* @requestField transitionName | String | Name of the transition to make active
|
||||
*
|
||||
* @requestType SetCurrentSceneTransition
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category transitions
|
||||
*/
|
||||
RequestResult RequestHandler::SetCurrentSceneTransition(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
if (!request.ValidateString("transitionName", statusCode, comment))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
std::string transitionName = request.RequestData["transitionName"];
|
||||
|
||||
OBSSourceAutoRelease transition = Utils::Obs::SearchHelper::GetSceneTransitionByName(transitionName);
|
||||
if (!transition)
|
||||
return RequestResult::Error(RequestStatus::ResourceNotFound, "No scene transition was found by that name.");
|
||||
|
||||
obs_frontend_set_current_transition(transition);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the duration of the current scene transition, if it is not fixed.
|
||||
*
|
||||
* @requestField transitionDuration | Number | Duration in milliseconds | >= 50, <= 20000
|
||||
*
|
||||
* @requestType SetCurrentSceneTransitionDuration
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category transitions
|
||||
*/
|
||||
RequestResult RequestHandler::SetCurrentSceneTransitionDuration(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
if (!request.ValidateNumber("transitionDuration", statusCode, comment, 50, 20000))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
int transitionDuration = request.RequestData["transitionDuration"];
|
||||
|
||||
obs_frontend_set_transition_duration(transitionDuration);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the settings of the current scene transition.
|
||||
*
|
||||
* @requestField transitionSettings | Object | Settings object to apply to the transition. Can be `{}`
|
||||
* @requestField ?overlay | Boolean | Whether to overlay over the current settings or replace them | true
|
||||
*
|
||||
* @requestType SetCurrentSceneTransitionSettings
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category transitions
|
||||
*/
|
||||
RequestResult RequestHandler::SetCurrentSceneTransitionSettings(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
if (!request.ValidateObject("transitionSettings", statusCode, comment, true))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
OBSSourceAutoRelease transition = obs_frontend_get_current_transition();
|
||||
if (!transition)
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "OBS does not currently have a scene transition set."); // This should not happen!
|
||||
|
||||
if (!obs_source_configurable(transition))
|
||||
return RequestResult::Error(RequestStatus::ResourceNotConfigurable, "The current transition does not support custom settings.");
|
||||
|
||||
bool overlay = true;
|
||||
if (request.Contains("overlay")) {
|
||||
if (!request.ValidateOptionalBoolean("overlay", statusCode, comment))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
overlay = request.RequestData["overlay"];
|
||||
}
|
||||
|
||||
OBSDataAutoRelease newSettings = Utils::Json::JsonToObsData(request.RequestData["transitionSettings"]);
|
||||
if (!newSettings)
|
||||
return RequestResult::Error(RequestStatus::RequestProcessingFailed, "An internal data conversion operation failed. Please report this!");
|
||||
|
||||
if (overlay)
|
||||
obs_source_update(transition, newSettings);
|
||||
else
|
||||
obs_source_reset_settings(transition, newSettings);
|
||||
|
||||
obs_source_update_properties(transition);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cursor position of the current scene transition.
|
||||
*
|
||||
* Note: `transitionCursor` will return 1.0 when the transition is inactive.
|
||||
*
|
||||
* @responseField transitionCursor | Number | Cursor position, between 0.0 and 1.0
|
||||
*
|
||||
* @requestType GetCurrentSceneTransitionCursor
|
||||
* @complexity 2
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category transitions
|
||||
*/
|
||||
RequestResult RequestHandler::GetCurrentSceneTransitionCursor(const Request&)
|
||||
{
|
||||
OBSSourceAutoRelease transition = obs_frontend_get_current_transition();
|
||||
if (!transition)
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "OBS does not currently have a scene transition set."); // This should not happen!
|
||||
|
||||
json responseData;
|
||||
responseData["transitionCursor"] = obs_transition_get_time(transition);
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the current scene transition. Same functionality as the `Transition` button in studio mode.
|
||||
*
|
||||
* @requestType TriggerStudioModeTransition
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category transitions
|
||||
*/
|
||||
RequestResult RequestHandler::TriggerStudioModeTransition(const Request&)
|
||||
{
|
||||
if (!obs_frontend_preview_program_mode_active())
|
||||
return RequestResult::Error(RequestStatus::StudioModeNotActive);
|
||||
|
||||
OBSSourceAutoRelease previewScene = obs_frontend_get_current_preview_scene();
|
||||
|
||||
obs_frontend_set_current_scene(previewScene);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position of the TBar.
|
||||
*
|
||||
* **Very important note**: This will be deprecated and replaced in a future version of obs-websocket.
|
||||
*
|
||||
* @requestField position | Number | New position | >= 0.0, <= 1.0
|
||||
* @requestField ?release | Boolean | Whether to release the TBar. Only set `false` if you know that you will be sending another position update | `true`
|
||||
*
|
||||
* @requestType SetTBarPosition
|
||||
* @complexity 3
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api requests
|
||||
* @category transitions
|
||||
*/
|
||||
RequestResult RequestHandler::SetTBarPosition(const Request& request)
|
||||
{
|
||||
if (!obs_frontend_preview_program_mode_active())
|
||||
return RequestResult::Error(RequestStatus::StudioModeNotActive);
|
||||
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
if (!request.ValidateNumber("position", statusCode, comment, 0.0, 1.0))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
bool release = true;
|
||||
if (request.Contains("release")) {
|
||||
if (!request.ValidateOptionalBoolean("release", statusCode, comment))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
}
|
||||
|
||||
OBSSourceAutoRelease transition = obs_frontend_get_current_transition();
|
||||
if (!transition)
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "OBS does not currently have a scene transition set."); // This should not happen!
|
||||
|
||||
float position = request.RequestData["position"];
|
||||
|
||||
obs_frontend_set_tbar_position((int)round(position * 1024.0));
|
||||
|
||||
if (release)
|
||||
obs_frontend_release_tbar();
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
150
src/requesthandler/RequestHandler_Ui.cpp
Normal file
150
src/requesthandler/RequestHandler_Ui.cpp
Normal file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
obs-websocket
|
||||
Copyright (C) 2016-2021 Stephane Lepin <stephane.lepin@gmail.com>
|
||||
Copyright (C) 2020-2021 Kyle Manning <tt2468@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "RequestHandler.h"
|
||||
|
||||
/**
|
||||
* Gets whether studio is enabled.
|
||||
*
|
||||
* @responseField studioModeEnabled | Boolean | Whether studio mode is enabled
|
||||
*
|
||||
* @requestType GetStudioModeEnabled
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @category ui
|
||||
* @api requests
|
||||
*/
|
||||
RequestResult RequestHandler::GetStudioModeEnabled(const Request&)
|
||||
{
|
||||
json responseData;
|
||||
responseData["studioModeEnabled"] = obs_frontend_preview_program_mode_active();
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables studio mode
|
||||
*
|
||||
* @requestField studioModeEnabled | Boolean | True == Enabled, False == Disabled
|
||||
*
|
||||
* @requestType SetStudioModeEnabled
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @category ui
|
||||
* @api requests
|
||||
*/
|
||||
RequestResult RequestHandler::SetStudioModeEnabled(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
if (!request.ValidateBoolean("studioModeEnabled", statusCode, comment))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
// Avoid queueing tasks if nothing will change
|
||||
if (obs_frontend_preview_program_mode_active() != request.RequestData["studioModeEnabled"]) {
|
||||
// (Bad) Create a boolean then pass it as a reference to the task. Requires `wait` in obs_queue_task() to be true, else undefined behavior
|
||||
bool studioModeEnabled = request.RequestData["studioModeEnabled"];
|
||||
// Queue the task inside of the UI thread to prevent race conditions
|
||||
obs_queue_task(OBS_TASK_UI, [](void* param) {
|
||||
auto studioModeEnabled = (bool*)param;
|
||||
obs_frontend_set_preview_program_mode(*studioModeEnabled);
|
||||
}, &studioModeEnabled, true);
|
||||
}
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the properties dialog of an input.
|
||||
*
|
||||
* @requestField inputName | String | Name of the input to open the dialog of
|
||||
*
|
||||
* @requestType OpenInputPropertiesDialog
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @category ui
|
||||
* @api requests
|
||||
*/
|
||||
RequestResult RequestHandler::OpenInputPropertiesDialog(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
|
||||
if (!input)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
obs_frontend_open_source_properties(input);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the filters dialog of an input.
|
||||
*
|
||||
* @requestField inputName | String | Name of the input to open the dialog of
|
||||
*
|
||||
* @requestType OpenInputFiltersDialog
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @category ui
|
||||
* @api requests
|
||||
*/
|
||||
RequestResult RequestHandler::OpenInputFiltersDialog(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
|
||||
if (!input)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
obs_frontend_open_source_filters(input);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the interact dialog of an input.
|
||||
*
|
||||
* @requestField inputName | String | Name of the input to open the dialog of
|
||||
*
|
||||
* @requestType OpenInputInteractDialog
|
||||
* @complexity 1
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @category ui
|
||||
* @api requests
|
||||
*/
|
||||
RequestResult RequestHandler::OpenInputInteractDialog(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
|
||||
if (!input)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
if (!(obs_source_get_output_flags(input) & OBS_SOURCE_INTERACTION))
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support interaction.");
|
||||
|
||||
obs_frontend_open_source_interaction(input);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
@ -264,18 +264,14 @@ obs_scene_t *Request::ValidateScene2(const std::string &keyName, RequestStatus::
|
||||
comment = "The specified source is not a scene. (Is group)";
|
||||
return nullptr;
|
||||
}
|
||||
OBSScene ret = obs_group_from_source(sceneSource);
|
||||
obs_scene_addref(ret);
|
||||
return ret;
|
||||
return obs_scene_get_ref(obs_group_from_source(sceneSource));
|
||||
} else {
|
||||
if (filter == OBS_WEBSOCKET_SCENE_FILTER_GROUP_ONLY) {
|
||||
statusCode = RequestStatus::InvalidResourceType;
|
||||
comment = "The specified source is not a group. (Is scene)";
|
||||
return nullptr;
|
||||
}
|
||||
OBSScene ret = obs_scene_from_source(sceneSource);
|
||||
obs_scene_addref(ret);
|
||||
return ret;
|
||||
return obs_scene_get_ref(obs_scene_from_source(sceneSource));
|
||||
}
|
||||
}
|
||||
|
||||
@ -295,25 +291,36 @@ obs_source_t *Request::ValidateInput(const std::string &keyName, RequestStatus::
|
||||
return ret;
|
||||
}
|
||||
|
||||
FilterPair Request::ValidateFilter(const std::string &sourceKeyName, const std::string &filterKeyName, RequestStatus::RequestStatus &statusCode, std::string &comment) const
|
||||
{
|
||||
obs_source_t *source = ValidateSource(sourceKeyName, statusCode, comment);
|
||||
if (!source)
|
||||
return FilterPair{source, nullptr};
|
||||
|
||||
if (!ValidateString(filterKeyName, statusCode, comment))
|
||||
return FilterPair{source, nullptr};
|
||||
|
||||
std::string filterName = RequestData[filterKeyName];
|
||||
|
||||
obs_source_t *filter = obs_source_get_filter_by_name(source, filterName.c_str());
|
||||
if (!filter) {
|
||||
statusCode = RequestStatus::ResourceNotFound;
|
||||
comment = std::string("No filter was found in the source `") + RequestData[sourceKeyName].get<std::string>() + "` with the name `" + filterName + "`.";
|
||||
return FilterPair{source, nullptr};
|
||||
}
|
||||
|
||||
return FilterPair{source, filter};
|
||||
}
|
||||
|
||||
obs_sceneitem_t *Request::ValidateSceneItem(const std::string &sceneKeyName, const std::string &sceneItemIdKeyName, RequestStatus::RequestStatus &statusCode, std::string &comment, const ObsWebSocketSceneFilter filter) const
|
||||
{
|
||||
OBSSourceAutoRelease sceneSource = ValidateScene(sceneKeyName, statusCode, comment, filter);
|
||||
if (!sceneSource)
|
||||
OBSSceneAutoRelease scene = ValidateScene2(sceneKeyName, statusCode, comment, filter);
|
||||
if (!scene)
|
||||
return nullptr;
|
||||
|
||||
if (!ValidateNumber(sceneItemIdKeyName, statusCode, comment, 0))
|
||||
return nullptr;
|
||||
|
||||
OBSScene scene = obs_scene_from_source(sceneSource);
|
||||
if (!scene) {
|
||||
scene = obs_group_from_source(sceneSource);
|
||||
if (!scene) { // This should never happen
|
||||
statusCode = RequestStatus::GenericError;
|
||||
comment = "Somehow the scene was found but the scene object could not be fetched. Please report this to the obs-websocket developers.";
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t sceneItemId = RequestData[sceneItemIdKeyName];
|
||||
|
||||
OBSSceneItem sceneItem = obs_scene_find_sceneitem_by_id(scene, sceneItemId);
|
||||
|
@ -29,6 +29,12 @@ enum ObsWebSocketSceneFilter {
|
||||
OBS_WEBSOCKET_SCENE_FILTER_SCENE_OR_GROUP,
|
||||
};
|
||||
|
||||
// We return filters as a pair because `obs_filter_get_parent()` is apparently volatile
|
||||
struct FilterPair {
|
||||
OBSSourceAutoRelease source;
|
||||
OBSSourceAutoRelease filter;
|
||||
};
|
||||
|
||||
struct Request
|
||||
{
|
||||
Request(const std::string &requestType, const json &requestData = nullptr, const RequestBatchExecutionType::RequestBatchExecutionType executionType = RequestBatchExecutionType::None);
|
||||
@ -53,6 +59,7 @@ struct Request
|
||||
obs_source_t *ValidateScene(const std::string &keyName, RequestStatus::RequestStatus &statusCode, std::string &comment, const ObsWebSocketSceneFilter filter = OBS_WEBSOCKET_SCENE_FILTER_SCENE_ONLY) const;
|
||||
obs_scene_t *ValidateScene2(const std::string &keyName, RequestStatus::RequestStatus &statusCode, std::string &comment, const ObsWebSocketSceneFilter filter = OBS_WEBSOCKET_SCENE_FILTER_SCENE_ONLY) const;
|
||||
obs_source_t *ValidateInput(const std::string &keyName, RequestStatus::RequestStatus &statusCode, std::string &comment) const;
|
||||
FilterPair ValidateFilter(const std::string &sourceKeyName, const std::string &filterKeyName, RequestStatus::RequestStatus &statusCode, std::string &comment) const;
|
||||
obs_sceneitem_t *ValidateSceneItem(const std::string &sceneKeyName, const std::string &sceneItemIdKeyName, RequestStatus::RequestStatus &statusCode, std::string &comment, const ObsWebSocketSceneFilter filter = OBS_WEBSOCKET_SCENE_FILTER_SCENE_ONLY) const;
|
||||
|
||||
std::string RequestType;
|
||||
|
@ -22,7 +22,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace RequestBatchExecutionType {
|
||||
enum RequestBatchExecutionType {
|
||||
enum RequestBatchExecutionType: int8_t {
|
||||
/**
|
||||
* Not a request batch.
|
||||
*
|
||||
@ -77,7 +77,7 @@ namespace RequestBatchExecutionType {
|
||||
Parallel = 2,
|
||||
};
|
||||
|
||||
inline bool IsValid(uint8_t executionType)
|
||||
inline bool IsValid(int8_t executionType)
|
||||
{
|
||||
return executionType >= None && executionType <= Parallel;
|
||||
}
|
||||
|
@ -332,6 +332,30 @@ namespace RequestStatus {
|
||||
* @api enums
|
||||
*/
|
||||
InvalidInputKind = 605,
|
||||
/**
|
||||
* The resource does not support being configured.
|
||||
*
|
||||
* This is particularly relevant to transitions, where they do not always have changeable settings.
|
||||
*
|
||||
* @enumIdentifier ResourceNotConfigurable
|
||||
* @enumValue 606
|
||||
* @enumType RequestStatus
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api enums
|
||||
*/
|
||||
ResourceNotConfigurable = 606,
|
||||
/**
|
||||
* The specified filter (obs_source_t-OBS_SOURCE_TYPE_FILTER) had the wrong kind.
|
||||
*
|
||||
* @enumIdentifier InvalidFilterKind
|
||||
* @enumValue 607
|
||||
* @enumType RequestStatus
|
||||
* @rpcVersion -1
|
||||
* @initialVersion 5.0.0
|
||||
* @api enums
|
||||
*/
|
||||
InvalidFilterKind = 607,
|
||||
|
||||
/**
|
||||
* Creating the resource failed.
|
||||
|
@ -21,7 +21,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
#include "Platform.h"
|
||||
#include "../plugin-macros.generated.h"
|
||||
|
||||
bool Utils::Json::JsonArrayIsValidObsArray(json j)
|
||||
bool Utils::Json::JsonArrayIsValidObsArray(const json &j)
|
||||
{
|
||||
for (auto it : j) {
|
||||
if (!it.is_object())
|
||||
@ -191,7 +191,7 @@ bool Utils::Json::GetJsonFileContent(std::string fileName, json &content)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Utils::Json::SetJsonFileContent(std::string fileName, json content, bool createNew)
|
||||
bool Utils::Json::SetJsonFileContent(std::string fileName, const json &content, bool createNew)
|
||||
{
|
||||
std::string textContent = content.dump(2);
|
||||
return Utils::Platform::SetTextFileContent(fileName, textContent, createNew);
|
||||
|
@ -27,10 +27,11 @@ using json = nlohmann::json;
|
||||
|
||||
namespace Utils {
|
||||
namespace Json {
|
||||
bool JsonArrayIsValidObsArray(json j);
|
||||
bool JsonArrayIsValidObsArray(const json &j);
|
||||
obs_data_t *JsonToObsData(json j);
|
||||
json ObsDataToJson(obs_data_t *d, bool includeDefault = false);
|
||||
bool GetJsonFileContent(std::string fileName, json &content);
|
||||
bool SetJsonFileContent(std::string fileName, json content, bool createNew = true);
|
||||
bool SetJsonFileContent(std::string fileName, const json &content, bool createNew = true);
|
||||
static inline bool Contains(const json &j, std::string key) { return j.contains(key) && !j[key].is_null(); }
|
||||
}
|
||||
}
|
||||
|
@ -17,562 +17,5 @@ You should have received a copy of the GNU General Public License along
|
||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <algorithm>
|
||||
#include <QString>
|
||||
#include <obs-frontend-api.h>
|
||||
#include <util/config-file.h>
|
||||
#include <util/util_uint64.h>
|
||||
|
||||
#include "Obs.h"
|
||||
#include "../obs-websocket.h"
|
||||
#include "../plugin-macros.generated.h"
|
||||
|
||||
#define CASE(x) case x: return #x;
|
||||
|
||||
#define RET_COMPARE(str, x) if (str == #x) return x;
|
||||
|
||||
std::vector<std::string> ConvertStringArray(char **array)
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
if (!array)
|
||||
return ret;
|
||||
|
||||
size_t index = 0;
|
||||
char* value = nullptr;
|
||||
do {
|
||||
value = array[index];
|
||||
if (value)
|
||||
ret.push_back(value);
|
||||
index++;
|
||||
} while (value);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetObsVersion()
|
||||
{
|
||||
uint32_t version = obs_get_version();
|
||||
|
||||
uint8_t major, minor, patch;
|
||||
major = (version >> 24) & 0xFF;
|
||||
minor = (version >> 16) & 0xFF;
|
||||
patch = version & 0xFF;
|
||||
|
||||
QString combined = QString("%1.%2.%3").arg(major).arg(minor).arg(patch);
|
||||
return combined.toStdString();
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetCurrentSceneCollection()
|
||||
{
|
||||
char *sceneCollectionName = obs_frontend_get_current_scene_collection();
|
||||
std::string ret = sceneCollectionName;
|
||||
bfree(sceneCollectionName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetCurrentProfile()
|
||||
{
|
||||
char *profileName = obs_frontend_get_current_profile();
|
||||
std::string ret = profileName;
|
||||
bfree(profileName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetCurrentProfilePath()
|
||||
{
|
||||
char *profilePath = obs_frontend_get_current_profile_path();
|
||||
std::string ret = profilePath;
|
||||
bfree(profilePath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetCurrentRecordOutputPath()
|
||||
{
|
||||
//char *recordOutputPath = obs_frontend_get_current_record_output_path();
|
||||
//std::string ret = recordOutputPath;
|
||||
//bfree(recordOutputPath);
|
||||
//return ret;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetSourceType(obs_source_t *source)
|
||||
{
|
||||
obs_source_type sourceType = obs_source_get_type(source);
|
||||
|
||||
switch (sourceType) {
|
||||
default:
|
||||
CASE(OBS_SOURCE_TYPE_INPUT)
|
||||
CASE(OBS_SOURCE_TYPE_FILTER)
|
||||
CASE(OBS_SOURCE_TYPE_TRANSITION)
|
||||
CASE(OBS_SOURCE_TYPE_SCENE)
|
||||
}
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetInputMonitorType(obs_source_t *input)
|
||||
{
|
||||
obs_monitoring_type monitorType = obs_source_get_monitoring_type(input);
|
||||
|
||||
switch (monitorType) {
|
||||
default:
|
||||
CASE(OBS_MONITORING_TYPE_NONE)
|
||||
CASE(OBS_MONITORING_TYPE_MONITOR_ONLY)
|
||||
CASE(OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT)
|
||||
}
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetMediaInputState(obs_source_t *input)
|
||||
{
|
||||
obs_media_state mediaState = obs_source_media_get_state(input);
|
||||
|
||||
switch (mediaState) {
|
||||
default:
|
||||
CASE(OBS_MEDIA_STATE_NONE)
|
||||
CASE(OBS_MEDIA_STATE_PLAYING)
|
||||
CASE(OBS_MEDIA_STATE_OPENING)
|
||||
CASE(OBS_MEDIA_STATE_BUFFERING)
|
||||
CASE(OBS_MEDIA_STATE_PAUSED)
|
||||
CASE(OBS_MEDIA_STATE_STOPPED)
|
||||
CASE(OBS_MEDIA_STATE_ENDED)
|
||||
CASE(OBS_MEDIA_STATE_ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetLastReplayBufferFilePath()
|
||||
{
|
||||
OBSOutputAutoRelease output = obs_frontend_get_replay_buffer_output();
|
||||
calldata_t cd = {0};
|
||||
proc_handler_t *ph = obs_output_get_proc_handler(output);
|
||||
proc_handler_call(ph, "get_last_replay", &cd);
|
||||
auto ret = calldata_string(&cd, "path");
|
||||
calldata_free(&cd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetSceneItemBoundsType(enum obs_bounds_type type)
|
||||
{
|
||||
switch (type) {
|
||||
default:
|
||||
CASE(OBS_BOUNDS_NONE)
|
||||
CASE(OBS_BOUNDS_STRETCH)
|
||||
CASE(OBS_BOUNDS_SCALE_INNER)
|
||||
CASE(OBS_BOUNDS_SCALE_OUTER)
|
||||
CASE(OBS_BOUNDS_SCALE_TO_WIDTH)
|
||||
CASE(OBS_BOUNDS_SCALE_TO_HEIGHT)
|
||||
CASE(OBS_BOUNDS_MAX_ONLY)
|
||||
}
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::DurationToTimecode(uint64_t ms)
|
||||
{
|
||||
uint64_t secs = ms / 1000ULL;
|
||||
uint64_t minutes = secs / 60ULL;
|
||||
|
||||
uint64_t hoursPart = minutes / 60ULL;
|
||||
uint64_t minutesPart = minutes % 60ULL;
|
||||
uint64_t secsPart = secs % 60ULL;
|
||||
uint64_t msPart = ms % 1000ULL;
|
||||
|
||||
QString formatted = QString::asprintf("%02" PRIu64 ":%02" PRIu64 ":%02" PRIu64 ".%03" PRIu64, hoursPart, minutesPart, secsPart, msPart);
|
||||
return formatted.toStdString();
|
||||
}
|
||||
|
||||
enum obs_bounds_type Utils::Obs::EnumHelper::GetSceneItemBoundsType(std::string boundsType)
|
||||
{
|
||||
RET_COMPARE(boundsType, OBS_BOUNDS_NONE);
|
||||
RET_COMPARE(boundsType, OBS_BOUNDS_STRETCH);
|
||||
RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_INNER);
|
||||
RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_OUTER);
|
||||
RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_TO_WIDTH);
|
||||
RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_TO_HEIGHT);
|
||||
RET_COMPARE(boundsType, OBS_BOUNDS_MAX_ONLY);
|
||||
|
||||
return OBS_BOUNDS_NONE;
|
||||
}
|
||||
|
||||
enum ObsMediaInputAction Utils::Obs::EnumHelper::GetMediaInputAction(std::string mediaAction)
|
||||
{
|
||||
RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY);
|
||||
RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE);
|
||||
RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP);
|
||||
RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART);
|
||||
RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT);
|
||||
RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS);
|
||||
|
||||
return OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE;
|
||||
}
|
||||
|
||||
uint64_t Utils::Obs::NumberHelper::GetOutputDuration(obs_output_t *output)
|
||||
{
|
||||
if (!output || !obs_output_active(output))
|
||||
return 0;
|
||||
|
||||
video_t* video = obs_output_video(output);
|
||||
uint64_t frameTimeNs = video_output_get_frame_time(video);
|
||||
int totalFrames = obs_output_get_total_frames(output);
|
||||
|
||||
return util_mul_div64(totalFrames, frameTimeNs, 1000000ULL);
|
||||
}
|
||||
|
||||
size_t Utils::Obs::NumberHelper::GetSceneCount()
|
||||
{
|
||||
size_t ret;
|
||||
auto sceneEnumProc = [](void *param, obs_source_t *scene) {
|
||||
auto ret = reinterpret_cast<size_t*>(param);
|
||||
|
||||
if (obs_source_is_group(scene))
|
||||
return true;
|
||||
|
||||
(*ret)++;
|
||||
return true;
|
||||
};
|
||||
|
||||
obs_enum_scenes(sceneEnumProc, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::string> Utils::Obs::ListHelper::GetSceneCollectionList()
|
||||
{
|
||||
char** sceneCollections = obs_frontend_get_scene_collections();
|
||||
auto ret = ConvertStringArray(sceneCollections);
|
||||
bfree(sceneCollections);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::string> Utils::Obs::ListHelper::GetProfileList()
|
||||
{
|
||||
char** profiles = obs_frontend_get_profiles();
|
||||
auto ret = ConvertStringArray(profiles);
|
||||
bfree(profiles);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<obs_hotkey_t *> Utils::Obs::ListHelper::GetHotkeyList()
|
||||
{
|
||||
std::vector<obs_hotkey_t *> ret;
|
||||
|
||||
obs_enum_hotkeys([](void* data, obs_hotkey_id, obs_hotkey_t* hotkey) {
|
||||
auto ret = reinterpret_cast<std::vector<obs_hotkey_t *> *>(data);
|
||||
|
||||
ret->push_back(hotkey);
|
||||
|
||||
return true;
|
||||
}, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::string> Utils::Obs::ListHelper::GetHotkeyNameList()
|
||||
{
|
||||
auto hotkeys = GetHotkeyList();
|
||||
|
||||
std::vector<std::string> ret;
|
||||
for (auto hotkey : hotkeys) {
|
||||
ret.emplace_back(obs_hotkey_get_name(hotkey));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<json> Utils::Obs::ListHelper::GetSceneList()
|
||||
{
|
||||
obs_frontend_source_list sceneList = {};
|
||||
obs_frontend_get_scenes(&sceneList);
|
||||
|
||||
std::vector<json> ret;
|
||||
for (size_t i = 0; i < sceneList.sources.num; i++) {
|
||||
obs_source_t *scene = sceneList.sources.array[i];
|
||||
|
||||
if (obs_source_is_group(scene))
|
||||
continue;
|
||||
|
||||
json sceneJson;
|
||||
sceneJson["sceneName"] = obs_source_get_name(scene);
|
||||
sceneJson["sceneIndex"] = sceneList.sources.num - i - 1;
|
||||
|
||||
ret.push_back(sceneJson);
|
||||
}
|
||||
|
||||
obs_frontend_source_list_free(&sceneList);
|
||||
|
||||
// Reverse the vector order to match other array returns
|
||||
std::reverse(ret.begin(), ret.end());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<json> Utils::Obs::ListHelper::GetSceneItemList(obs_scene_t *scene, bool basic)
|
||||
{
|
||||
std::pair<std::vector<json>, bool> enumData;
|
||||
enumData.second = basic;
|
||||
|
||||
obs_scene_enum_items(scene, [](obs_scene_t*, obs_sceneitem_t* sceneItem, void* param) {
|
||||
auto enumData = reinterpret_cast<std::pair<std::vector<json>, bool>*>(param);
|
||||
|
||||
json item;
|
||||
item["sceneItemId"] = obs_sceneitem_get_id(sceneItem);
|
||||
// Should be slightly faster than calling obs_sceneitem_get_order_position()
|
||||
item["sceneItemIndex"] = enumData->first.size();
|
||||
if (!enumData->second) {
|
||||
OBSSource itemSource = obs_sceneitem_get_source(sceneItem);
|
||||
item["sourceName"] = obs_source_get_name(itemSource);
|
||||
item["sourceType"] = StringHelper::GetSourceType(itemSource);
|
||||
if (obs_source_get_type(itemSource) == OBS_SOURCE_TYPE_INPUT)
|
||||
item["inputKind"] = obs_source_get_id(itemSource);
|
||||
else
|
||||
item["inputKind"] = nullptr;
|
||||
if (obs_source_get_type(itemSource) == OBS_SOURCE_TYPE_SCENE)
|
||||
item["isGroup"] = obs_source_is_group(itemSource);
|
||||
else
|
||||
item["isGroup"] = nullptr;
|
||||
}
|
||||
|
||||
enumData->first.push_back(item);
|
||||
|
||||
return true;
|
||||
}, &enumData);
|
||||
|
||||
return enumData.first;
|
||||
}
|
||||
|
||||
std::vector<json> Utils::Obs::ListHelper::GetTransitionList()
|
||||
{
|
||||
obs_frontend_source_list transitionList = {};
|
||||
obs_frontend_get_transitions(&transitionList);
|
||||
|
||||
std::vector<json> ret;
|
||||
for (size_t i = 0; i < transitionList.sources.num; i++) {
|
||||
obs_source_t *transition = transitionList.sources.array[i];
|
||||
json transitionJson;
|
||||
transitionJson["transitionName"] = obs_source_get_name(transition);
|
||||
transitionJson["transitionKind"] = obs_source_get_id(transition);
|
||||
transitionJson["transitionFixed"] = obs_transition_fixed(transition);
|
||||
ret.push_back(transitionJson);
|
||||
}
|
||||
|
||||
obs_frontend_source_list_free(&transitionList);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct EnumInputInfo {
|
||||
std::string inputKind; // For searching by input kind
|
||||
std::vector<json> inputs;
|
||||
};
|
||||
|
||||
std::vector<json> Utils::Obs::ListHelper::GetInputList(std::string inputKind)
|
||||
{
|
||||
EnumInputInfo inputInfo;
|
||||
inputInfo.inputKind = inputKind;
|
||||
|
||||
auto inputEnumProc = [](void *param, obs_source_t *input) {
|
||||
// Sanity check in case the API changes
|
||||
if (obs_source_get_type(input) != OBS_SOURCE_TYPE_INPUT)
|
||||
return true;
|
||||
|
||||
auto inputInfo = reinterpret_cast<EnumInputInfo*>(param);
|
||||
|
||||
std::string inputKind = obs_source_get_id(input);
|
||||
|
||||
if (!inputInfo->inputKind.empty() && inputInfo->inputKind != inputKind)
|
||||
return true;
|
||||
|
||||
json inputJson;
|
||||
inputJson["inputName"] = obs_source_get_name(input);
|
||||
inputJson["inputKind"] = inputKind;
|
||||
inputJson["unversionedInputKind"] = obs_source_get_unversioned_id(input);
|
||||
|
||||
inputInfo->inputs.push_back(inputJson);
|
||||
return true;
|
||||
};
|
||||
// Actually enumerates only public inputs, despite the name
|
||||
obs_enum_sources(inputEnumProc, &inputInfo);
|
||||
|
||||
return inputInfo.inputs;
|
||||
}
|
||||
|
||||
std::vector<std::string> Utils::Obs::ListHelper::GetInputKindList(bool unversioned, bool includeDisabled)
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
|
||||
size_t idx = 0;
|
||||
const char *kind;
|
||||
const char *unversioned_kind;
|
||||
while (obs_enum_input_types2(idx++, &kind, &unversioned_kind)) {
|
||||
uint32_t caps = obs_get_source_output_flags(kind);
|
||||
|
||||
if (!includeDisabled && (caps & OBS_SOURCE_CAP_DISABLED) != 0)
|
||||
continue;
|
||||
|
||||
if (unversioned)
|
||||
ret.push_back(unversioned_kind);
|
||||
else
|
||||
ret.push_back(kind);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
json Utils::Obs::DataHelper::GetStats()
|
||||
{
|
||||
json ret;
|
||||
|
||||
config_t* currentProfile = obs_frontend_get_profile_config();
|
||||
const char* outputMode = config_get_string(currentProfile, "Output", "Mode");
|
||||
const char* recordPath = strcmp(outputMode, "Advanced") ? config_get_string(currentProfile, "SimpleOutput", "FilePath") : config_get_string(currentProfile, "AdvOut", "RecFilePath");
|
||||
|
||||
video_t* video = obs_get_video();
|
||||
|
||||
ret["cpuUsage"] = os_cpu_usage_info_query(GetCpuUsageInfo());
|
||||
ret["memoryUsage"] = (double)os_get_proc_resident_size() / (1024.0 * 1024.0);
|
||||
ret["availableDiskSpace"] = (double)os_get_free_disk_space(recordPath) / (1024.0 * 1024.0);
|
||||
ret["activeFps"] = obs_get_active_fps();
|
||||
ret["averageFrameRenderTime"] = (double)obs_get_average_frame_time_ns() / 1000000.0;
|
||||
ret["renderSkippedFrames"] = obs_get_lagged_frames();
|
||||
ret["renderTotalFrames"] = obs_get_total_frames();
|
||||
ret["outputSkippedFrames"] = video_output_get_skipped_frames(video);
|
||||
ret["outputTotalFrames"] = video_output_get_total_frames(video);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
json Utils::Obs::DataHelper::GetSceneItemTransform(obs_sceneitem_t *item)
|
||||
{
|
||||
json ret;
|
||||
|
||||
obs_transform_info osi;
|
||||
obs_sceneitem_crop crop;
|
||||
obs_sceneitem_get_info(item, &osi);
|
||||
obs_sceneitem_get_crop(item, &crop);
|
||||
|
||||
OBSSource source = obs_sceneitem_get_source(item);
|
||||
float sourceWidth = float(obs_source_get_width(source));
|
||||
float sourceHeight = float(obs_source_get_height(source));
|
||||
|
||||
ret["sourceWidth"] = sourceWidth;
|
||||
ret["sourceHeight"] = sourceHeight;
|
||||
|
||||
ret["positionX"] = osi.pos.x;
|
||||
ret["positionY"] = osi.pos.y;
|
||||
|
||||
ret["rotation"] = osi.rot;
|
||||
|
||||
ret["scaleX"] = osi.scale.x;
|
||||
ret["scaleY"] = osi.scale.y;
|
||||
|
||||
ret["width"] = osi.scale.x * sourceWidth;
|
||||
ret["height"] = osi.scale.y * sourceHeight;
|
||||
|
||||
ret["alignment"] = osi.alignment;
|
||||
|
||||
ret["boundsType"] = StringHelper::GetSceneItemBoundsType(osi.bounds_type);
|
||||
ret["boundsAlignment"] = osi.bounds_alignment;
|
||||
ret["boundsWidth"] = osi.bounds.x;
|
||||
ret["boundsHeight"] = osi.bounds.y;
|
||||
|
||||
ret["cropLeft"] = int(crop.left);
|
||||
ret["cropRight"] = int(crop.right);
|
||||
ret["cropTop"] = int(crop.top);
|
||||
ret["cropBottom"] = int(crop.bottom);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
obs_hotkey_t *Utils::Obs::SearchHelper::GetHotkeyByName(std::string name)
|
||||
{
|
||||
if (name.empty())
|
||||
return nullptr;
|
||||
|
||||
auto hotkeys = ListHelper::GetHotkeyList();
|
||||
|
||||
for (auto hotkey : hotkeys) {
|
||||
if (obs_hotkey_get_name(hotkey) == name)
|
||||
return hotkey;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Increments item ref. Use OBSSceneItemAutoRelease
|
||||
obs_sceneitem_t *Utils::Obs::SearchHelper::GetSceneItemByName(obs_scene_t *scene, std::string name)
|
||||
{
|
||||
if (name.empty())
|
||||
return nullptr;
|
||||
|
||||
// Finds first matching scene item in scene, search starts at index 0
|
||||
OBSSceneItem ret = obs_scene_find_source(scene, name.c_str());
|
||||
obs_sceneitem_addref(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct CreateSceneItemData {
|
||||
obs_source_t *source; // In
|
||||
bool sceneItemEnabled; // In
|
||||
obs_transform_info *sceneItemTransform = nullptr; // In
|
||||
obs_sceneitem_crop *sceneItemCrop = nullptr; // In
|
||||
OBSSceneItem sceneItem; // Out
|
||||
};
|
||||
|
||||
void CreateSceneItemHelper(void *_data, obs_scene_t *scene)
|
||||
{
|
||||
auto *data = reinterpret_cast<CreateSceneItemData*>(_data);
|
||||
data->sceneItem = obs_scene_add(scene, data->source);
|
||||
|
||||
if (data->sceneItemTransform)
|
||||
obs_sceneitem_set_info(data->sceneItem, data->sceneItemTransform);
|
||||
|
||||
if (data->sceneItemCrop)
|
||||
obs_sceneitem_set_crop(data->sceneItem, data->sceneItemCrop);
|
||||
|
||||
obs_sceneitem_set_visible(data->sceneItem, data->sceneItemEnabled);
|
||||
}
|
||||
|
||||
obs_sceneitem_t *Utils::Obs::ActionHelper::CreateSceneItem(obs_source_t *source, obs_scene_t *scene, bool sceneItemEnabled, obs_transform_info *sceneItemTransform, obs_sceneitem_crop *sceneItemCrop)
|
||||
{
|
||||
// Sanity check for valid scene
|
||||
if (!(source && scene))
|
||||
return nullptr;
|
||||
|
||||
// Create data struct and populate for scene item creation
|
||||
CreateSceneItemData data;
|
||||
data.source = source;
|
||||
data.sceneItemEnabled = sceneItemEnabled;
|
||||
data.sceneItemTransform = sceneItemTransform;
|
||||
data.sceneItemCrop = sceneItemCrop;
|
||||
|
||||
// Enter graphics context and create the scene item
|
||||
obs_enter_graphics();
|
||||
obs_scene_atomic_update(scene, CreateSceneItemHelper, &data);
|
||||
obs_leave_graphics();
|
||||
|
||||
obs_sceneitem_addref(data.sceneItem);
|
||||
|
||||
return data.sceneItem;
|
||||
}
|
||||
|
||||
obs_sceneitem_t *Utils::Obs::ActionHelper::CreateInput(std::string inputName, std::string inputKind, obs_data_t *inputSettings, obs_scene_t *scene, bool sceneItemEnabled)
|
||||
{
|
||||
// Create the input
|
||||
OBSSourceAutoRelease input = obs_source_create(inputKind.c_str(), inputName.c_str(), inputSettings, nullptr);
|
||||
|
||||
// Check that everything was created properly
|
||||
if (!input)
|
||||
return nullptr;
|
||||
|
||||
// Apparently not all default input properties actually get applied on creation (smh)
|
||||
uint32_t flags = obs_source_get_output_flags(input);
|
||||
if ((flags & OBS_SOURCE_MONITOR_BY_DEFAULT) != 0)
|
||||
obs_source_set_monitoring_type(input, OBS_MONITORING_TYPE_MONITOR_ONLY);
|
||||
|
||||
// Create a scene item for the input
|
||||
obs_sceneitem_t *ret = CreateSceneItem(input, scene, sceneItemEnabled);
|
||||
|
||||
// If creation failed, remove the input
|
||||
if (!ret)
|
||||
obs_source_remove(input);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
124
src/utils/Obs.h
124
src/utils/Obs.h
@ -21,33 +21,132 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
#include <string>
|
||||
#include <obs.hpp>
|
||||
#include <obs-frontend-api.h>
|
||||
|
||||
#include "Json.h"
|
||||
|
||||
// Autorelease object definitions
|
||||
inline void ___properties_dummy_addref(obs_properties_t*){}
|
||||
using OBSPropertiesAutoDestroy = OBSRef<obs_properties_t*, ___properties_dummy_addref, obs_properties_destroy>;
|
||||
|
||||
#if !defined(OBS_AUTORELEASE)
|
||||
inline void ___source_dummy_addref(obs_source_t*){}
|
||||
inline void ___scene_dummy_addref(obs_scene_t*){}
|
||||
inline void ___sceneitem_dummy_addref(obs_sceneitem_t*){}
|
||||
inline void ___data_dummy_addref(obs_data_t*){}
|
||||
inline void ___data_array_dummy_addref(obs_data_array_t*){}
|
||||
inline void ___output_dummy_addref(obs_output_t*){}
|
||||
inline void ___encoder_dummy_addref(obs_encoder_t *){}
|
||||
inline void ___service_dummy_addref(obs_service_t *){}
|
||||
|
||||
inline void ___weak_source_dummy_addref(obs_weak_source_t*){}
|
||||
inline void ___weak_output_dummy_addref(obs_weak_output_t *){}
|
||||
inline void ___weak_encoder_dummy_addref(obs_weak_encoder_t *){}
|
||||
inline void ___weak_service_dummy_addref(obs_weak_service_t *){}
|
||||
|
||||
using OBSSourceAutoRelease = OBSRef<obs_source_t*, ___source_dummy_addref, obs_source_release>;
|
||||
using OBSSceneAutoRelease = OBSRef<obs_scene_t*, ___scene_dummy_addref, obs_scene_release>;
|
||||
using OBSSceneItemAutoRelease = OBSRef<obs_sceneitem_t*, ___sceneitem_dummy_addref, obs_sceneitem_release>;
|
||||
using OBSDataAutoRelease = OBSRef<obs_data_t*, ___data_dummy_addref, obs_data_release>;
|
||||
using OBSDataArrayAutoRelease = OBSRef<obs_data_array_t*, ___data_array_dummy_addref, obs_data_array_release>;
|
||||
using OBSOutputAutoRelease = OBSRef<obs_output_t*, ___output_dummy_addref, obs_output_release>;
|
||||
using OBSEncoderAutoRelease = OBSRef<obs_encoder_t *, ___encoder_dummy_addref, obs_encoder_release>;
|
||||
using OBSServiceAutoRelease = OBSRef<obs_service_t *, ___service_dummy_addref, obs_service_release>;
|
||||
|
||||
using OBSWeakSourceAutoRelease = OBSRef<obs_weak_source_t*, ___weak_source_dummy_addref, obs_weak_source_release>;
|
||||
using OBSWeakOutputAutoRelease = OBSRef<obs_weak_output_t *, ___weak_output_dummy_addref, obs_weak_output_release>;
|
||||
using OBSWeakEncoderAutoRelease = OBSRef<obs_weak_encoder_t *, ___weak_encoder_dummy_addref, obs_weak_encoder_release>;
|
||||
using OBSWeakServiceAutoRelease = OBSRef<obs_weak_service_t *, ___weak_service_dummy_addref, obs_weak_service_release>;
|
||||
#endif
|
||||
|
||||
template <typename T> T* GetCalldataPointer(const calldata_t *data, const char* name) {
|
||||
void *ptr = nullptr;
|
||||
calldata_get_ptr(data, name, &ptr);
|
||||
return reinterpret_cast<T*>(ptr);
|
||||
return static_cast<T*>(ptr);
|
||||
}
|
||||
|
||||
enum ObsOutputState {
|
||||
OBS_WEBSOCKET_OUTPUT_UNKNOWN,
|
||||
OBS_WEBSOCKET_OUTPUT_STARTING,
|
||||
OBS_WEBSOCKET_OUTPUT_STARTED,
|
||||
OBS_WEBSOCKET_OUTPUT_STOPPING,
|
||||
OBS_WEBSOCKET_OUTPUT_STOPPED,
|
||||
OBS_WEBSOCKET_OUTPUT_RECONNECTING,
|
||||
OBS_WEBSOCKET_OUTPUT_PAUSED,
|
||||
OBS_WEBSOCKET_OUTPUT_RESUMED
|
||||
OBS_WEBSOCKET_OUTPUT_RESUMED,
|
||||
};
|
||||
|
||||
enum ObsMediaInputAction {
|
||||
/**
|
||||
* No action.
|
||||
*
|
||||
* @enumIdentifier OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE
|
||||
* @enumType ObsMediaInputAction
|
||||
* @rpcVersion 1
|
||||
* @initialVersion 5.0.0
|
||||
* @api enums
|
||||
*/
|
||||
OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE,
|
||||
/**
|
||||
* Play the media input.
|
||||
*
|
||||
* @enumIdentifier OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY
|
||||
* @enumType ObsMediaInputAction
|
||||
* @rpcVersion 1
|
||||
* @initialVersion 5.0.0
|
||||
* @api enums
|
||||
*/
|
||||
OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY,
|
||||
/**
|
||||
* Pause the media input.
|
||||
*
|
||||
* @enumIdentifier OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE
|
||||
* @enumType ObsMediaInputAction
|
||||
* @rpcVersion 1
|
||||
* @initialVersion 5.0.0
|
||||
* @api enums
|
||||
*/
|
||||
OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE,
|
||||
/**
|
||||
* Stop the media input.
|
||||
*
|
||||
* @enumIdentifier OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP
|
||||
* @enumType ObsMediaInputAction
|
||||
* @rpcVersion 1
|
||||
* @initialVersion 5.0.0
|
||||
* @api enums
|
||||
*/
|
||||
OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP,
|
||||
/**
|
||||
* Restart the media input.
|
||||
*
|
||||
* @enumIdentifier OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART
|
||||
* @enumType ObsMediaInputAction
|
||||
* @rpcVersion 1
|
||||
* @initialVersion 5.0.0
|
||||
* @api enums
|
||||
*/
|
||||
OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART,
|
||||
/**
|
||||
* Go to the next playlist item.
|
||||
*
|
||||
* @enumIdentifier OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT
|
||||
* @enumType ObsMediaInputAction
|
||||
* @rpcVersion 1
|
||||
* @initialVersion 5.0.0
|
||||
* @api enums
|
||||
*/
|
||||
OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT,
|
||||
OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS
|
||||
/**
|
||||
* Go to the previous playlist item.
|
||||
*
|
||||
* @enumIdentifier OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS
|
||||
* @enumType ObsMediaInputAction
|
||||
* @rpcVersion 1
|
||||
* @initialVersion 5.0.0
|
||||
* @api enums
|
||||
*/
|
||||
OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS,
|
||||
};
|
||||
|
||||
namespace Utils {
|
||||
@ -59,48 +158,61 @@ namespace Utils {
|
||||
std::string GetCurrentProfilePath();
|
||||
std::string GetCurrentRecordOutputPath();
|
||||
std::string GetSourceType(obs_source_t *source);
|
||||
std::string GetInputMonitorType(enum obs_monitoring_type monitorType);
|
||||
std::string GetInputMonitorType(obs_source_t *input);
|
||||
std::string GetMediaInputState(obs_source_t *input);
|
||||
std::string GetLastReplayBufferFilePath();
|
||||
std::string GetSceneItemBoundsType(enum obs_bounds_type type);
|
||||
std::string GetSceneItemBlendMode(enum obs_blending_type mode);
|
||||
std::string DurationToTimecode(uint64_t);
|
||||
std::string GetOutputState(ObsOutputState state);
|
||||
}
|
||||
|
||||
namespace EnumHelper {
|
||||
enum obs_bounds_type GetSceneItemBoundsType(std::string boundsType);
|
||||
enum ObsMediaInputAction GetMediaInputAction(std::string mediaAction);
|
||||
enum obs_blending_type GetSceneItemBlendMode(std::string mode);
|
||||
}
|
||||
|
||||
namespace NumberHelper {
|
||||
uint64_t GetOutputDuration(obs_output_t *output);
|
||||
size_t GetSceneCount();
|
||||
size_t GetSourceFilterIndex(obs_source_t *source, obs_source_t *filter);
|
||||
}
|
||||
|
||||
namespace ListHelper {
|
||||
namespace ArrayHelper {
|
||||
std::vector<std::string> GetSceneCollectionList();
|
||||
std::vector<std::string> GetProfileList();
|
||||
std::vector<obs_hotkey_t *> GetHotkeyList();
|
||||
std::vector<std::string> GetHotkeyNameList();
|
||||
std::vector<json> GetSceneList();
|
||||
std::vector<std::string> GetGroupList();
|
||||
std::vector<json> GetSceneItemList(obs_scene_t *scene, bool basic = false);
|
||||
std::vector<json> GetTransitionList();
|
||||
std::vector<json> GetInputList(std::string inputKind = "");
|
||||
std::vector<std::string> GetInputKindList(bool unversioned = false, bool includeDisabled = false);
|
||||
std::vector<json> GetListPropertyItems(obs_property_t *property);
|
||||
std::vector<std::string> GetTransitionKindList();
|
||||
std::vector<json> GetSceneTransitionList();
|
||||
std::vector<json> GetSourceFilterList(obs_source_t *source);
|
||||
std::vector<std::string> GetFilterKindList();
|
||||
}
|
||||
|
||||
namespace DataHelper {
|
||||
namespace ObjectHelper {
|
||||
json GetStats();
|
||||
json GetSceneItemTransform(obs_sceneitem_t *item);
|
||||
}
|
||||
|
||||
namespace SearchHelper {
|
||||
obs_hotkey_t *GetHotkeyByName(std::string name);
|
||||
obs_source_t *GetSceneTransitionByName(std::string name); // Increments source ref. Use OBSSourceAutoRelease
|
||||
obs_sceneitem_t *GetSceneItemByName(obs_scene_t *scene, std::string name); // Increments ref. Use OBSSceneItemAutoRelease
|
||||
}
|
||||
|
||||
namespace ActionHelper {
|
||||
obs_sceneitem_t *CreateSceneItem(obs_source_t *source, obs_scene_t *scene, bool sceneItemEnabled = true, obs_transform_info *sceneItemTransform = nullptr, obs_sceneitem_crop *sceneItemCrop = nullptr); // Increments ref. Use OBSSceneItemAutoRelease
|
||||
obs_sceneitem_t *CreateInput(std::string inputName, std::string inputKind, obs_data_t *inputSettings, obs_scene_t *scene, bool sceneItemEnabled = true); // Increments ref. Use OBSSceneItemAutoRelease
|
||||
obs_source_t *CreateSourceFilter(obs_source_t *source, std::string filterName, std::string filterKind, obs_data_t *filterSettings); // Increments source ref. Use OBSSourceAutoRelease
|
||||
void SetSourceFilterIndex(obs_source_t *source, obs_source_t *filter, size_t index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
116
src/utils/Obs_ActionHelper.cpp
Normal file
116
src/utils/Obs_ActionHelper.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
obs-websocket
|
||||
Copyright (C) 2020-2021 Kyle Manning <tt2468@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "Obs.h"
|
||||
#include "../plugin-macros.generated.h"
|
||||
|
||||
struct CreateSceneItemData {
|
||||
obs_source_t *source; // In
|
||||
bool sceneItemEnabled; // In
|
||||
obs_transform_info *sceneItemTransform = nullptr; // In
|
||||
obs_sceneitem_crop *sceneItemCrop = nullptr; // In
|
||||
OBSSceneItem sceneItem; // Out
|
||||
};
|
||||
|
||||
void CreateSceneItemHelper(void *_data, obs_scene_t *scene)
|
||||
{
|
||||
auto *data = static_cast<CreateSceneItemData*>(_data);
|
||||
data->sceneItem = obs_scene_add(scene, data->source);
|
||||
|
||||
if (data->sceneItemTransform)
|
||||
obs_sceneitem_set_info(data->sceneItem, data->sceneItemTransform);
|
||||
|
||||
if (data->sceneItemCrop)
|
||||
obs_sceneitem_set_crop(data->sceneItem, data->sceneItemCrop);
|
||||
|
||||
obs_sceneitem_set_visible(data->sceneItem, data->sceneItemEnabled);
|
||||
}
|
||||
|
||||
obs_sceneitem_t *Utils::Obs::ActionHelper::CreateSceneItem(obs_source_t *source, obs_scene_t *scene, bool sceneItemEnabled, obs_transform_info *sceneItemTransform, obs_sceneitem_crop *sceneItemCrop)
|
||||
{
|
||||
// Sanity check for valid scene
|
||||
if (!(source && scene))
|
||||
return nullptr;
|
||||
|
||||
// Create data struct and populate for scene item creation
|
||||
CreateSceneItemData data;
|
||||
data.source = source;
|
||||
data.sceneItemEnabled = sceneItemEnabled;
|
||||
data.sceneItemTransform = sceneItemTransform;
|
||||
data.sceneItemCrop = sceneItemCrop;
|
||||
|
||||
// Enter graphics context and create the scene item
|
||||
obs_enter_graphics();
|
||||
obs_scene_atomic_update(scene, CreateSceneItemHelper, &data);
|
||||
obs_leave_graphics();
|
||||
|
||||
obs_sceneitem_addref(data.sceneItem);
|
||||
|
||||
return data.sceneItem;
|
||||
}
|
||||
|
||||
obs_sceneitem_t *Utils::Obs::ActionHelper::CreateInput(std::string inputName, std::string inputKind, obs_data_t *inputSettings, obs_scene_t *scene, bool sceneItemEnabled)
|
||||
{
|
||||
// Create the input
|
||||
OBSSourceAutoRelease input = obs_source_create(inputKind.c_str(), inputName.c_str(), inputSettings, nullptr);
|
||||
|
||||
// Check that everything was created properly
|
||||
if (!input)
|
||||
return nullptr;
|
||||
|
||||
// Apparently not all default input properties actually get applied on creation (smh)
|
||||
uint32_t flags = obs_source_get_output_flags(input);
|
||||
if ((flags & OBS_SOURCE_MONITOR_BY_DEFAULT) != 0)
|
||||
obs_source_set_monitoring_type(input, OBS_MONITORING_TYPE_MONITOR_ONLY);
|
||||
|
||||
// Create a scene item for the input
|
||||
obs_sceneitem_t *ret = CreateSceneItem(input, scene, sceneItemEnabled);
|
||||
|
||||
// If creation failed, remove the input
|
||||
if (!ret)
|
||||
obs_source_remove(input);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
obs_source_t *Utils::Obs::ActionHelper::CreateSourceFilter(obs_source_t *source, std::string filterName, std::string filterKind, obs_data_t *filterSettings)
|
||||
{
|
||||
obs_source_t *filter = obs_source_create_private(filterKind.c_str(), filterName.c_str(), filterSettings);
|
||||
|
||||
if (!filter)
|
||||
return nullptr;
|
||||
|
||||
obs_source_filter_add(source, filter);
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
void Utils::Obs::ActionHelper::SetSourceFilterIndex(obs_source_t *source, obs_source_t *filter, size_t index)
|
||||
{
|
||||
size_t currentIndex = Utils::Obs::NumberHelper::GetSourceFilterIndex(source, filter);
|
||||
obs_order_movement direction = index > currentIndex ? OBS_ORDER_MOVE_DOWN : OBS_ORDER_MOVE_UP;
|
||||
|
||||
while(currentIndex != index) {
|
||||
obs_source_filter_set_order(source, filter, direction);
|
||||
|
||||
if (direction == OBS_ORDER_MOVE_DOWN)
|
||||
currentIndex++;
|
||||
else
|
||||
currentIndex--;
|
||||
}
|
||||
}
|
313
src/utils/Obs_ArrayHelper.cpp
Normal file
313
src/utils/Obs_ArrayHelper.cpp
Normal file
@ -0,0 +1,313 @@
|
||||
/*
|
||||
obs-websocket
|
||||
Copyright (C) 2016-2021 Stephane Lepin <stephane.lepin@gmail.com>
|
||||
Copyright (C) 2020-2021 Kyle Manning <tt2468@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "Obs.h"
|
||||
#include "../plugin-macros.generated.h"
|
||||
|
||||
static std::vector<std::string> ConvertStringArray(char **array)
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
if (!array)
|
||||
return ret;
|
||||
|
||||
size_t index = 0;
|
||||
char* value = nullptr;
|
||||
do {
|
||||
value = array[index];
|
||||
if (value)
|
||||
ret.push_back(value);
|
||||
index++;
|
||||
} while (value);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::string> Utils::Obs::ArrayHelper::GetSceneCollectionList()
|
||||
{
|
||||
char** sceneCollections = obs_frontend_get_scene_collections();
|
||||
auto ret = ConvertStringArray(sceneCollections);
|
||||
bfree(sceneCollections);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::string> Utils::Obs::ArrayHelper::GetProfileList()
|
||||
{
|
||||
char** profiles = obs_frontend_get_profiles();
|
||||
auto ret = ConvertStringArray(profiles);
|
||||
bfree(profiles);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<obs_hotkey_t *> Utils::Obs::ArrayHelper::GetHotkeyList()
|
||||
{
|
||||
std::vector<obs_hotkey_t *> ret;
|
||||
|
||||
obs_enum_hotkeys([](void* data, obs_hotkey_id, obs_hotkey_t* hotkey) {
|
||||
auto ret = static_cast<std::vector<obs_hotkey_t *> *>(data);
|
||||
|
||||
ret->push_back(hotkey);
|
||||
|
||||
return true;
|
||||
}, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::string> Utils::Obs::ArrayHelper::GetHotkeyNameList()
|
||||
{
|
||||
auto hotkeys = GetHotkeyList();
|
||||
|
||||
std::vector<std::string> ret;
|
||||
for (auto hotkey : hotkeys)
|
||||
ret.emplace_back(obs_hotkey_get_name(hotkey));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<json> Utils::Obs::ArrayHelper::GetSceneList()
|
||||
{
|
||||
obs_frontend_source_list sceneList = {};
|
||||
obs_frontend_get_scenes(&sceneList);
|
||||
|
||||
std::vector<json> ret;
|
||||
for (size_t i = 0; i < sceneList.sources.num; i++) {
|
||||
obs_source_t *scene = sceneList.sources.array[i];
|
||||
|
||||
json sceneJson;
|
||||
sceneJson["sceneName"] = obs_source_get_name(scene);
|
||||
sceneJson["sceneIndex"] = sceneList.sources.num - i - 1;
|
||||
|
||||
ret.push_back(sceneJson);
|
||||
}
|
||||
|
||||
obs_frontend_source_list_free(&sceneList);
|
||||
|
||||
// Reverse the vector order to match other array returns
|
||||
std::reverse(ret.begin(), ret.end());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::string> Utils::Obs::ArrayHelper::GetGroupList()
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
|
||||
auto cb = [](void *priv_data, obs_source_t *scene) {
|
||||
auto ret = static_cast<std::vector<std::string>*>(priv_data);
|
||||
|
||||
if (!obs_source_is_group(scene))
|
||||
return true;
|
||||
|
||||
ret->emplace_back(obs_source_get_name(scene));
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
obs_enum_scenes(cb, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<json> Utils::Obs::ArrayHelper::GetSceneItemList(obs_scene_t *scene, bool basic)
|
||||
{
|
||||
std::pair<std::vector<json>, bool> enumData;
|
||||
enumData.second = basic;
|
||||
|
||||
obs_scene_enum_items(scene, [](obs_scene_t*, obs_sceneitem_t* sceneItem, void* param) {
|
||||
auto enumData = static_cast<std::pair<std::vector<json>, bool>*>(param);
|
||||
|
||||
json item;
|
||||
item["sceneItemId"] = obs_sceneitem_get_id(sceneItem);
|
||||
// Should be slightly faster than calling obs_sceneitem_get_order_position()
|
||||
item["sceneItemIndex"] = enumData->first.size();
|
||||
if (!enumData->second) {
|
||||
OBSSource itemSource = obs_sceneitem_get_source(sceneItem);
|
||||
item["sourceName"] = obs_source_get_name(itemSource);
|
||||
item["sourceType"] = StringHelper::GetSourceType(itemSource);
|
||||
if (obs_source_get_type(itemSource) == OBS_SOURCE_TYPE_INPUT)
|
||||
item["inputKind"] = obs_source_get_id(itemSource);
|
||||
else
|
||||
item["inputKind"] = nullptr;
|
||||
if (obs_source_get_type(itemSource) == OBS_SOURCE_TYPE_SCENE)
|
||||
item["isGroup"] = obs_source_is_group(itemSource);
|
||||
else
|
||||
item["isGroup"] = nullptr;
|
||||
}
|
||||
|
||||
enumData->first.push_back(item);
|
||||
|
||||
return true;
|
||||
}, &enumData);
|
||||
|
||||
return enumData.first;
|
||||
}
|
||||
|
||||
struct EnumInputInfo {
|
||||
std::string inputKind; // For searching by input kind
|
||||
std::vector<json> inputs;
|
||||
};
|
||||
|
||||
std::vector<json> Utils::Obs::ArrayHelper::GetInputList(std::string inputKind)
|
||||
{
|
||||
EnumInputInfo inputInfo;
|
||||
inputInfo.inputKind = inputKind;
|
||||
|
||||
auto inputEnumProc = [](void *param, obs_source_t *input) {
|
||||
// Sanity check in case the API changes
|
||||
if (obs_source_get_type(input) != OBS_SOURCE_TYPE_INPUT)
|
||||
return true;
|
||||
|
||||
auto inputInfo = static_cast<EnumInputInfo*>(param);
|
||||
|
||||
std::string inputKind = obs_source_get_id(input);
|
||||
|
||||
if (!inputInfo->inputKind.empty() && inputInfo->inputKind != inputKind)
|
||||
return true;
|
||||
|
||||
json inputJson;
|
||||
inputJson["inputName"] = obs_source_get_name(input);
|
||||
inputJson["inputKind"] = inputKind;
|
||||
inputJson["unversionedInputKind"] = obs_source_get_unversioned_id(input);
|
||||
|
||||
inputInfo->inputs.push_back(inputJson);
|
||||
return true;
|
||||
};
|
||||
// Actually enumerates only public inputs, despite the name
|
||||
obs_enum_sources(inputEnumProc, &inputInfo);
|
||||
|
||||
return inputInfo.inputs;
|
||||
}
|
||||
|
||||
std::vector<std::string> Utils::Obs::ArrayHelper::GetInputKindList(bool unversioned, bool includeDisabled)
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
|
||||
size_t idx = 0;
|
||||
const char *kind;
|
||||
const char *unversioned_kind;
|
||||
while (obs_enum_input_types2(idx++, &kind, &unversioned_kind)) {
|
||||
uint32_t caps = obs_get_source_output_flags(kind);
|
||||
|
||||
if (!includeDisabled && (caps & OBS_SOURCE_CAP_DISABLED) != 0)
|
||||
continue;
|
||||
|
||||
if (unversioned)
|
||||
ret.push_back(unversioned_kind);
|
||||
else
|
||||
ret.push_back(kind);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<json> Utils::Obs::ArrayHelper::GetListPropertyItems(obs_property_t *property)
|
||||
{
|
||||
std::vector<json> ret;
|
||||
|
||||
enum obs_combo_format itemFormat = obs_property_list_format(property);
|
||||
size_t itemCount = obs_property_list_item_count(property);
|
||||
|
||||
for (size_t i = 0; i < itemCount; i++) {
|
||||
json itemData;
|
||||
itemData["itemName"] = obs_property_list_item_name(property, i);
|
||||
itemData["itemEnabled"] = !obs_property_list_item_disabled(property, i);
|
||||
if (itemFormat == OBS_COMBO_FORMAT_INT) {
|
||||
itemData["itemValue"] = obs_property_list_item_int(property, i);
|
||||
} else if (itemFormat == OBS_COMBO_FORMAT_FLOAT) {
|
||||
itemData["itemValue"] = obs_property_list_item_float(property, i);
|
||||
} else if (itemFormat == OBS_COMBO_FORMAT_STRING) {
|
||||
itemData["itemValue"] = obs_property_list_item_string(property, i);
|
||||
} else {
|
||||
itemData["itemValue"] = nullptr;
|
||||
}
|
||||
ret.push_back(itemData);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::string> Utils::Obs::ArrayHelper::GetTransitionKindList()
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
|
||||
size_t idx = 0;
|
||||
const char *kind;
|
||||
while (obs_enum_transition_types(idx++, &kind))
|
||||
ret.emplace_back(kind);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<json> Utils::Obs::ArrayHelper::GetSceneTransitionList()
|
||||
{
|
||||
obs_frontend_source_list transitionList = {};
|
||||
obs_frontend_get_transitions(&transitionList);
|
||||
|
||||
std::vector<json> ret;
|
||||
for (size_t i = 0; i < transitionList.sources.num; i++) {
|
||||
obs_source_t *transition = transitionList.sources.array[i];
|
||||
json transitionJson;
|
||||
transitionJson["transitionName"] = obs_source_get_name(transition);
|
||||
transitionJson["transitionKind"] = obs_source_get_id(transition);
|
||||
transitionJson["transitionFixed"] = obs_transition_fixed(transition);
|
||||
transitionJson["transitionConfigurable"] = obs_source_configurable(transition);
|
||||
ret.push_back(transitionJson);
|
||||
}
|
||||
|
||||
obs_frontend_source_list_free(&transitionList);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::string> Utils::Obs::ArrayHelper::GetFilterKindList()
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
|
||||
size_t idx = 0;
|
||||
const char *kind;
|
||||
while(obs_enum_filter_types(idx++, &kind))
|
||||
ret.push_back(kind);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<json> Utils::Obs::ArrayHelper::GetSourceFilterList(obs_source_t *source)
|
||||
{
|
||||
std::vector<json> filters;
|
||||
|
||||
auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *param) {
|
||||
auto filters = reinterpret_cast<std::vector<json>*>(param);
|
||||
|
||||
json filterJson;
|
||||
filterJson["filterEnabled"] = obs_source_enabled(filter);
|
||||
filterJson["filterIndex"] = filters->size();
|
||||
filterJson["filterKind"] = obs_source_get_id(filter);
|
||||
filterJson["filterName"] = obs_source_get_name(filter);
|
||||
|
||||
OBSDataAutoRelease filterSettings = obs_source_get_settings(filter);
|
||||
filterJson["filterSettings"] = Utils::Json::ObsDataToJson(filterSettings);
|
||||
|
||||
filters->push_back(filterJson);
|
||||
};
|
||||
obs_source_enum_filters(source, enumFilters, &filters);
|
||||
|
||||
return filters;
|
||||
}
|
60
src/utils/Obs_EnumHelper.cpp
Normal file
60
src/utils/Obs_EnumHelper.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
obs-websocket
|
||||
Copyright (C) 2020-2021 Kyle Manning <tt2468@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "Obs.h"
|
||||
#include "../plugin-macros.generated.h"
|
||||
|
||||
#define RET_COMPARE(str, x) if (str == #x) return x;
|
||||
|
||||
enum obs_bounds_type Utils::Obs::EnumHelper::GetSceneItemBoundsType(std::string boundsType)
|
||||
{
|
||||
RET_COMPARE(boundsType, OBS_BOUNDS_NONE)
|
||||
RET_COMPARE(boundsType, OBS_BOUNDS_STRETCH)
|
||||
RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_INNER)
|
||||
RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_OUTER)
|
||||
RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_TO_WIDTH)
|
||||
RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_TO_HEIGHT)
|
||||
RET_COMPARE(boundsType, OBS_BOUNDS_MAX_ONLY)
|
||||
|
||||
return OBS_BOUNDS_NONE;
|
||||
}
|
||||
|
||||
enum ObsMediaInputAction Utils::Obs::EnumHelper::GetMediaInputAction(std::string mediaAction)
|
||||
{
|
||||
RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY)
|
||||
RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE)
|
||||
RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP)
|
||||
RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART)
|
||||
RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT)
|
||||
RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS)
|
||||
|
||||
return OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE;
|
||||
}
|
||||
|
||||
enum obs_blending_type Utils::Obs::EnumHelper::GetSceneItemBlendMode(std::string mode)
|
||||
{
|
||||
RET_COMPARE(mode, OBS_BLEND_NORMAL)
|
||||
RET_COMPARE(mode, OBS_BLEND_ADDITIVE)
|
||||
RET_COMPARE(mode, OBS_BLEND_SUBTRACT)
|
||||
RET_COMPARE(mode, OBS_BLEND_SCREEN)
|
||||
RET_COMPARE(mode, OBS_BLEND_MULTIPLY)
|
||||
RET_COMPARE(mode, OBS_BLEND_LIGHTEN)
|
||||
RET_COMPARE(mode, OBS_BLEND_DARKEN)
|
||||
|
||||
return OBS_BLEND_NORMAL;
|
||||
}
|
79
src/utils/Obs_NumberHelper.cpp
Normal file
79
src/utils/Obs_NumberHelper.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
obs-websocket
|
||||
Copyright (C) 2016-2021 Stephane Lepin <stephane.lepin@gmail.com>
|
||||
Copyright (C) 2020-2021 Kyle Manning <tt2468@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <util/util_uint64.h>
|
||||
|
||||
#include "Obs.h"
|
||||
#include "../plugin-macros.generated.h"
|
||||
|
||||
uint64_t Utils::Obs::NumberHelper::GetOutputDuration(obs_output_t *output)
|
||||
{
|
||||
if (!output || !obs_output_active(output))
|
||||
return 0;
|
||||
|
||||
video_t* video = obs_output_video(output);
|
||||
uint64_t frameTimeNs = video_output_get_frame_time(video);
|
||||
int totalFrames = obs_output_get_total_frames(output);
|
||||
|
||||
return util_mul_div64(totalFrames, frameTimeNs, 1000000ULL);
|
||||
}
|
||||
|
||||
size_t Utils::Obs::NumberHelper::GetSceneCount()
|
||||
{
|
||||
size_t ret;
|
||||
auto sceneEnumProc = [](void *param, obs_source_t *scene) {
|
||||
auto ret = static_cast<size_t*>(param);
|
||||
|
||||
if (obs_source_is_group(scene))
|
||||
return true;
|
||||
|
||||
(*ret)++;
|
||||
return true;
|
||||
};
|
||||
|
||||
obs_enum_scenes(sceneEnumProc, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t Utils::Obs::NumberHelper::GetSourceFilterIndex(obs_source_t *source, obs_source_t *filter)
|
||||
{
|
||||
struct FilterSearch {
|
||||
obs_source_t *filter;
|
||||
bool found;
|
||||
size_t index;
|
||||
};
|
||||
|
||||
auto search = [](obs_source_t *, obs_source_t *filter, void *priv_data) {
|
||||
auto filterSearch = static_cast<FilterSearch*>(priv_data);
|
||||
|
||||
if (filter == filterSearch->filter)
|
||||
filterSearch->found = true;
|
||||
|
||||
if (!filterSearch->found)
|
||||
filterSearch->index++;
|
||||
};
|
||||
|
||||
FilterSearch filterSearch = {filter, 0, 0};
|
||||
|
||||
obs_source_enum_filters(source, search, &filterSearch);
|
||||
|
||||
return filterSearch.index;
|
||||
}
|
87
src/utils/Obs_ObjectHelper.cpp
Normal file
87
src/utils/Obs_ObjectHelper.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
obs-websocket
|
||||
Copyright (C) 2016-2021 Stephane Lepin <stephane.lepin@gmail.com>
|
||||
Copyright (C) 2020-2021 Kyle Manning <tt2468@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include <util/config-file.h>
|
||||
|
||||
#include "Obs.h"
|
||||
#include "../obs-websocket.h"
|
||||
#include "../plugin-macros.generated.h"
|
||||
|
||||
json Utils::Obs::ObjectHelper::GetStats()
|
||||
{
|
||||
json ret;
|
||||
|
||||
std::string outputPath = Utils::Obs::StringHelper::GetCurrentRecordOutputPath();
|
||||
|
||||
video_t* video = obs_get_video();
|
||||
|
||||
ret["cpuUsage"] = os_cpu_usage_info_query(GetCpuUsageInfo());
|
||||
ret["memoryUsage"] = (double)os_get_proc_resident_size() / (1024.0 * 1024.0);
|
||||
ret["availableDiskSpace"] = (double)os_get_free_disk_space(outputPath.c_str()) / (1024.0 * 1024.0);
|
||||
ret["activeFps"] = obs_get_active_fps();
|
||||
ret["averageFrameRenderTime"] = (double)obs_get_average_frame_time_ns() / 1000000.0;
|
||||
ret["renderSkippedFrames"] = obs_get_lagged_frames();
|
||||
ret["renderTotalFrames"] = obs_get_total_frames();
|
||||
ret["outputSkippedFrames"] = video_output_get_skipped_frames(video);
|
||||
ret["outputTotalFrames"] = video_output_get_total_frames(video);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
json Utils::Obs::ObjectHelper::GetSceneItemTransform(obs_sceneitem_t *item)
|
||||
{
|
||||
json ret;
|
||||
|
||||
obs_transform_info osi;
|
||||
obs_sceneitem_crop crop;
|
||||
obs_sceneitem_get_info(item, &osi);
|
||||
obs_sceneitem_get_crop(item, &crop);
|
||||
|
||||
OBSSource source = obs_sceneitem_get_source(item);
|
||||
float sourceWidth = float(obs_source_get_width(source));
|
||||
float sourceHeight = float(obs_source_get_height(source));
|
||||
|
||||
ret["sourceWidth"] = sourceWidth;
|
||||
ret["sourceHeight"] = sourceHeight;
|
||||
|
||||
ret["positionX"] = osi.pos.x;
|
||||
ret["positionY"] = osi.pos.y;
|
||||
|
||||
ret["rotation"] = osi.rot;
|
||||
|
||||
ret["scaleX"] = osi.scale.x;
|
||||
ret["scaleY"] = osi.scale.y;
|
||||
|
||||
ret["width"] = osi.scale.x * sourceWidth;
|
||||
ret["height"] = osi.scale.y * sourceHeight;
|
||||
|
||||
ret["alignment"] = osi.alignment;
|
||||
|
||||
ret["boundsType"] = StringHelper::GetSceneItemBoundsType(osi.bounds_type);
|
||||
ret["boundsAlignment"] = osi.bounds_alignment;
|
||||
ret["boundsWidth"] = osi.bounds.x;
|
||||
ret["boundsHeight"] = osi.bounds.y;
|
||||
|
||||
ret["cropLeft"] = int(crop.left);
|
||||
ret["cropRight"] = int(crop.right);
|
||||
ret["cropTop"] = int(crop.top);
|
||||
ret["cropBottom"] = int(crop.bottom);
|
||||
|
||||
return ret;
|
||||
}
|
68
src/utils/Obs_SearchHelper.cpp
Normal file
68
src/utils/Obs_SearchHelper.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
obs-websocket
|
||||
Copyright (C) 2020-2021 Kyle Manning <tt2468@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "Obs.h"
|
||||
#include "../plugin-macros.generated.h"
|
||||
|
||||
obs_hotkey_t *Utils::Obs::SearchHelper::GetHotkeyByName(std::string name)
|
||||
{
|
||||
if (name.empty())
|
||||
return nullptr;
|
||||
|
||||
auto hotkeys = ArrayHelper::GetHotkeyList();
|
||||
|
||||
for (auto hotkey : hotkeys) {
|
||||
if (obs_hotkey_get_name(hotkey) == name)
|
||||
return hotkey;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Increments source ref. Use OBSSourceAutoRelease
|
||||
obs_source_t *Utils::Obs::SearchHelper::GetSceneTransitionByName(std::string name)
|
||||
{
|
||||
obs_frontend_source_list transitionList = {};
|
||||
obs_frontend_get_transitions(&transitionList);
|
||||
|
||||
obs_source_t *ret = nullptr;
|
||||
for (size_t i = 0; i < transitionList.sources.num; i++) {
|
||||
obs_source_t *transition = transitionList.sources.array[i];
|
||||
if (obs_source_get_name(transition) == name) {
|
||||
ret = obs_source_get_ref(transition);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
obs_frontend_source_list_free(&transitionList);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Increments item ref. Use OBSSceneItemAutoRelease
|
||||
obs_sceneitem_t *Utils::Obs::SearchHelper::GetSceneItemByName(obs_scene_t *scene, std::string name)
|
||||
{
|
||||
if (name.empty())
|
||||
return nullptr;
|
||||
|
||||
// Finds first matching scene item in scene, search starts at index 0
|
||||
OBSSceneItem ret = obs_scene_find_source(scene, name.c_str());
|
||||
obs_sceneitem_addref(ret);
|
||||
|
||||
return ret;
|
||||
}
|
192
src/utils/Obs_StringHelper.cpp
Normal file
192
src/utils/Obs_StringHelper.cpp
Normal file
@ -0,0 +1,192 @@
|
||||
/*
|
||||
obs-websocket
|
||||
Copyright (C) 2016-2021 Stephane Lepin <stephane.lepin@gmail.com>
|
||||
Copyright (C) 2020-2021 Kyle Manning <tt2468@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <QString>
|
||||
|
||||
#include "Obs.h"
|
||||
#include "../plugin-macros.generated.h"
|
||||
|
||||
#define CASE(x) case x: return #x;
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetObsVersion()
|
||||
{
|
||||
uint32_t version = obs_get_version();
|
||||
|
||||
uint8_t major, minor, patch;
|
||||
major = (version >> 24) & 0xFF;
|
||||
minor = (version >> 16) & 0xFF;
|
||||
patch = version & 0xFF;
|
||||
|
||||
QString combined = QString("%1.%2.%3").arg(major).arg(minor).arg(patch);
|
||||
return combined.toStdString();
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetCurrentSceneCollection()
|
||||
{
|
||||
char *sceneCollectionName = obs_frontend_get_current_scene_collection();
|
||||
std::string ret = sceneCollectionName;
|
||||
bfree(sceneCollectionName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetCurrentProfile()
|
||||
{
|
||||
char *profileName = obs_frontend_get_current_profile();
|
||||
std::string ret = profileName;
|
||||
bfree(profileName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetCurrentProfilePath()
|
||||
{
|
||||
char *profilePath = obs_frontend_get_current_profile_path();
|
||||
std::string ret = profilePath;
|
||||
bfree(profilePath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetCurrentRecordOutputPath()
|
||||
{
|
||||
char *recordOutputPath = obs_frontend_get_current_record_output_path();
|
||||
std::string ret = recordOutputPath;
|
||||
bfree(recordOutputPath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetSourceType(obs_source_t *source)
|
||||
{
|
||||
obs_source_type sourceType = obs_source_get_type(source);
|
||||
|
||||
switch (sourceType) {
|
||||
default:
|
||||
CASE(OBS_SOURCE_TYPE_INPUT)
|
||||
CASE(OBS_SOURCE_TYPE_FILTER)
|
||||
CASE(OBS_SOURCE_TYPE_TRANSITION)
|
||||
CASE(OBS_SOURCE_TYPE_SCENE)
|
||||
}
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetInputMonitorType(enum obs_monitoring_type monitorType)
|
||||
{
|
||||
switch (monitorType) {
|
||||
default:
|
||||
CASE(OBS_MONITORING_TYPE_NONE)
|
||||
CASE(OBS_MONITORING_TYPE_MONITOR_ONLY)
|
||||
CASE(OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT)
|
||||
}
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetInputMonitorType(obs_source_t *input)
|
||||
{
|
||||
obs_monitoring_type monitorType = obs_source_get_monitoring_type(input);
|
||||
|
||||
return GetInputMonitorType(monitorType);
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetMediaInputState(obs_source_t *input)
|
||||
{
|
||||
obs_media_state mediaState = obs_source_media_get_state(input);
|
||||
|
||||
switch (mediaState) {
|
||||
default:
|
||||
CASE(OBS_MEDIA_STATE_NONE)
|
||||
CASE(OBS_MEDIA_STATE_PLAYING)
|
||||
CASE(OBS_MEDIA_STATE_OPENING)
|
||||
CASE(OBS_MEDIA_STATE_BUFFERING)
|
||||
CASE(OBS_MEDIA_STATE_PAUSED)
|
||||
CASE(OBS_MEDIA_STATE_STOPPED)
|
||||
CASE(OBS_MEDIA_STATE_ENDED)
|
||||
CASE(OBS_MEDIA_STATE_ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetLastReplayBufferFilePath()
|
||||
{
|
||||
OBSOutputAutoRelease output = obs_frontend_get_replay_buffer_output();
|
||||
if (!output)
|
||||
return "";
|
||||
|
||||
calldata_t cd = {0};
|
||||
proc_handler_t *ph = obs_output_get_proc_handler(output);
|
||||
proc_handler_call(ph, "get_last_replay", &cd);
|
||||
const char *savedReplayPath = calldata_string(&cd, "path");
|
||||
calldata_free(&cd);
|
||||
|
||||
if (!savedReplayPath)
|
||||
return "";
|
||||
|
||||
return savedReplayPath;
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetSceneItemBoundsType(enum obs_bounds_type type)
|
||||
{
|
||||
switch (type) {
|
||||
default:
|
||||
CASE(OBS_BOUNDS_NONE)
|
||||
CASE(OBS_BOUNDS_STRETCH)
|
||||
CASE(OBS_BOUNDS_SCALE_INNER)
|
||||
CASE(OBS_BOUNDS_SCALE_OUTER)
|
||||
CASE(OBS_BOUNDS_SCALE_TO_WIDTH)
|
||||
CASE(OBS_BOUNDS_SCALE_TO_HEIGHT)
|
||||
CASE(OBS_BOUNDS_MAX_ONLY)
|
||||
}
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetSceneItemBlendMode(enum obs_blending_type mode)
|
||||
{
|
||||
switch (mode) {
|
||||
default:
|
||||
CASE(OBS_BLEND_NORMAL)
|
||||
CASE(OBS_BLEND_ADDITIVE)
|
||||
CASE(OBS_BLEND_SUBTRACT)
|
||||
CASE(OBS_BLEND_SCREEN)
|
||||
CASE(OBS_BLEND_MULTIPLY)
|
||||
CASE(OBS_BLEND_LIGHTEN)
|
||||
CASE(OBS_BLEND_DARKEN)
|
||||
}
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::DurationToTimecode(uint64_t ms)
|
||||
{
|
||||
uint64_t secs = ms / 1000ULL;
|
||||
uint64_t minutes = secs / 60ULL;
|
||||
|
||||
uint64_t hoursPart = minutes / 60ULL;
|
||||
uint64_t minutesPart = minutes % 60ULL;
|
||||
uint64_t secsPart = secs % 60ULL;
|
||||
uint64_t msPart = ms % 1000ULL;
|
||||
|
||||
QString formatted = QString::asprintf("%02" PRIu64 ":%02" PRIu64 ":%02" PRIu64 ".%03" PRIu64, hoursPart, minutesPart, secsPart, msPart);
|
||||
return formatted.toStdString();
|
||||
}
|
||||
|
||||
std::string Utils::Obs::StringHelper::GetOutputState(ObsOutputState state)
|
||||
{
|
||||
switch (state) {
|
||||
default:
|
||||
CASE(OBS_WEBSOCKET_OUTPUT_UNKNOWN)
|
||||
CASE(OBS_WEBSOCKET_OUTPUT_STARTING)
|
||||
CASE(OBS_WEBSOCKET_OUTPUT_STARTED)
|
||||
CASE(OBS_WEBSOCKET_OUTPUT_STOPPING)
|
||||
CASE(OBS_WEBSOCKET_OUTPUT_STOPPED)
|
||||
CASE(OBS_WEBSOCKET_OUTPUT_PAUSED)
|
||||
CASE(OBS_WEBSOCKET_OUTPUT_RESUMED)
|
||||
}
|
||||
}
|
@ -22,8 +22,9 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
#include <algorithm>
|
||||
|
||||
#include "Obs.h"
|
||||
#include "ObsVolumeMeter.h"
|
||||
#include "ObsVolumeMeter_Helpers.h"
|
||||
#include "Obs_VolumeMeter.h"
|
||||
#include "Obs_VolumeMeter_Helpers.h"
|
||||
#include "../obs-websocket.h"
|
||||
|
||||
Utils::Obs::VolumeMeter::Meter::Meter(obs_source_t *input) :
|
||||
PeakMeterType(SAMPLE_PEAK_METER),
|
||||
@ -58,8 +59,7 @@ Utils::Obs::VolumeMeter::Meter::~Meter()
|
||||
|
||||
bool Utils::Obs::VolumeMeter::Meter::InputValid()
|
||||
{
|
||||
// return !obs_weak_source_expired(_input);
|
||||
return true;
|
||||
return !obs_weak_source_expired(_input);
|
||||
}
|
||||
|
||||
json Utils::Obs::VolumeMeter::Meter::GetMeterData()
|
||||
@ -277,9 +277,7 @@ Utils::Obs::VolumeMeter::Handler::~Handler()
|
||||
signal_handler_disconnect(sh, "source_deactivate", Handler::InputDeactivateCallback, this);
|
||||
|
||||
if (_running) {
|
||||
_mutex.lock();
|
||||
_running = false;
|
||||
_mutex.unlock();
|
||||
_cond.notify_all();
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
#include <thread>
|
||||
#include <obs.hpp>
|
||||
|
||||
#include "../obs-websocket.h"
|
||||
#include "Obs.h"
|
||||
#include "Json.h"
|
||||
|
||||
namespace Utils {
|
||||
@ -87,7 +87,7 @@ namespace Utils {
|
||||
|
||||
std::mutex _mutex;
|
||||
std::condition_variable _cond;
|
||||
bool _running;
|
||||
std::atomic<bool> _running;
|
||||
std::thread _updateThread;
|
||||
|
||||
void UpdateThread();
|
@ -56,7 +56,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
r = fmaxf(r, x4_mem[3]); \
|
||||
} while (false)
|
||||
|
||||
float GetSamplePeak(__m128 previousSamples, const float *samples, size_t sampleCount)
|
||||
static float GetSamplePeak(__m128 previousSamples, const float *samples, size_t sampleCount)
|
||||
{
|
||||
__m128 peak = previousSamples;
|
||||
for (size_t i = 0; (i + 3) < sampleCount; i += 4) {
|
||||
@ -69,7 +69,7 @@ float GetSamplePeak(__m128 previousSamples, const float *samples, size_t sampleC
|
||||
return ret;
|
||||
}
|
||||
|
||||
float GetTruePeak(__m128 previousSamples, const float *samples, size_t sampleCount)
|
||||
static float GetTruePeak(__m128 previousSamples, const float *samples, size_t sampleCount)
|
||||
{
|
||||
const __m128 m3 = _mm_set_ps(-0.155915f, 0.935489f, 0.233872f, -0.103943f);
|
||||
const __m128 m1 = _mm_set_ps(-0.216236f, 0.756827f, 0.504551f, -0.189207f);
|
@ -111,9 +111,9 @@ void Utils::Platform::SendTrayNotification(QSystemTrayIcon::MessageIcon icon, QS
|
||||
|
||||
obs_queue_task(OBS_TASK_UI, [](void* param) {
|
||||
void *systemTrayPtr = obs_frontend_get_system_tray();
|
||||
auto systemTray = reinterpret_cast<QSystemTrayIcon*>(systemTrayPtr);
|
||||
auto systemTray = static_cast<QSystemTrayIcon*>(systemTrayPtr);
|
||||
|
||||
auto notification = reinterpret_cast<SystemTrayNotification*>(param);
|
||||
auto notification = static_cast<SystemTrayNotification*>(param);
|
||||
systemTray->showMessage(notification->title, notification->body, notification->icon);
|
||||
delete notification;
|
||||
}, (void*)notification, false);
|
||||
|
@ -22,6 +22,6 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
#include "Crypto.h"
|
||||
#include "Json.h"
|
||||
#include "Obs.h"
|
||||
#include "ObsVolumeMeter.h"
|
||||
#include "Obs_VolumeMeter.h"
|
||||
#include "Platform.h"
|
||||
#include "Compat.h"
|
||||
|
@ -23,6 +23,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
#include <QObject>
|
||||
#include <QThreadPool>
|
||||
#include <QString>
|
||||
#include <asio.hpp>
|
||||
#include <websocketpp/config/asio_no_tls.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
|
@ -233,7 +233,7 @@ void WebSocketServer::ProcessMessage(SessionPtr session, WebSocketServer::Proces
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t requestedExecutionType = payloadData["executionType"];
|
||||
int8_t requestedExecutionType = payloadData["executionType"];
|
||||
if (!RequestBatchExecutionType::IsValid(requestedExecutionType) || requestedExecutionType == RequestBatchExecutionType::None) {
|
||||
ret.closeCode = WebSocketCloseCode::InvalidDataFieldValue;
|
||||
ret.closeReason = "Your `executionType` has an invalid value.";
|
||||
@ -296,7 +296,7 @@ void WebSocketServer::ProcessMessage(SessionPtr session, WebSocketServer::Proces
|
||||
} return;
|
||||
default:
|
||||
ret.closeCode = WebSocketCloseCode::UnknownOpCode;
|
||||
ret.closeReason = std::string("Unknown OpCode: %s") + std::to_string(opCode);
|
||||
ret.closeReason = std::string("Unknown OpCode: ") + std::to_string(opCode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user