mirror of
https://github.com/Palakis/obs-websocket.git
synced 2024-08-30 18:12:16 +00:00
Docs: Initial generation of docs from code comments (#106)
This commit is contained in:
parent
1eccf4c899
commit
a263d8a364
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
2
.gitignore
vendored
2
.gitignore
vendored
@ -5,3 +5,5 @@
|
|||||||
/build64/
|
/build64/
|
||||||
/release/
|
/release/
|
||||||
/installer/Output/
|
/installer/Output/
|
||||||
|
|
||||||
|
.vscode
|
17
.travis.yml
17
.travis.yml
@ -1,7 +1,4 @@
|
|||||||
language: cpp
|
language: cpp
|
||||||
branches:
|
|
||||||
except:
|
|
||||||
- gh-pages
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
@ -10,8 +7,15 @@ env:
|
|||||||
# AWS key secret
|
# AWS key secret
|
||||||
- secure: bGwljoP3E1OVBXLXox0O6p8kwQXLcNQ8YDKVa4H8u9Y+Ic7uqE4iV3rYS3ynNWSBMVRWY3ZbyClnhrCNwRhBAlcd8qWSJdpjVzs6HdQyzhuKa1P3V4FJPb7upGP/5R/DECGwex8Mun9dmXpYDak75LxfKIJUidPis5VDCYqul7k/xVVCou6Ctjpj7vQhWXDj2G/py+mdB8DERhymnQCtyK1Ziu8c4QlFKByZmnD72GFm/h3JPI1Pq1V2mz3x6x6GaYjb9Rdbd0UNwqjGQX4q2M/c3GEJa6B2JBCoTncawNZBNnPUF9qtv+zh0TNaNHMRWX13AJ/qYB+nVDub0C9b/6Mc48mt0Tv4ze15MproVrylZdV6qHYEG8yGPBqpTVbRP6gv6Y2TXIHWoTzqA+F/Gv2IDChyHXsld/MQQS2MSo5iaYktIrZKtX8Z0qAmTzPwIVBromaSI3vrE7UH0fRSQ6fAM8+Tn+MRthOBdqu23kS1dnG+X2CPbUhBfsJp0OSwVQD5jQtA51/sREVeGFiJvzQIkvwQDjb5MYilsRnwmoBXemkLmqaviXVY4rz1o5AIvz2pgZS2YggK1xHZCuI5tSjcNEkb77VwZTfsqrdDo9EJh6VgfdnGlHQhR2/A5hUJ4ANpJ/LgZlgfVp71Xg2GWQW6M4Znc5uj6A6xLBkO6FA=
|
- secure: bGwljoP3E1OVBXLXox0O6p8kwQXLcNQ8YDKVa4H8u9Y+Ic7uqE4iV3rYS3ynNWSBMVRWY3ZbyClnhrCNwRhBAlcd8qWSJdpjVzs6HdQyzhuKa1P3V4FJPb7upGP/5R/DECGwex8Mun9dmXpYDak75LxfKIJUidPis5VDCYqul7k/xVVCou6Ctjpj7vQhWXDj2G/py+mdB8DERhymnQCtyK1Ziu8c4QlFKByZmnD72GFm/h3JPI1Pq1V2mz3x6x6GaYjb9Rdbd0UNwqjGQX4q2M/c3GEJa6B2JBCoTncawNZBNnPUF9qtv+zh0TNaNHMRWX13AJ/qYB+nVDub0C9b/6Mc48mt0Tv4ze15MproVrylZdV6qHYEG8yGPBqpTVbRP6gv6Y2TXIHWoTzqA+F/Gv2IDChyHXsld/MQQS2MSo5iaYktIrZKtX8Z0qAmTzPwIVBromaSI3vrE7UH0fRSQ6fAM8+Tn+MRthOBdqu23kS1dnG+X2CPbUhBfsJp0OSwVQD5jQtA51/sREVeGFiJvzQIkvwQDjb5MYilsRnwmoBXemkLmqaviXVY4rz1o5AIvz2pgZS2YggK1xHZCuI5tSjcNEkb77VwZTfsqrdDo9EJh6VgfdnGlHQhR2/A5hUJ4ANpJ/LgZlgfVp71Xg2GWQW6M4Znc5uj6A6xLBkO6FA=
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- node_modules
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
|
- os: linux
|
||||||
|
script: "./CI/generate-docs.sh"
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
sudo: required
|
sudo: required
|
||||||
@ -30,7 +34,8 @@ matrix:
|
|||||||
osx_image: xcode8.3
|
osx_image: xcode8.3
|
||||||
before_install: "./CI/install-dependencies-osx.sh"
|
before_install: "./CI/install-dependencies-osx.sh"
|
||||||
script: "./CI/build-osx.sh"
|
script: "./CI/build-osx.sh"
|
||||||
after_success: "./CI/package-osx.sh"
|
after_success:
|
||||||
|
- ./CI/package-osx.sh
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
- provider: s3
|
- provider: s3
|
||||||
@ -43,7 +48,9 @@ deploy:
|
|||||||
acl: public_read
|
acl: public_read
|
||||||
on:
|
on:
|
||||||
repo: Palakis/obs-websocket
|
repo: Palakis/obs-websocket
|
||||||
condition: "$TRAVIS_OS_NAME = linux"
|
condition:
|
||||||
|
- "$TRAVIS_OS_NAME = linux"
|
||||||
|
- "-d /home/travis/package"
|
||||||
all_branches: true
|
all_branches: true
|
||||||
- provider: s3
|
- provider: s3
|
||||||
region: eu-central-1
|
region: eu-central-1
|
||||||
|
32
CI/generate-docs.sh
Executable file
32
CI/generate-docs.sh
Executable file
@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
echo "-- Generating documentation."
|
||||||
|
echo "-- Node version: $(node -v)"
|
||||||
|
echo "-- NPM version: $(npm -v)"
|
||||||
|
|
||||||
|
cd docs
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
echo "-- Documentation successfully generated."
|
||||||
|
|
||||||
|
if git diff --quiet; then
|
||||||
|
echo "-- No documentation changes to commit."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$TRAVIS_PULL_REQUEST" != "false" -o "$TRAVIS_BRANCH" != "master" ]; then
|
||||||
|
echo "-- Skipping documentation deployment because this is either a pull request or a non-master branch."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
REMOTE_URL="$(git config remote.origin.url)"
|
||||||
|
TARGET_REPO=${REMOTE_URL/https:\/\/github.com\//github.com/}
|
||||||
|
GITHUB_REPO=https://${GH_TOKEN:-git}@${TARGET_REPO}
|
||||||
|
|
||||||
|
git config user.name "Travis CI"
|
||||||
|
git config user.email "$COMMIT_AUTHOR_EMAIL"
|
||||||
|
|
||||||
|
git add ./generated
|
||||||
|
git pull
|
||||||
|
git commit -m "docs(travis): Update protocol.md - $(git rev-parse --short HEAD) [skip ci]"
|
||||||
|
git push -q $GITHUB_REPO HEAD:$TRAVIS_BRANCH
|
1004
PROTOCOL.md
1004
PROTOCOL.md
File diff suppressed because it is too large
Load Diff
@ -21,7 +21,7 @@ It is **highly recommended** to protect obs-websocket with a password against un
|
|||||||
|
|
||||||
### For developers
|
### 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 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](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 :
|
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
|
- Javascript (browser & nodejs): [obs-websocket-js](https://github.com/haganbmj/obs-websocket-js) by Brendan Hagan
|
||||||
@ -39,7 +39,7 @@ See the [build instructions](BUILDING.md).
|
|||||||
|
|
||||||
## Special thanks
|
## Special thanks
|
||||||
In order of appearance:
|
In order of appearance:
|
||||||
- [Brendan H.](https://github.com/haganbmj) : Code contributions and better English in the Protocol specification
|
- [Brendan H.](https://github.com/haganbmj) : Code contributions and gooder English in the Protocol specification
|
||||||
- [Mikhail Swift](https://github.com/mikhailswift) : Code contributions
|
- [Mikhail Swift](https://github.com/mikhailswift) : Code contributions
|
||||||
- [Tobias Frahmer](https://github.com/Frahmer) : German translation
|
- [Tobias Frahmer](https://github.com/Frahmer) : German translation
|
||||||
- [Genture](https://github.com/Genteure) : Simplified Chinese and Traditional Chinese translations
|
- [Genture](https://github.com/Genteure) : Simplified Chinese and Traditional Chinese translations
|
||||||
@ -61,10 +61,10 @@ They have contributed financially to the project and made possible the addition
|
|||||||
|
|
||||||
[Support Class](http://supportclass.net) designs and develops professional livestreams, with services ranging from broadcast graphics design and integration to event organization, along many other skills.
|
[Support Class](http://supportclass.net) designs and develops professional livestreams, with services ranging from broadcast graphics design and integration to event organization, along many other skills.
|
||||||
|
|
||||||
[](http://supportclass.net)
|
[](http://supportclass.net)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[MediaUnit](http://www.mediaunit.no) is a Norwegian media company developing products and services for the media industry, primarly focused on web and events.
|
[MediaUnit](http://www.mediaunit.no) is a Norwegian media company developing products and services for the media industry, primarly focused on web and events.
|
||||||
|
|
||||||
[](http://www.mediaunit.no/)
|
[](http://www.mediaunit.no/)
|
||||||
|
262
WSEvents.cpp
262
WSEvents.cpp
@ -1,21 +1,21 @@
|
|||||||
/*
|
/**
|
||||||
obs-websocket
|
* obs-websocket
|
||||||
Copyright (C) 2016-2017 Stéphane Lepin <stephane.lepin@gmail.com>
|
* Copyright (C) 2016-2017 Stéphane Lepin <stephane.lepin@gmail.com>
|
||||||
Copyright (C) 2017 Brendan Hagan <https://github.com/haganbmj>
|
* Copyright (C) 2017 Brendan Hagan <https://github.com/haganbmj>
|
||||||
|
*
|
||||||
This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
(at your option) any later version.
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
You should have received a copy of the GNU General Public License along
|
* You should have received a copy of the GNU General Public License along
|
||||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
* with this program. If not, see <https://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <util/platform.h>
|
#include <util/platform.h>
|
||||||
|
|
||||||
@ -259,6 +259,16 @@ const char* WSEvents::GetRecordingTimecode() {
|
|||||||
return ns_to_timestamp(GetRecordingTime());
|
return ns_to_timestamp(GetRecordingTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates a scene change.
|
||||||
|
*
|
||||||
|
* @return {String} `scene-name` The new scene.
|
||||||
|
* @return {Array} `sources` List of sources in the new scene.
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name OnSceneChange
|
||||||
|
* @category scenes
|
||||||
|
*/
|
||||||
void WSEvents::OnSceneChange() {
|
void WSEvents::OnSceneChange() {
|
||||||
obs_data_t* data = obs_data_create();
|
obs_data_t* data = obs_data_create();
|
||||||
|
|
||||||
@ -283,10 +293,25 @@ void WSEvents::OnSceneChange() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The scene list has been modified.
|
||||||
|
* Scenes have been added, removed, or renamed.
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name ScenesChanged
|
||||||
|
* @category scenes
|
||||||
|
*/
|
||||||
void WSEvents::OnSceneListChange() {
|
void WSEvents::OnSceneListChange() {
|
||||||
broadcastUpdate("ScenesChanged");
|
broadcastUpdate("ScenesChanged");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggered when switching to another scene collection or when renaming the current scene collection.
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name SceneCollectionChanged
|
||||||
|
* @category scenes
|
||||||
|
*/
|
||||||
void WSEvents::OnSceneCollectionChange() {
|
void WSEvents::OnSceneCollectionChange() {
|
||||||
broadcastUpdate("SceneCollectionChanged");
|
broadcastUpdate("SceneCollectionChanged");
|
||||||
|
|
||||||
@ -300,10 +325,26 @@ void WSEvents::OnSceneCollectionChange() {
|
|||||||
OnSceneChange();
|
OnSceneChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggered when a scene collection is created, added, renamed, or removed.
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name SceneCollectionListChanged
|
||||||
|
* @category scenes
|
||||||
|
*/
|
||||||
void WSEvents::OnSceneCollectionListChange() {
|
void WSEvents::OnSceneCollectionListChange() {
|
||||||
broadcastUpdate("SceneCollectionListChanged");
|
broadcastUpdate("SceneCollectionListChanged");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The active transition has been changed.
|
||||||
|
*
|
||||||
|
* @return {String} `transition-name` The name of the new active transition.
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name SwitchTransition
|
||||||
|
* @category transitions
|
||||||
|
*/
|
||||||
void WSEvents::OnTransitionChange() {
|
void WSEvents::OnTransitionChange() {
|
||||||
obs_source_t* current_transition = obs_frontend_get_current_transition();
|
obs_source_t* current_transition = obs_frontend_get_current_transition();
|
||||||
connectTransitionSignals(current_transition);
|
connectTransitionSignals(current_transition);
|
||||||
@ -318,18 +359,49 @@ void WSEvents::OnTransitionChange() {
|
|||||||
obs_source_release(current_transition);
|
obs_source_release(current_transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of available transitions has been modified.
|
||||||
|
* Transitions have been added, removed, or renamed.
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name TransitionListChanged
|
||||||
|
* @category transitions
|
||||||
|
*/
|
||||||
void WSEvents::OnTransitionListChange() {
|
void WSEvents::OnTransitionListChange() {
|
||||||
broadcastUpdate("TransitionListChanged");
|
broadcastUpdate("TransitionListChanged");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggered when switching to another profile or when renaming the current profile.
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name ProfileChanged
|
||||||
|
* @category profiles
|
||||||
|
*/
|
||||||
void WSEvents::OnProfileChange() {
|
void WSEvents::OnProfileChange() {
|
||||||
broadcastUpdate("ProfileChanged");
|
broadcastUpdate("ProfileChanged");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggered when a profile is created, added, renamed, or removed.
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name ProfileListChanged
|
||||||
|
* @category profiles
|
||||||
|
*/
|
||||||
void WSEvents::OnProfileListChange() {
|
void WSEvents::OnProfileListChange() {
|
||||||
broadcastUpdate("ProfileListChanged");
|
broadcastUpdate("ProfileListChanged");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A request to start streaming has been issued.
|
||||||
|
*
|
||||||
|
* @return {boolean} `preview-only` Always false (retrocompatibility).
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name StreamStarting
|
||||||
|
* @category streaming
|
||||||
|
*/
|
||||||
void WSEvents::OnStreamStarting() {
|
void WSEvents::OnStreamStarting() {
|
||||||
obs_data_t* data = obs_data_create();
|
obs_data_t* data = obs_data_create();
|
||||||
obs_data_set_bool(data, "preview-only", false);
|
obs_data_set_bool(data, "preview-only", false);
|
||||||
@ -339,12 +411,28 @@ void WSEvents::OnStreamStarting() {
|
|||||||
obs_data_release(data);
|
obs_data_release(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Streaming started successfully.
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name StreamStarted
|
||||||
|
* @category streaming
|
||||||
|
*/
|
||||||
void WSEvents::OnStreamStarted() {
|
void WSEvents::OnStreamStarted() {
|
||||||
_stream_starttime = os_gettime_ns();
|
_stream_starttime = os_gettime_ns();
|
||||||
_lastBytesSent = 0;
|
_lastBytesSent = 0;
|
||||||
broadcastUpdate("StreamStarted");
|
broadcastUpdate("StreamStarted");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A request to stop streaming has been issued.
|
||||||
|
*
|
||||||
|
* @return {boolean} `preview-only` Always false (retrocompatibility).
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name StreamStopping
|
||||||
|
* @category streaming
|
||||||
|
*/
|
||||||
void WSEvents::OnStreamStopping() {
|
void WSEvents::OnStreamStopping() {
|
||||||
obs_data_t* data = obs_data_create();
|
obs_data_t* data = obs_data_create();
|
||||||
obs_data_set_bool(data, "preview-only", false);
|
obs_data_set_bool(data, "preview-only", false);
|
||||||
@ -354,33 +442,93 @@ void WSEvents::OnStreamStopping() {
|
|||||||
obs_data_release(data);
|
obs_data_release(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Streaming stopped successfully.
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name StreamStopped
|
||||||
|
* @category streaming
|
||||||
|
*/
|
||||||
void WSEvents::OnStreamStopped() {
|
void WSEvents::OnStreamStopped() {
|
||||||
_stream_starttime = 0;
|
_stream_starttime = 0;
|
||||||
broadcastUpdate("StreamStopped");
|
broadcastUpdate("StreamStopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A request to start recording has been issued.
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name RecordingStarting
|
||||||
|
* @category recording
|
||||||
|
*/
|
||||||
void WSEvents::OnRecordingStarting() {
|
void WSEvents::OnRecordingStarting() {
|
||||||
broadcastUpdate("RecordingStarting");
|
broadcastUpdate("RecordingStarting");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recording started successfully.
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name RecordingStarted
|
||||||
|
* @category recording
|
||||||
|
*/
|
||||||
void WSEvents::OnRecordingStarted() {
|
void WSEvents::OnRecordingStarted() {
|
||||||
_rec_starttime = os_gettime_ns();
|
_rec_starttime = os_gettime_ns();
|
||||||
broadcastUpdate("RecordingStarted");
|
broadcastUpdate("RecordingStarted");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A request to stop recording has been issued.
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name RecordingStopping
|
||||||
|
* @category recording
|
||||||
|
*/
|
||||||
void WSEvents::OnRecordingStopping() {
|
void WSEvents::OnRecordingStopping() {
|
||||||
broadcastUpdate("RecordingStopping");
|
broadcastUpdate("RecordingStopping");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recording stopped successfully.
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name RecordingStopped
|
||||||
|
* @category recording
|
||||||
|
*/
|
||||||
void WSEvents::OnRecordingStopped() {
|
void WSEvents::OnRecordingStopped() {
|
||||||
_rec_starttime = 0;
|
_rec_starttime = 0;
|
||||||
broadcastUpdate("RecordingStopped");
|
broadcastUpdate("RecordingStopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OBS is exiting.
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name Exiting
|
||||||
|
* @category other
|
||||||
|
*/
|
||||||
void WSEvents::OnExit() {
|
void WSEvents::OnExit() {
|
||||||
broadcastUpdate("Exiting");
|
broadcastUpdate("Exiting");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit every 2 seconds.
|
||||||
|
*
|
||||||
|
* @return {boolean} `streaming` Current streaming state.
|
||||||
|
* @return {boolean} `recording` Current recording state.
|
||||||
|
* @return {boolean} `preview-only` Always false (retrocompatibility).
|
||||||
|
* @return {int} `bytes-per-sec` Amount of data per second (in bytes) transmitted by the stream encoder.
|
||||||
|
* @return {int} `kbits-per-sec` Amount of data per second (in kilobits) transmitted by the stream encoder.
|
||||||
|
* @return {double} `strain` Percentage of dropped frames.
|
||||||
|
* @return {int} `total-stream-time` Total time (in seconds) since the stream started.
|
||||||
|
* @return {int} `num-total-frames` Total number of frames transmitted since the stream started.
|
||||||
|
* @return {int} `num-dropped-frames` Number of frames dropped by the encoder since the stream started.
|
||||||
|
* @return {double} `fps` Current framerate.
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name StreamStatus
|
||||||
|
* @category streaming
|
||||||
|
*/
|
||||||
void WSEvents::StreamStatus() {
|
void WSEvents::StreamStatus() {
|
||||||
bool streaming_active = obs_frontend_streaming_active();
|
bool streaming_active = obs_frontend_streaming_active();
|
||||||
bool recording_active = obs_frontend_recording_active();
|
bool recording_active = obs_frontend_recording_active();
|
||||||
@ -438,6 +586,15 @@ void WSEvents::StreamStatus() {
|
|||||||
obs_output_release(stream_output);
|
obs_output_release(stream_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The active transition duration has been changed.
|
||||||
|
*
|
||||||
|
* @return {int} `new-duration` New transition duration.
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name TransitionDurationChanged
|
||||||
|
* @category transitions
|
||||||
|
*/
|
||||||
void WSEvents::TransitionDurationChanged(int ms) {
|
void WSEvents::TransitionDurationChanged(int ms) {
|
||||||
obs_data_t* fields = obs_data_create();
|
obs_data_t* fields = obs_data_create();
|
||||||
obs_data_set_int(fields, "new-duration", ms);
|
obs_data_set_int(fields, "new-duration", ms);
|
||||||
@ -446,6 +603,16 @@ void WSEvents::TransitionDurationChanged(int ms) {
|
|||||||
obs_data_release(fields);
|
obs_data_release(fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A transition (other than "cut") has begun.
|
||||||
|
*
|
||||||
|
* @return {String} `name` Transition name.
|
||||||
|
* @return {int} `duration` Transition duration (in milliseconds).
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name TransitionBegin
|
||||||
|
* @category transitions
|
||||||
|
*/
|
||||||
void WSEvents::OnTransitionBegin(void* param, calldata_t* data) {
|
void WSEvents::OnTransitionBegin(void* param, calldata_t* data) {
|
||||||
UNUSED_PARAMETER(data);
|
UNUSED_PARAMETER(data);
|
||||||
WSEvents* instance = static_cast<WSEvents*>(param);
|
WSEvents* instance = static_cast<WSEvents*>(param);
|
||||||
@ -463,6 +630,15 @@ void WSEvents::OnTransitionBegin(void* param, calldata_t* data) {
|
|||||||
obs_source_release(current_transition);
|
obs_source_release(current_transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scene items have been reordered.
|
||||||
|
*
|
||||||
|
* @return {String} `scene-name` Name of the scene where items have been reordered.
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name SourceOrderChanged
|
||||||
|
* @category sources
|
||||||
|
*/
|
||||||
void WSEvents::OnSceneReordered(void* param, calldata_t* data) {
|
void WSEvents::OnSceneReordered(void* param, calldata_t* data) {
|
||||||
WSEvents* instance = static_cast<WSEvents*>(param);
|
WSEvents* instance = static_cast<WSEvents*>(param);
|
||||||
|
|
||||||
@ -477,6 +653,16 @@ void WSEvents::OnSceneReordered(void* param, calldata_t* data) {
|
|||||||
obs_data_release(fields);
|
obs_data_release(fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An item has been added to the current scene.
|
||||||
|
*
|
||||||
|
* @return {String} `scene-name` Name of the scene.
|
||||||
|
* @return {String} `item-name` Name of the item added to the scene.
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name SceneItemAdded
|
||||||
|
* @category sources
|
||||||
|
*/
|
||||||
void WSEvents::OnSceneItemAdd(void* param, calldata_t* data) {
|
void WSEvents::OnSceneItemAdd(void* param, calldata_t* data) {
|
||||||
WSEvents* instance = static_cast<WSEvents*>(param);
|
WSEvents* instance = static_cast<WSEvents*>(param);
|
||||||
|
|
||||||
@ -499,6 +685,16 @@ void WSEvents::OnSceneItemAdd(void* param, calldata_t* data) {
|
|||||||
obs_data_release(fields);
|
obs_data_release(fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An item has been removed from the current scene.
|
||||||
|
*
|
||||||
|
* @return {String} `scene-name` Name of the scene.
|
||||||
|
* @return {String} `item-name` Name of the item removed from the scene.
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name SceneItemRemoved
|
||||||
|
* @category sources
|
||||||
|
*/
|
||||||
void WSEvents::OnSceneItemDelete(void* param, calldata_t* data) {
|
void WSEvents::OnSceneItemDelete(void* param, calldata_t* data) {
|
||||||
WSEvents* instance = static_cast<WSEvents*>(param);
|
WSEvents* instance = static_cast<WSEvents*>(param);
|
||||||
|
|
||||||
@ -521,6 +717,17 @@ void WSEvents::OnSceneItemDelete(void* param, calldata_t* data) {
|
|||||||
obs_data_release(fields);
|
obs_data_release(fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An item's visibility has been toggled.
|
||||||
|
*
|
||||||
|
* @return {String} `scene-name` Name of the scene.
|
||||||
|
* @return {String} `item-name` Name of the item in the scene.
|
||||||
|
* @return {boolean} `item-visible` New visibility state of the item.
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name SceneItemVisibilityChanged
|
||||||
|
* @category sources
|
||||||
|
*/
|
||||||
void WSEvents::OnSceneItemVisibilityChanged(void* param, calldata_t* data) {
|
void WSEvents::OnSceneItemVisibilityChanged(void* param, calldata_t* data) {
|
||||||
WSEvents* instance = static_cast<WSEvents*>(param);
|
WSEvents* instance = static_cast<WSEvents*>(param);
|
||||||
|
|
||||||
@ -547,6 +754,16 @@ void WSEvents::OnSceneItemVisibilityChanged(void* param, calldata_t* data) {
|
|||||||
obs_data_release(fields);
|
obs_data_release(fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The selected preview scene has changed (only available in Studio Mode).
|
||||||
|
*
|
||||||
|
* @return {String} `scene-name` Name of the scene being previewed.
|
||||||
|
* @return {Source|Array} `sources` List of sources composing the scene. Same specification as [`GetCurrentScene`](#getcurrentscene).
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name PreviewSceneChanged
|
||||||
|
* @category studio mode
|
||||||
|
*/
|
||||||
void WSEvents::SelectedSceneChanged(QListWidgetItem* current, QListWidgetItem* prev) {
|
void WSEvents::SelectedSceneChanged(QListWidgetItem* current, QListWidgetItem* prev) {
|
||||||
if (Utils::IsPreviewModeActive()) {
|
if (Utils::IsPreviewModeActive()) {
|
||||||
obs_scene_t* scene = Utils::SceneListItemToScene(current);
|
obs_scene_t* scene = Utils::SceneListItemToScene(current);
|
||||||
@ -566,6 +783,15 @@ void WSEvents::SelectedSceneChanged(QListWidgetItem* current, QListWidgetItem* p
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Studio Mode has been enabled or disabled.
|
||||||
|
*
|
||||||
|
* @return {boolean} `new-state` The new enabled state of Studio Mode.
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name StudioModeSwitched
|
||||||
|
* @category studio mode
|
||||||
|
*/
|
||||||
void WSEvents::ModeSwitchClicked(bool checked) {
|
void WSEvents::ModeSwitchClicked(bool checked) {
|
||||||
obs_data_t* data = obs_data_create();
|
obs_data_t* data = obs_data_create();
|
||||||
obs_data_set_bool(data, "new-state", checked);
|
obs_data_set_bool(data, "new-state", checked);
|
||||||
|
File diff suppressed because it is too large
Load Diff
11
docs/.editorconfig
Normal file
11
docs/.editorconfig
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.md, *.mustache]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
insert_final_newline = false
|
4
docs/.gitignore
vendored
Normal file
4
docs/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
node_modules
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
1
docs/.npmrc
Normal file
1
docs/.npmrc
Normal file
@ -0,0 +1 @@
|
|||||||
|
package-lock=false
|
21
docs/README.md
Normal file
21
docs/README.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
## Installation
|
||||||
|
|
||||||
|
Install node and update npm if necessary.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd obs-websocket/docs
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Just extract the comments.
|
||||||
|
npm run comments
|
||||||
|
|
||||||
|
# Just render the markdown.
|
||||||
|
npm run docs
|
||||||
|
|
||||||
|
# Do both comments and markdown.
|
||||||
|
npm run build
|
||||||
|
```
|
52
docs/comments.js
Normal file
52
docs/comments.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const glob = require('glob');
|
||||||
|
const parseComments = require('parse-comments');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read each file and call `parse-comments` on it.
|
||||||
|
*
|
||||||
|
* @param {String|Array} `files` List of file paths to read from.
|
||||||
|
* @return {Object|Array} Array of `parse-comments` objects.
|
||||||
|
*/
|
||||||
|
const parseFiles = files => {
|
||||||
|
let response = [];
|
||||||
|
files.forEach(file => {
|
||||||
|
const f = fs.readFileSync(file, 'utf8').toString();
|
||||||
|
response = response.concat(parseComments(f));
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters/sorts the results from `parse-comments`.
|
||||||
|
* @param {Object|Array} `comments` Array of `parse-comments` objects.
|
||||||
|
* @return {Object} Filtered comments sorted by `@api` and `@category`.
|
||||||
|
*/
|
||||||
|
const processComments = comments => {
|
||||||
|
let sorted = {};
|
||||||
|
|
||||||
|
comments.forEach(comment => {
|
||||||
|
if (typeof comment.api === 'undefined') return;
|
||||||
|
|
||||||
|
// Store the object based on its api (ie. requests, events) and category (ie. general, scenes, etc).
|
||||||
|
comment.category = comment.category || 'miscellaneous';
|
||||||
|
|
||||||
|
// Remove some unnecessary properties to avoid result differences in travis.
|
||||||
|
comment.comment = undefined;
|
||||||
|
comment.context = undefined;
|
||||||
|
|
||||||
|
// Create an entry in sorted for the api/category if one does not exist.
|
||||||
|
sorted[comment.api] = sorted[comment.api] || {};
|
||||||
|
sorted[comment.api][comment.category] = sorted[comment.api][comment.category] || [];
|
||||||
|
|
||||||
|
// Store the comment in the appropriate api/category.
|
||||||
|
sorted[comment.api][comment.category].push(comment);
|
||||||
|
});
|
||||||
|
|
||||||
|
return sorted;
|
||||||
|
};
|
||||||
|
|
||||||
|
const files = glob.sync("./../*.@(cpp|h)");
|
||||||
|
const comments = processComments(parseFiles(files));
|
||||||
|
fs.writeFileSync('./generated/comments.json', JSON.stringify(comments, null, 2));
|
31
docs/docs.js
Normal file
31
docs/docs.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const toc = require('markdown-toc');
|
||||||
|
const handlebars = require('handlebars');
|
||||||
|
|
||||||
|
const helpers = require('handlebars-helpers')({
|
||||||
|
handlebars: handlebars
|
||||||
|
});
|
||||||
|
|
||||||
|
// Allows pipe characters to be used within markdown tables.
|
||||||
|
handlebars.registerHelper('depipe', (text) => {
|
||||||
|
return text.replace('|', `\\|`);
|
||||||
|
});
|
||||||
|
|
||||||
|
const insertHeader = (text) => {
|
||||||
|
return '<!-- This file was generated based on handlebars templates. Do not edit directly! -->\n\n' + text;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes `protocol.md` using `protocol.mustache`.
|
||||||
|
*
|
||||||
|
* @param {Object} `data` Data to assign to the mustache template.
|
||||||
|
*/
|
||||||
|
const generateProtocol = (templatePath, data) => {
|
||||||
|
const template = fs.readFileSync(templatePath).toString();
|
||||||
|
const generated = handlebars.compile(template)(data);
|
||||||
|
return insertHeader(toc.insert(generated));
|
||||||
|
};
|
||||||
|
|
||||||
|
const comments = fs.readFileSync('./generated/comments.json', 'utf8');
|
||||||
|
const markdown = generateProtocol('./protocol.hbs', JSON.parse(comments));
|
||||||
|
fs.writeFileSync('./generated/protocol.md', markdown);
|
3464
docs/generated/comments.json
Normal file
3464
docs/generated/comments.json
Normal file
File diff suppressed because it is too large
Load Diff
1508
docs/generated/protocol.md
Normal file
1508
docs/generated/protocol.md
Normal file
File diff suppressed because it is too large
Load Diff
21
docs/package.json
Normal file
21
docs/package.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "obs-websocket-docs",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "docs.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"docs": "node ./docs.js",
|
||||||
|
"comments": "node ./comments.js",
|
||||||
|
"build": "npm run comments && npm run docs"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"glob": "^7.1.2",
|
||||||
|
"handlebars": "^4.0.10",
|
||||||
|
"handlebars-helpers": "^0.9.6",
|
||||||
|
"markdown-toc": "^1.1.0",
|
||||||
|
"parse-comments": "^0.4.3"
|
||||||
|
}
|
||||||
|
}
|
11
docs/partials/eventsHeader.md
Normal file
11
docs/partials/eventsHeader.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Events
|
||||||
|
Events are broadcast by the server to each connected client when a recognized action occurs within OBS.
|
||||||
|
|
||||||
|
An event message will contain at least the following base fields:
|
||||||
|
- `update-type` _String_: the type of event.
|
||||||
|
- `stream-timecode` _String (optional)_: time elapsed between now and stream start (only present if OBS Studio is streaming).
|
||||||
|
- `rec-timecode` _String (optional)_: time elapsed between now and recording start (only present if OBS Studio is recording).
|
||||||
|
|
||||||
|
Timecodes are sent using the format: `HH:MM:SS.mmm`
|
||||||
|
|
||||||
|
Additional fields may be present in the event message depending on the event type.
|
37
docs/partials/introduction.md
Normal file
37
docs/partials/introduction.md
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# obs-websocket 4.1 protocol reference
|
||||||
|
|
||||||
|
**This is the reference for the latest 4.1 development build. [See here for obs-websocket 4.0.0!](https://github.com/Palakis/obs-websocket/blob/4.0.0/PROTOCOL.md)**
|
||||||
|
|
||||||
|
# General Introduction
|
||||||
|
Messages are exchanged between the client and the server as JSON objects.
|
||||||
|
This protocol is based on the original OBS Remote protocol created by Bill Hamilton, with new commands specific to OBS Studio.
|
||||||
|
|
||||||
|
|
||||||
|
# Authentication
|
||||||
|
OBSWebSocket uses SHA256 to transmit credentials.
|
||||||
|
|
||||||
|
A request for [`GetAuthRequired`](#getauthrequired) returns two elements:
|
||||||
|
- A `challenge`: a random string that will be used to generate the auth response.
|
||||||
|
- A `salt`: applied to the password when generating the auth response.
|
||||||
|
|
||||||
|
To generate the answer to the auth challenge, follow this procedure:
|
||||||
|
- Concatenate the user declared password with the `salt` sent by the server (in this order: `password + server salt`).
|
||||||
|
- Generate a binary SHA256 hash of the result and encode the resulting SHA256 binary hash to base64, known as a `base64 secret`.
|
||||||
|
- Concatenate the base64 secret with the `challenge` sent by the server (in this order: `base64 secret + server challenge`).
|
||||||
|
- Generate a binary SHA256 hash of the result and encode it to base64.
|
||||||
|
- Voilà, this last base64 string is the `auth response`. You may now use it to authenticate to the server with the [`Authenticate`](#authenticate) request.
|
||||||
|
|
||||||
|
Pseudo Code Example:
|
||||||
|
```
|
||||||
|
password = "supersecretpassword"
|
||||||
|
challenge = "ztTBnnuqrqaKDzRM3xcVdbYm"
|
||||||
|
salt = "PZVbYpvAnZut2SS6JNJytDm9"
|
||||||
|
|
||||||
|
secret_string = password + salt
|
||||||
|
secret_hash = binary_sha256(secret_string)
|
||||||
|
secret = base64_encode(secret_hash)
|
||||||
|
|
||||||
|
auth_response_string = secret + challenge
|
||||||
|
auth_response_hash = binary_sha256(auth_response_string)
|
||||||
|
auth_response = base64_encode(auth_response_hash)
|
||||||
|
```
|
11
docs/partials/requestsHeader.md
Normal file
11
docs/partials/requestsHeader.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Requests
|
||||||
|
Requests are sent by the client and require at least the following two fields:
|
||||||
|
- `request-type` _String_: String name of the request type.
|
||||||
|
- `message-id` _String_: Client defined identifier for the message, will be echoed in the response.
|
||||||
|
|
||||||
|
Once a request is sent, the server will return a JSON response with at least the following fields:
|
||||||
|
- `message-id` _String_: The client defined identifier specified in the request.
|
||||||
|
- `status` _String_: Response status, will be one of the following: `ok`, `error`
|
||||||
|
- `error` _String_: An error message accompanying an `error` status.
|
||||||
|
|
||||||
|
Additional information may be required/returned depending on the request type. See below for more information.
|
80
docs/protocol.hbs
Normal file
80
docs/protocol.hbs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
{{#read "partials/introduction.md"}}{{/read}}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Table of Contents
|
||||||
|
<!-- toc -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{{#read "partials/eventsHeader.md"}}{{/read}}
|
||||||
|
|
||||||
|
{{#each events}}
|
||||||
|
## {{capitalizeAll @key}}
|
||||||
|
|
||||||
|
{{#each this}}
|
||||||
|
### {{name}}
|
||||||
|
|
||||||
|
{{{description}}}
|
||||||
|
|
||||||
|
**Response Items:**
|
||||||
|
|
||||||
|
{{#if returns.length}}
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | :---: | ------------|
|
||||||
|
{{#each returns}}
|
||||||
|
| `{{name}}` | _{{depipe type}}_ | {{{description}}} |
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
{{else}}
|
||||||
|
_No additional response items._
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
{{/each}}
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{{#read "partials/requestsHeader.md"}}{{/read}}
|
||||||
|
|
||||||
|
{{#each requests}}
|
||||||
|
## {{capitalizeAll @key}}
|
||||||
|
|
||||||
|
{{#each this}}
|
||||||
|
### {{name}}
|
||||||
|
|
||||||
|
{{{description}}}
|
||||||
|
|
||||||
|
**Request Fields:**
|
||||||
|
|
||||||
|
{{#if params.length}}
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | :---: | ------------|
|
||||||
|
{{#each params}}
|
||||||
|
| `{{name}}` | _{{depipe type}}_ | {{{description}}} |
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
{{else}}
|
||||||
|
_No specified parameters._
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
**Response Items:**
|
||||||
|
|
||||||
|
{{#if returns.length}}
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | :---: | ------------|
|
||||||
|
{{#each returns}}
|
||||||
|
| `{{name}}` | _{{depipe type}}_ | {{{description}}} |
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
{{else}}
|
||||||
|
_No additional response items._
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
{{/each}}
|
||||||
|
{{/each}}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user