diff --git a/BUILDING.md b/BUILDING.md index 83f93a99..0770fd59 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -24,7 +24,7 @@ sudo apt-get install libboost-all-dev git clone --recursive https://github.com/Palakis/obs-websocket.git cd obs-websocket mkdir build && cd build -cmake -DLIBOBS_INCLUDE_DIR="" -DCMAKE_INSTALL_PREFIX=/usr .. +cmake -DLIBOBS_INCLUDE_DIR="" -DCMAKE_INSTALL_PREFIX=/usr -DUSE_UBUNTU_FIX=true .. make -j4 sudo make install ``` diff --git a/CI/build-ubuntu.sh b/CI/build-ubuntu.sh index b19158ae..498840ef 100755 --- a/CI/build-ubuntu.sh +++ b/CI/build-ubuntu.sh @@ -2,5 +2,5 @@ set -ex mkdir build && cd build -cmake -DCMAKE_INSTALL_PREFIX=/usr .. +cmake -DCMAKE_INSTALL_PREFIX=/usr -DUSE_UBUNTU_FIX=true .. make -j4 diff --git a/CI/checkout-cmake-obs-windows.cmd b/CI/checkout-cmake-obs-windows.cmd deleted file mode 100644 index 0fc6c12c..00000000 --- a/CI/checkout-cmake-obs-windows.cmd +++ /dev/null @@ -1,137 +0,0 @@ -@echo off -SETLOCAL EnableDelayedExpansion - -REM Check if obs-studio build exists. -REM If the obs-studio directory does exist, check if the last OBS tag built -REM matches the latest OBS tag. -REM If the tags match, do not build obs-studio. -REM If the tags do not match, build obs-studio. -REM If the obs-studio directory doesn't exist, build obs-studio. -echo Checking for obs-studio build... - -set OBSLatestTagPrePull=0 -set OBSLatestTagPostPull=0 -echo Latest tag pre-pull: %OBSLatestTagPrePull% -echo Latest tag post-pull: %OBSLatestTagPostPull% - -REM Set up the build flag as undefined. -set "BuildOBS=" - -REM Check the last tag successfully built by CI. -if exist "%OBSPath%\obs-studio-last-tag-built.txt" ( - set /p OBSLastTagBuilt=<"%OBSPath%\obs-studio-last-tag-built.txt" -) else ( - set OBSLastTagBuilt=0 -) - -REM If obs-studio directory exists, run git pull and get the latest tag number. -if exist %OBSPath% ( - echo obs-studio directory exists - echo Updating tag info - cd /D %OBSPath% - git describe --tags --abbrev=0 --exclude="*-rc*" > "%OBSPath%\latest-obs-studio-tag-pre-pull.txt" - set /p OBSLatestTagPrePull=<"%OBSPath%\latest-obs-studio-tag-pre-pull.txt" - git checkout master - git pull - git describe --tags --abbrev=0 --exclude="*-rc*" > "%OBSPath%\latest-obs-studio-tag-post-pull.txt" - set /p OBSLatestTagPostPull=<"%OBSPath%\latest-obs-studio-tag-post-pull.txt" - set /p OBSLatestTag=<"%OBSPath%\latest-obs-studio-tag-post-pull.txt" - echo %OBSLatestTagPostPull%> "%OBSPath%\latest-obs-studio-tag.txt" -) - -REM Check the obs-studio tags for mismatches. -REM If a new tag was pulled, set the build flag. -if not %OBSLatestTagPrePull%==%OBSLatestTagPostPull% ( - echo Latest tag pre-pull: %OBSLatestTagPrePull% - echo Latest tag post-pull: %OBSLatestTagPostPull% - echo Tags do not match. Need to rebuild OBS. - set BuildOBS=true -) - -REM If the latest git tag doesn't match the last built tag, set the build flag. -if not %OBSLatestTagPostPull%==%OBSLastTagBuilt% ( - echo Last built OBS tag: %OBSLastTagBuilt% - echo Latest tag post-pull: %OBSLatestTagPostPull% - echo Tags do not match. Need to rebuild OBS. - set BuildOBS=true -) - -REM If obs-studio directory does not exist, clone the git repo, get the latest -REM tag number, and set the build flag. -if not exist %OBSPath% ( - echo obs-studio directory does not exist - git clone https://github.com/obsproject/obs-studio %OBSPath% - cd /D %OBSPath%\ - git describe --tags --abbrev=0 --exclude="*-rc*" > "%OBSPath%\obs-studio-latest-tag.txt" - set /p OBSLatestTag=<"%OBSPath%\obs-studio-latest-tag.txt" - set BuildOBS=true -) - -REM If the needed obs-studio libs for this build_config do not exist, -REM set the build flag. -if not exist %OBSPath%\build32\libobs\%build_config%\obs.lib ( - echo obs-studio\build32\libobs\%build_config%\obs.lib does not exist - set BuildOBS=true -) -if not exist %OBSPath%\build32\UI\obs-frontend-api\%build_config%\obs-frontend-api.lib ( - echo obs-studio\build32\UI\obs-frontend-api\%build_config%\obs-frontend-api.lib does not exist - set BuildOBS=true -) - -REM Some debug info -echo: -echo Latest tag pre-pull: %OBSLatestTagPrePull% -echo Latest tag post-pull: %OBSLatestTagPostPull% -echo Latest tag: %OBSLatestTag% -echo Last built OBS tag: %OBSLastTagBuilt% - -if defined BuildOBS ( - echo BuildOBS: true -) else ( - echo BuildOBS: false -) -echo: - -REM If the build flag is set, build obs-studio. -if defined BuildOBS ( - echo Building obs-studio... - cd /D %OBSPath% - echo git checkout %OBSLatestTag% - git checkout %OBSLatestTag% - echo: - - echo Removing previous build dirs... - if exist build32 rmdir /s /q "%OBSPath%\build32" - if exist build64 rmdir /s /q "%OBSPath%\build64" - - echo Making new build dirs... - mkdir build32 - mkdir build64 - - echo Running cmake for obs-studio %OBSLatestTag% 32-bit... - cd build32 - cmake -G "Visual Studio 16 2019" -A Win32 -DCMAKE_SYSTEM_VERSION=10.0 -DQTDIR="%QTDIR32%" -DDepsPath="%DepsPath32%" -DBUILD_CAPTIONS=true -DDISABLE_PLUGINS=true -DCOPIED_DEPENDENCIES=false -DCOPY_DEPENDENCIES=true .. - echo: - echo: - - echo Running cmake for obs-studio %OBSLatestTag% 64-bit... - cd ..\build64 - cmake -G "Visual Studio 16 2019" -A x64 -DCMAKE_SYSTEM_VERSION=10.0 -DQTDIR="%QTDIR64%" -DDepsPath="%DepsPath64%" -DBUILD_CAPTIONS=true -DDISABLE_PLUGINS=true -DCOPIED_DEPENDENCIES=false -DCOPY_DEPENDENCIES=true .. - echo: - echo: - - REM echo Building obs-studio %OBSLatestTag% 32-bit ^(Build Config: %build_config%^)... - REM call msbuild /m /p:Configuration=%build_config% %OBSPath%\build32\obs-studio.sln - - REM echo Building obs-studio %OBSLatestTag% 64-bit ^(Build Config: %build_config%^)... - REM call msbuild /m /p:Configuration=%build_config% %OBSPath%\build64\obs-studio.sln - - cd .. - git describe --tags --abbrev=0 > "%OBSPath%\obs-studio-last-tag-built.txt" - set /p OBSLastTagBuilt=<"%OBSPath%\obs-studio-last-tag-built.txt" -) else ( - echo Last OBS tag built is: %OBSLastTagBuilt% - echo No need to rebuild OBS. -) - -dir "%OBSPath%\libobs" diff --git a/CI/prepare-obs-windows.cmd b/CI/prepare-obs-windows.cmd new file mode 100644 index 00000000..961fbe17 --- /dev/null +++ b/CI/prepare-obs-windows.cmd @@ -0,0 +1,37 @@ + +@echo off +SETLOCAL EnableDelayedExpansion + +REM If obs-studio directory does not exist, clone the git repo +if not exist %OBSPath% ( + echo obs-studio directory does not exist + git clone https://github.com/obsproject/obs-studio %OBSPath% + cd /D %OBSPath%\ + git describe --tags --abbrev=0 --exclude="*-rc*" > "%OBSPath%\obs-studio-latest-tag.txt" + set /p OBSLatestTag=<"%OBSPath%\obs-studio-latest-tag.txt" +) + +REM Prepare OBS Studio builds + +echo Running CMake... +cd /D %OBSPath% +echo git checkout %OBSLatestTag% +git checkout %OBSLatestTag% +echo: + +if not exist build32 mkdir build32 +if not exist build64 mkdir build64 + +echo Running cmake for obs-studio %OBSLatestTag% 32-bit... +cd build32 +cmake -G "Visual Studio 16 2019" -A Win32 -DCMAKE_SYSTEM_VERSION=10.0 -DQTDIR="%QTDIR32%" -DDepsPath="%DepsPath32%" -DBUILD_CAPTIONS=true -DDISABLE_PLUGINS=true -DCOPIED_DEPENDENCIES=false -DCOPY_DEPENDENCIES=true .. +echo: +echo: + +echo Running cmake for obs-studio %OBSLatestTag% 64-bit... +cd ..\build64 +cmake -G "Visual Studio 16 2019" -A x64 -DCMAKE_SYSTEM_VERSION=10.0 -DQTDIR="%QTDIR64%" -DDepsPath="%DepsPath64%" -DBUILD_CAPTIONS=true -DDISABLE_PLUGINS=true -DCOPIED_DEPENDENCIES=false -DCOPY_DEPENDENCIES=true .. +echo: +echo: + +dir "%OBSPath%\libobs" \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index c7e34a88..9230d197 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -188,6 +188,10 @@ if(UNIX AND NOT APPLE) file(GLOB locale_files data/locale/*.ini) + if(${USE_UBUNTU_FIX}) + install(TARGETS obs-websocket + LIBRARY DESTINATION "/usr/lib/obs-plugins") + endif() install(TARGETS obs-websocket LIBRARY DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/obs-plugins") diff --git a/README.md b/README.md index a0afb404..1c210f96 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ It is **highly recommended** to protect obs-websocket with a password against un ### For developers The server is a typical Websockets server running by default on port 4444 (the port number can be changed in the Settings dialog). -The protocol understood by the server is documented in [PROTOCOL.md](docs/generated/protocol.md). +The protocol understood by the server is documented in [PROTOCOL.md](docs/generated/protocol.md). Here's a list of available language APIs for obs-websocket : - Javascript (browser & nodejs): [obs-websocket-js](https://github.com/haganbmj/obs-websocket-js) by Brendan Hagan @@ -36,6 +36,7 @@ Here's a list of available language APIs for obs-websocket : - Python 3.6+ with asyncio: [simpleobsws](https://github.com/IRLToolkit/simpleobsws) by tt2468 - Java 8+: [obs-websocket-java](https://github.com/Twasi/websocket-obs-java) by TwasiNET - Golang: [go-obs-websocket](https://github.com/christopher-dG/go-obs-websocket) by Chris de Graaf +- HTTP API: [obs-websocket-http](https://github.com/IRLToolkit/obs-websocket-http) by tt2468 I'd like to know what you're building with or for obs-websocket. If you do something in this fashion, feel free to drop me an email at `stephane /dot/ lepin /at/ gmail /dot/ com` ! diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 0f3f10b9..7fce0542 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -68,7 +68,7 @@ jobs: obs | "$(Agent.OS)" path: $(OBSPath) - - script: ./CI/checkout-cmake-obs-windows.cmd + - script: ./CI/prepare-obs-windows.cmd displayName: 'Checkout & CMake OBS Studio' env: build_config: $(build_config) diff --git a/docs/generated/comments.json b/docs/generated/comments.json index 0731d3d7..a6e24f82 100644 --- a/docs/generated/comments.json +++ b/docs/generated/comments.json @@ -5642,11 +5642,14 @@ }, { "subheads": [], - "description": "Get the volume of the specified source.", - "param": "{String} `source` Source name.", + "description": "Get the volume of the specified source. Default response uses mul format, NOT SLIDER PERCENTAGE.", + "param": [ + "{String} `source` Source name.", + "{boolean (optional)} `useDecibel` Output volume in decibels of attenuation instead of amplitude/mul." + ], "return": [ "{String} `name` Source name.", - "{double} `volume` Volume of the source. Between `0.0` and `1.0`.", + "{double} `volume` Volume of the source. Between `0.0` and `1.0` if using mul, under `0.0` if using dB (since it is attenuating).", "{boolean} `muted` Indicates whether the source is muted." ], "api": "requests", @@ -5662,7 +5665,7 @@ { "type": "double", "name": "volume", - "description": "Volume of the source. Between `0.0` and `1.0`." + "description": "Volume of the source. Between `0.0` and `1.0` if using mul, under `0.0` if using dB (since it is attenuating)." }, { "type": "boolean", @@ -5675,6 +5678,11 @@ "type": "String", "name": "source", "description": "Source name." + }, + { + "type": "boolean (optional)", + "name": "useDecibel", + "description": "Output volume in decibels of attenuation instead of amplitude/mul." } ], "names": [ @@ -5705,10 +5713,11 @@ }, { "subheads": [], - "description": "Set the volume of the specified source.", + "description": "Set the volume of the specified source. Default request format uses mul, NOT SLIDER PERCENTAGE.", "param": [ "{String} `source` Source name.", - "{double} `volume` Desired volume. Must be between `0.0` and `1.0`." + "{double} `volume` Desired volume. Must be between `0.0` and `1.0` for mul, and under 0.0 for dB. Note: OBS will interpret dB values under -100.0 as Inf.", + "{boolean (optional)} `useDecibel` Interperet `volume` data as decibels instead of amplitude/mul." ], "api": "requests", "name": "SetVolume", @@ -5723,7 +5732,12 @@ { "type": "double", "name": "volume", - "description": "Desired volume. Must be between `0.0` and `1.0`." + "description": "Desired volume. Must be between `0.0` and `1.0` for mul, and under 0.0 for dB. Note: OBS will interpret dB values under -100.0 as Inf." + }, + { + "type": "boolean (optional)", + "name": "useDecibel", + "description": "Interperet `volume` data as decibels instead of amplitude/mul." } ], "names": [ @@ -6870,6 +6884,7 @@ "name": "GetBrowserSourceProperties", "category": "sources", "since": "4.1.0", + "deprecated": "Since 4.8.0. Prefer the use of GetSourceSettings.", "returns": [ { "type": "String", @@ -6942,6 +6957,12 @@ "description": "4.1.0" } ], + "deprecateds": [ + { + "name": "", + "description": "Since 4.8.0. Prefer the use of GetSourceSettings." + } + ], "heading": { "level": 2, "text": "GetBrowserSourceProperties" @@ -6968,6 +6989,7 @@ "api": "requests", "name": "SetBrowserSourceProperties", "category": "sources", + "deprecated": "Since 4.8.0. Prefer the use of SetSourceSettings.", "since": "4.1.0", "params": [ { @@ -7033,6 +7055,12 @@ "description": "sources" } ], + "deprecateds": [ + { + "name": "", + "description": "Since 4.8.0. Prefer the use of SetSourceSettings." + } + ], "sinces": [ { "name": "", @@ -7596,6 +7624,104 @@ "type": "class", "examples": [] }, + { + "subheads": [], + "description": "Get the audio monitoring type of the specified source.", + "param": "{String} `sourceName` Source name.", + "return": "{String} `monitorType` The monitor type in use. Options: `none`, `monitorOnly`, `monitorAndOutput`.", + "api": "requests", + "name": "GetAudioMonitorType", + "category": "sources", + "since": "4.8.0", + "returns": [ + { + "type": "String", + "name": "monitorType", + "description": "The monitor type in use. Options: `none`, `monitorOnly`, `monitorAndOutput`." + } + ], + "params": [ + { + "type": "String", + "name": "sourceName", + "description": "Source name." + } + ], + "names": [ + { + "name": "", + "description": "GetAudioMonitorType" + } + ], + "categories": [ + { + "name": "", + "description": "sources" + } + ], + "sinces": [ + { + "name": "", + "description": "4.8.0" + } + ], + "heading": { + "level": 2, + "text": "GetAudioMonitorType" + }, + "lead": "", + "type": "class", + "examples": [] + }, + { + "subheads": [], + "description": "Set the audio monitoring type of the specified source.", + "param": [ + "{String} `sourceName` Source name.", + "{String} `monitorType` The monitor type to use. Options: `none`, `monitorOnly`, `monitorAndOutput`." + ], + "api": "requests", + "name": "SetAudioMonitorType", + "category": "sources", + "since": "4.8.0", + "params": [ + { + "type": "String", + "name": "sourceName", + "description": "Source name." + }, + { + "type": "String", + "name": "monitorType", + "description": "The monitor type to use. Options: `none`, `monitorOnly`, `monitorAndOutput`." + } + ], + "names": [ + { + "name": "", + "description": "SetAudioMonitorType" + } + ], + "categories": [ + { + "name": "", + "description": "sources" + } + ], + "sinces": [ + { + "name": "", + "description": "4.8.0" + } + ], + "heading": { + "level": 2, + "text": "SetAudioMonitorType" + }, + "lead": "", + "type": "class", + "examples": [] + }, { "subheads": [], "description": "\n\nAt least `embedPictureFormat` or `saveToFilePath` must be specified.\n\nClients can specify `width` and `height` parameters to receive scaled pictures. Aspect ratio is\npreserved if only one of these two parameters is specified.", @@ -7603,6 +7729,8 @@ "{String} `sourceName` Source name. Note that, since scenes are also sources, you can also provide a scene name.", "{String (optional)} `embedPictureFormat` Format of the Data URI encoded picture. Can be \"png\", \"jpg\", \"jpeg\" or \"bmp\" (or any other value supported by Qt's Image module)", "{String (optional)} `saveToFilePath` Full file path (file extension included) where the captured image is to be saved. Can be in a format different from `pictureFormat`. Can be a relative path.", + "{String (optional)} `fileFormat` Format to save the image file as (one of the values provided in the `supported-image-export-formats` response field of `GetVersion`). If not specified, tries to guess based on file extension.", + "{int (optional)} `compressionQuality` Compression ratio between -1 and 100 to write the image with. -1 is automatic, 1 is smallest file/most compression, 100 is largest file/least compression. Varies with image type.", "{int (optional)} `width` Screenshot width. Defaults to the source's base width.", "{int (optional)} `height` Screenshot height. Defaults to the source's base height." ], @@ -7648,6 +7776,16 @@ "name": "saveToFilePath", "description": "Full file path (file extension included) where the captured image is to be saved. Can be in a format different from `pictureFormat`. Can be a relative path." }, + { + "type": "String (optional)", + "name": "fileFormat", + "description": "Format to save the image file as (one of the values provided in the `supported-image-export-formats` response field of `GetVersion`). If not specified, tries to guess based on file extension." + }, + { + "type": "int (optional)", + "name": "compressionQuality", + "description": "Compression ratio between -1 and 100 to write the image with. -1 is automatic, 1 is smallest file/most compression, 100 is largest file/least compression. Varies with image type." + }, { "type": "int (optional)", "name": "width", @@ -8664,6 +8802,47 @@ "lead": "", "type": "class", "examples": [] + }, + { + "subheads": [], + "description": "Get the position of the current transition.", + "return": "{double} `position` current transition position. This value will be between 0.0 and 1.0. Note: Transition returns 1.0 when not active.", + "api": "requests", + "name": "GetTransitionPosition", + "category": "transitions", + "since": "4.8.0", + "returns": [ + { + "type": "double", + "name": "position", + "description": "current transition position. This value will be between 0.0 and 1.0. Note: Transition returns 1.0 when not active." + } + ], + "names": [ + { + "name": "", + "description": "GetTransitionPosition" + } + ], + "categories": [ + { + "name": "", + "description": "transitions" + } + ], + "sinces": [ + { + "name": "", + "description": "4.8.0" + } + ], + "heading": { + "level": 2, + "text": "GetTransitionPosition" + }, + "lead": "", + "type": "class", + "examples": [] } ] } diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index 5325ee13..b7ff296b 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -1,6 +1,6 @@ -# obs-websocket 4.7.0 protocol reference +# obs-websocket 4.8.0 protocol reference # General Introduction Messages are exchanged between the client and the server as JSON objects. @@ -191,6 +191,8 @@ auth_response = base64_encode(auth_response_hash) + [MoveSourceFilter](#movesourcefilter) + [SetSourceFilterSettings](#setsourcefiltersettings) + [SetSourceFilterVisibility](#setsourcefiltervisibility) + + [GetAudioMonitorType](#getaudiomonitortype) + + [SetAudioMonitorType](#setaudiomonitortype) + [TakeSourceScreenshot](#takesourcescreenshot) * [Streaming](#streaming-1) + [GetStreamingStatus](#getstreamingstatus) @@ -215,6 +217,7 @@ auth_response = base64_encode(auth_response_hash) + [SetCurrentTransition](#setcurrenttransition) + [SetTransitionDuration](#settransitionduration) + [GetTransitionDuration](#gettransitionduration) + + [GetTransitionPosition](#gettransitionposition) @@ -2266,13 +2269,14 @@ _No specified parameters._ - Added in v4.0.0 -Get the volume of the specified source. +Get the volume of the specified source. Default response uses mul format, NOT SLIDER PERCENTAGE. **Request Fields:** | Name | Type | Description | | ---- | :---: | ------------| | `source` | _String_ | Source name. | +| `useDecibel` | _boolean (optional)_ | Output volume in decibels of attenuation instead of amplitude/mul. | **Response Items:** @@ -2280,7 +2284,7 @@ Get the volume of the specified source. | Name | Type | Description | | ---- | :---: | ------------| | `name` | _String_ | Source name. | -| `volume` | _double_ | Volume of the source. Between `0.0` and `1.0`. | +| `volume` | _double_ | Volume of the source. Between `0.0` and `1.0` if using mul, under `0.0` if using dB (since it is attenuating). | | `muted` | _boolean_ | Indicates whether the source is muted. | @@ -2291,14 +2295,15 @@ Get the volume of the specified source. - Added in v4.0.0 -Set the volume of the specified source. +Set the volume of the specified source. Default request format uses mul, NOT SLIDER PERCENTAGE. **Request Fields:** | Name | Type | Description | | ---- | :---: | ------------| | `source` | _String_ | Source name. | -| `volume` | _double_ | Desired volume. Must be between `0.0` and `1.0`. | +| `volume` | _double_ | Desired volume. Must be between `0.0` and `1.0` for mul, and under 0.0 for dB. Note: OBS will interpret dB values under -100.0 as Inf. | +| `useDecibel` | _boolean (optional)_ | Interperet `volume` data as decibels instead of amplitude/mul. | **Response Items:** @@ -2643,6 +2648,7 @@ _No additional response items._ ### GetBrowserSourceProperties +- **⚠️ Deprecated. Since 4.8.0. Prefer the use of GetSourceSettings. ⚠️** - Added in v4.1.0 @@ -2674,6 +2680,7 @@ Get current properties for a Browser Source. ### SetBrowserSourceProperties +- **⚠️ Deprecated. Since 4.8.0. Prefer the use of SetSourceSettings. ⚠️** - Added in v4.1.0 @@ -2905,6 +2912,50 @@ Change the visibility/enabled state of a filter | `filterEnabled` | _Boolean_ | New filter state | +**Response Items:** + +_No additional response items._ + +--- + +### GetAudioMonitorType + + +- Added in v4.8.0 + +Get the audio monitoring type of the specified source. + +**Request Fields:** + +| Name | Type | Description | +| ---- | :---: | ------------| +| `sourceName` | _String_ | Source name. | + + +**Response Items:** + +| Name | Type | Description | +| ---- | :---: | ------------| +| `monitorType` | _String_ | The monitor type in use. Options: `none`, `monitorOnly`, `monitorAndOutput`. | + + +--- + +### SetAudioMonitorType + + +- Added in v4.8.0 + +Set the audio monitoring type of the specified source. + +**Request Fields:** + +| Name | Type | Description | +| ---- | :---: | ------------| +| `sourceName` | _String_ | Source name. | +| `monitorType` | _String_ | The monitor type to use. Options: `none`, `monitorOnly`, `monitorAndOutput`. | + + **Response Items:** _No additional response items._ @@ -2930,6 +2981,8 @@ preserved if only one of these two parameters is specified. | `sourceName` | _String_ | Source name. Note that, since scenes are also sources, you can also provide a scene name. | | `embedPictureFormat` | _String (optional)_ | Format of the Data URI encoded picture. Can be "png", "jpg", "jpeg" or "bmp" (or any other value supported by Qt's Image module) | | `saveToFilePath` | _String (optional)_ | Full file path (file extension included) where the captured image is to be saved. Can be in a format different from `pictureFormat`. Can be a relative path. | +| `fileFormat` | _String (optional)_ | Format to save the image file as (one of the values provided in the `supported-image-export-formats` response field of `GetVersion`). If not specified, tries to guess based on file extension. | +| `compressionQuality` | _int (optional)_ | Compression ratio between -1 and 100 to write the image with. -1 is automatic, 1 is smallest file/most compression, 100 is largest file/least compression. Varies with image type. | | `width` | _int (optional)_ | Screenshot width. Defaults to the source's base width. | | `height` | _int (optional)_ | Screenshot height. Defaults to the source's base height. | @@ -3370,3 +3423,23 @@ _No specified parameters._ --- +### GetTransitionPosition + + +- Added in v4.8.0 + +Get the position of the current transition. + +**Request Fields:** + +_No specified parameters._ + +**Response Items:** + +| Name | Type | Description | +| ---- | :---: | ------------| +| `position` | _double_ | current transition position. This value will be between 0.0 and 1.0. Note: Transition returns 1.0 when not active. | + + +--- + diff --git a/docs/partials/introduction.md b/docs/partials/introduction.md index c8de4503..c63a52cd 100644 --- a/docs/partials/introduction.md +++ b/docs/partials/introduction.md @@ -1,4 +1,4 @@ -# obs-websocket 4.7.0 protocol reference +# obs-websocket 4.8.0 protocol reference # General Introduction Messages are exchanged between the client and the server as JSON objects. diff --git a/src/WSRequestHandler.cpp b/src/WSRequestHandler.cpp index 6f637d19..702d75fc 100644 --- a/src/WSRequestHandler.cpp +++ b/src/WSRequestHandler.cpp @@ -84,6 +84,7 @@ const QHash WSRequestHandler::messageMap { { "SetCurrentTransition", &WSRequestHandler::SetCurrentTransition }, { "SetTransitionDuration", &WSRequestHandler::SetTransitionDuration }, { "GetTransitionDuration", &WSRequestHandler::GetTransitionDuration }, + { "GetTransitionPosition", &WSRequestHandler::GetTransitionPosition }, { "SetVolume", &WSRequestHandler::SetVolume }, { "GetVolume", &WSRequestHandler::GetVolume }, @@ -97,6 +98,8 @@ const QHash WSRequestHandler::messageMap { { "GetSourceTypesList", &WSRequestHandler::GetSourceTypesList }, { "GetSourceSettings", &WSRequestHandler::GetSourceSettings }, { "SetSourceSettings", &WSRequestHandler::SetSourceSettings }, + { "GetAudioMonitorType", &WSRequestHandler::GetAudioMonitorType }, + { "SetAudioMonitorType", &WSRequestHandler::SetAudioMonitorType }, { "TakeSourceScreenshot", &WSRequestHandler::TakeSourceScreenshot }, { "GetSourceFilters", &WSRequestHandler::GetSourceFilters }, diff --git a/src/WSRequestHandler.h b/src/WSRequestHandler.h index 6b82eb0d..6f31265b 100644 --- a/src/WSRequestHandler.h +++ b/src/WSRequestHandler.h @@ -99,6 +99,9 @@ class WSRequestHandler { RpcResponse GetTransitionList(const RpcRequest&); RpcResponse GetCurrentTransition(const RpcRequest&); RpcResponse SetCurrentTransition(const RpcRequest&); + RpcResponse SetTransitionDuration(const RpcRequest&); + RpcResponse GetTransitionDuration(const RpcRequest&); + RpcResponse GetTransitionPosition(const RpcRequest&); RpcResponse SetVolume(const RpcRequest&); RpcResponse GetVolume(const RpcRequest&); @@ -112,6 +115,8 @@ class WSRequestHandler { RpcResponse GetSourceTypesList(const RpcRequest&); RpcResponse GetSourceSettings(const RpcRequest&); RpcResponse SetSourceSettings(const RpcRequest&); + RpcResponse GetAudioMonitorType(const RpcRequest&); + RpcResponse SetAudioMonitorType(const RpcRequest&); RpcResponse TakeSourceScreenshot(const RpcRequest&); RpcResponse GetSourceFilters(const RpcRequest&); @@ -138,9 +143,6 @@ class WSRequestHandler { RpcResponse SendCaptions(const RpcRequest&); #endif - RpcResponse SetTransitionDuration(const RpcRequest&); - RpcResponse GetTransitionDuration(const RpcRequest&); - RpcResponse GetStudioModeStatus(const RpcRequest&); RpcResponse GetPreviewScene(const RpcRequest&); RpcResponse SetPreviewScene(const RpcRequest&); diff --git a/src/WSRequestHandler_Sources.cpp b/src/WSRequestHandler_Sources.cpp index 579f76b4..a9ef5bef 100644 --- a/src/WSRequestHandler_Sources.cpp +++ b/src/WSRequestHandler_Sources.cpp @@ -15,7 +15,7 @@ bool isTextGDIPlusSource(const QString& sourceKind) bool isTextFreeType2Source(const QString& sourceKind) { - return (sourceKind == "text_ft2" || sourceKind == "text_ft2_v2"); + return (sourceKind == "text_ft2_source" || sourceKind == "text_ft2_source_v2"); } /** @@ -156,12 +156,13 @@ RpcResponse WSRequestHandler::GetSourceTypesList(const RpcRequest& request) } /** -* Get the volume of the specified source. +* Get the volume of the specified source. Default response uses mul format, NOT SLIDER PERCENTAGE. * * @param {String} `source` Source name. +* @param {boolean (optional)} `useDecibel` Output volume in decibels of attenuation instead of amplitude/mul. * * @return {String} `name` Source name. -* @return {double} `volume` Volume of the source. Between `0.0` and `1.0`. +* @return {double} `volume` Volume of the source. Between `0.0` and `1.0` if using mul, under `0.0` if using dB (since it is attenuating). * @return {boolean} `muted` Indicates whether the source is muted. * * @api requests @@ -185,35 +186,46 @@ RpcResponse WSRequestHandler::GetVolume(const RpcRequest& request) return request.failed("specified source doesn't exist"); } + float volume = obs_source_get_volume(source); + + bool useDecibel = obs_data_get_bool(request.parameters(), "useDecibel"); + if (useDecibel) { + volume = obs_mul_to_db(volume); + } + OBSDataAutoRelease response = obs_data_create(); obs_data_set_string(response, "name", obs_source_get_name(source)); - obs_data_set_double(response, "volume", obs_source_get_volume(source)); + obs_data_set_double(response, "volume", volume); obs_data_set_bool(response, "muted", obs_source_muted(source)); - return request.success(response); } /** - * Set the volume of the specified source. - * - * @param {String} `source` Source name. - * @param {double} `volume` Desired volume. Must be between `0.0` and `1.0`. - * - * @api requests - * @name SetVolume - * @category sources - * @since 4.0.0 - */ +* Set the volume of the specified source. Default request format uses mul, NOT SLIDER PERCENTAGE. +* +* @param {String} `source` Source name. +* @param {double} `volume` Desired volume. Must be between `0.0` and `1.0` for mul, and under 0.0 for dB. Note: OBS will interpret dB values under -100.0 as Inf. +* @param {boolean (optional)} `useDecibel` Interperet `volume` data as decibels instead of amplitude/mul. +* +* @api requests +* @name SetVolume +* @category sources +* @since 4.0.0 +*/ RpcResponse WSRequestHandler::SetVolume(const RpcRequest& request) { if (!request.hasField("source") || !request.hasField("volume")) { return request.failed("missing request parameters"); } + bool useDecibel = obs_data_get_bool(request.parameters(), "useDecibel"); + QString sourceName = obs_data_get_string(request.parameters(), "source"); float sourceVolume = obs_data_get_double(request.parameters(), "volume"); - if (sourceName.isEmpty() || sourceVolume < 0.0 || sourceVolume > 1.0) { + bool isNotValidDecibel = (useDecibel && sourceVolume > 0.0); + bool isNotValidMul = (!useDecibel && (sourceVolume < 0.0 || sourceVolume > 1.0)); + if (sourceName.isEmpty() || isNotValidDecibel || isNotValidMul) { return request.failed("invalid request parameters"); } @@ -222,7 +234,11 @@ RpcResponse WSRequestHandler::SetVolume(const RpcRequest& request) return request.failed("specified source doesn't exist"); } + if (useDecibel) { + sourceVolume = obs_db_to_mul(sourceVolume); + } obs_source_set_volume(source, sourceVolume); + return request.success(); } @@ -919,6 +935,7 @@ RpcResponse WSRequestHandler::SetTextFreetype2Properties(const RpcRequest& reque * @name GetBrowserSourceProperties * @category sources * @since 4.1.0 + * @deprecated Since 4.8.0. Prefer the use of GetSourceSettings. */ RpcResponse WSRequestHandler::GetBrowserSourceProperties(const RpcRequest& request) { @@ -960,6 +977,7 @@ RpcResponse WSRequestHandler::GetBrowserSourceProperties(const RpcRequest& reque * @api requests * @name SetBrowserSourceProperties * @category sources + * @deprecated Since 4.8.0. Prefer the use of SetSourceSettings. * @since 4.1.0 */ RpcResponse WSRequestHandler::SetBrowserSourceProperties(const RpcRequest& request) @@ -1424,6 +1442,99 @@ RpcResponse WSRequestHandler::SetSourceFilterVisibility(const RpcRequest& reques return request.success(); } +/** +* Get the audio monitoring type of the specified source. +* +* @param {String} `sourceName` Source name. +* +* @return {String} `monitorType` The monitor type in use. Options: `none`, `monitorOnly`, `monitorAndOutput`. +* +* @api requests +* @name GetAudioMonitorType +* @category sources +* @since 4.8.0 +*/ +RpcResponse WSRequestHandler::GetAudioMonitorType(const RpcRequest& request) + { + if (!request.hasField("sourceName")) { + return request.failed("missing request parameters"); + } + + QString sourceName = obs_data_get_string(request.parameters(), "sourceName"); + + if (sourceName.isEmpty()) { + return request.failed("invalid request parameters"); + } + + OBSSourceAutoRelease source = obs_get_source_by_name(sourceName.toUtf8()); + if (!source) { + return request.failed("specified source doesn't exist"); + } + + OBSDataAutoRelease response = obs_data_create(); + + QString monitorType; + enum obs_monitoring_type mtype = obs_source_get_monitoring_type(source); + switch (mtype) { + case OBS_MONITORING_TYPE_NONE: + monitorType = "none"; + break; + case OBS_MONITORING_TYPE_MONITOR_ONLY: + monitorType = "monitorOnly"; + break; + case OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT: + monitorType = "monitorAndOutput"; + break; + default: + monitorType = "unknown"; + break; + } + obs_data_set_string(response, "monitorType", monitorType.toUtf8()); + + return request.success(response); +} + +/** +* Set the audio monitoring type of the specified source. +* +* @param {String} `sourceName` Source name. +* @param {String} `monitorType` The monitor type to use. Options: `none`, `monitorOnly`, `monitorAndOutput`. +* +* @api requests +* @name SetAudioMonitorType +* @category sources +* @since 4.8.0 +*/ +RpcResponse WSRequestHandler::SetAudioMonitorType(const RpcRequest& request) + { + if (!request.hasField("sourceName") || !request.hasField("monitorType")) { + return request.failed("missing request parameters"); + } + + QString sourceName = obs_data_get_string(request.parameters(), "sourceName"); + QString monitorType = obs_data_get_string(request.parameters(), "monitorType"); + + if (sourceName.isEmpty() || monitorType.isEmpty()) { + return request.failed("invalid request parameters"); + } + + OBSSourceAutoRelease source = obs_get_source_by_name(sourceName.toUtf8()); + if (!source) { + return request.failed("specified source doesn't exist"); + } + + if (monitorType == "none") { + obs_source_set_monitoring_type(source, OBS_MONITORING_TYPE_NONE); + } else if (monitorType == "monitorOnly") { + obs_source_set_monitoring_type(source, OBS_MONITORING_TYPE_MONITOR_ONLY); + } else if (monitorType == "monitorAndOutput") { + obs_source_set_monitoring_type(source, OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT); + } else { + return request.failed("invalid monitorType"); + } + return request.success(); +} + /** * Takes a picture snapshot of a source and then can either or both: * - Send it over as a Data URI (base64-encoded data) in the response (by specifying `embedPictureFormat` in the request) @@ -1437,6 +1548,8 @@ RpcResponse WSRequestHandler::SetSourceFilterVisibility(const RpcRequest& reques * @param {String} `sourceName` Source name. Note that, since scenes are also sources, you can also provide a scene name. * @param {String (optional)} `embedPictureFormat` Format of the Data URI encoded picture. Can be "png", "jpg", "jpeg" or "bmp" (or any other value supported by Qt's Image module) * @param {String (optional)} `saveToFilePath` Full file path (file extension included) where the captured image is to be saved. Can be in a format different from `pictureFormat`. Can be a relative path. +* @param {String (optional)} `fileFormat` Format to save the image file as (one of the values provided in the `supported-image-export-formats` response field of `GetVersion`). If not specified, tries to guess based on file extension. +* @param {int (optional)} `compressionQuality` Compression ratio between -1 and 100 to write the image with. -1 is automatic, 1 is smallest file/most compression, 100 is largest file/least compression. Varies with image type. * @param {int (optional)} `width` Screenshot width. Defaults to the source's base width. * @param {int (optional)} `height` Screenshot height. Defaults to the source's base height. * @@ -1539,20 +1652,30 @@ RpcResponse WSRequestHandler::TakeSourceScreenshot(const RpcRequest& request) { OBSDataAutoRelease response = obs_data_create(); + int compressionQuality {-1}; + if (request.hasField("compressionQuality")) { + compressionQuality = obs_data_get_int(request.parameters(), "compressionQuality"); + + if (compressionQuality < -1 || compressionQuality > 100) { + QString errorMessage = QString("compression quality out of range: %1").arg(compressionQuality); + return request.failed(errorMessage.toUtf8()); + } + } + if (request.hasField("embedPictureFormat")) { const char* pictureFormat = obs_data_get_string(request.parameters(), "embedPictureFormat"); QByteArrayList supportedFormats = QImageWriter::supportedImageFormats(); if (!supportedFormats.contains(pictureFormat)) { - QString errorMessage = QString("Unsupported picture format: %1").arg(pictureFormat); + QString errorMessage = QString("unsupported picture format: %1").arg(pictureFormat); return request.failed(errorMessage.toUtf8()); } QByteArray encodedImgBytes; QBuffer buffer(&encodedImgBytes); buffer.open(QBuffer::WriteOnly); - if (!sourceImage.save(&buffer, pictureFormat)) { - return request.failed("Embed image encoding failed"); + if (!sourceImage.save(&buffer, pictureFormat, compressionQuality)) { + return request.failed("embed image encoding failed"); } buffer.close(); @@ -1569,7 +1692,18 @@ RpcResponse WSRequestHandler::TakeSourceScreenshot(const RpcRequest& request) { QFileInfo filePathInfo(filePathStr); QString absoluteFilePath = filePathInfo.absoluteFilePath(); - if (!sourceImage.save(absoluteFilePath)) { + const char* fileFormat = nullptr; + if (request.hasField("fileFormat")) { + fileFormat = obs_data_get_string(request.parameters(), "fileFormat"); + QByteArrayList supportedFormats = QImageWriter::supportedImageFormats(); + + if (!supportedFormats.contains(fileFormat)) { + QString errorMessage = QString("unsupported file format: %1").arg(fileFormat); + return request.failed(errorMessage.toUtf8()); + } + } + + if (!sourceImage.save(absoluteFilePath, fileFormat, compressionQuality)) { return request.failed("Image save failed"); } obs_data_set_string(response, "imageFile", absoluteFilePath.toUtf8()); diff --git a/src/WSRequestHandler_StudioMode.cpp b/src/WSRequestHandler_StudioMode.cpp index fb958f3b..badae29d 100644 --- a/src/WSRequestHandler_StudioMode.cpp +++ b/src/WSRequestHandler_StudioMode.cpp @@ -133,6 +133,9 @@ RpcResponse WSRequestHandler::TransitionToProgram(const RpcRequest& request) { * @since 4.1.0 */ RpcResponse WSRequestHandler::EnableStudioMode(const RpcRequest& request) { + if (obs_frontend_preview_program_mode_active()) { + return request.failed("studio mode already active"); + } obs_queue_task(OBS_TASK_UI, [](void* param) { obs_frontend_set_preview_program_mode(true); @@ -150,6 +153,9 @@ RpcResponse WSRequestHandler::EnableStudioMode(const RpcRequest& request) { * @since 4.1.0 */ RpcResponse WSRequestHandler::DisableStudioMode(const RpcRequest& request) { + if (!obs_frontend_preview_program_mode_active()) { + return request.failed("studio mode not active"); + } obs_queue_task(OBS_TASK_UI, [](void* param) { obs_frontend_set_preview_program_mode(false); diff --git a/src/WSRequestHandler_Transitions.cpp b/src/WSRequestHandler_Transitions.cpp index 7c22687c..9bcee450 100644 --- a/src/WSRequestHandler_Transitions.cpp +++ b/src/WSRequestHandler_Transitions.cpp @@ -120,3 +120,22 @@ RpcResponse WSRequestHandler::GetTransitionDuration(const RpcRequest& request) { obs_data_set_int(response, "transition-duration", obs_frontend_get_transition_duration()); return request.success(response); } + +/** + * Get the position of the current transition. + * + * @return {double} `position` current transition position. This value will be between 0.0 and 1.0. Note: Transition returns 1.0 when not active. + * + * @api requests + * @name GetTransitionPosition + * @category transitions + * @since 4.8.0 + */ +RpcResponse WSRequestHandler::GetTransitionPosition(const RpcRequest& request) { + OBSSourceAutoRelease currentTransition = obs_frontend_get_current_transition(); + + OBSDataAutoRelease response = obs_data_create(); + obs_data_set_double(response, "position", obs_transition_get_time(currentTransition)); + + return request.success(response); +}