mirror of
https://github.com/Palakis/obs-websocket.git
synced 2024-08-30 18:12:16 +00:00
Compare commits
36 Commits
5.0.0-alph
...
5.0.0-alph
Author | SHA1 | Date | |
---|---|---|---|
333737f400 | |||
82d8a3d7ce | |||
d7f96b6dea | |||
c16669c7b0 | |||
0269209d59 | |||
d2d2bdd730 | |||
9a8587d6df | |||
8a45560297 | |||
fb0656c31e | |||
26bef074ac | |||
e18aaff661 | |||
4271730dc2 | |||
b86107a699 | |||
6035f258d2 | |||
a40160e305 | |||
b58f6e8366 | |||
670fa7c249 | |||
d858118e28 | |||
bb71a4c77b | |||
3dfd091e71 | |||
a3d0ff5eea | |||
5988f0f97a | |||
eb6015df05 | |||
15188e3ebe | |||
1ecf2a4fdb | |||
292b2b0d3b | |||
b3676586e4 | |||
6d882ba94f | |||
d669db24ac | |||
fc8dce45ee | |||
ac78acd28c | |||
f37edbd71c | |||
78f9c93739 | |||
96c5818395 | |||
85fa41962d | |||
ccb42f1f0c |
713
.github/workflows/main.yml
vendored
713
.github/workflows/main.yml
vendored
@ -1,356 +1,357 @@
|
||||
name: "CI Multiplatform Build"
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
branches:
|
||||
- master
|
||||
tags:
|
||||
- '[45].[0-9]+.[0-9]+*'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**.md'
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
windows:
|
||||
name: 'Windows 32/64-bit'
|
||||
runs-on: [windows-latest]
|
||||
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"
|
||||
steps:
|
||||
- name: 'Add msbuild to PATH'
|
||||
uses: microsoft/setup-msbuild@v1.0.2
|
||||
- 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: '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 --tags --abbrev=0)
|
||||
echo "GIT_TAG=$GIT_TAG" >> $GITHUB_ENV
|
||||
if [ "$GIT_TAG" ] ; then \
|
||||
VERSION="$GIT_TAG" ; \
|
||||
else \
|
||||
VERSION="$GIT_HASH-git" ; \
|
||||
fi
|
||||
echo "PACKAGE_VERSION=$VERSION" >> $GITHUB_ENV
|
||||
- name: 'Restore Cached Qt'
|
||||
id: qtcache
|
||||
uses: actions/cache@v2
|
||||
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: |
|
||||
curl -kLO https://tt2468.net/dl/Qt_${{ env.QT_VERSION }}.7z -f --retry 5 -C -
|
||||
- name: 'Extract Prerequisite: Qt'
|
||||
run: |
|
||||
7z x Qt_${{ env.QT_VERSION }}.7z -o"${{ github.workspace }}\cmbuild\QT"
|
||||
- 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'
|
||||
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'
|
||||
id: build-cache-obs-32
|
||||
uses: actions/cache@v2
|
||||
env:
|
||||
CACHE_NAME: 'build-cache-obs-32'
|
||||
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'
|
||||
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'
|
||||
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'
|
||||
id: build-cache-obs-64
|
||||
uses: actions/cache@v1
|
||||
env:
|
||||
CACHE_NAME: 'build-cache-obs-64'
|
||||
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'
|
||||
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'
|
||||
if: steps.build-cache-obs-64.outputs.cache-hit != 'true'
|
||||
working-directory: ${{ github.workspace }}/obs-studio
|
||||
run: |
|
||||
msbuild /m /p:Configuration=RelWithDebInfo .\build64\libobs\libobs.vcxproj
|
||||
msbuild /m /p:Configuration=RelWithDebInfo .\build64\UI\obs-frontend-api\obs-frontend-api.vcxproj
|
||||
- name: 'Configure obs-websocket 32-bit'
|
||||
working-directory: ${{ github.workspace }}/obs-websocket
|
||||
run: |
|
||||
mkdir .\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" -DLibObs_DIR="${{ github.workspace }}\obs-studio\build32\libobs" -DLIBOBS_INCLUDE_DIR="${{ github.workspace }}\obs-studio\libobs" -DLIBOBS_LIB="${{ github.workspace }}\obs-studio\build32\libobs\RelWithDebInfo\obs.lib" -DOBS_FRONTEND_LIB="${{ github.workspace }}\obs-studio\build32\UI\obs-frontend-api\RelWithDebInfo\obs-frontend-api.lib" ..
|
||||
- name: 'Configure obs-websocket 64-bit'
|
||||
working-directory: ${{ github.workspace }}/obs-websocket
|
||||
run: |
|
||||
mkdir .\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" -DLibObs_DIR="${{ github.workspace }}\obs-studio\build64\libobs" -DLIBOBS_INCLUDE_DIR="${{ github.workspace }}\obs-studio\libobs" -DLIBOBS_LIB="${{ github.workspace }}\obs-studio\build64\libobs\RelWithDebInfo\obs.lib" -DOBS_FRONTEND_LIB="${{ github.workspace }}\obs-studio\build64\UI\obs-frontend-api\RelWithDebInfo\obs-frontend-api.lib" ..
|
||||
- name: 'Build obs-websocket 32-bit'
|
||||
working-directory: ${{ github.workspace }}/obs-websocket
|
||||
run: msbuild /m /p:Configuration=RelWithDebInfo .\build32\obs-websocket.sln
|
||||
- name: 'Build obs-websocket 64-bit'
|
||||
working-directory: ${{ github.workspace }}/obs-websocket
|
||||
run: msbuild /m /p:Configuration=RelWithDebInfo .\build64\obs-websocket.sln
|
||||
- name: 'Set PR Artifact Filename'
|
||||
shell: bash
|
||||
run: |
|
||||
if [ "${{ env.GIT_TAG }}" ] ; then \
|
||||
FILENAME="obs-websocket-${{ env.GIT_TAG }}-Windows" ; \
|
||||
else \
|
||||
FILENAME="obs-websocket-${{ env.GIT_HASH }}-git-Windows" ; \
|
||||
fi
|
||||
echo "WIN_FILENAME=$FILENAME" >> $GITHUB_ENV
|
||||
- name: 'Package obs-websocket'
|
||||
working-directory: ${{ github.workspace }}/obs-websocket
|
||||
run: |
|
||||
mkdir package
|
||||
cd package
|
||||
7z a "${{ env.WIN_FILENAME }}.zip" "..\release\*"
|
||||
iscc ..\installer\installer-windows.generated.iss /O. /F"${{ env.WIN_FILENAME }}-Installer"
|
||||
- name: 'Publish ${{ env.WIN_FILENAME }}.zip'
|
||||
if: success()
|
||||
uses: actions/upload-artifact@v2-preview
|
||||
with:
|
||||
name: 'obs-websocket-${{ env.PACKAGE_VERSION }}-Windows'
|
||||
path: ${{ github.workspace }}/obs-websocket/package/*.zip
|
||||
- name: 'Publish ${{ env.WIN_FILENAME }}-Installer.exe'
|
||||
if: success()
|
||||
uses: actions/upload-artifact@v2-preview
|
||||
with:
|
||||
name: 'obs-websocket-${{ env.PACKAGE_VERSION }}-Windows-Installer'
|
||||
path: ${{ github.workspace }}/obs-websocket/package/*.exe
|
||||
ubuntu64:
|
||||
name: "Linux/Ubuntu 64-bit"
|
||||
runs-on: [ubuntu-latest]
|
||||
if: contains(github.event.head_commit.message, '[skip ci]') != true
|
||||
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: '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'
|
||||
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 --tags --abbrev=0)
|
||||
echo "GIT_TAG=$GIT_TAG" >> $GITHUB_ENV
|
||||
if [ "$GIT_TAG" ] ; then \
|
||||
VERSION="$GIT_TAG" ; \
|
||||
else \
|
||||
VERSION="$GIT_HASH-git" ; \
|
||||
fi
|
||||
echo "PACKAGE_VERSION=$VERSION" >> $GITHUB_ENV
|
||||
- name: 'Install prerequisites (Apt)'
|
||||
shell: bash
|
||||
run: |
|
||||
sudo dpkg --add-architecture amd64
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get install -y \
|
||||
build-essential \
|
||||
checkinstall \
|
||||
cmake \
|
||||
libasound2-dev \
|
||||
libavcodec-dev \
|
||||
libavdevice-dev \
|
||||
libavfilter-dev \
|
||||
libavformat-dev \
|
||||
libavutil-dev \
|
||||
libcurl4-openssl-dev \
|
||||
libfdk-aac-dev \
|
||||
libfontconfig-dev \
|
||||
libfreetype6-dev \
|
||||
libgl1-mesa-dev \
|
||||
libjack-jackd2-dev \
|
||||
libjansson-dev \
|
||||
libluajit-5.1-dev \
|
||||
libpulse-dev \
|
||||
libqt5x11extras5-dev \
|
||||
libspeexdsp-dev \
|
||||
libswresample-dev \
|
||||
libswscale-dev \
|
||||
libudev-dev \
|
||||
libv4l-dev \
|
||||
libva-dev \
|
||||
libvlc-dev \
|
||||
libx11-dev \
|
||||
libx264-dev \
|
||||
libxcb-randr0-dev \
|
||||
libxcb-shm0-dev \
|
||||
libxcb-xinerama0-dev \
|
||||
libxcomposite-dev \
|
||||
libxinerama-dev \
|
||||
libmbedtls-dev \
|
||||
pkg-config \
|
||||
python3-dev \
|
||||
qtbase5-dev \
|
||||
qtbase5-private-dev \
|
||||
libqt5svg5-dev \
|
||||
swig \
|
||||
libxcb-randr0-dev \
|
||||
libxcb-xfixes0-dev \
|
||||
libx11-xcb-dev \
|
||||
libxcb1-dev \
|
||||
libxss-dev \
|
||||
- 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'
|
||||
working-directory: ${{ github.workspace }}/obs-studio
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
cd ./build
|
||||
make -j4 libobs obs-frontend-api
|
||||
- name: 'Install OBS-Studio'
|
||||
working-directory: ${{ github.workspace }}/obs-studio
|
||||
shell: bash
|
||||
run: |
|
||||
cd ./build
|
||||
sudo cp ./libobs/libobs.so /usr/lib
|
||||
sudo cp ./UI/obs-frontend-api/libobs-frontend-api.so /usr/lib
|
||||
sudo mkdir -p /usr/include/obs
|
||||
sudo cp ../UI/obs-frontend-api/obs-frontend-api.h /usr/include/obs/obs-frontend-api.h
|
||||
- name: 'Configure obs-websocket'
|
||||
working-directory: ${{ github.workspace }}/obs-websocket
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir ./build
|
||||
cd ./build
|
||||
if [ "${{ env.GIT_TAG }}" ] ; then \
|
||||
cmake -DLIBOBS_INCLUDE_DIR=${{ github.workspace }}/obs-studio/libobs -DCMAKE_INSTALL_PREFIX=/usr -DUSE_UBUNTU_FIX=TRUE -DCMAKE_BUILD_TYPE=Release .. ; \
|
||||
else \
|
||||
cmake -DLIBOBS_INCLUDE_DIR=${{ github.workspace }}/obs-studio/libobs -DCMAKE_INSTALL_PREFIX=/usr -DUSE_UBUNTU_FIX=TRUE .. ; \
|
||||
fi
|
||||
- name: 'Build obs-websocket'
|
||||
working-directory: ${{ github.workspace }}/obs-websocket
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
cd ./build
|
||||
make -j4
|
||||
- name: 'Set PR Artifact Filename'
|
||||
shell: bash
|
||||
run: |
|
||||
if [ "${{ env.GIT_TAG }}" ] ; then \
|
||||
FILENAME="obs-websocket-${{ env.GIT_TAG }}-Ubuntu64.deb" ; \
|
||||
else \
|
||||
FILENAME="obs-websocket-${{ env.GIT_HASH }}-git-Ubuntu64.deb" ; \
|
||||
fi
|
||||
echo "FILENAME=$FILENAME" >> $GITHUB_ENV
|
||||
- name: 'Package ${{ env.FILENAME }}'
|
||||
if: success()
|
||||
working-directory: ${{ github.workspace }}/obs-websocket
|
||||
shell: bash
|
||||
run: |
|
||||
cd ./build
|
||||
sudo checkinstall -y --type=debian --fstrans=no -nodoc \
|
||||
--backup=no --deldoc=yes --install=no --pkgname=obs-websocket --pkgversion=${{ env.PACKAGE_VERSION }} \
|
||||
--pkglicense="GPLv2.0" --maintainer="${{ github.event.pusher.email }}" --pkggroup="video" \
|
||||
--pkgsource="${{ github.event.repository.html_url }}" \
|
||||
--requires="obs-studio,libqt5network5,libqt5concurrent5,qt5-image-formats-plugins" \
|
||||
--pakdir="../package"
|
||||
sudo chmod ao+r ../package/*
|
||||
sudo mv ../package/* ../package/${{ env.FILENAME }}
|
||||
cd -
|
||||
- name: 'Publish ${{ env.FILENAME }}'
|
||||
if: success()
|
||||
uses: actions/upload-artifact@v2-preview
|
||||
with:
|
||||
name: 'obs-websocket-${{ env.PACKAGE_VERSION }}-Ubuntu64'
|
||||
path: '${{ github.workspace }}/obs-websocket/package/*.deb'
|
||||
name: "CI Multiplatform Build"
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
branches:
|
||||
- master
|
||||
tags:
|
||||
- '[45].[0-9]+.[0-9]+*'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**.md'
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
windows:
|
||||
name: 'Windows 32/64-bit'
|
||||
runs-on: [windows-latest]
|
||||
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"
|
||||
steps:
|
||||
- name: 'Add msbuild to PATH'
|
||||
uses: microsoft/setup-msbuild@v1.0.2
|
||||
- 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: '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: 'Restore Cached Qt'
|
||||
id: qtcache
|
||||
uses: actions/cache@v2
|
||||
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: |
|
||||
curl -kLO https://tt2468.net/dl/Qt_${{ env.QT_VERSION }}.7z -f --retry 5 -C -
|
||||
- name: 'Extract Prerequisite: Qt'
|
||||
run: |
|
||||
7z x Qt_${{ env.QT_VERSION }}.7z -o"${{ github.workspace }}\cmbuild\QT"
|
||||
- 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'
|
||||
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'
|
||||
id: build-cache-obs-32
|
||||
uses: actions/cache@v2
|
||||
env:
|
||||
CACHE_NAME: 'build-cache-obs-32'
|
||||
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'
|
||||
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'
|
||||
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'
|
||||
id: build-cache-obs-64
|
||||
uses: actions/cache@v1
|
||||
env:
|
||||
CACHE_NAME: 'build-cache-obs-64'
|
||||
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'
|
||||
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'
|
||||
if: steps.build-cache-obs-64.outputs.cache-hit != 'true'
|
||||
working-directory: ${{ github.workspace }}/obs-studio
|
||||
run: |
|
||||
msbuild /m /p:Configuration=RelWithDebInfo .\build64\libobs\libobs.vcxproj
|
||||
msbuild /m /p:Configuration=RelWithDebInfo .\build64\UI\obs-frontend-api\obs-frontend-api.vcxproj
|
||||
- name: 'Configure obs-websocket 32-bit'
|
||||
working-directory: ${{ github.workspace }}/obs-websocket
|
||||
run: |
|
||||
mkdir .\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" -DLibObs_DIR="${{ github.workspace }}\obs-studio\build32\libobs" -DLIBOBS_INCLUDE_DIR="${{ github.workspace }}\obs-studio\libobs" -DLIBOBS_LIB="${{ github.workspace }}\obs-studio\build32\libobs\RelWithDebInfo\obs.lib" -DOBS_FRONTEND_LIB="${{ github.workspace }}\obs-studio\build32\UI\obs-frontend-api\RelWithDebInfo\obs-frontend-api.lib" -DOBS_WEBSOCKET_VERSION_SUFFIX="${{ env.CMAKE_VERSION_SUFFIX }}" ..
|
||||
- name: 'Configure obs-websocket 64-bit'
|
||||
working-directory: ${{ github.workspace }}/obs-websocket
|
||||
run: |
|
||||
mkdir .\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" -DLibObs_DIR="${{ github.workspace }}\obs-studio\build64\libobs" -DLIBOBS_INCLUDE_DIR="${{ github.workspace }}\obs-studio\libobs" -DLIBOBS_LIB="${{ github.workspace }}\obs-studio\build64\libobs\RelWithDebInfo\obs.lib" -DOBS_FRONTEND_LIB="${{ github.workspace }}\obs-studio\build64\UI\obs-frontend-api\RelWithDebInfo\obs-frontend-api.lib" -DOBS_WEBSOCKET_VERSION_SUFFIX="${{ env.CMAKE_VERSION_SUFFIX }}" ..
|
||||
- name: 'Build obs-websocket 32-bit'
|
||||
working-directory: ${{ github.workspace }}/obs-websocket
|
||||
run: msbuild /m /p:Configuration=RelWithDebInfo .\build32\obs-websocket.sln
|
||||
- name: 'Build obs-websocket 64-bit'
|
||||
working-directory: ${{ github.workspace }}/obs-websocket
|
||||
run: msbuild /m /p:Configuration=RelWithDebInfo .\build64\obs-websocket.sln
|
||||
- name: 'Set PR Artifact Filename'
|
||||
shell: bash
|
||||
run: |
|
||||
echo "WIN_FILENAME=obs-websocket-${{ env.PACKAGE_VERSION }}-Windows" >> $GITHUB_ENV
|
||||
- name: 'Package obs-websocket'
|
||||
working-directory: ${{ github.workspace }}/obs-websocket
|
||||
run: |
|
||||
mkdir package
|
||||
cd package
|
||||
7z a "${{ env.WIN_FILENAME }}.zip" "..\release\*"
|
||||
iscc ..\installer\installer-windows.generated.iss /O. /F"${{ env.WIN_FILENAME }}-Installer"
|
||||
- name: 'Publish ${{ env.WIN_FILENAME }}.zip'
|
||||
if: success()
|
||||
uses: actions/upload-artifact@v2-preview
|
||||
with:
|
||||
name: 'obs-websocket-${{ env.PACKAGE_VERSION }}-Windows'
|
||||
path: ${{ github.workspace }}/obs-websocket/package/*.zip
|
||||
- name: 'Publish ${{ env.WIN_FILENAME }}-Installer.exe'
|
||||
if: success()
|
||||
uses: actions/upload-artifact@v2-preview
|
||||
with:
|
||||
name: 'obs-websocket-${{ env.PACKAGE_VERSION }}-Windows-Installer'
|
||||
path: ${{ github.workspace }}/obs-websocket/package/*.exe
|
||||
ubuntu64:
|
||||
name: "Linux/Ubuntu 64-bit"
|
||||
runs-on: [ubuntu-latest]
|
||||
if: contains(github.event.head_commit.message, '[skip ci]') != true
|
||||
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: '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'
|
||||
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 prerequisites (Apt)'
|
||||
shell: bash
|
||||
run: |
|
||||
sudo dpkg --add-architecture amd64
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get install -y \
|
||||
build-essential \
|
||||
checkinstall \
|
||||
cmake \
|
||||
libasound2-dev \
|
||||
libavcodec-dev \
|
||||
libavdevice-dev \
|
||||
libavfilter-dev \
|
||||
libavformat-dev \
|
||||
libavutil-dev \
|
||||
libcurl4-openssl-dev \
|
||||
libfdk-aac-dev \
|
||||
libfontconfig-dev \
|
||||
libfreetype6-dev \
|
||||
libgl1-mesa-dev \
|
||||
libjack-jackd2-dev \
|
||||
libjansson-dev \
|
||||
libluajit-5.1-dev \
|
||||
libpulse-dev \
|
||||
libqt5x11extras5-dev \
|
||||
libspeexdsp-dev \
|
||||
libswresample-dev \
|
||||
libswscale-dev \
|
||||
libudev-dev \
|
||||
libv4l-dev \
|
||||
libva-dev \
|
||||
libvlc-dev \
|
||||
libx11-dev \
|
||||
libx264-dev \
|
||||
libxcb-randr0-dev \
|
||||
libxcb-shm0-dev \
|
||||
libxcb-xinerama0-dev \
|
||||
libxcomposite-dev \
|
||||
libxinerama-dev \
|
||||
libmbedtls-dev \
|
||||
pkg-config \
|
||||
python3-dev \
|
||||
qtbase5-dev \
|
||||
qtbase5-private-dev \
|
||||
libqt5svg5-dev \
|
||||
swig \
|
||||
libxcb-randr0-dev \
|
||||
libxcb-xfixes0-dev \
|
||||
libx11-xcb-dev \
|
||||
libxcb1-dev \
|
||||
libxss-dev \
|
||||
- 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'
|
||||
working-directory: ${{ github.workspace }}/obs-studio
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
cd ./build
|
||||
make -j4 libobs obs-frontend-api
|
||||
- name: 'Install OBS-Studio'
|
||||
working-directory: ${{ github.workspace }}/obs-studio
|
||||
shell: bash
|
||||
run: |
|
||||
cd ./build
|
||||
sudo cp ./libobs/libobs.so /usr/lib
|
||||
sudo cp ./UI/obs-frontend-api/libobs-frontend-api.so /usr/lib
|
||||
sudo mkdir -p /usr/include/obs
|
||||
sudo cp ../UI/obs-frontend-api/obs-frontend-api.h /usr/include/obs/obs-frontend-api.h
|
||||
- name: 'Configure obs-websocket'
|
||||
working-directory: ${{ github.workspace }}/obs-websocket
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir ./build
|
||||
cd ./build
|
||||
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 }}" .. ; \
|
||||
fi
|
||||
- name: 'Build obs-websocket'
|
||||
working-directory: ${{ github.workspace }}/obs-websocket
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
cd ./build
|
||||
make -j4
|
||||
- name: 'Set PR Artifact Filename'
|
||||
shell: bash
|
||||
run: |
|
||||
echo "LINUX_FILENAME=obs-websocket-${{ env.PACKAGE_VERSION }}-Ubuntu64.deb" >> $GITHUB_ENV
|
||||
- name: 'Package ${{ env.LINUX_FILENAME }}'
|
||||
if: success()
|
||||
working-directory: ${{ github.workspace }}/obs-websocket
|
||||
shell: bash
|
||||
run: |
|
||||
if [ "${{ env.GIT_TAG }}" ] ; then \
|
||||
CHECKINSTALL_VERSION="${{ env.PACKAGE_VERSION }}" ; \
|
||||
else \
|
||||
CHECKINSTALL_VERSION="1-${{ env.PACKAGE_VERSION }}" ; \
|
||||
fi
|
||||
cd ./build
|
||||
sudo checkinstall -y --type=debian --fstrans=no -nodoc \
|
||||
--backup=no --deldoc=yes --install=no --pkgname=obs-websocket --pkgversion="$CHECKINSTALL_VERSION" \
|
||||
--pkglicense="GPLv2.0" --maintainer="${{ github.event.pusher.email }}" --pkggroup="video" \
|
||||
--pkgsource="${{ github.event.repository.html_url }}" \
|
||||
--requires="obs-studio,libqt5network5,libqt5concurrent5,qt5-image-formats-plugins" \
|
||||
--pakdir="../package"
|
||||
sudo chmod ao+r ../package/*
|
||||
sudo mv ../package/* ../package/${{ env.LINUX_FILENAME }}
|
||||
cd -
|
||||
- name: 'Publish ${{ env.LINUX_FILENAME }}'
|
||||
if: success()
|
||||
uses: actions/upload-artifact@v2-preview
|
||||
with:
|
||||
name: 'obs-websocket-${{ env.PACKAGE_VERSION }}-Ubuntu64'
|
||||
path: '${{ github.workspace }}/obs-websocket/package/*.deb'
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -9,3 +9,5 @@
|
||||
.idea
|
||||
.vscode
|
||||
/docs/node_modules/
|
||||
/src/plugin-macros.generated.h
|
||||
/installer/installer-windows.generated.iss
|
||||
|
@ -1,10 +1,23 @@
|
||||
cmake_minimum_required(VERSION 3.16...3.20)
|
||||
|
||||
# Version variables
|
||||
project(obs-websocket VERSION 5.0.0)
|
||||
set(OBS_WEBSOCKET_RPC_VERSION 1)
|
||||
|
||||
|
||||
# Set correct version string
|
||||
if(DEFINED OBS_WEBSOCKET_VERSION_SUFFIX AND NOT OBS_WEBSOCKET_VERSION_SUFFIX STREQUAL "")
|
||||
set(OBS_WEBSOCKET_VERSION "${CMAKE_PROJECT_VERSION}${OBS_WEBSOCKET_VERSION_SUFFIX}")
|
||||
message(WARNING "-----------------------------------\nVersion Suffix provided. OBS_WEBSOCKET_VERSION is now ${OBS_WEBSOCKET_VERSION}\n-----------------------------------")
|
||||
else()
|
||||
set(OBS_WEBSOCKET_VERSION "${CMAKE_PROJECT_VERSION}")
|
||||
endif()
|
||||
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
|
||||
# Prohibit in-source builds
|
||||
file(TO_CMAKE_PATH "${PROJECT_BINARY_DIR}/CMakeLists.txt" _LOC_PATH)
|
||||
if(EXISTS "${LOC_PATH}")
|
||||
@ -91,6 +104,7 @@ set(obs-websocket_SOURCES
|
||||
src/requesthandler/RequestHandler_Sources.cpp
|
||||
src/requesthandler/RequestHandler_Scenes.cpp
|
||||
src/requesthandler/RequestHandler_Inputs.cpp
|
||||
src/requesthandler/RequestHandler_SceneItems.cpp
|
||||
src/requesthandler/RequestHandler_Stream.cpp
|
||||
src/requesthandler/rpc/Request.cpp
|
||||
src/requesthandler/rpc/RequestResult.cpp
|
||||
|
@ -32,7 +32,7 @@ brew install obs-websocket
|
||||
|
||||
Here is a list of available web clients: (compatible with tablets and other touch interfaces)
|
||||
|
||||
- (No known clients supporting 5.0.0)
|
||||
- Python 3.7+ (Asyncio): [simpleobsws](https://github.com/IRLToolkit/simpleobsws/tree/master) by IRLToolkit
|
||||
|
||||
It is **highly recommended** to protect obs-websocket with a password against unauthorized control. To do this, open the "Websocket server settings" dialog under OBS' "Tools" menu. In the settings dialogs, you can enable or disable authentication and set a password for it.
|
||||
|
||||
|
@ -44,10 +44,9 @@ Here's info on how to connect to obs-websocket
|
||||
These steps should be followed precisely. Failure to connect to the server as instructed will likely result in your client being treated in an undefined way.
|
||||
|
||||
- Initial HTTP request made to the obs-websocket server.
|
||||
- HTTP request headers can be used to set the websocket communication type. The default format is JSON. Example headers:
|
||||
- `Content-Type: application/json`
|
||||
- `Content-Type: application/msgpack`
|
||||
- If an invalid `Content-Type` is specified, the connection will be closed with [`WebSocketCloseCode::InvalidContentType`](#websocketclosecode-enum) after upgrade (but before `Hello`).
|
||||
- The `Sec-WebSocket-Protocol` header can be used to tell obs-websocket which kind of message encoding to use. By default, obs-websocket uses JSON over text. Available subprotocols:
|
||||
- `obswebsocket.json` - JSON over text frames
|
||||
- `obswebsocket.msgpack` - MsgPack over binary frames
|
||||
|
||||
- Once the connection is upgraded, the websocket server will immediately send an [OpCode 0 `Hello`](#hello-opcode-0) message to the client.
|
||||
|
||||
@ -57,9 +56,9 @@ These steps should be followed precisely. Failure to connect to the server as in
|
||||
- The client determines if the server's `rpcVersion` is supported, and if not it provides its closest supported version in `Identify`.
|
||||
|
||||
- The server receives and processes the `Identify` sent by the client.
|
||||
- If authentication is required and the `Identify` message data does not contain an `authentication` string, or the string is not correct, the connection is dropped with [`WebSocketCloseCode::AuthenticationFailed`](#websocketclosecode-enum)
|
||||
- If the client has requested an `rpcVersion` which the server cannot use, the connection is dropped with [`WebSocketCloseCode::UnsupportedProtocolVersion`](#websocketclosecode-enum). This system allows both the server and client to have seamless backwards compatability.
|
||||
- If any other parameters are malformed (invalid type, etc), the connection is dropped with [`WebSocketCloseCode::InvalidIdentifyParameter`](#websocketclosecode-enum)
|
||||
- If authentication is required and the `Identify` message data does not contain an `authentication` string, or the string is not correct, the connection is closed with [`WebSocketCloseCode::AuthenticationFailed`](#websocketclosecode-enum)
|
||||
- If the client has requested an `rpcVersion` which the server cannot use, the connection is closed with [`WebSocketCloseCode::UnsupportedRpcVersion`](#websocketclosecode-enum). This system allows both the server and client to have seamless backwards compatability.
|
||||
- If any other parameters are malformed (invalid type, etc), the connection is closed with an appropriate close code.
|
||||
|
||||
- Once identification is processed on the server, the server responds to the client with an [OpCode 2 `Identified`](#identified-opcode-2).
|
||||
|
||||
@ -68,10 +67,10 @@ These steps should be followed precisely. Failure to connect to the server as in
|
||||
- At any time after a client has been identified, it may send an [OpCode 3 `Reidentify`](#reidentify-opcode-3) message to update certain allowed session parameters. The server will respond in the same way it does during initial identification.
|
||||
|
||||
#### Connection Notes
|
||||
- If the Content Type is `application/msgpack`, all messages must be sent over binary. If it is `application/json`, all messages must be sent over text.
|
||||
- The obs-websocket server listens for any messages containing a `request-type` key in the first level JSON from unidentified clients. If a message matches, the connection is dropped with [`WebSocketCloseCode::UnsupportedProtocolVersion`](#websocketclosecode-enum) and a warning is logged.
|
||||
- If a message with a `messageType` is not recognized to the obs-websocket server, the connection is dropped with [`WebSocketCloseCode::UnknownMessageType`](#websocketclosecode-enum).
|
||||
- At no point may the client send any message other than a single `Identify` before it has received an `Identified`. Doing so will result in the connection being dropped by the server with [`WebSocketCloseCode::NotIdentified`](#websocketclosecode-enum).
|
||||
- If a binary frame is received when using the `obswebsocket.json` (default) subprotocol, or a text frame is received while using the `obswebsocket.msgpack` subprotocol, the connection is closed with [`WebSocketCloseCode::MessageDecodeError`](#websocketclosecode-enum).
|
||||
- The obs-websocket server listens for any messages containing a `request-type` key in the first level JSON from unidentified clients. If a message matches, the connection is closed with [`WebSocketCloseCode::UnsupportedRpcVersion`](#websocketclosecode-enum) and a warning is logged.
|
||||
- If a message with a `messageType` is not recognized to the obs-websocket server, the connection is closed with [`WebSocketCloseCode::UnknownOpCode`](#websocketclosecode-enum).
|
||||
- At no point may the client send any message other than a single `Identify` before it has received an `Identified`. Doing so will result in the connection being closed with [`WebSocketCloseCode::NotIdentified`](#websocketclosecode-enum).
|
||||
|
||||
---
|
||||
|
||||
@ -123,8 +122,6 @@ enum WebSocketCloseCode {
|
||||
DontClose = 0,
|
||||
// Reserved
|
||||
UnknownReason = 4000,
|
||||
// The requested `Content-Type` specified in the request HTTP header is invalid.
|
||||
InvalidContentType = 4001,
|
||||
// The server was unable to decode the incoming websocket message
|
||||
MessageDecodeError = 4002,
|
||||
// A data key is missing but required
|
||||
@ -191,11 +188,11 @@ enum RequestStatus {
|
||||
|
||||
Success = 100,
|
||||
|
||||
// The `requestType` key is missing from the request data
|
||||
// The `requestType` field is missing from the request data
|
||||
MissingRequestType = 203,
|
||||
// The request type is invalid (does not exist)
|
||||
// The request type is invalid or does not exist
|
||||
UnknownRequestType = 204,
|
||||
// Generic error code (comment is expected to be provided)
|
||||
// Generic error code (comment required)
|
||||
GenericError = 205,
|
||||
|
||||
// A required request parameter is missing
|
||||
@ -203,10 +200,10 @@ enum RequestStatus {
|
||||
// The request does not have a valid requestData object.
|
||||
MissingRequestData = 301,
|
||||
|
||||
// Generic invalid request parameter message
|
||||
// Generic invalid request parameter message (comment required)
|
||||
InvalidRequestParameter = 400,
|
||||
// A request parameter has the wrong data type
|
||||
InvalidRequestParameterDataType = 401,
|
||||
InvalidRequestParameterType = 401,
|
||||
// A request parameter (float or int) is out of valid range
|
||||
RequestParameterOutOfRange = 402,
|
||||
// A request parameter (string or array) is empty and cannot be
|
||||
@ -218,102 +215,36 @@ enum RequestStatus {
|
||||
OutputRunning = 500,
|
||||
// An output is not running and should be
|
||||
OutputNotRunning = 501,
|
||||
// Stream is running and cannot be
|
||||
StreamRunning = 502,
|
||||
// Stream is not running and should be
|
||||
StreamNotRunning = 503,
|
||||
// Record is running and cannot be
|
||||
RecordRunning = 504,
|
||||
// Record is not running and should be
|
||||
RecordNotRunning = 505,
|
||||
// Record is paused and cannot be
|
||||
RecordPaused = 506,
|
||||
// Replay buffer is running and cannot be
|
||||
ReplayBufferRunning = 507,
|
||||
// Replay buffer is not running and should be
|
||||
ReplayBufferNotRunning = 508,
|
||||
// Replay buffer is disabled and cannot be
|
||||
ReplayBufferDisabled = 509,
|
||||
// An output is paused and should not be
|
||||
OutputPaused = 502,
|
||||
// An output is disabled and should not be
|
||||
OutputDisabled = 503,
|
||||
// Studio mode is active and cannot be
|
||||
StudioModeActive = 510,
|
||||
StudioModeActive = 504,
|
||||
// Studio mode is not active and should be
|
||||
StudioModeNotActive = 511,
|
||||
// Virtualcam is running and cannot be
|
||||
VirtualcamRunning = 512,
|
||||
// Virtualcam is not running and should be
|
||||
VirtualcamNotRunning = 513,
|
||||
StudioModeNotActive = 505,
|
||||
|
||||
// The specified source (obs_source_t) was of the invalid type (Eg. input instead of scene)
|
||||
InvalidSourceType = 600,
|
||||
// The specified source (obs_source_t) was not found (generic for input, filter, transition, scene)
|
||||
SourceNotFound = 601,
|
||||
// The specified source (obs_source_t) already exists. Applicable to inputs, filters, transitions, scenes
|
||||
SourceAlreadyExists = 602,
|
||||
// The specified input (obs_source_t-OBS_SOURCE_TYPE_FILTER) was not found
|
||||
InputNotFound = 603,
|
||||
// The resource was not found
|
||||
ResourceNotFound = 600,
|
||||
// The resource already exists
|
||||
ResourceAlreadyExists = 601,
|
||||
// The type of resource found is invalid
|
||||
InvalidResourceType = 602,
|
||||
// There are not enough instances of the resource in order to perform the request
|
||||
NotEnoughResources = 603,
|
||||
// The state of the resource is invalid. For example, if the resource is blocked from being accessed
|
||||
InvalidResourceState = 604,
|
||||
// The specified input (obs_source_t-OBS_SOURCE_TYPE_INPUT) had the wrong kind
|
||||
InvalidInputKind = 604,
|
||||
// The specified filter (obs_source_t-OBS_SOURCE_TYPE_FILTER) was not found
|
||||
FilterNotFound = 605,
|
||||
// The specified transition (obs_source_t-OBS_SOURCE_TYPE_TRANSITION) was not found
|
||||
TransitionNotFound = 606,
|
||||
// The specified transition (obs_source_t-OBS_SOURCE_TYPE_TRANSITION) does not support setting its position (transition is of fixed type)
|
||||
TransitionDurationFixed = 607,
|
||||
// The specified scene (obs_source_t-OBS_SOURCE_TYPE_SCENE), (obs_scene_t) was not found
|
||||
SceneNotFound = 608,
|
||||
// The specified scene item (obs_sceneitem_t) was not found
|
||||
SceneItemNotFound = 609,
|
||||
// The specified scene collection was not found
|
||||
SceneCollectionNotFound = 610,
|
||||
// The specified profile was not found
|
||||
ProfileNotFound = 611,
|
||||
// The specified output (obs_output_t) was not found
|
||||
OutputNotFound = 612,
|
||||
// The specified encoder (obs_encoder_t) was not found
|
||||
EncoderNotFound = 613,
|
||||
// The specified service (obs_service_t) was not found
|
||||
ServiceNotFound = 614,
|
||||
// The specified hotkey was not found
|
||||
HotkeyNotFound = 615,
|
||||
// The specified directory was not found
|
||||
DirectoryNotFound = 616,
|
||||
// The specified config item (config_t) was not found. Could be section or parameter name
|
||||
ConfigParameterNotFound = 617,
|
||||
// The specified property (obs_properties_t) was not found
|
||||
PropertyNotFound = 618,
|
||||
// The specififed key (OBS_KEY_*) was not found
|
||||
KeyNotFound = 619,
|
||||
// The specified data realm (OBS_WEBSOCKET_DATA_REALM_*) was not found
|
||||
DataRealmNotFound = 620,
|
||||
// The scene collection already exists
|
||||
SceneCollectionAlreadyExists = 621,
|
||||
// There are not enough scene collections to perform the action
|
||||
NotEnoughSceneCollections = 622,
|
||||
// The profile already exists
|
||||
ProfileAlreadyExists = 623,
|
||||
// There are not enough profiles to perform the action
|
||||
NotEnoughProfiles = 624,
|
||||
// There are not enough scenes to perform the action
|
||||
NotEnoughScenes = 625,
|
||||
InvalidInputKind = 605,
|
||||
|
||||
// Processing the request failed unexpectedly
|
||||
RequestProcessingFailed = 700,
|
||||
// Starting the Output failed
|
||||
OutputStartFailed = 701,
|
||||
// Duplicating the scene item failed
|
||||
SceneItemDuplicationFailed = 702,
|
||||
// Rendering the screenshot failed
|
||||
ScreenshotRenderFailed = 703,
|
||||
// Encoding the screenshot failed
|
||||
ScreenshotEncodeFailed = 704,
|
||||
// Saving the screenshot failed
|
||||
ScreenshotSaveFailed = 705,
|
||||
// Creating the directory failed
|
||||
DirectoryCreationFailed = 706,
|
||||
// Creating the resource failed
|
||||
ResourceCreationFailed = 700,
|
||||
// Performing an action on the resource failed
|
||||
ResourceActionFailed = 701,
|
||||
// Processing the request failed unexpectedly (comment required)
|
||||
RequestProcessingFailed = 702,
|
||||
// The combination of request parameters cannot be used to perform an action
|
||||
CannotAct = 707,
|
||||
// Creation of a new stream service failed
|
||||
StreamServiceCreationFailed = 708,
|
||||
CannotAct = 703,
|
||||
};
|
||||
```
|
||||
|
||||
@ -393,7 +324,7 @@ Authentication is not required
|
||||
}
|
||||
```
|
||||
- `rpcVersion` is the version number that the client would like the obs-websocket server to use.
|
||||
- When `ignoreInvalidMessages` is true, the socket will not be closed for [`WebSocketCloseCode`](#websocketclosecode-enum): `MessageDecodeError`, `UnknownMessageType`, or `RequestMissingRequestId`. Instead, the message will be logged and dropped.
|
||||
- When `ignoreInvalidMessages` is true, the socket will not be closed for [`WebSocketCloseCode`](#websocketclosecode-enum): `MessageDecodeError`, `UnknownOpCode`, or `MissingDataKey`. Instead, the message will be logged and ignored.
|
||||
- When `ignoreNonFatalRequestChecks` is true, requests will ignore checks which are not critical to the function of the request. Eg calling `DeleteScene` when the target scene does not exist would still return [`RequestStatus::Success`](#requeststatus-enum) if this flag is enabled.
|
||||
- `eventSubscriptions` is a bitmask of [`EventSubscriptions`](#eventsubscriptions-enum) items to subscribe to events and event categories at will. By default, all event categories are subscribed, except for events marked as high volume. High volume events must be explicitly subscribed to.
|
||||
|
||||
@ -462,9 +393,11 @@ Authentication is not required
|
||||
```
|
||||
{
|
||||
"eventType": string,
|
||||
"eventIntent": number,
|
||||
"eventData": object(optional)
|
||||
}
|
||||
```
|
||||
- `eventIntent` is the original intent required to be subscribed to in order to receive the event.
|
||||
|
||||
**Example Message:**
|
||||
```json
|
||||
@ -472,6 +405,7 @@ Authentication is not required
|
||||
"op": 2,
|
||||
"d": {
|
||||
"eventType": "StudioModeStateChanged",
|
||||
"eventIntent": 1,
|
||||
"eventData": {
|
||||
"studioModeEnabled": true
|
||||
}
|
||||
|
@ -42,10 +42,9 @@ Here's info on how to connect to obs-websocket
|
||||
These steps should be followed precisely. Failure to connect to the server as instructed will likely result in your client being treated in an undefined way.
|
||||
|
||||
- Initial HTTP request made to the obs-websocket server.
|
||||
- HTTP request headers can be used to set the websocket communication type. The default format is JSON. Example headers:
|
||||
- `Content-Type: application/json`
|
||||
- `Content-Type: application/msgpack`
|
||||
- If an invalid `Content-Type` is specified, the connection will be closed with [`WebSocketCloseCode::InvalidContentType`](#websocketclosecode-enum) after upgrade (but before `Hello`).
|
||||
- The `Sec-WebSocket-Protocol` header can be used to tell obs-websocket which kind of message encoding to use. By default, obs-websocket uses JSON over text. Available subprotocols:
|
||||
- `obswebsocket.json` - JSON over text frames
|
||||
- `obswebsocket.msgpack` - MsgPack over binary frames
|
||||
|
||||
- Once the connection is upgraded, the websocket server will immediately send an [OpCode 0 `Hello`](#hello-opcode-0) message to the client.
|
||||
|
||||
@ -55,9 +54,9 @@ These steps should be followed precisely. Failure to connect to the server as in
|
||||
- The client determines if the server's `rpcVersion` is supported, and if not it provides its closest supported version in `Identify`.
|
||||
|
||||
- The server receives and processes the `Identify` sent by the client.
|
||||
- If authentication is required and the `Identify` message data does not contain an `authentication` string, or the string is not correct, the connection is dropped with [`WebSocketCloseCode::AuthenticationFailed`](#websocketclosecode-enum)
|
||||
- If the client has requested an `rpcVersion` which the server cannot use, the connection is dropped with [`WebSocketCloseCode::UnsupportedProtocolVersion`](#websocketclosecode-enum). This system allows both the server and client to have seamless backwards compatability.
|
||||
- If any other parameters are malformed (invalid type, etc), the connection is dropped with [`WebSocketCloseCode::InvalidIdentifyParameter`](#websocketclosecode-enum)
|
||||
- If authentication is required and the `Identify` message data does not contain an `authentication` string, or the string is not correct, the connection is closed with [`WebSocketCloseCode::AuthenticationFailed`](#websocketclosecode-enum)
|
||||
- If the client has requested an `rpcVersion` which the server cannot use, the connection is closed with [`WebSocketCloseCode::UnsupportedRpcVersion`](#websocketclosecode-enum). This system allows both the server and client to have seamless backwards compatability.
|
||||
- If any other parameters are malformed (invalid type, etc), the connection is closed with an appropriate close code.
|
||||
|
||||
- Once identification is processed on the server, the server responds to the client with an [OpCode 2 `Identified`](#identified-opcode-2).
|
||||
|
||||
@ -66,10 +65,10 @@ These steps should be followed precisely. Failure to connect to the server as in
|
||||
- At any time after a client has been identified, it may send an [OpCode 3 `Reidentify`](#reidentify-opcode-3) message to update certain allowed session parameters. The server will respond in the same way it does during initial identification.
|
||||
|
||||
#### Connection Notes
|
||||
- If the Content Type is `application/msgpack`, all messages must be sent over binary. If it is `application/json`, all messages must be sent over text.
|
||||
- The obs-websocket server listens for any messages containing a `request-type` key in the first level JSON from unidentified clients. If a message matches, the connection is dropped with [`WebSocketCloseCode::UnsupportedProtocolVersion`](#websocketclosecode-enum) and a warning is logged.
|
||||
- If a message with a `messageType` is not recognized to the obs-websocket server, the connection is dropped with [`WebSocketCloseCode::UnknownMessageType`](#websocketclosecode-enum).
|
||||
- At no point may the client send any message other than a single `Identify` before it has received an `Identified`. Doing so will result in the connection being dropped by the server with [`WebSocketCloseCode::NotIdentified`](#websocketclosecode-enum).
|
||||
- If a binary frame is received when using the `obswebsocket.json` (default) subprotocol, or a text frame is received while using the `obswebsocket.msgpack` subprotocol, the connection is closed with [`WebSocketCloseCode::MessageDecodeError`](#websocketclosecode-enum).
|
||||
- The obs-websocket server listens for any messages containing a `request-type` key in the first level JSON from unidentified clients. If a message matches, the connection is closed with [`WebSocketCloseCode::UnsupportedRpcVersion`](#websocketclosecode-enum) and a warning is logged.
|
||||
- If a message with a `messageType` is not recognized to the obs-websocket server, the connection is closed with [`WebSocketCloseCode::UnknownOpCode`](#websocketclosecode-enum).
|
||||
- At no point may the client send any message other than a single `Identify` before it has received an `Identified`. Doing so will result in the connection being closed with [`WebSocketCloseCode::NotIdentified`](#websocketclosecode-enum).
|
||||
|
||||
---
|
||||
|
||||
@ -121,8 +120,6 @@ enum WebSocketCloseCode {
|
||||
DontClose = 0,
|
||||
// Reserved
|
||||
UnknownReason = 4000,
|
||||
// The requested `Content-Type` specified in the request HTTP header is invalid.
|
||||
InvalidContentType = 4001,
|
||||
// The server was unable to decode the incoming websocket message
|
||||
MessageDecodeError = 4002,
|
||||
// A data key is missing but required
|
||||
@ -189,11 +186,11 @@ enum RequestStatus {
|
||||
|
||||
Success = 100,
|
||||
|
||||
// The `requestType` key is missing from the request data
|
||||
// The `requestType` field is missing from the request data
|
||||
MissingRequestType = 203,
|
||||
// The request type is invalid (does not exist)
|
||||
// The request type is invalid or does not exist
|
||||
UnknownRequestType = 204,
|
||||
// Generic error code (comment is expected to be provided)
|
||||
// Generic error code (comment required)
|
||||
GenericError = 205,
|
||||
|
||||
// A required request parameter is missing
|
||||
@ -201,10 +198,10 @@ enum RequestStatus {
|
||||
// The request does not have a valid requestData object.
|
||||
MissingRequestData = 301,
|
||||
|
||||
// Generic invalid request parameter message
|
||||
// Generic invalid request parameter message (comment required)
|
||||
InvalidRequestParameter = 400,
|
||||
// A request parameter has the wrong data type
|
||||
InvalidRequestParameterDataType = 401,
|
||||
InvalidRequestParameterType = 401,
|
||||
// A request parameter (float or int) is out of valid range
|
||||
RequestParameterOutOfRange = 402,
|
||||
// A request parameter (string or array) is empty and cannot be
|
||||
@ -216,102 +213,36 @@ enum RequestStatus {
|
||||
OutputRunning = 500,
|
||||
// An output is not running and should be
|
||||
OutputNotRunning = 501,
|
||||
// Stream is running and cannot be
|
||||
StreamRunning = 502,
|
||||
// Stream is not running and should be
|
||||
StreamNotRunning = 503,
|
||||
// Record is running and cannot be
|
||||
RecordRunning = 504,
|
||||
// Record is not running and should be
|
||||
RecordNotRunning = 505,
|
||||
// Record is paused and cannot be
|
||||
RecordPaused = 506,
|
||||
// Replay buffer is running and cannot be
|
||||
ReplayBufferRunning = 507,
|
||||
// Replay buffer is not running and should be
|
||||
ReplayBufferNotRunning = 508,
|
||||
// Replay buffer is disabled and cannot be
|
||||
ReplayBufferDisabled = 509,
|
||||
// An output is paused and should not be
|
||||
OutputPaused = 502,
|
||||
// An output is disabled and should not be
|
||||
OutputDisabled = 503,
|
||||
// Studio mode is active and cannot be
|
||||
StudioModeActive = 510,
|
||||
StudioModeActive = 504,
|
||||
// Studio mode is not active and should be
|
||||
StudioModeNotActive = 511,
|
||||
// Virtualcam is running and cannot be
|
||||
VirtualcamRunning = 512,
|
||||
// Virtualcam is not running and should be
|
||||
VirtualcamNotRunning = 513,
|
||||
StudioModeNotActive = 505,
|
||||
|
||||
// The specified source (obs_source_t) was of the invalid type (Eg. input instead of scene)
|
||||
InvalidSourceType = 600,
|
||||
// The specified source (obs_source_t) was not found (generic for input, filter, transition, scene)
|
||||
SourceNotFound = 601,
|
||||
// The specified source (obs_source_t) already exists. Applicable to inputs, filters, transitions, scenes
|
||||
SourceAlreadyExists = 602,
|
||||
// The specified input (obs_source_t-OBS_SOURCE_TYPE_FILTER) was not found
|
||||
InputNotFound = 603,
|
||||
// The resource was not found
|
||||
ResourceNotFound = 600,
|
||||
// The resource already exists
|
||||
ResourceAlreadyExists = 601,
|
||||
// The type of resource found is invalid
|
||||
InvalidResourceType = 602,
|
||||
// There are not enough instances of the resource in order to perform the request
|
||||
NotEnoughResources = 603,
|
||||
// The state of the resource is invalid. For example, if the resource is blocked from being accessed
|
||||
InvalidResourceState = 604,
|
||||
// The specified input (obs_source_t-OBS_SOURCE_TYPE_INPUT) had the wrong kind
|
||||
InvalidInputKind = 604,
|
||||
// The specified filter (obs_source_t-OBS_SOURCE_TYPE_FILTER) was not found
|
||||
FilterNotFound = 605,
|
||||
// The specified transition (obs_source_t-OBS_SOURCE_TYPE_TRANSITION) was not found
|
||||
TransitionNotFound = 606,
|
||||
// The specified transition (obs_source_t-OBS_SOURCE_TYPE_TRANSITION) does not support setting its position (transition is of fixed type)
|
||||
TransitionDurationFixed = 607,
|
||||
// The specified scene (obs_source_t-OBS_SOURCE_TYPE_SCENE), (obs_scene_t) was not found
|
||||
SceneNotFound = 608,
|
||||
// The specified scene item (obs_sceneitem_t) was not found
|
||||
SceneItemNotFound = 609,
|
||||
// The specified scene collection was not found
|
||||
SceneCollectionNotFound = 610,
|
||||
// The specified profile was not found
|
||||
ProfileNotFound = 611,
|
||||
// The specified output (obs_output_t) was not found
|
||||
OutputNotFound = 612,
|
||||
// The specified encoder (obs_encoder_t) was not found
|
||||
EncoderNotFound = 613,
|
||||
// The specified service (obs_service_t) was not found
|
||||
ServiceNotFound = 614,
|
||||
// The specified hotkey was not found
|
||||
HotkeyNotFound = 615,
|
||||
// The specified directory was not found
|
||||
DirectoryNotFound = 616,
|
||||
// The specified config item (config_t) was not found. Could be section or parameter name
|
||||
ConfigParameterNotFound = 617,
|
||||
// The specified property (obs_properties_t) was not found
|
||||
PropertyNotFound = 618,
|
||||
// The specififed key (OBS_KEY_*) was not found
|
||||
KeyNotFound = 619,
|
||||
// The specified data realm (OBS_WEBSOCKET_DATA_REALM_*) was not found
|
||||
DataRealmNotFound = 620,
|
||||
// The scene collection already exists
|
||||
SceneCollectionAlreadyExists = 621,
|
||||
// There are not enough scene collections to perform the action
|
||||
NotEnoughSceneCollections = 622,
|
||||
// The profile already exists
|
||||
ProfileAlreadyExists = 623,
|
||||
// There are not enough profiles to perform the action
|
||||
NotEnoughProfiles = 624,
|
||||
// There are not enough scenes to perform the action
|
||||
NotEnoughScenes = 625,
|
||||
InvalidInputKind = 605,
|
||||
|
||||
// Processing the request failed unexpectedly
|
||||
RequestProcessingFailed = 700,
|
||||
// Starting the Output failed
|
||||
OutputStartFailed = 701,
|
||||
// Duplicating the scene item failed
|
||||
SceneItemDuplicationFailed = 702,
|
||||
// Rendering the screenshot failed
|
||||
ScreenshotRenderFailed = 703,
|
||||
// Encoding the screenshot failed
|
||||
ScreenshotEncodeFailed = 704,
|
||||
// Saving the screenshot failed
|
||||
ScreenshotSaveFailed = 705,
|
||||
// Creating the directory failed
|
||||
DirectoryCreationFailed = 706,
|
||||
// Creating the resource failed
|
||||
ResourceCreationFailed = 700,
|
||||
// Performing an action on the resource failed
|
||||
ResourceActionFailed = 701,
|
||||
// Processing the request failed unexpectedly (comment required)
|
||||
RequestProcessingFailed = 702,
|
||||
// The combination of request parameters cannot be used to perform an action
|
||||
CannotAct = 707,
|
||||
// Creation of a new stream service failed
|
||||
StreamServiceCreationFailed = 708,
|
||||
CannotAct = 703,
|
||||
};
|
||||
```
|
||||
|
||||
@ -391,7 +322,7 @@ Authentication is not required
|
||||
}
|
||||
```
|
||||
- `rpcVersion` is the version number that the client would like the obs-websocket server to use.
|
||||
- When `ignoreInvalidMessages` is true, the socket will not be closed for [`WebSocketCloseCode`](#websocketclosecode-enum): `MessageDecodeError`, `UnknownMessageType`, or `RequestMissingRequestId`. Instead, the message will be logged and dropped.
|
||||
- When `ignoreInvalidMessages` is true, the socket will not be closed for [`WebSocketCloseCode`](#websocketclosecode-enum): `MessageDecodeError`, `UnknownOpCode`, or `MissingDataKey`. Instead, the message will be logged and ignored.
|
||||
- When `ignoreNonFatalRequestChecks` is true, requests will ignore checks which are not critical to the function of the request. Eg calling `DeleteScene` when the target scene does not exist would still return [`RequestStatus::Success`](#requeststatus-enum) if this flag is enabled.
|
||||
- `eventSubscriptions` is a bitmask of [`EventSubscriptions`](#eventsubscriptions-enum) items to subscribe to events and event categories at will. By default, all event categories are subscribed, except for events marked as high volume. High volume events must be explicitly subscribed to.
|
||||
|
||||
@ -460,9 +391,11 @@ Authentication is not required
|
||||
```
|
||||
{
|
||||
"eventType": string,
|
||||
"eventIntent": number,
|
||||
"eventData": object(optional)
|
||||
}
|
||||
```
|
||||
- `eventIntent` is the original intent required to be subscribed to in order to receive the event.
|
||||
|
||||
**Example Message:**
|
||||
```json
|
||||
@ -470,6 +403,7 @@ Authentication is not required
|
||||
"op": 2,
|
||||
"d": {
|
||||
"eventType": "StudioModeStateChanged",
|
||||
"eventIntent": 1,
|
||||
"eventData": {
|
||||
"studioModeEnabled": true
|
||||
}
|
||||
|
@ -1,63 +0,0 @@
|
||||
#define MyAppName "obs-websocket"
|
||||
#define MyAppVersion "5.0.0"
|
||||
#define MyAppPublisher "Stephane Lepin"
|
||||
#define MyAppURL "http://github.com/Palakis/obs-websocket"
|
||||
|
||||
[Setup]
|
||||
; NOTE: The value of AppId uniquely identifies this application.
|
||||
; Do not use the same AppId value in installers for other applications.
|
||||
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
|
||||
AppId={{117EE44F-48E1-49E5-A381-CC8D9195CF35}
|
||||
AppName={#MyAppName}
|
||||
AppVersion={#MyAppVersion}
|
||||
AppPublisher={#MyAppPublisher}
|
||||
AppPublisherURL={#MyAppURL}
|
||||
AppSupportURL={#MyAppURL}
|
||||
AppUpdatesURL={#MyAppURL}
|
||||
DefaultDirName={code:GetDirName}
|
||||
DefaultGroupName={#MyAppName}
|
||||
OutputBaseFilename=obs-websocket-{#MyAppVersion}-Windows-Installer
|
||||
Compression=lzma
|
||||
SolidCompression=yes
|
||||
DirExistsWarning=no
|
||||
|
||||
[Languages]
|
||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||
|
||||
[Files]
|
||||
Source: "..\release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
Source: "..\LICENSE"; Flags: dontcopy
|
||||
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
|
||||
|
||||
[Icons]
|
||||
Name: "{group}\{cm:ProgramOnTheWeb,{#MyAppName}}"; Filename: "{#MyAppURL}"
|
||||
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
|
||||
|
||||
[Code]
|
||||
procedure InitializeWizard();
|
||||
var
|
||||
GPLText: AnsiString;
|
||||
Page: TOutputMsgMemoWizardPage;
|
||||
begin
|
||||
ExtractTemporaryFile('LICENSE');
|
||||
LoadStringFromFile(ExpandConstant('{tmp}\LICENSE'), GPLText);
|
||||
Page := CreateOutputMsgMemoPage(wpWelcome,
|
||||
'License Information', 'Please review the license terms before installing obs-websocket',
|
||||
'Press Page Down to see the rest of the agreement. Once you are aware of your rights, click Next to continue.',
|
||||
String(GPLText)
|
||||
);
|
||||
end;
|
||||
|
||||
// credit where it's due :
|
||||
// following function come from https://github.com/Xaymar/obs-studio_amf-encoder-plugin/blob/master/%23Resources/Installer.in.iss#L45
|
||||
function GetDirName(Value: string): string;
|
||||
var
|
||||
InstallPath: string;
|
||||
begin
|
||||
// initialize default path, which will be returned when the following registry
|
||||
// key queries fail due to missing keys or for some different reason
|
||||
Result := '{pf}\obs-studio';
|
||||
// query the first registry value; if this succeeds, return the obtained value
|
||||
if RegQueryStringValue(HKLM32, 'SOFTWARE\OBS Studio', '', InstallPath) then
|
||||
Result := InstallPath
|
||||
end;
|
@ -1,5 +1,5 @@
|
||||
#define MyAppName "obs-websocket"
|
||||
#define MyAppVersion "@CMAKE_PROJECT_VERSION@"
|
||||
#define MyAppVersion "@OBS_WEBSOCKET_VERSION@"
|
||||
#define MyAppPublisher "Stephane Lepin"
|
||||
#define MyAppURL "http://github.com/Palakis/obs-websocket"
|
||||
|
||||
|
@ -26,6 +26,11 @@ WebSocketServer::WebSocketServer() :
|
||||
_server.set_reuse_addr(true);
|
||||
#endif
|
||||
|
||||
_server.set_validate_handler(
|
||||
websocketpp::lib::bind(
|
||||
&WebSocketServer::onValidate, this, websocketpp::lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
_server.set_open_handler(
|
||||
websocketpp::lib::bind(
|
||||
&WebSocketServer::onOpen, this, websocketpp::lib::placeholders::_1
|
||||
@ -199,6 +204,7 @@ void WebSocketServer::BroadcastEvent(uint64_t requiredIntent, std::string eventT
|
||||
json eventMessage;
|
||||
eventMessage["op"] = 5;
|
||||
eventMessage["d"]["eventType"] = eventType;
|
||||
eventMessage["d"]["eventIntent"] = requiredIntent;
|
||||
if (eventData.is_object())
|
||||
eventMessage["d"]["eventData"] = eventData;
|
||||
|
||||
@ -244,6 +250,21 @@ void WebSocketServer::BroadcastEvent(uint64_t requiredIntent, std::string eventT
|
||||
});
|
||||
}
|
||||
|
||||
bool WebSocketServer::onValidate(websocketpp::connection_hdl hdl)
|
||||
{
|
||||
auto conn = _server.get_con_from_hdl(hdl);
|
||||
|
||||
std::vector<std::string> requestedSubprotocols = conn->get_requested_subprotocols();
|
||||
for (auto subprotocol : requestedSubprotocols) {
|
||||
if (subprotocol == "obswebsocket.json" || subprotocol == "obswebsocket.msgpack") {
|
||||
conn->select_subprotocol(subprotocol);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WebSocketServer::onOpen(websocketpp::connection_hdl hdl)
|
||||
{
|
||||
auto conn = _server.get_con_from_hdl(hdl);
|
||||
@ -258,16 +279,12 @@ void WebSocketServer::onOpen(websocketpp::connection_hdl hdl)
|
||||
session->SetRemoteAddress(conn->get_remote_endpoint());
|
||||
session->SetConnectedAt(QDateTime::currentSecsSinceEpoch());
|
||||
session->SetAuthenticationRequired(AuthenticationRequired);
|
||||
std::string contentType = conn->get_request_header("Content-Type");
|
||||
if (contentType == "") {
|
||||
;
|
||||
} else if (contentType == "application/json") {
|
||||
session->SetEncoding(WebSocketEncoding::Json);
|
||||
} else if (contentType == "application/msgpack") {
|
||||
session->SetEncoding(WebSocketEncoding::MsgPack);
|
||||
} else {
|
||||
conn->close(WebSocketCloseCode::InvalidContentType, "Your HTTP `Content-Type` header specifies an invalid encoding type.");
|
||||
return;
|
||||
std::string selectedSubprotocol = conn->get_subprotocol();
|
||||
if (!selectedSubprotocol.empty()) {
|
||||
if (selectedSubprotocol == "obswebsocket.json")
|
||||
session->SetEncoding(WebSocketEncoding::Json);
|
||||
else if (selectedSubprotocol == "obswebsocket.msgpack")
|
||||
session->SetEncoding(WebSocketEncoding::MsgPack);
|
||||
}
|
||||
|
||||
// Build `Hello`
|
||||
@ -438,7 +455,7 @@ void WebSocketServer::onMessage(websocketpp::connection_hdl hdl, websocketpp::se
|
||||
if (!incomingMessage.contains("op")) {
|
||||
if (!session->IgnoreInvalidMessages()) {
|
||||
ret.closeCode = WebSocketServer::WebSocketCloseCode::UnknownOpCode;
|
||||
ret.closeReason = std::string("Your request is missing an `op`.");
|
||||
ret.closeReason = "Your request is missing an `op`.";
|
||||
goto skipProcessing;
|
||||
}
|
||||
return;
|
||||
|
@ -46,8 +46,6 @@ class WebSocketServer : QObject
|
||||
DontClose = 0,
|
||||
// Reserved
|
||||
UnknownReason = 4000,
|
||||
// The requested `Content-Type` specified in the request HTTP header is invalid.
|
||||
InvalidContentType = 4001,
|
||||
// The server was unable to decode the incoming websocket message
|
||||
MessageDecodeError = 4002,
|
||||
// A data key is missing but required
|
||||
@ -99,6 +97,7 @@ class WebSocketServer : QObject
|
||||
private:
|
||||
void ServerRunner();
|
||||
|
||||
bool onValidate(websocketpp::connection_hdl hdl);
|
||||
void onOpen(websocketpp::connection_hdl hdl);
|
||||
void onClose(websocketpp::connection_hdl hdl);
|
||||
void onMessage(websocketpp::connection_hdl hdl, websocketpp::server<websocketpp::config::asio>::message_ptr message);
|
||||
|
@ -62,6 +62,7 @@ void EventHandler::ConnectSourceSignals(obs_source_t *source) // Applies to inpu
|
||||
signal_handler_connect(sh, "volume", HandleInputVolumeChanged, 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);
|
||||
|
||||
if (sourceType == OBS_SOURCE_TYPE_INPUT) {
|
||||
signal_handler_connect(sh, "media_started", HandleMediaInputPlaybackStarted, this);
|
||||
@ -101,6 +102,7 @@ void EventHandler::DisconnectSourceSignals(obs_source_t *source)
|
||||
signal_handler_disconnect(sh, "volume", HandleInputVolumeChanged, 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, "media_started", HandleMediaInputPlaybackStarted, this);
|
||||
signal_handler_disconnect(sh, "media_ended", HandleMediaInputPlaybackEnded, this);
|
||||
signal_handler_disconnect(sh, "media_pause", SourceMediaPauseMultiHandler, this);
|
||||
|
@ -75,6 +75,7 @@ class EventHandler
|
||||
static void HandleInputVolumeChanged(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);
|
||||
|
@ -149,3 +149,36 @@ void EventHandler::HandleInputAudioTracksChanged(void *param, calldata_t *data)
|
||||
eventData["inputAudioTracks"] = inputAudioTracks;
|
||||
eventHandler->_webSocketServer->BroadcastEvent(EventSubscription::Inputs, "InputAudioTracksChanged", eventData);
|
||||
}
|
||||
|
||||
void EventHandler::HandleInputAudioMonitorTypeChanged(void *param, calldata_t *data)
|
||||
{
|
||||
auto eventHandler = reinterpret_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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
json eventData;
|
||||
eventData["inputName"] = obs_source_get_name(source);
|
||||
eventData["monitorType"] = monitorTypeString;
|
||||
eventHandler->_webSocketServer->BroadcastEvent(EventSubscription::Inputs, "InputAudioMonitorTypeChanged", eventData);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <QClipboard>
|
||||
#include <QPainter>
|
||||
#include <QUrl>
|
||||
#include <obs-module.h>
|
||||
|
||||
#include "ConnectInfo.h"
|
||||
@ -45,7 +46,7 @@ void ConnectInfo::showEvent(QShowEvent *event)
|
||||
QString serverPassword;
|
||||
if (conf->AuthRequired) {
|
||||
ui->copyServerPasswordButton->setEnabled(true);
|
||||
serverPassword = conf->ServerPassword;
|
||||
serverPassword = QUrl::toPercentEncoding(conf->ServerPassword);
|
||||
} else {
|
||||
ui->copyServerPasswordButton->setEnabled(false);
|
||||
serverPassword = obs_module_text("OBSWebSocket.ConnectInfo.ServerPasswordPlaceholderText");
|
||||
@ -54,9 +55,9 @@ void ConnectInfo::showEvent(QShowEvent *event)
|
||||
|
||||
QString connectString;
|
||||
if (conf->AuthRequired)
|
||||
connectString = QString("obswebsocket|%1:%2|%3").arg(serverIp).arg(serverPort).arg(serverPassword);
|
||||
connectString = QString("obsws://%1:%2/%3").arg(serverIp).arg(serverPort).arg(serverPassword);
|
||||
else
|
||||
connectString = QString("obswebsocket|%1:%2").arg(serverIp).arg(serverPort);
|
||||
connectString = QString("obsws://%1:%2").arg(serverIp).arg(serverPort);
|
||||
DrawQr(connectString);
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ 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*) {};
|
||||
|
||||
bool obs_module_load(void)
|
||||
{
|
||||
|
@ -18,6 +18,7 @@ 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>;
|
||||
@ -31,6 +32,8 @@ 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;
|
||||
|
@ -1,28 +0,0 @@
|
||||
/*
|
||||
obs-websocket
|
||||
Copyright (C) 2021 Kyle Manning <tt2468@irltoolkit.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/>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <util/base.h>
|
||||
#define blog(level, msg, ...) blog(level, "[obs-websocket] " msg, ##__VA_ARGS__)
|
||||
|
||||
#define OBS_WEBSOCKET_VERSION "5.0.0"
|
||||
|
||||
#define OBS_WEBSOCKET_RPC_VERSION 1
|
||||
|
||||
#define QT_TO_UTF8(str) str.toUtf8().constData()
|
@ -21,7 +21,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
#include <util/base.h>
|
||||
#define blog(level, msg, ...) blog(level, "[obs-websocket] " msg, ##__VA_ARGS__)
|
||||
|
||||
#define OBS_WEBSOCKET_VERSION "@CMAKE_PROJECT_VERSION@"
|
||||
#define OBS_WEBSOCKET_VERSION "@OBS_WEBSOCKET_VERSION@"
|
||||
|
||||
#define OBS_WEBSOCKET_RPC_VERSION @OBS_WEBSOCKET_RPC_VERSION@
|
||||
|
||||
|
@ -59,9 +59,22 @@ const std::map<std::string, RequestMethodHandler> RequestHandler::_handlerMap
|
||||
{"ToggleInputMute", &RequestHandler::ToggleInputMute},
|
||||
{"GetInputVolume", &RequestHandler::GetInputVolume},
|
||||
{"SetInputVolume", &RequestHandler::SetInputVolume},
|
||||
{"GetInputAudioSyncOffset", &RequestHandler::GetInputAudioSyncOffset},
|
||||
{"SetInputAudioSyncOffset", &RequestHandler::SetInputAudioSyncOffset},
|
||||
{"GetInputAudioMonitorType", &RequestHandler::GetInputAudioMonitorType},
|
||||
{"SetInputAudioMonitorType", &RequestHandler::SetInputAudioMonitorType},
|
||||
{"GetInputPropertiesListPropertyItems", &RequestHandler::GetInputPropertiesListPropertyItems},
|
||||
{"PressInputPropertiesButton", &RequestHandler::PressInputPropertiesButton},
|
||||
|
||||
// Scene Items
|
||||
{"GetSceneItemList", &RequestHandler::GetSceneItemList},
|
||||
{"GetGroupSceneItemList", &RequestHandler::GetGroupSceneItemList},
|
||||
{"CreateSceneItem", &RequestHandler::CreateSceneItem},
|
||||
{"RemoveSceneItem", &RequestHandler::RemoveSceneItem},
|
||||
|
||||
// Stream
|
||||
{"GetStreamStatus", &RequestHandler::GetStreamStatus},
|
||||
{"ToggleStream", &RequestHandler::ToggleStream},
|
||||
{"StartStream", &RequestHandler::StartStream},
|
||||
{"StopStream", &RequestHandler::StopStream},
|
||||
};
|
||||
@ -69,7 +82,7 @@ const std::map<std::string, RequestMethodHandler> RequestHandler::_handlerMap
|
||||
RequestResult RequestHandler::ProcessRequest(const Request& request)
|
||||
{
|
||||
if (!request.RequestData.is_null() && !request.RequestData.is_object())
|
||||
return RequestResult::Error(RequestStatus::InvalidRequestParameterDataType, "Your request data is not an object.");
|
||||
return RequestResult::Error(RequestStatus::InvalidRequestParameterType, "Your request data is not an object.");
|
||||
|
||||
if (request.RequestType.empty())
|
||||
return RequestResult::Error(RequestStatus::MissingRequestType, "Your request is missing a `requestType`");
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "rpc/RequestResult.h"
|
||||
#include "../obs-websocket.h"
|
||||
#include "../utils/Obs.h"
|
||||
#include "../plugin-macros.generated.h"
|
||||
|
||||
class RequestHandler;
|
||||
typedef RequestResult(RequestHandler::*RequestMethodHandler)(const Request&);
|
||||
@ -74,9 +75,22 @@ class RequestHandler {
|
||||
RequestResult ToggleInputMute(const Request&);
|
||||
RequestResult GetInputVolume(const Request&);
|
||||
RequestResult SetInputVolume(const Request&);
|
||||
RequestResult GetInputAudioSyncOffset(const Request&);
|
||||
RequestResult SetInputAudioSyncOffset(const Request&);
|
||||
RequestResult GetInputAudioMonitorType(const Request&);
|
||||
RequestResult SetInputAudioMonitorType(const Request&);
|
||||
RequestResult GetInputPropertiesListPropertyItems(const Request&);
|
||||
RequestResult PressInputPropertiesButton(const Request&);
|
||||
|
||||
// Scene Items
|
||||
RequestResult GetSceneItemList(const Request&);
|
||||
RequestResult GetGroupSceneItemList(const Request&);
|
||||
RequestResult CreateSceneItem(const Request&);
|
||||
RequestResult RemoveSceneItem(const Request&);
|
||||
|
||||
// Stream
|
||||
RequestResult GetStreamStatus(const Request&);
|
||||
RequestResult ToggleStream(const Request&);
|
||||
RequestResult StartStream(const Request&);
|
||||
RequestResult StopStream(const Request&);
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
#include <util/config-file.h>
|
||||
|
||||
#include "RequestHandler.h"
|
||||
#include "../plugin-macros.generated.h"
|
||||
|
||||
RequestResult RequestHandler::GetPersistentData(const Request& request)
|
||||
{
|
||||
@ -16,11 +15,11 @@ RequestResult RequestHandler::GetPersistentData(const Request& request)
|
||||
|
||||
std::string persistentDataPath = Utils::Obs::StringHelper::GetCurrentProfilePath();
|
||||
if (realm == "OBS_WEBSOCKET_DATA_REALM_GLOBAL")
|
||||
persistentDataPath += "../../../obsWebSocketPersistentData.json";
|
||||
persistentDataPath += "/../../../obsWebSocketPersistentData.json";
|
||||
else if (realm == "OBS_WEBSOCKET_DATA_REALM_PROFILE")
|
||||
persistentDataPath += "/obsWebSocketPersistentData.json";
|
||||
else
|
||||
return RequestResult::Error(RequestStatus::DataRealmNotFound, "You have specified an invalid persistent data realm.");
|
||||
return RequestResult::Error(RequestStatus::ResourceNotFound, "You have specified an invalid persistent data realm.");
|
||||
|
||||
json responseData;
|
||||
json persistentData;
|
||||
@ -45,11 +44,11 @@ RequestResult RequestHandler::SetPersistentData(const Request& request)
|
||||
|
||||
std::string persistentDataPath = Utils::Obs::StringHelper::GetCurrentProfilePath();
|
||||
if (realm == "OBS_WEBSOCKET_DATA_REALM_GLOBAL")
|
||||
persistentDataPath += "../../../obsWebSocketPersistentData.json";
|
||||
persistentDataPath += "/../../../obsWebSocketPersistentData.json";
|
||||
else if (realm == "OBS_WEBSOCKET_DATA_REALM_PROFILE")
|
||||
persistentDataPath += "/obsWebSocketPersistentData.json";
|
||||
else
|
||||
return RequestResult::Error(RequestStatus::DataRealmNotFound, "You have specified an invalid persistent data realm.");
|
||||
return RequestResult::Error(RequestStatus::ResourceNotFound, "You have specified an invalid persistent data realm.");
|
||||
|
||||
json persistentData = json::object();
|
||||
Utils::Json::GetJsonFileContent(persistentDataPath, persistentData);
|
||||
@ -79,7 +78,7 @@ RequestResult RequestHandler::SetCurrentSceneCollection(const Request& request)
|
||||
|
||||
auto sceneCollections = Utils::Obs::ListHelper::GetSceneCollectionList();
|
||||
if (std::find(sceneCollections.begin(), sceneCollections.end(), sceneCollectionName) == sceneCollections.end())
|
||||
return RequestResult::Error(RequestStatus::SceneCollectionNotFound);
|
||||
return RequestResult::Error(RequestStatus::ResourceNotFound);
|
||||
|
||||
std::string currentSceneCollectionName = Utils::Obs::StringHelper::GetCurrentSceneCollection();
|
||||
// Avoid queueing tasks if nothing will change
|
||||
@ -103,7 +102,7 @@ RequestResult RequestHandler::CreateSceneCollection(const Request& request)
|
||||
|
||||
auto sceneCollections = Utils::Obs::ListHelper::GetSceneCollectionList();
|
||||
if (std::find(sceneCollections.begin(), sceneCollections.end(), sceneCollectionName) != sceneCollections.end())
|
||||
return RequestResult::Error(RequestStatus::SceneCollectionAlreadyExists);
|
||||
return RequestResult::Error(RequestStatus::ResourceAlreadyExists);
|
||||
|
||||
QMainWindow* mainWindow = reinterpret_cast<QMainWindow*>(obs_frontend_get_main_window());
|
||||
bool success = false;
|
||||
@ -133,7 +132,7 @@ RequestResult RequestHandler::SetCurrentProfile(const Request& request)
|
||||
|
||||
auto profiles = Utils::Obs::ListHelper::GetProfileList();
|
||||
if (std::find(profiles.begin(), profiles.end(), profileName) == profiles.end())
|
||||
return RequestResult::Error(RequestStatus::ProfileNotFound);
|
||||
return RequestResult::Error(RequestStatus::ResourceNotFound);
|
||||
|
||||
std::string currentProfileName = Utils::Obs::StringHelper::GetCurrentProfile();
|
||||
// Avoid queueing tasks if nothing will change
|
||||
@ -157,7 +156,7 @@ RequestResult RequestHandler::CreateProfile(const Request& request)
|
||||
|
||||
auto profiles = Utils::Obs::ListHelper::GetProfileList();
|
||||
if (std::find(profiles.begin(), profiles.end(), profileName) != profiles.end())
|
||||
return RequestResult::Error(RequestStatus::ProfileAlreadyExists);
|
||||
return RequestResult::Error(RequestStatus::ResourceAlreadyExists);
|
||||
|
||||
QMainWindow* mainWindow = reinterpret_cast<QMainWindow*>(obs_frontend_get_main_window());
|
||||
QMetaObject::invokeMethod(mainWindow, "NewProfile", Qt::BlockingQueuedConnection, Q_ARG(QString, QString::fromStdString(profileName)));
|
||||
@ -176,10 +175,10 @@ RequestResult RequestHandler::RemoveProfile(const Request& request)
|
||||
|
||||
auto profiles = Utils::Obs::ListHelper::GetProfileList();
|
||||
if (std::find(profiles.begin(), profiles.end(), profileName) == profiles.end())
|
||||
return RequestResult::Error(RequestStatus::ProfileNotFound);
|
||||
return RequestResult::Error(RequestStatus::ResourceNotFound);
|
||||
|
||||
if (profiles.size() < 2)
|
||||
return RequestResult::Error(RequestStatus::NotEnoughProfiles);
|
||||
return RequestResult::Error(RequestStatus::NotEnoughResources);
|
||||
|
||||
QMainWindow* mainWindow = reinterpret_cast<QMainWindow*>(obs_frontend_get_main_window());
|
||||
QMetaObject::invokeMethod(mainWindow, "DeleteProfile", Qt::BlockingQueuedConnection, Q_ARG(QString, QString::fromStdString(profileName)));
|
||||
@ -233,12 +232,12 @@ RequestResult RequestHandler::SetProfileParameter(const Request& request)
|
||||
// Using check helpers here would just make the logic more complicated
|
||||
if (!request.RequestData.contains("parameterValue") || request.RequestData["parameterValue"].is_null()) {
|
||||
if (!config_remove_value(profile, parameterCategory.c_str(), parameterName.c_str()))
|
||||
return RequestResult::Error(RequestStatus::ConfigParameterNotFound);
|
||||
return RequestResult::Error(RequestStatus::ResourceNotFound, "There are no existing instances of that profile parameter.");
|
||||
} else if (request.RequestData["parameterValue"].is_string()) {
|
||||
std::string parameterValue = request.RequestData["parameterValue"];
|
||||
config_set_string(profile, parameterCategory.c_str(), parameterName.c_str(), parameterValue.c_str());
|
||||
} else {
|
||||
return RequestResult::Error(RequestStatus::InvalidRequestParameterDataType, "The parameter `parameterValue` must be a string.");
|
||||
return RequestResult::Error(RequestStatus::InvalidRequestParameterType, "The parameter `parameterValue` must be a string.");
|
||||
}
|
||||
|
||||
return RequestResult::Success();
|
||||
@ -322,7 +321,7 @@ RequestResult RequestHandler::GetStreamServiceSettings(const Request& request)
|
||||
RequestResult RequestHandler::SetStreamServiceSettings(const Request& request)
|
||||
{
|
||||
if (obs_frontend_streaming_active())
|
||||
return RequestResult::Error(RequestStatus::StreamRunning);
|
||||
return RequestResult::Error(RequestStatus::OutputRunning, "You cannot change stream service settings while streaming.");
|
||||
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
@ -350,7 +349,7 @@ RequestResult RequestHandler::SetStreamServiceSettings(const Request& request)
|
||||
OBSService newStreamService = obs_service_create(requestedStreamServiceType.c_str(), "obs_websocket_custom_service", requestedStreamServiceSettings, NULL);
|
||||
// TODO: Check service type here, instead of relying on service creation to fail.
|
||||
if (!newStreamService)
|
||||
return RequestResult::Error(RequestStatus::StreamServiceCreationFailed, "Creating the stream service with the requested streamServiceType failed. It may be an invalid type.");
|
||||
return RequestResult::Error(RequestStatus::ResourceCreationFailed, "Creating the stream service with the requested streamServiceType failed. It may be an invalid type.");
|
||||
|
||||
obs_frontend_set_streaming_service(newStreamService);
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include "../eventhandler/types/EventSubscription.h"
|
||||
#include "../obs-websocket.h"
|
||||
#include "../WebSocketServer.h"
|
||||
#include "../plugin-macros.generated.h"
|
||||
|
||||
RequestResult RequestHandler::GetVersion(const Request& request)
|
||||
{
|
||||
@ -66,7 +65,7 @@ RequestResult RequestHandler::TriggerHotkeyByName(const Request& request)
|
||||
|
||||
obs_hotkey_t *hotkey = Utils::Obs::SearchHelper::GetHotkeyByName(request.RequestData["hotkeyName"]);
|
||||
if (!hotkey)
|
||||
return RequestResult::Error(RequestStatus::HotkeyNotFound);
|
||||
return RequestResult::Error(RequestStatus::ResourceNotFound, "No hotkeys were found by that name.");
|
||||
|
||||
obs_hotkey_trigger_routed_callback(obs_hotkey_get_id(hotkey), true);
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include "RequestHandler.h"
|
||||
#include "../plugin-macros.generated.h"
|
||||
|
||||
RequestResult RequestHandler::GetInputList(const Request& request)
|
||||
{
|
||||
@ -50,7 +49,7 @@ RequestResult RequestHandler::CreateInput(const Request& request)
|
||||
std::string inputName = request.RequestData["inputName"];
|
||||
OBSSourceAutoRelease existingInput = obs_get_source_by_name(inputName.c_str());
|
||||
if (existingInput)
|
||||
return RequestResult::Error(RequestStatus::SourceAlreadyExists, "A source already exists by that input name.");
|
||||
return RequestResult::Error(RequestStatus::ResourceAlreadyExists, "A source already exists by that input name.");
|
||||
|
||||
std::string inputKind = request.RequestData["inputKind"];
|
||||
|
||||
@ -99,7 +98,7 @@ RequestResult RequestHandler::SetInputName(const Request& request)
|
||||
|
||||
OBSSourceAutoRelease existingSource = obs_get_source_by_name(newInputName.c_str());
|
||||
if (existingSource)
|
||||
return RequestResult::Error(RequestStatus::SourceAlreadyExists, "A source already exists by that new input name.");
|
||||
return RequestResult::Error(RequestStatus::ResourceAlreadyExists, "A source already exists by that new input name.");
|
||||
|
||||
obs_source_set_name(input, newInputName.c_str());
|
||||
|
||||
@ -268,3 +267,141 @@ RequestResult RequestHandler::SetInputVolume(const Request& request)
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
RequestResult RequestHandler::GetInputAudioSyncOffset(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
|
||||
if (!input)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
json responseData;
|
||||
// Offset is stored in nanoseconds in OBS.
|
||||
responseData["inputAudioSyncOffset"] = obs_source_get_sync_offset(input) / 1000000;
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
RequestResult RequestHandler::SetInputAudioSyncOffset(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
|
||||
if (!(input && request.ValidateNumber("inputAudioSyncOffset", statusCode, comment, -950, 20000)))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
int64_t syncOffset = request.RequestData["inputAudioSyncOffset"];
|
||||
obs_source_set_sync_offset(input, syncOffset * 1000000);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
RequestResult RequestHandler::GetInputAudioMonitorType(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
|
||||
if (!input)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
json responseData;
|
||||
responseData["monitorType"] = Utils::Obs::StringHelper::GetInputMonitorTypeString(input);
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
RequestResult RequestHandler::SetInputAudioMonitorType(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
|
||||
if (!(input && request.ValidateString("monitorType", statusCode, comment)))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
enum obs_monitoring_type monitorType;
|
||||
std::string monitorTypeString = request.RequestData["monitorType"];
|
||||
if (monitorTypeString == "OBS_MONITORING_TYPE_NONE")
|
||||
monitorType = OBS_MONITORING_TYPE_NONE;
|
||||
else if (monitorTypeString == "OBS_MONITORING_TYPE_MONITOR_ONLY")
|
||||
monitorType = OBS_MONITORING_TYPE_MONITOR_ONLY;
|
||||
else if (monitorTypeString == "OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT")
|
||||
monitorType = OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT;
|
||||
else
|
||||
return RequestResult::Error(RequestStatus::InvalidRequestParameter, std::string("Unknown monitor type: ") + monitorTypeString);
|
||||
|
||||
obs_source_set_monitoring_type(input, monitorType);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
||||
std::vector<json> 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);
|
||||
}
|
||||
ret.push_back(itemData);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
RequestResult RequestHandler::GetInputPropertiesListPropertyItems(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
|
||||
if (!(input && request.ValidateString("propertyName", statusCode, comment)))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
std::string propertyName = request.RequestData["propertyName"];
|
||||
|
||||
OBSPropertiesAutoDestroy inputProperties = obs_source_properties(input);
|
||||
obs_property_t *property = obs_properties_get(inputProperties, propertyName.c_str());
|
||||
if (!property)
|
||||
return RequestResult::Error(RequestStatus::ResourceNotFound, "Unable to find a property by that name.");
|
||||
if (obs_property_get_type(property) != OBS_PROPERTY_LIST)
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceType, "The property found is not a list.");
|
||||
|
||||
json responseData;
|
||||
responseData["propertyItems"] = GetListPropertyItems(property);
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
RequestResult RequestHandler::PressInputPropertiesButton(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
|
||||
if (!(input && request.ValidateString("propertyName", statusCode, comment)))
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
std::string propertyName = request.RequestData["propertyName"];
|
||||
|
||||
OBSPropertiesAutoDestroy inputProperties = obs_source_properties(input);
|
||||
obs_property_t *property = obs_properties_get(inputProperties, propertyName.c_str());
|
||||
if (!property)
|
||||
return RequestResult::Error(RequestStatus::ResourceNotFound, "Unable to find a property by that name.");
|
||||
if (obs_property_get_type(property) != OBS_PROPERTY_BUTTON)
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceType, "The property found is not a button.");
|
||||
if (!obs_property_enabled(property))
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceState, "The property item found is not enabled.");
|
||||
|
||||
obs_property_button_clicked(property, input);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
71
src/requesthandler/RequestHandler_SceneItems.cpp
Normal file
71
src/requesthandler/RequestHandler_SceneItems.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
#include "RequestHandler.h"
|
||||
|
||||
RequestResult RequestHandler::GetSceneItemList(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease scene = request.ValidateScene("sceneName", statusCode, comment);
|
||||
if (!scene)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
json responseData;
|
||||
responseData["sceneItems"] = Utils::Obs::ListHelper::GetSceneItemList(obs_scene_from_source(scene));
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
RequestResult RequestHandler::GetGroupSceneItemList(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease scene = request.ValidateScene("sceneName", statusCode, comment, OBS_WEBSOCKET_SCENE_FILTER_GROUP_ONLY);
|
||||
if (!scene)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
json responseData;
|
||||
responseData["sceneItems"] = Utils::Obs::ListHelper::GetSceneItemList(obs_group_from_source(scene));
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
RequestResult RequestHandler::CreateSceneItem(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSourceAutoRelease sceneSource = request.ValidateScene("sceneName", statusCode, comment);
|
||||
if (!sceneSource)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
OBSScene scene = obs_scene_from_source(sceneSource);
|
||||
|
||||
OBSSourceAutoRelease source = request.ValidateSource("sourceName", statusCode, comment);
|
||||
if (!source)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
if (request.RequestData["sceneName"] == request.RequestData["sourceName"])
|
||||
return RequestResult::Error(RequestStatus::CannotAct, "You cannot create scene item of a scene within itself.");
|
||||
|
||||
bool sceneItemEnabled = true;
|
||||
if (request.RequestData.contains("sceneItemEnabled") && request.RequestData["sceneItemEnabled"].is_boolean())
|
||||
sceneItemEnabled = request.RequestData["sceneItemEnabled"];
|
||||
|
||||
obs_sceneitem_t *sceneItem = Utils::Obs::ActionHelper::CreateSceneItem(source, scene, sceneItemEnabled);
|
||||
|
||||
json responseData;
|
||||
responseData["sceneItemId"] = obs_sceneitem_get_id(sceneItem);
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
RequestResult RequestHandler::RemoveSceneItem(const Request& request)
|
||||
{
|
||||
RequestStatus::RequestStatus statusCode;
|
||||
std::string comment;
|
||||
OBSSceneItemAutoRelease sceneItem = request.ValidateSceneItem("sceneName", "sceneItemId", statusCode, comment);
|
||||
if (!sceneItem)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
obs_sceneitem_remove(sceneItem);
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
#include "RequestHandler.h"
|
||||
#include "../plugin-macros.generated.h"
|
||||
|
||||
RequestResult RequestHandler::GetSceneList(const Request& request)
|
||||
{
|
||||
@ -79,7 +78,7 @@ RequestResult RequestHandler::CreateScene(const Request& request)
|
||||
|
||||
OBSSourceAutoRelease scene = obs_get_source_by_name(sceneName.c_str());
|
||||
if (scene)
|
||||
return RequestResult::Error(RequestStatus::SourceAlreadyExists, "A source already exists by that scene name.");
|
||||
return RequestResult::Error(RequestStatus::ResourceAlreadyExists, "A source already exists by that scene name.");
|
||||
|
||||
obs_scene_t *createdScene = obs_scene_create(sceneName.c_str());
|
||||
obs_scene_release(createdScene);
|
||||
@ -95,6 +94,9 @@ RequestResult RequestHandler::RemoveScene(const Request& request)
|
||||
if (!scene)
|
||||
return RequestResult::Error(statusCode, comment);
|
||||
|
||||
if (Utils::Obs::NumberHelper::GetSceneCount() < 2)
|
||||
return RequestResult::Error(RequestStatus::NotEnoughResources, "You cannot remove the last scene in the collection.");
|
||||
|
||||
obs_source_remove(scene);
|
||||
|
||||
return RequestResult::Success();
|
||||
@ -112,7 +114,7 @@ RequestResult RequestHandler::SetSceneName(const Request& request)
|
||||
|
||||
OBSSourceAutoRelease existingSource = obs_get_source_by_name(newSceneName.c_str());
|
||||
if (existingSource)
|
||||
return RequestResult::Error(RequestStatus::SourceAlreadyExists, "A source already exists by that new scene name.");
|
||||
return RequestResult::Error(RequestStatus::ResourceAlreadyExists, "A source already exists by that new scene name.");
|
||||
|
||||
obs_source_set_name(scene, newSceneName.c_str());
|
||||
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <QDir>
|
||||
|
||||
#include "RequestHandler.h"
|
||||
#include "../plugin-macros.generated.h"
|
||||
|
||||
QImage TakeSourceScreenshot(obs_source_t *source, bool &success, uint32_t requestedWidth = 0, uint32_t requestedHeight = 0)
|
||||
{
|
||||
@ -102,10 +101,10 @@ RequestResult RequestHandler::GetSourceActive(const Request& request)
|
||||
|
||||
OBSSourceAutoRelease source = obs_get_source_by_name(sourceName.c_str());
|
||||
if (!source)
|
||||
return RequestResult::Error(RequestStatus::SourceNotFound);
|
||||
return RequestResult::Error(RequestStatus::ResourceNotFound);
|
||||
|
||||
if (obs_source_get_type(source) != OBS_SOURCE_TYPE_INPUT && obs_source_get_type(source) != OBS_SOURCE_TYPE_SCENE)
|
||||
return RequestResult::Error(RequestStatus::InvalidSourceType, "The specified source is not an input or a scene.");
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceType, "The specified source is not an input or a scene.");
|
||||
|
||||
json responseData;
|
||||
responseData["videoActive"] = obs_source_active(source);
|
||||
@ -124,10 +123,10 @@ RequestResult RequestHandler::GetSourceScreenshot(const Request& request)
|
||||
|
||||
OBSSourceAutoRelease source = obs_get_source_by_name(sourceName.c_str());
|
||||
if (!source)
|
||||
return RequestResult::Error(RequestStatus::SourceNotFound);
|
||||
return RequestResult::Error(RequestStatus::ResourceNotFound);
|
||||
|
||||
if (obs_source_get_type(source) != OBS_SOURCE_TYPE_INPUT && obs_source_get_type(source) != OBS_SOURCE_TYPE_SCENE)
|
||||
return RequestResult::Error(RequestStatus::InvalidSourceType, "The specified source is not an input or a scene.");
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceType, "The specified source is not an input or a scene.");
|
||||
|
||||
std::string imageFormat = request.RequestData["imageFormat"];
|
||||
|
||||
@ -163,14 +162,14 @@ RequestResult RequestHandler::GetSourceScreenshot(const Request& request)
|
||||
QImage renderedImage = TakeSourceScreenshot(source, success, requestedWidth, requestedHeight);
|
||||
|
||||
if (!success)
|
||||
return RequestResult::Error(RequestStatus::ScreenshotRenderFailed);
|
||||
return RequestResult::Error(RequestStatus::RequestProcessingFailed, "Failed to render screenshot.");
|
||||
|
||||
QByteArray encodedImgBytes;
|
||||
QBuffer buffer(&encodedImgBytes);
|
||||
buffer.open(QBuffer::WriteOnly);
|
||||
|
||||
if (!renderedImage.save(&buffer, imageFormat.c_str(), compressionQuality))
|
||||
return RequestResult::Error(RequestStatus::ScreenshotEncodeFailed);
|
||||
return RequestResult::Error(RequestStatus::RequestProcessingFailed, "Failed to encode screenshot.");
|
||||
|
||||
buffer.close();
|
||||
|
||||
@ -192,10 +191,10 @@ RequestResult RequestHandler::SaveSourceScreenshot(const Request& request)
|
||||
|
||||
OBSSourceAutoRelease source = obs_get_source_by_name(sourceName.c_str());
|
||||
if (!source)
|
||||
return RequestResult::Error(RequestStatus::SourceNotFound);
|
||||
return RequestResult::Error(RequestStatus::ResourceNotFound, "No source was found by that name.");
|
||||
|
||||
if (obs_source_get_type(source) != OBS_SOURCE_TYPE_INPUT && obs_source_get_type(source) != OBS_SOURCE_TYPE_SCENE)
|
||||
return RequestResult::Error(RequestStatus::InvalidSourceType, "The specified source is not an input or a scene.");
|
||||
return RequestResult::Error(RequestStatus::InvalidResourceType, "The specified source is not an input or a scene.");
|
||||
|
||||
std::string imageFormat = request.RequestData["imageFormat"];
|
||||
|
||||
@ -231,18 +230,18 @@ RequestResult RequestHandler::SaveSourceScreenshot(const Request& request)
|
||||
QImage renderedImage = TakeSourceScreenshot(source, success, requestedWidth, requestedHeight);
|
||||
|
||||
if (!success)
|
||||
return RequestResult::Error(RequestStatus::ScreenshotRenderFailed);
|
||||
return RequestResult::Error(RequestStatus::RequestProcessingFailed, "Failed to render screenshot.");
|
||||
|
||||
std::string imageFilePath = request.RequestData["imageFilePath"];
|
||||
|
||||
QFileInfo filePathInfo(QString::fromStdString(imageFilePath));
|
||||
if (!filePathInfo.absoluteDir().exists())
|
||||
return RequestResult::Error(RequestStatus::DirectoryNotFound, "The directory for your file path does not exist.");
|
||||
return RequestResult::Error(RequestStatus::ResourceNotFound, "The directory for your file path does not exist.");
|
||||
|
||||
QString absoluteFilePath = filePathInfo.absoluteFilePath();
|
||||
|
||||
if (!renderedImage.save(absoluteFilePath, imageFormat.c_str(), compressionQuality))
|
||||
return RequestResult::Error(RequestStatus::ScreenshotSaveFailed);
|
||||
return RequestResult::Error(RequestStatus::RequestProcessingFailed, "Failed to save screenshot.");
|
||||
|
||||
return RequestResult::Success();
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include "RequestHandler.h"
|
||||
#include "../plugin-macros.generated.h"
|
||||
|
||||
RequestResult RequestHandler::GetStreamStatus(const Request& request)
|
||||
{
|
||||
@ -17,10 +16,24 @@ RequestResult RequestHandler::GetStreamStatus(const Request& request)
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
RequestResult RequestHandler::ToggleStream(const Request& request)
|
||||
{
|
||||
json responseData;
|
||||
if (obs_frontend_streaming_active()) {
|
||||
obs_frontend_streaming_stop();
|
||||
responseData["outputActive"] = false;
|
||||
} else {
|
||||
obs_frontend_streaming_start();
|
||||
responseData["outputActive"] = true;
|
||||
}
|
||||
|
||||
return RequestResult::Success(responseData);
|
||||
}
|
||||
|
||||
RequestResult RequestHandler::StartStream(const Request& request)
|
||||
{
|
||||
if (obs_frontend_streaming_active())
|
||||
return RequestResult::Error(RequestStatus::StreamRunning);
|
||||
return RequestResult::Error(RequestStatus::OutputRunning);
|
||||
|
||||
// TODO: Call signal directly to perform blocking wait
|
||||
obs_frontend_streaming_start();
|
||||
@ -31,7 +44,7 @@ RequestResult RequestHandler::StartStream(const Request& request)
|
||||
RequestResult RequestHandler::StopStream(const Request& request)
|
||||
{
|
||||
if (!obs_frontend_streaming_active())
|
||||
return RequestResult::Error(RequestStatus::StreamNotRunning);
|
||||
return RequestResult::Error(RequestStatus::OutputNotRunning);
|
||||
|
||||
// TODO: Call signal directly to perform blocking wait
|
||||
obs_frontend_streaming_stop();
|
||||
|
@ -42,7 +42,7 @@ const bool Request::ValidateNumber(const std::string keyName, RequestStatus::Req
|
||||
return false;
|
||||
|
||||
if (!RequestData[keyName].is_number()) {
|
||||
statusCode = RequestStatus::InvalidRequestParameterDataType;
|
||||
statusCode = RequestStatus::InvalidRequestParameterType;
|
||||
comment = std::string("The parameter `") + keyName + "` must be a number.";
|
||||
return false;
|
||||
}
|
||||
@ -68,7 +68,7 @@ const bool Request::ValidateString(const std::string keyName, RequestStatus::Req
|
||||
return false;
|
||||
|
||||
if (!RequestData[keyName].is_string()) {
|
||||
statusCode = RequestStatus::InvalidRequestParameterDataType;
|
||||
statusCode = RequestStatus::InvalidRequestParameterType;
|
||||
comment = std::string("The parameter `") + keyName + "` must be a string.";
|
||||
return false;
|
||||
}
|
||||
@ -88,7 +88,7 @@ const bool Request::ValidateBoolean(const std::string keyName, RequestStatus::Re
|
||||
return false;
|
||||
|
||||
if (!RequestData[keyName].is_boolean()) {
|
||||
statusCode = RequestStatus::InvalidRequestParameterDataType;
|
||||
statusCode = RequestStatus::InvalidRequestParameterType;
|
||||
comment = std::string("The parameter `") + keyName + "` must be boolean.";
|
||||
return false;
|
||||
}
|
||||
@ -102,7 +102,7 @@ const bool Request::ValidateObject(const std::string keyName, RequestStatus::Req
|
||||
return false;
|
||||
|
||||
if (!RequestData[keyName].is_object()) {
|
||||
statusCode = RequestStatus::InvalidRequestParameterDataType;
|
||||
statusCode = RequestStatus::InvalidRequestParameterType;
|
||||
comment = std::string("The parameter `") + keyName + "` must be an object.";
|
||||
return false;
|
||||
}
|
||||
@ -122,7 +122,7 @@ const bool Request::ValidateArray(const std::string keyName, RequestStatus::Requ
|
||||
return false;
|
||||
|
||||
if (!RequestData[keyName].is_array()) {
|
||||
statusCode = RequestStatus::InvalidRequestParameterDataType;
|
||||
statusCode = RequestStatus::InvalidRequestParameterType;
|
||||
comment = std::string("The parameter `") + keyName + "` must be an array.";
|
||||
return false;
|
||||
}
|
||||
@ -136,33 +136,47 @@ const bool Request::ValidateArray(const std::string keyName, RequestStatus::Requ
|
||||
return true;
|
||||
}
|
||||
|
||||
obs_source_t *Request::ValidateScene(const std::string keyName, RequestStatus::RequestStatus &statusCode, std::string &comment) const
|
||||
obs_source_t *Request::ValidateSource(const std::string keyName, RequestStatus::RequestStatus &statusCode, std::string &comment) const
|
||||
{
|
||||
if (!ValidateString(keyName, statusCode, comment))
|
||||
return nullptr;
|
||||
|
||||
std::string sceneName = RequestData[keyName];
|
||||
std::string sourceName = RequestData[keyName];
|
||||
|
||||
obs_source_t *ret = obs_get_source_by_name(sceneName.c_str());
|
||||
obs_source_t *ret = obs_get_source_by_name(sourceName.c_str());
|
||||
if (!ret) {
|
||||
statusCode = RequestStatus::SceneNotFound;
|
||||
comment = std::string("No scene was found by the name of `") + sceneName + "`.";
|
||||
statusCode = RequestStatus::ResourceNotFound;
|
||||
comment = std::string("No source was found by the name of `") + sourceName + "`.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
obs_source_t *Request::ValidateScene(const std::string keyName, RequestStatus::RequestStatus &statusCode, std::string &comment, const ObsWebSocketSceneFilter filter) const
|
||||
{
|
||||
obs_source_t *ret = ValidateSource(keyName, statusCode, comment);
|
||||
if (!ret)
|
||||
return nullptr;
|
||||
|
||||
if (obs_source_get_type(ret) != OBS_SOURCE_TYPE_SCENE) {
|
||||
obs_source_release(ret);
|
||||
statusCode = RequestStatus::InvalidSourceType;
|
||||
statusCode = RequestStatus::InvalidResourceType;
|
||||
comment = "The specified source is not a scene.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OBSScene scene = obs_scene_from_source(ret);
|
||||
if (obs_scene_is_group(scene)) {
|
||||
bool isGroup = obs_source_is_group(ret);
|
||||
if (filter == OBS_WEBSOCKET_SCENE_FILTER_SCENE_ONLY && isGroup) {
|
||||
obs_source_release(ret);
|
||||
statusCode = RequestStatus::InvalidSourceType;
|
||||
statusCode = RequestStatus::InvalidResourceType;
|
||||
comment = "The specified source is not a scene.";
|
||||
return nullptr;
|
||||
} else if (filter == OBS_WEBSOCKET_SCENE_FILTER_GROUP_ONLY && !isGroup) {
|
||||
obs_source_release(ret);
|
||||
statusCode = RequestStatus::InvalidResourceType;
|
||||
comment = "The specified source is not a group.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -170,24 +184,41 @@ obs_source_t *Request::ValidateScene(const std::string keyName, RequestStatus::R
|
||||
|
||||
obs_source_t *Request::ValidateInput(const std::string keyName, RequestStatus::RequestStatus &statusCode, std::string &comment) const
|
||||
{
|
||||
if (!ValidateString(keyName, statusCode, comment))
|
||||
obs_source_t *ret = ValidateSource(keyName, statusCode, comment);
|
||||
if (!ret)
|
||||
return nullptr;
|
||||
|
||||
std::string inputName = RequestData[keyName];
|
||||
|
||||
obs_source_t *ret = obs_get_source_by_name(inputName.c_str());
|
||||
if (!ret) {
|
||||
statusCode = RequestStatus::InputNotFound;
|
||||
comment = std::string("No input was found by the name of `") + inputName + "`.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (obs_source_get_type(ret) != OBS_SOURCE_TYPE_INPUT) {
|
||||
obs_source_release(ret);
|
||||
statusCode = RequestStatus::InvalidSourceType;
|
||||
statusCode = RequestStatus::InvalidResourceType;
|
||||
comment = "The specified source is not an input.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
obs_sceneitem_t *Request::ValidateSceneItem(const std::string sceneKeyName, const std::string sceneItemIdKeyName, RequestStatus::RequestStatus &statusCode, std::string &comment, const ObsWebSocketSceneFilter filter) const
|
||||
{
|
||||
OBSSource sceneSource = ValidateScene(sceneKeyName, statusCode, comment, filter);
|
||||
obs_source_release(sceneSource);
|
||||
if (!sceneSource)
|
||||
return nullptr;
|
||||
|
||||
if (!ValidateNumber(sceneItemIdKeyName, statusCode, comment, 0))
|
||||
return nullptr;
|
||||
|
||||
OBSScene scene = obs_scene_from_source(sceneSource);
|
||||
|
||||
int64_t sceneItemId = RequestData[sceneItemIdKeyName];
|
||||
|
||||
OBSSceneItem sceneItem = obs_scene_find_sceneitem_by_id(scene, sceneItemId);
|
||||
if (!sceneItem) {
|
||||
statusCode = RequestStatus::ResourceNotFound;
|
||||
comment = std::string("No scene items were found in scene `") + RequestData[sceneKeyName].get<std::string>() + "` with the ID `" + std::to_string(sceneItemId) + "`.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
obs_sceneitem_addref(sceneItem);
|
||||
return sceneItem;
|
||||
}
|
||||
|
@ -4,6 +4,12 @@
|
||||
#include "../../WebSocketSession.h"
|
||||
#include "../../utils/Json.h"
|
||||
|
||||
enum ObsWebSocketSceneFilter {
|
||||
OBS_WEBSOCKET_SCENE_FILTER_SCENE_ONLY,
|
||||
OBS_WEBSOCKET_SCENE_FILTER_GROUP_ONLY,
|
||||
OBS_WEBSOCKET_SCENE_FILTER_SCENE_OR_GROUP,
|
||||
};
|
||||
|
||||
struct Request
|
||||
{
|
||||
Request(SessionPtr session, const std::string requestType, const json requestData = nullptr);
|
||||
@ -20,8 +26,11 @@ struct Request
|
||||
const bool ValidateObject(const std::string keyName, RequestStatus::RequestStatus &statusCode, std::string &comment, const bool allowEmpty = false) const;
|
||||
const bool ValidateArray(const std::string keyName, RequestStatus::RequestStatus &statusCode, std::string &comment, const bool allowEmpty = false) const;
|
||||
|
||||
obs_source_t *ValidateScene(const std::string keyName, RequestStatus::RequestStatus &statusCode, std::string &comment) const;
|
||||
// All return values have incremented refcounts
|
||||
obs_source_t *ValidateSource(const std::string keyName, RequestStatus::RequestStatus &statusCode, std::string &comment) const;
|
||||
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_source_t *ValidateInput(const std::string keyName, 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;
|
||||
|
||||
SessionPtr Session;
|
||||
const uint8_t RpcVersion;
|
||||
|
@ -11,9 +11,9 @@ namespace RequestStatus {
|
||||
|
||||
// The `requestType` field is missing from the request data
|
||||
MissingRequestType = 203,
|
||||
// The request type is invalid (does not exist)
|
||||
// The request type is invalid or does not exist
|
||||
UnknownRequestType = 204,
|
||||
// Generic error code (comment is expected to be provided)
|
||||
// Generic error code (comment required)
|
||||
GenericError = 205,
|
||||
|
||||
// A required request parameter is missing
|
||||
@ -21,10 +21,10 @@ namespace RequestStatus {
|
||||
// The request does not have a valid requestData object.
|
||||
MissingRequestData = 301,
|
||||
|
||||
// Generic invalid request parameter message
|
||||
// Generic invalid request parameter message (comment required)
|
||||
InvalidRequestParameter = 400,
|
||||
// A request parameter has the wrong data type
|
||||
InvalidRequestParameterDataType = 401,
|
||||
InvalidRequestParameterType = 401,
|
||||
// A request parameter (float or int) is out of valid range
|
||||
RequestParameterOutOfRange = 402,
|
||||
// A request parameter (string or array) is empty and cannot be
|
||||
@ -36,101 +36,35 @@ namespace RequestStatus {
|
||||
OutputRunning = 500,
|
||||
// An output is not running and should be
|
||||
OutputNotRunning = 501,
|
||||
// Stream is running and cannot be
|
||||
StreamRunning = 502,
|
||||
// Stream is not running and should be
|
||||
StreamNotRunning = 503,
|
||||
// Record is running and cannot be
|
||||
RecordRunning = 504,
|
||||
// Record is not running and should be
|
||||
RecordNotRunning = 505,
|
||||
// Record is paused and cannot be
|
||||
RecordPaused = 506,
|
||||
// Replay buffer is running and cannot be
|
||||
ReplayBufferRunning = 507,
|
||||
// Replay buffer is not running and should be
|
||||
ReplayBufferNotRunning = 508,
|
||||
// Replay buffer is disabled and cannot be
|
||||
ReplayBufferDisabled = 509,
|
||||
// An output is paused and should not be
|
||||
OutputPaused = 502,
|
||||
// An output is disabled and should not be
|
||||
OutputDisabled = 503,
|
||||
// Studio mode is active and cannot be
|
||||
StudioModeActive = 510,
|
||||
StudioModeActive = 504,
|
||||
// Studio mode is not active and should be
|
||||
StudioModeNotActive = 511,
|
||||
// Virtualcam is running and cannot be
|
||||
VirtualcamRunning = 512,
|
||||
// Virtualcam is not running and should be
|
||||
VirtualcamNotRunning = 513,
|
||||
StudioModeNotActive = 505,
|
||||
|
||||
// The specified source (obs_source_t) was of the invalid type (Eg. input instead of scene)
|
||||
InvalidSourceType = 600,
|
||||
// The specified source (obs_source_t) was not found (generic for input, filter, transition, scene)
|
||||
SourceNotFound = 601,
|
||||
// The specified source (obs_source_t) already exists. Applicable to inputs, filters, transitions, scenes
|
||||
SourceAlreadyExists = 602,
|
||||
// The specified input (obs_source_t-OBS_SOURCE_TYPE_FILTER) was not found
|
||||
InputNotFound = 603,
|
||||
// The resource was not found
|
||||
ResourceNotFound = 600,
|
||||
// The resource already exists
|
||||
ResourceAlreadyExists = 601,
|
||||
// The type of resource found is invalid
|
||||
InvalidResourceType = 602,
|
||||
// There are not enough instances of the resource in order to perform the request
|
||||
NotEnoughResources = 603,
|
||||
// The state of the resource is invalid. For example, if the resource is blocked from being accessed
|
||||
InvalidResourceState = 604,
|
||||
// The specified input (obs_source_t-OBS_SOURCE_TYPE_INPUT) had the wrong kind
|
||||
InvalidInputKind = 604,
|
||||
// The specified filter (obs_source_t-OBS_SOURCE_TYPE_FILTER) was not found
|
||||
FilterNotFound = 605,
|
||||
// The specified transition (obs_source_t-OBS_SOURCE_TYPE_TRANSITION) was not found
|
||||
TransitionNotFound = 606,
|
||||
// The specified transition (obs_source_t-OBS_SOURCE_TYPE_TRANSITION) does not support setting its position (transition is of fixed type)
|
||||
TransitionDurationFixed = 607,
|
||||
// The specified scene (obs_source_t-OBS_SOURCE_TYPE_SCENE), (obs_scene_t) was not found
|
||||
SceneNotFound = 608,
|
||||
// The specified scene item (obs_sceneitem_t) was not found
|
||||
SceneItemNotFound = 609,
|
||||
// The specified scene collection was not found
|
||||
SceneCollectionNotFound = 610,
|
||||
// The specified profile was not found
|
||||
ProfileNotFound = 611,
|
||||
// The specified output (obs_output_t) was not found
|
||||
OutputNotFound = 612,
|
||||
// The specified encoder (obs_encoder_t) was not found
|
||||
EncoderNotFound = 613,
|
||||
// The specified service (obs_service_t) was not found
|
||||
ServiceNotFound = 614,
|
||||
// The specified hotkey was not found
|
||||
HotkeyNotFound = 615,
|
||||
// The specified directory was not found
|
||||
DirectoryNotFound = 616,
|
||||
// The specified config item (config_t) was not found. Could be section or parameter name
|
||||
ConfigParameterNotFound = 617,
|
||||
// The specified property (obs_properties_t) was not found
|
||||
PropertyNotFound = 618,
|
||||
// The specififed key (OBS_KEY_*) was not found
|
||||
KeyNotFound = 619,
|
||||
// The specified data realm (OBS_WEBSOCKET_DATA_REALM_*) was not found
|
||||
DataRealmNotFound = 620,
|
||||
// The scene collection already exists
|
||||
SceneCollectionAlreadyExists = 621,
|
||||
// There are not enough scene collections to perform the action
|
||||
NotEnoughSceneCollections = 622,
|
||||
// The profile already exists
|
||||
ProfileAlreadyExists = 623,
|
||||
// There are not enough profiles to perform the action
|
||||
NotEnoughProfiles = 624,
|
||||
// There are not enough scenes to perform the action
|
||||
NotEnoughScenes = 625,
|
||||
InvalidInputKind = 605,
|
||||
|
||||
// Processing the request failed unexpectedly
|
||||
RequestProcessingFailed = 700,
|
||||
// Starting the Output failed
|
||||
OutputStartFailed = 701,
|
||||
// Duplicating the scene item failed
|
||||
SceneItemDuplicationFailed = 702,
|
||||
// Rendering the screenshot failed
|
||||
ScreenshotRenderFailed = 703,
|
||||
// Encoding the screenshot failed
|
||||
ScreenshotEncodeFailed = 704,
|
||||
// Saving the screenshot failed
|
||||
ScreenshotSaveFailed = 705,
|
||||
// Creating the directory failed
|
||||
DirectoryCreationFailed = 706,
|
||||
// Creating the resource failed
|
||||
ResourceCreationFailed = 700,
|
||||
// Performing an action on the resource failed
|
||||
ResourceActionFailed = 701,
|
||||
// Processing the request failed unexpectedly (comment required)
|
||||
RequestProcessingFailed = 702,
|
||||
// The combination of request parameters cannot be used to perform an action
|
||||
CannotAct = 707,
|
||||
// Creation of a new stream service failed
|
||||
StreamServiceCreationFailed = 708,
|
||||
CannotAct = 703,
|
||||
};
|
||||
};
|
||||
|
@ -153,6 +153,24 @@ uint64_t Utils::Obs::NumberHelper::GetOutputDuration(obs_output_t *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();
|
||||
@ -217,42 +235,32 @@ std::vector<json> Utils::Obs::ListHelper::GetSceneList()
|
||||
|
||||
std::vector<json> Utils::Obs::ListHelper::GetSceneItemList(obs_scene_t *scene, bool basic)
|
||||
{
|
||||
std::vector<json> ret;
|
||||
std::pair<std::vector<json>, bool> enumData;
|
||||
enumData.second = basic;
|
||||
|
||||
if (basic) {
|
||||
obs_scene_enum_items(scene, [](obs_scene_t* scene, obs_sceneitem_t* sceneItem, void* param) {
|
||||
auto ret = reinterpret_cast<std::vector<json>*>(param);
|
||||
|
||||
json item;
|
||||
item["sceneItemId"] = obs_sceneitem_get_id(sceneItem);
|
||||
// Should be slightly faster than calling obs_sceneitem_get_order_position()
|
||||
item["sceneItemIndex"] = ret->size();
|
||||
|
||||
ret->push_back(item);
|
||||
|
||||
return true;
|
||||
}, &ret);
|
||||
} else {
|
||||
obs_scene_enum_items(scene, [](obs_scene_t* scene, obs_sceneitem_t* sceneItem, void* param) {
|
||||
auto ret = reinterpret_cast<std::vector<json>*>(param);
|
||||
obs_scene_enum_items(scene, [](obs_scene_t* scene, 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);
|
||||
|
||||
json item;
|
||||
item["sceneItemId"] = obs_sceneitem_get_id(sceneItem);
|
||||
item["sceneItemIndex"] = ret->size();
|
||||
item["sourceName"] = obs_source_get_name(itemSource);
|
||||
item["sourceType"] = StringHelper::GetSourceTypeString(itemSource);
|
||||
if (obs_source_get_type(itemSource) == OBS_SOURCE_TYPE_INPUT)
|
||||
item["inputKind"] = obs_source_get_id(itemSource);
|
||||
else if (obs_source_get_type(itemSource) == OBS_SOURCE_TYPE_SCENE)
|
||||
item["isGroup"] = obs_source_is_group(itemSource);
|
||||
}
|
||||
|
||||
ret->push_back(item);
|
||||
enumData->first.push_back(item);
|
||||
|
||||
return true;
|
||||
}, &ret);
|
||||
}
|
||||
return true;
|
||||
}, &enumData);
|
||||
|
||||
return ret;
|
||||
return enumData.first;
|
||||
}
|
||||
|
||||
std::vector<json> Utils::Obs::ListHelper::GetTransitionList()
|
||||
@ -369,7 +377,7 @@ obs_hotkey_t *Utils::Obs::SearchHelper::GetHotkeyByName(std::string name)
|
||||
}
|
||||
|
||||
struct CreateSceneItemData {
|
||||
obs_source_t *input;
|
||||
obs_source_t *source;
|
||||
bool sceneItemEnabled;
|
||||
obs_sceneitem_t *sceneItem;
|
||||
};
|
||||
@ -377,19 +385,19 @@ struct CreateSceneItemData {
|
||||
void CreateSceneItemHelper(void *_data, obs_scene_t *scene)
|
||||
{
|
||||
auto *data = reinterpret_cast<CreateSceneItemData*>(_data);
|
||||
data->sceneItem = obs_scene_add(scene, data->input);
|
||||
data->sceneItem = obs_scene_add(scene, data->source);
|
||||
obs_sceneitem_set_visible(data->sceneItem, data->sceneItemEnabled);
|
||||
}
|
||||
|
||||
obs_sceneitem_t *Utils::Obs::ActionHelper::CreateSceneItem(obs_source_t *input, obs_scene_t *scene, bool sceneItemEnabled)
|
||||
obs_sceneitem_t *Utils::Obs::ActionHelper::CreateSceneItem(obs_source_t *source, obs_scene_t *scene, bool sceneItemEnabled)
|
||||
{
|
||||
// Sanity check for valid scene
|
||||
if (!(input && scene))
|
||||
if (!(source && scene))
|
||||
return nullptr;
|
||||
|
||||
// Create data struct and populate for scene item creation
|
||||
CreateSceneItemData data;
|
||||
data.input = input;
|
||||
data.source = source;
|
||||
data.sceneItemEnabled = sceneItemEnabled;
|
||||
|
||||
// Enter graphics context and create the scene item
|
||||
|
@ -40,6 +40,7 @@ namespace Utils {
|
||||
|
||||
namespace NumberHelper {
|
||||
uint64_t GetOutputDuration(obs_output_t *output);
|
||||
size_t GetSceneCount();
|
||||
}
|
||||
|
||||
namespace ListHelper {
|
||||
@ -63,7 +64,7 @@ namespace Utils {
|
||||
}
|
||||
|
||||
namespace ActionHelper {
|
||||
obs_sceneitem_t *CreateSceneItem(obs_source_t *input, obs_scene_t *scene, bool sceneItemEnabled = true);
|
||||
obs_sceneitem_t *CreateSceneItem(obs_source_t *source, obs_scene_t *scene, bool sceneItemEnabled = true);
|
||||
obs_sceneitem_t *CreateInput(std::string inputName, std::string inputKind, obs_data_t *inputSettings, obs_scene_t *scene, bool sceneItemEnabled = true);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user