Merge branch '4.x-current' into category-mediacontrol

This commit is contained in:
tt2468
2020-05-16 11:41:30 -07:00
15 changed files with 498 additions and 177 deletions

View File

@ -24,7 +24,7 @@ sudo apt-get install libboost-all-dev
git clone --recursive https://github.com/Palakis/obs-websocket.git git clone --recursive https://github.com/Palakis/obs-websocket.git
cd obs-websocket cd obs-websocket
mkdir build && cd build mkdir build && cd build
cmake -DLIBOBS_INCLUDE_DIR="<path to the libobs sub-folder in obs-studio's source code>" -DCMAKE_INSTALL_PREFIX=/usr .. cmake -DLIBOBS_INCLUDE_DIR="<path to the libobs sub-folder in obs-studio's source code>" -DCMAKE_INSTALL_PREFIX=/usr -DUSE_UBUNTU_FIX=true ..
make -j4 make -j4
sudo make install sudo make install
``` ```

View File

@ -2,5 +2,5 @@
set -ex set -ex
mkdir build && cd build mkdir build && cd build
cmake -DCMAKE_INSTALL_PREFIX=/usr .. cmake -DCMAKE_INSTALL_PREFIX=/usr -DUSE_UBUNTU_FIX=true ..
make -j4 make -j4

View File

@ -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"

View File

@ -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"

View File

@ -188,6 +188,10 @@ if(UNIX AND NOT APPLE)
file(GLOB locale_files data/locale/*.ini) 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 install(TARGETS obs-websocket
LIBRARY DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/obs-plugins") LIBRARY DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/obs-plugins")

View File

@ -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 - 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 - 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 - 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` ! 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` !

View File

@ -68,7 +68,7 @@ jobs:
obs | "$(Agent.OS)" obs | "$(Agent.OS)"
path: $(OBSPath) path: $(OBSPath)
- script: ./CI/checkout-cmake-obs-windows.cmd - script: ./CI/prepare-obs-windows.cmd
displayName: 'Checkout & CMake OBS Studio' displayName: 'Checkout & CMake OBS Studio'
env: env:
build_config: $(build_config) build_config: $(build_config)

View File

@ -5642,11 +5642,14 @@
}, },
{ {
"subheads": [], "subheads": [],
"description": "Get the volume of the specified source.", "description": "Get the volume of the specified source. Default response uses mul format, NOT SLIDER PERCENTAGE.",
"param": "{String} `source` Source name.", "param": [
"{String} `source` Source name.",
"{boolean (optional)} `useDecibel` Output volume in decibels of attenuation instead of amplitude/mul."
],
"return": [ "return": [
"{String} `name` Source name.", "{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." "{boolean} `muted` Indicates whether the source is muted."
], ],
"api": "requests", "api": "requests",
@ -5662,7 +5665,7 @@
{ {
"type": "double", "type": "double",
"name": "volume", "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", "type": "boolean",
@ -5675,6 +5678,11 @@
"type": "String", "type": "String",
"name": "source", "name": "source",
"description": "Source name." "description": "Source name."
},
{
"type": "boolean (optional)",
"name": "useDecibel",
"description": "Output volume in decibels of attenuation instead of amplitude/mul."
} }
], ],
"names": [ "names": [
@ -5705,10 +5713,11 @@
}, },
{ {
"subheads": [], "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": [ "param": [
"{String} `source` Source name.", "{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", "api": "requests",
"name": "SetVolume", "name": "SetVolume",
@ -5723,7 +5732,12 @@
{ {
"type": "double", "type": "double",
"name": "volume", "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": [ "names": [
@ -6870,6 +6884,7 @@
"name": "GetBrowserSourceProperties", "name": "GetBrowserSourceProperties",
"category": "sources", "category": "sources",
"since": "4.1.0", "since": "4.1.0",
"deprecated": "Since 4.8.0. Prefer the use of GetSourceSettings.",
"returns": [ "returns": [
{ {
"type": "String", "type": "String",
@ -6942,6 +6957,12 @@
"description": "4.1.0" "description": "4.1.0"
} }
], ],
"deprecateds": [
{
"name": "",
"description": "Since 4.8.0. Prefer the use of GetSourceSettings."
}
],
"heading": { "heading": {
"level": 2, "level": 2,
"text": "GetBrowserSourceProperties" "text": "GetBrowserSourceProperties"
@ -6968,6 +6989,7 @@
"api": "requests", "api": "requests",
"name": "SetBrowserSourceProperties", "name": "SetBrowserSourceProperties",
"category": "sources", "category": "sources",
"deprecated": "Since 4.8.0. Prefer the use of SetSourceSettings.",
"since": "4.1.0", "since": "4.1.0",
"params": [ "params": [
{ {
@ -7033,6 +7055,12 @@
"description": "sources" "description": "sources"
} }
], ],
"deprecateds": [
{
"name": "",
"description": "Since 4.8.0. Prefer the use of SetSourceSettings."
}
],
"sinces": [ "sinces": [
{ {
"name": "", "name": "",
@ -7596,6 +7624,104 @@
"type": "class", "type": "class",
"examples": [] "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": [], "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.", "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} `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)} `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)} `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)} `width` Screenshot width. Defaults to the source's base width.",
"{int (optional)} `height` Screenshot height. Defaults to the source's base height." "{int (optional)} `height` Screenshot height. Defaults to the source's base height."
], ],
@ -7648,6 +7776,16 @@
"name": "saveToFilePath", "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." "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)", "type": "int (optional)",
"name": "width", "name": "width",
@ -8664,6 +8802,47 @@
"lead": "", "lead": "",
"type": "class", "type": "class",
"examples": [] "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": []
} }
] ]
} }

View File

@ -1,6 +1,6 @@
<!-- This file was generated based on handlebars templates. Do not edit directly! --> <!-- This file was generated based on handlebars templates. Do not edit directly! -->
# obs-websocket 4.7.0 protocol reference # obs-websocket 4.8.0 protocol reference
# General Introduction # General Introduction
Messages are exchanged between the client and the server as JSON objects. 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) + [MoveSourceFilter](#movesourcefilter)
+ [SetSourceFilterSettings](#setsourcefiltersettings) + [SetSourceFilterSettings](#setsourcefiltersettings)
+ [SetSourceFilterVisibility](#setsourcefiltervisibility) + [SetSourceFilterVisibility](#setsourcefiltervisibility)
+ [GetAudioMonitorType](#getaudiomonitortype)
+ [SetAudioMonitorType](#setaudiomonitortype)
+ [TakeSourceScreenshot](#takesourcescreenshot) + [TakeSourceScreenshot](#takesourcescreenshot)
* [Streaming](#streaming-1) * [Streaming](#streaming-1)
+ [GetStreamingStatus](#getstreamingstatus) + [GetStreamingStatus](#getstreamingstatus)
@ -215,6 +217,7 @@ auth_response = base64_encode(auth_response_hash)
+ [SetCurrentTransition](#setcurrenttransition) + [SetCurrentTransition](#setcurrenttransition)
+ [SetTransitionDuration](#settransitionduration) + [SetTransitionDuration](#settransitionduration)
+ [GetTransitionDuration](#gettransitionduration) + [GetTransitionDuration](#gettransitionduration)
+ [GetTransitionPosition](#gettransitionposition)
<!-- tocstop --> <!-- tocstop -->
@ -2266,13 +2269,14 @@ _No specified parameters._
- Added in v4.0.0 - 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:** **Request Fields:**
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `source` | _String_ | Source name. | | `source` | _String_ | Source name. |
| `useDecibel` | _boolean (optional)_ | Output volume in decibels of attenuation instead of amplitude/mul. |
**Response Items:** **Response Items:**
@ -2280,7 +2284,7 @@ Get the volume of the specified source.
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `name` | _String_ | Source name. | | `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. | | `muted` | _boolean_ | Indicates whether the source is muted. |
@ -2291,14 +2295,15 @@ Get the volume of the specified source.
- Added in v4.0.0 - 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:** **Request Fields:**
| Name | Type | Description | | Name | Type | Description |
| ---- | :---: | ------------| | ---- | :---: | ------------|
| `source` | _String_ | Source name. | | `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:** **Response Items:**
@ -2643,6 +2648,7 @@ _No additional response items._
### GetBrowserSourceProperties ### GetBrowserSourceProperties
- **⚠️ Deprecated. Since 4.8.0. Prefer the use of GetSourceSettings. ⚠️**
- Added in v4.1.0 - Added in v4.1.0
@ -2674,6 +2680,7 @@ Get current properties for a Browser Source.
### SetBrowserSourceProperties ### SetBrowserSourceProperties
- **⚠️ Deprecated. Since 4.8.0. Prefer the use of SetSourceSettings. ⚠️**
- Added in v4.1.0 - Added in v4.1.0
@ -2905,6 +2912,50 @@ Change the visibility/enabled state of a filter
| `filterEnabled` | _Boolean_ | New filter state | | `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:** **Response Items:**
_No additional 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. | | `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) | | `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. | | `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. | | `width` | _int (optional)_ | Screenshot width. Defaults to the source's base width. |
| `height` | _int (optional)_ | Screenshot height. Defaults to the source's base height. | | `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. |
---

View File

@ -1,4 +1,4 @@
# obs-websocket 4.7.0 protocol reference # obs-websocket 4.8.0 protocol reference
# General Introduction # General Introduction
Messages are exchanged between the client and the server as JSON objects. Messages are exchanged between the client and the server as JSON objects.

View File

@ -84,6 +84,7 @@ const QHash<QString, RpcMethodHandler> WSRequestHandler::messageMap {
{ "SetCurrentTransition", &WSRequestHandler::SetCurrentTransition }, { "SetCurrentTransition", &WSRequestHandler::SetCurrentTransition },
{ "SetTransitionDuration", &WSRequestHandler::SetTransitionDuration }, { "SetTransitionDuration", &WSRequestHandler::SetTransitionDuration },
{ "GetTransitionDuration", &WSRequestHandler::GetTransitionDuration }, { "GetTransitionDuration", &WSRequestHandler::GetTransitionDuration },
{ "GetTransitionPosition", &WSRequestHandler::GetTransitionPosition },
{ "SetVolume", &WSRequestHandler::SetVolume }, { "SetVolume", &WSRequestHandler::SetVolume },
{ "GetVolume", &WSRequestHandler::GetVolume }, { "GetVolume", &WSRequestHandler::GetVolume },
@ -97,6 +98,8 @@ const QHash<QString, RpcMethodHandler> WSRequestHandler::messageMap {
{ "GetSourceTypesList", &WSRequestHandler::GetSourceTypesList }, { "GetSourceTypesList", &WSRequestHandler::GetSourceTypesList },
{ "GetSourceSettings", &WSRequestHandler::GetSourceSettings }, { "GetSourceSettings", &WSRequestHandler::GetSourceSettings },
{ "SetSourceSettings", &WSRequestHandler::SetSourceSettings }, { "SetSourceSettings", &WSRequestHandler::SetSourceSettings },
{ "GetAudioMonitorType", &WSRequestHandler::GetAudioMonitorType },
{ "SetAudioMonitorType", &WSRequestHandler::SetAudioMonitorType },
{ "TakeSourceScreenshot", &WSRequestHandler::TakeSourceScreenshot }, { "TakeSourceScreenshot", &WSRequestHandler::TakeSourceScreenshot },
{ "GetSourceFilters", &WSRequestHandler::GetSourceFilters }, { "GetSourceFilters", &WSRequestHandler::GetSourceFilters },

View File

@ -99,6 +99,9 @@ class WSRequestHandler {
RpcResponse GetTransitionList(const RpcRequest&); RpcResponse GetTransitionList(const RpcRequest&);
RpcResponse GetCurrentTransition(const RpcRequest&); RpcResponse GetCurrentTransition(const RpcRequest&);
RpcResponse SetCurrentTransition(const RpcRequest&); RpcResponse SetCurrentTransition(const RpcRequest&);
RpcResponse SetTransitionDuration(const RpcRequest&);
RpcResponse GetTransitionDuration(const RpcRequest&);
RpcResponse GetTransitionPosition(const RpcRequest&);
RpcResponse SetVolume(const RpcRequest&); RpcResponse SetVolume(const RpcRequest&);
RpcResponse GetVolume(const RpcRequest&); RpcResponse GetVolume(const RpcRequest&);
@ -112,6 +115,8 @@ class WSRequestHandler {
RpcResponse GetSourceTypesList(const RpcRequest&); RpcResponse GetSourceTypesList(const RpcRequest&);
RpcResponse GetSourceSettings(const RpcRequest&); RpcResponse GetSourceSettings(const RpcRequest&);
RpcResponse SetSourceSettings(const RpcRequest&); RpcResponse SetSourceSettings(const RpcRequest&);
RpcResponse GetAudioMonitorType(const RpcRequest&);
RpcResponse SetAudioMonitorType(const RpcRequest&);
RpcResponse TakeSourceScreenshot(const RpcRequest&); RpcResponse TakeSourceScreenshot(const RpcRequest&);
RpcResponse GetSourceFilters(const RpcRequest&); RpcResponse GetSourceFilters(const RpcRequest&);
@ -138,9 +143,6 @@ class WSRequestHandler {
RpcResponse SendCaptions(const RpcRequest&); RpcResponse SendCaptions(const RpcRequest&);
#endif #endif
RpcResponse SetTransitionDuration(const RpcRequest&);
RpcResponse GetTransitionDuration(const RpcRequest&);
RpcResponse GetStudioModeStatus(const RpcRequest&); RpcResponse GetStudioModeStatus(const RpcRequest&);
RpcResponse GetPreviewScene(const RpcRequest&); RpcResponse GetPreviewScene(const RpcRequest&);
RpcResponse SetPreviewScene(const RpcRequest&); RpcResponse SetPreviewScene(const RpcRequest&);

View File

@ -15,7 +15,7 @@ bool isTextGDIPlusSource(const QString& sourceKind)
bool isTextFreeType2Source(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 {String} `source` Source name.
* @param {boolean (optional)} `useDecibel` Output volume in decibels of attenuation instead of amplitude/mul.
* *
* @return {String} `name` Source name. * @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. * @return {boolean} `muted` Indicates whether the source is muted.
* *
* @api requests * @api requests
@ -185,19 +186,26 @@ RpcResponse WSRequestHandler::GetVolume(const RpcRequest& request)
return request.failed("specified source doesn't exist"); 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(); OBSDataAutoRelease response = obs_data_create();
obs_data_set_string(response, "name", obs_source_get_name(source)); 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)); obs_data_set_bool(response, "muted", obs_source_muted(source));
return request.success(response); return request.success(response);
} }
/** /**
* Set the volume of the specified source. * Set the volume of the specified source. Default request format uses mul, NOT SLIDER PERCENTAGE.
* *
* @param {String} `source` Source name. * @param {String} `source` Source name.
* @param {double} `volume` Desired volume. Must be between `0.0` and `1.0`. * @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 * @api requests
* @name SetVolume * @name SetVolume
@ -210,10 +218,14 @@ RpcResponse WSRequestHandler::SetVolume(const RpcRequest& request)
return request.failed("missing request parameters"); return request.failed("missing request parameters");
} }
bool useDecibel = obs_data_get_bool(request.parameters(), "useDecibel");
QString sourceName = obs_data_get_string(request.parameters(), "source"); QString sourceName = obs_data_get_string(request.parameters(), "source");
float sourceVolume = obs_data_get_double(request.parameters(), "volume"); 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"); return request.failed("invalid request parameters");
} }
@ -222,7 +234,11 @@ RpcResponse WSRequestHandler::SetVolume(const RpcRequest& request)
return request.failed("specified source doesn't exist"); return request.failed("specified source doesn't exist");
} }
if (useDecibel) {
sourceVolume = obs_db_to_mul(sourceVolume);
}
obs_source_set_volume(source, sourceVolume); obs_source_set_volume(source, sourceVolume);
return request.success(); return request.success();
} }
@ -919,6 +935,7 @@ RpcResponse WSRequestHandler::SetTextFreetype2Properties(const RpcRequest& reque
* @name GetBrowserSourceProperties * @name GetBrowserSourceProperties
* @category sources * @category sources
* @since 4.1.0 * @since 4.1.0
* @deprecated Since 4.8.0. Prefer the use of GetSourceSettings.
*/ */
RpcResponse WSRequestHandler::GetBrowserSourceProperties(const RpcRequest& request) RpcResponse WSRequestHandler::GetBrowserSourceProperties(const RpcRequest& request)
{ {
@ -960,6 +977,7 @@ RpcResponse WSRequestHandler::GetBrowserSourceProperties(const RpcRequest& reque
* @api requests * @api requests
* @name SetBrowserSourceProperties * @name SetBrowserSourceProperties
* @category sources * @category sources
* @deprecated Since 4.8.0. Prefer the use of SetSourceSettings.
* @since 4.1.0 * @since 4.1.0
*/ */
RpcResponse WSRequestHandler::SetBrowserSourceProperties(const RpcRequest& request) RpcResponse WSRequestHandler::SetBrowserSourceProperties(const RpcRequest& request)
@ -1424,6 +1442,99 @@ RpcResponse WSRequestHandler::SetSourceFilterVisibility(const RpcRequest& reques
return request.success(); 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: * 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) * - 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} `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)} `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)} `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)} `width` Screenshot width. Defaults to the source's base width.
* @param {int (optional)} `height` Screenshot height. Defaults to the source's base height. * @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(); 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")) { if (request.hasField("embedPictureFormat")) {
const char* pictureFormat = obs_data_get_string(request.parameters(), "embedPictureFormat"); const char* pictureFormat = obs_data_get_string(request.parameters(), "embedPictureFormat");
QByteArrayList supportedFormats = QImageWriter::supportedImageFormats(); QByteArrayList supportedFormats = QImageWriter::supportedImageFormats();
if (!supportedFormats.contains(pictureFormat)) { 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()); return request.failed(errorMessage.toUtf8());
} }
QByteArray encodedImgBytes; QByteArray encodedImgBytes;
QBuffer buffer(&encodedImgBytes); QBuffer buffer(&encodedImgBytes);
buffer.open(QBuffer::WriteOnly); buffer.open(QBuffer::WriteOnly);
if (!sourceImage.save(&buffer, pictureFormat)) { if (!sourceImage.save(&buffer, pictureFormat, compressionQuality)) {
return request.failed("Embed image encoding failed"); return request.failed("embed image encoding failed");
} }
buffer.close(); buffer.close();
@ -1569,7 +1692,18 @@ RpcResponse WSRequestHandler::TakeSourceScreenshot(const RpcRequest& request) {
QFileInfo filePathInfo(filePathStr); QFileInfo filePathInfo(filePathStr);
QString absoluteFilePath = filePathInfo.absoluteFilePath(); 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"); return request.failed("Image save failed");
} }
obs_data_set_string(response, "imageFile", absoluteFilePath.toUtf8()); obs_data_set_string(response, "imageFile", absoluteFilePath.toUtf8());

View File

@ -133,6 +133,9 @@ RpcResponse WSRequestHandler::TransitionToProgram(const RpcRequest& request) {
* @since 4.1.0 * @since 4.1.0
*/ */
RpcResponse WSRequestHandler::EnableStudioMode(const RpcRequest& request) { 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_queue_task(OBS_TASK_UI, [](void* param) {
obs_frontend_set_preview_program_mode(true); obs_frontend_set_preview_program_mode(true);
@ -150,6 +153,9 @@ RpcResponse WSRequestHandler::EnableStudioMode(const RpcRequest& request) {
* @since 4.1.0 * @since 4.1.0
*/ */
RpcResponse WSRequestHandler::DisableStudioMode(const RpcRequest& request) { 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_queue_task(OBS_TASK_UI, [](void* param) {
obs_frontend_set_preview_program_mode(false); obs_frontend_set_preview_program_mode(false);

View File

@ -120,3 +120,22 @@ RpcResponse WSRequestHandler::GetTransitionDuration(const RpcRequest& request) {
obs_data_set_int(response, "transition-duration", obs_frontend_get_transition_duration()); obs_data_set_int(response, "transition-duration", obs_frontend_get_transition_duration());
return request.success(response); 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);
}