mirror of
https://github.com/Palakis/obs-websocket.git
synced 2024-08-30 18:12:16 +00:00
Merge pull request #851 from obs-websocket/event/changing_events
Put normal commits on this branch by accident dammit
This commit is contained in:
commit
061c228ad5
4
.github/pull_request_template.md
vendored
4
.github/pull_request_template.md
vendored
@ -1,6 +1,6 @@
|
|||||||
<!--- Please fill out the following template, which will help other contributors review your Pull Request. -->
|
<!--- Please fill out the following template, which will help other contributors review your Pull Request. -->
|
||||||
|
|
||||||
<!--- Make sure you’ve read the contribution guidelines here: https://github.com/Palakis/obs-websocket/blob/master/CONTRIBUTING.md -->
|
<!--- Make sure you’ve read the contribution guidelines here: https://github.com/obs-websocket/obs-websocket/blob/master/CONTRIBUTING.md -->
|
||||||
|
|
||||||
### Description
|
### Description
|
||||||
<!--- Describe your changes. -->
|
<!--- Describe your changes. -->
|
||||||
@ -27,7 +27,7 @@ Tested OS(s):
|
|||||||
### Checklist:
|
### Checklist:
|
||||||
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
|
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
|
||||||
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
|
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
|
||||||
- [ ] I have read the [**contributing** document](https://github.com/Palakis/obs-websocket/blob/4.x-current/CONTRIBUTING.md).
|
- [ ] I have read the [**contributing** document](https://github.com/obs-websocket/obs-websocket/blob/4.x-current/CONTRIBUTING.md).
|
||||||
- [ ] My code is not on the master branch.
|
- [ ] My code is not on the master branch.
|
||||||
- [ ] The code has been tested.
|
- [ ] The code has been tested.
|
||||||
- [ ] All commit messages are properly formatted and commits squashed where appropriate.
|
- [ ] All commit messages are properly formatted and commits squashed where appropriate.
|
||||||
|
@ -21,7 +21,7 @@ On Debian/Ubuntu :
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
sudo apt-get install libboost-all-dev
|
sudo apt-get install libboost-all-dev
|
||||||
git clone --recursive https://github.com/Palakis/obs-websocket.git
|
git clone --recursive https://github.com/obs-websocket/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 -DUSE_UBUNTU_FIX=true ..
|
cmake -DLIBOBS_INCLUDE_DIR="<path to the libobs sub-folder in obs-studio's source code>" -DCMAKE_INSTALL_PREFIX=/usr -DUSE_UBUNTU_FIX=true ..
|
||||||
@ -51,7 +51,7 @@ Of course, you're encouraged to dig through the contents of these scripts to
|
|||||||
look for issues or specificities.
|
look for issues or specificities.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git clone --recursive https://github.com/Palakis/obs-websocket.git
|
git clone --recursive https://github.com/obs-websocket/obs-websocket.git
|
||||||
cd obs-websocket
|
cd obs-websocket
|
||||||
./CI/install-dependencies-macos.sh
|
./CI/install-dependencies-macos.sh
|
||||||
./CI/install-build-obs-macos.sh
|
./CI/install-build-obs-macos.sh
|
||||||
@ -63,4 +63,4 @@ This will result in a ready-to-use `obs-websocket.pkg` installer in the `release
|
|||||||
|
|
||||||
## Automated Builds
|
## Automated Builds
|
||||||
|
|
||||||

|

|
||||||
|
@ -108,6 +108,7 @@ set(obs-websocket_SOURCES
|
|||||||
src/requesthandler/RequestHandler_SceneItems.cpp
|
src/requesthandler/RequestHandler_SceneItems.cpp
|
||||||
src/requesthandler/RequestHandler_Stream.cpp
|
src/requesthandler/RequestHandler_Stream.cpp
|
||||||
src/requesthandler/RequestHandler_Record.cpp
|
src/requesthandler/RequestHandler_Record.cpp
|
||||||
|
src/requesthandler/RequestHandler_MediaInputs.cpp
|
||||||
src/requesthandler/rpc/Request.cpp
|
src/requesthandler/rpc/Request.cpp
|
||||||
src/requesthandler/rpc/RequestResult.cpp
|
src/requesthandler/rpc/RequestResult.cpp
|
||||||
src/forms/SettingsDialog.cpp
|
src/forms/SettingsDialog.cpp
|
||||||
|
@ -29,21 +29,20 @@ These are required to automatically generate the [protocol specification documen
|
|||||||
|
|
||||||
* Favor return-early code and avoid wrapping huge portions of code in conditionals. As an example, this:
|
* Favor return-early code and avoid wrapping huge portions of code in conditionals. As an example, this:
|
||||||
```cpp
|
```cpp
|
||||||
if (success) {
|
if (success)
|
||||||
return RequestResult::Success();
|
return RequestResult::Success();
|
||||||
} else {
|
else
|
||||||
return RequestResult::Error(RequestStatus::GenericError);
|
return RequestResult::Error(RequestStatus::GenericError);
|
||||||
}
|
|
||||||
```
|
```
|
||||||
is better like this:
|
is better like this:
|
||||||
```cpp
|
```cpp
|
||||||
if (!success) {
|
if (!success)
|
||||||
return RequestResult::Error(RequestStatus::GenericError);
|
return RequestResult::Error(RequestStatus::GenericError);
|
||||||
}
|
|
||||||
return RequestResult::Success();
|
return RequestResult::Success();
|
||||||
```
|
```
|
||||||
|
|
||||||
* Try to use the [built-in](https://github.com/Palakis/obs-websocket/blob/master/src/requesthandler/rpc/Request.h) request checks when possible.
|
* Try to use the [built-in](https://github.com/obs-websocket/obs-websocket/blob/master/src/requesthandler/rpc/Request.h) request checks when possible.
|
||||||
* Refer to existing requests for usage examples.
|
* Refer to existing requests for usage examples.
|
||||||
|
|
||||||
* Some example common response/request property names are:
|
* Some example common response/request property names are:
|
||||||
@ -54,12 +53,14 @@ return RequestResult::Success();
|
|||||||
|
|
||||||
* Response parameters which have no attributed data due to an invalid state should be set to `null` (versus being left out)
|
* Response parameters which have no attributed data due to an invalid state should be set to `null` (versus being left out)
|
||||||
* For example, when `GetSceneList` is called and OBS is not in studio mode, `currentPreviewSceneName` will be `null`
|
* For example, when `GetSceneList` is called and OBS is not in studio mode, `currentPreviewSceneName` will be `null`
|
||||||
* If a request's core response data depends on a state, an error should be thrown unless `ignoreNonFatalRequestChecks` is set. See `GetCurrentPreviewScene` as an example.
|
* If a request's core response data depends on a state, an error should be thrown. See `GetCurrentPreviewScene` as an example.
|
||||||
|
|
||||||
|
* In general, try to match the style of existing code as best as possible. We try our best to keep a consistent code style, and may suggest nitpicks as necessary.
|
||||||
|
|
||||||
### Commit Guidelines
|
### Commit Guidelines
|
||||||
|
|
||||||
* Commits follow the 50/72 standard:
|
* Commits follow the 50/72 standard:
|
||||||
* 50 characters max for the commit title (excluding scope name)
|
* 50 characters suggested max for the commit title (absolute maximum 72 including scope)
|
||||||
* One empty line after the title
|
* One empty line after the title
|
||||||
* Description wrapped to 72 columns max width per line.
|
* Description wrapped to 72 columns max width per line.
|
||||||
|
|
||||||
|
@ -12,13 +12,13 @@
|
|||||||
|
|
||||||
WebSockets API for OBS Studio.
|
WebSockets API for OBS Studio.
|
||||||
|
|
||||||
[](https://github.com/Palakis/obs-websocket/actions/workflows/main.yml)
|
[](https://github.com/obs-websocket/obs-websocket/actions/workflows/main.yml)
|
||||||
[](https://discord.gg/WBaSQ3A)
|
[](https://discord.gg/WBaSQ3A)
|
||||||
[](https://opencollective.com/obs-websocket)
|
[](https://opencollective.com/obs-websocket)
|
||||||
|
|
||||||
## Downloads
|
## Downloads
|
||||||
|
|
||||||
Binaries for Windows, MacOS, and Linux are available in the [Releases](https://github.com/Palakis/obs-websocket/releases) section.
|
Binaries for Windows, MacOS, and Linux are available in the [Releases](https://github.com/obs-websocket/obs-websocket/releases) section.
|
||||||
|
|
||||||
### Homebrew
|
### Homebrew
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ Please join the localization project on [Crowdin](https://crowdin.com/project/ob
|
|||||||
### Code Contributors
|
### Code Contributors
|
||||||
|
|
||||||
This project exists thanks to all the people who contribute. [Contribute](CONTRIBUTING.md).
|
This project exists thanks to all the people who contribute. [Contribute](CONTRIBUTING.md).
|
||||||
<a href="https://github.com/Palakis/obs-websocket/graphs/contributors"><img src="https://opencollective.com/obs-websocket/contributors.svg?width=890&button=false" /></a>
|
<a href="https://github.com/obs-websocket/obs-websocket/graphs/contributors"><img src="https://opencollective.com/obs-websocket/contributors.svg?width=890&button=false" /></a>
|
||||||
|
|
||||||
### Financial Contributors
|
### Financial Contributors
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#define MyAppName "obs-websocket"
|
#define MyAppName "obs-websocket"
|
||||||
#define MyAppVersion "@OBS_WEBSOCKET_VERSION@"
|
#define MyAppVersion "@OBS_WEBSOCKET_VERSION@"
|
||||||
#define MyAppPublisher "Stephane Lepin"
|
#define MyAppPublisher "Stephane Lepin"
|
||||||
#define MyAppURL "http://github.com/Palakis/obs-websocket"
|
#define MyAppURL "http://github.com/obs-websocket/obs-websocket"
|
||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
; NOTE: The value of AppId uniquely identifies this application.
|
; NOTE: The value of AppId uniquely identifies this application.
|
||||||
|
@ -237,18 +237,18 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
// Config
|
// Config
|
||||||
//case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGING:
|
case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGING:
|
||||||
// eventHandler->HandleCurrentSceneCollectionChanging();
|
eventHandler->HandleCurrentSceneCollectionChanging();
|
||||||
// break;
|
break;
|
||||||
case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED:
|
case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED:
|
||||||
eventHandler->HandleCurrentSceneCollectionChanged();
|
eventHandler->HandleCurrentSceneCollectionChanged();
|
||||||
break;
|
break;
|
||||||
case OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED:
|
case OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED:
|
||||||
eventHandler->HandleSceneCollectionListChanged();
|
eventHandler->HandleSceneCollectionListChanged();
|
||||||
break;
|
break;
|
||||||
//case OBS_FRONTEND_EVENT_PROFILE_CHANGING:
|
case OBS_FRONTEND_EVENT_PROFILE_CHANGING:
|
||||||
// eventHandler->HandleCurrentProfileChanging();
|
eventHandler->HandleCurrentProfileChanging();
|
||||||
// break;
|
break;
|
||||||
case OBS_FRONTEND_EVENT_PROFILE_CHANGED:
|
case OBS_FRONTEND_EVENT_PROFILE_CHANGED:
|
||||||
eventHandler->HandleCurrentProfileChanged();
|
eventHandler->HandleCurrentProfileChanged();
|
||||||
break;
|
break;
|
||||||
|
@ -97,6 +97,12 @@ const std::map<std::string, RequestMethodHandler> RequestHandler::_handlerMap
|
|||||||
{"PauseRecord", &RequestHandler::PauseRecord},
|
{"PauseRecord", &RequestHandler::PauseRecord},
|
||||||
{"ResumeRecord", &RequestHandler::ResumeRecord},
|
{"ResumeRecord", &RequestHandler::ResumeRecord},
|
||||||
//{"GetRecordDirectory", &RequestHandler::GetRecordDirectory},
|
//{"GetRecordDirectory", &RequestHandler::GetRecordDirectory},
|
||||||
|
|
||||||
|
// Media Inputs
|
||||||
|
{"GetMediaInputStatus", &RequestHandler::GetMediaInputStatus},
|
||||||
|
{"SetMediaInputCursor", &RequestHandler::SetMediaInputCursor},
|
||||||
|
{"OffsetMediaInputCursor", &RequestHandler::OffsetMediaInputCursor},
|
||||||
|
{"TriggerMediaInputAction", &RequestHandler::TriggerMediaInputAction},
|
||||||
};
|
};
|
||||||
|
|
||||||
RequestHandler::RequestHandler(SessionPtr session) :
|
RequestHandler::RequestHandler(SessionPtr session) :
|
||||||
|
@ -119,6 +119,12 @@ class RequestHandler {
|
|||||||
RequestResult ResumeRecord(const Request&);
|
RequestResult ResumeRecord(const Request&);
|
||||||
RequestResult GetRecordDirectory(const Request&);
|
RequestResult GetRecordDirectory(const Request&);
|
||||||
|
|
||||||
|
// Media Inputs
|
||||||
|
RequestResult GetMediaInputStatus(const Request&);
|
||||||
|
RequestResult SetMediaInputCursor(const Request&);
|
||||||
|
RequestResult OffsetMediaInputCursor(const Request&);
|
||||||
|
RequestResult TriggerMediaInputAction(const Request&);
|
||||||
|
|
||||||
SessionPtr _session;
|
SessionPtr _session;
|
||||||
static const std::map<std::string, RequestMethodHandler> _handlerMap;
|
static const std::map<std::string, RequestMethodHandler> _handlerMap;
|
||||||
};
|
};
|
||||||
|
@ -23,10 +23,10 @@ RequestResult RequestHandler::GetPersistentData(const Request& request)
|
|||||||
|
|
||||||
json responseData;
|
json responseData;
|
||||||
json persistentData;
|
json persistentData;
|
||||||
if (!(Utils::Json::GetJsonFileContent(persistentDataPath, persistentData) && persistentData.contains(slotName)))
|
if (Utils::Json::GetJsonFileContent(persistentDataPath, persistentData) && persistentData.contains(slotName))
|
||||||
responseData["slotValue"] = nullptr;
|
|
||||||
else
|
|
||||||
responseData["slotValue"] = persistentData[slotName];
|
responseData["slotValue"] = persistentData[slotName];
|
||||||
|
else
|
||||||
|
responseData["slotValue"] = nullptr;
|
||||||
|
|
||||||
return RequestResult::Success(responseData);
|
return RequestResult::Success(responseData);
|
||||||
}
|
}
|
||||||
@ -347,7 +347,7 @@ RequestResult RequestHandler::SetStreamServiceSettings(const Request& request)
|
|||||||
obs_service_update(currentStreamService, newStreamServiceSettings);
|
obs_service_update(currentStreamService, newStreamServiceSettings);
|
||||||
} else {
|
} else {
|
||||||
// TODO: This leaks memory. I have no idea why.
|
// TODO: This leaks memory. I have no idea why.
|
||||||
OBSService newStreamService = obs_service_create(requestedStreamServiceType.c_str(), "obs_websocket_custom_service", requestedStreamServiceSettings, NULL);
|
OBSService newStreamService = obs_service_create(requestedStreamServiceType.c_str(), "obs_websocket_custom_service", requestedStreamServiceSettings, nullptr);
|
||||||
// TODO: Check service type here, instead of relying on service creation to fail.
|
// TODO: Check service type here, instead of relying on service creation to fail.
|
||||||
if (!newStreamService)
|
if (!newStreamService)
|
||||||
return RequestResult::Error(RequestStatus::ResourceCreationFailed, "Failed to create the stream service with the requested streamServiceType. It may be an invalid type.");
|
return RequestResult::Error(RequestStatus::ResourceCreationFailed, "Failed to create the stream service with the requested streamServiceType. It may be an invalid type.");
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
RequestResult RequestHandler::GetVersion(const Request& request)
|
RequestResult RequestHandler::GetVersion(const Request& request)
|
||||||
{
|
{
|
||||||
json responseData;
|
json responseData;
|
||||||
responseData["obsVersion"] = Utils::Obs::StringHelper::GetObsVersionString();
|
responseData["obsVersion"] = Utils::Obs::StringHelper::GetObsVersion();
|
||||||
responseData["obsWebSocketVersion"] = OBS_WEBSOCKET_VERSION;
|
responseData["obsWebSocketVersion"] = OBS_WEBSOCKET_VERSION;
|
||||||
responseData["rpcVersion"] = OBS_WEBSOCKET_RPC_VERSION;
|
responseData["rpcVersion"] = OBS_WEBSOCKET_RPC_VERSION;
|
||||||
responseData["availableRequests"] = GetRequestList();
|
responseData["availableRequests"] = GetRequestList();
|
||||||
|
@ -319,7 +319,7 @@ RequestResult RequestHandler::GetInputAudioMonitorType(const Request& request)
|
|||||||
return RequestResult::Error(statusCode, comment);
|
return RequestResult::Error(statusCode, comment);
|
||||||
|
|
||||||
json responseData;
|
json responseData;
|
||||||
responseData["monitorType"] = Utils::Obs::StringHelper::GetInputMonitorTypeString(input);
|
responseData["monitorType"] = Utils::Obs::StringHelper::GetInputMonitorType(input);
|
||||||
|
|
||||||
return RequestResult::Success(responseData);
|
return RequestResult::Success(responseData);
|
||||||
}
|
}
|
||||||
@ -365,6 +365,8 @@ std::vector<json> GetListPropertyItems(obs_property_t *property)
|
|||||||
itemData["itemValue"] = obs_property_list_item_float(property, i);
|
itemData["itemValue"] = obs_property_list_item_float(property, i);
|
||||||
} else if (itemFormat == OBS_COMBO_FORMAT_STRING) {
|
} else if (itemFormat == OBS_COMBO_FORMAT_STRING) {
|
||||||
itemData["itemValue"] = obs_property_list_item_string(property, i);
|
itemData["itemValue"] = obs_property_list_item_string(property, i);
|
||||||
|
} else {
|
||||||
|
itemData["itemValue"] = nullptr;
|
||||||
}
|
}
|
||||||
ret.push_back(itemData);
|
ret.push_back(itemData);
|
||||||
}
|
}
|
||||||
|
110
src/requesthandler/RequestHandler_MediaInputs.cpp
Normal file
110
src/requesthandler/RequestHandler_MediaInputs.cpp
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
#include "RequestHandler.h"
|
||||||
|
|
||||||
|
bool IsMediaTimeValid(obs_source_t *input)
|
||||||
|
{
|
||||||
|
auto mediaState = obs_source_media_get_state(input);
|
||||||
|
return mediaState == OBS_MEDIA_STATE_PLAYING || mediaState == OBS_MEDIA_STATE_PAUSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestResult RequestHandler::GetMediaInputStatus(const Request& request)
|
||||||
|
{
|
||||||
|
RequestStatus::RequestStatus statusCode;
|
||||||
|
std::string comment;
|
||||||
|
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
|
||||||
|
if (!input)
|
||||||
|
return RequestResult::Error(statusCode, comment);
|
||||||
|
|
||||||
|
json responseData;
|
||||||
|
responseData["mediaState"] = Utils::Obs::StringHelper::GetMediaInputState(input);
|
||||||
|
|
||||||
|
if (IsMediaTimeValid(input)) {
|
||||||
|
responseData["mediaDuration"] = obs_source_media_get_duration(input);
|
||||||
|
responseData["mediaCursor"] = obs_source_media_get_time(input);
|
||||||
|
} else {
|
||||||
|
responseData["mediaDuration"] = nullptr;
|
||||||
|
responseData["mediaCursor"] = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RequestResult::Success(responseData);
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestResult RequestHandler::SetMediaInputCursor(const Request& request)
|
||||||
|
{
|
||||||
|
RequestStatus::RequestStatus statusCode;
|
||||||
|
std::string comment;
|
||||||
|
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
|
||||||
|
if (!(input && request.ValidateNumber("mediaCursor", statusCode, comment, 0)))
|
||||||
|
return RequestResult::Error(statusCode, comment);
|
||||||
|
|
||||||
|
if (!IsMediaTimeValid(input))
|
||||||
|
return RequestResult::Error(RequestStatus::InvalidResourceState, "The media input must be playing or paused in order to set the cursor position.");
|
||||||
|
|
||||||
|
int64_t mediaCursor = request.RequestData["mediaCursor"];
|
||||||
|
|
||||||
|
// Yes, we're setting the time without checking if it's valid. Can't baby everything.
|
||||||
|
obs_source_media_set_time(input, mediaCursor);
|
||||||
|
|
||||||
|
return RequestResult::Success();
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestResult RequestHandler::OffsetMediaInputCursor(const Request& request)
|
||||||
|
{
|
||||||
|
RequestStatus::RequestStatus statusCode;
|
||||||
|
std::string comment;
|
||||||
|
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
|
||||||
|
if (!(input && request.ValidateNumber("mediaCursorOffset", statusCode, comment)))
|
||||||
|
return RequestResult::Error(statusCode, comment);
|
||||||
|
|
||||||
|
if (!IsMediaTimeValid(input))
|
||||||
|
return RequestResult::Error(RequestStatus::InvalidResourceState, "The media input must be playing or paused in order to set the cursor position.");
|
||||||
|
|
||||||
|
int64_t mediaCursorOffset = request.RequestData["mediaCursorOffset"];
|
||||||
|
int64_t mediaCursor = obs_source_media_get_time(input) + mediaCursorOffset;
|
||||||
|
|
||||||
|
if (mediaCursor < 0)
|
||||||
|
mediaCursor = 0;
|
||||||
|
|
||||||
|
obs_source_media_set_time(input, mediaCursor);
|
||||||
|
|
||||||
|
return RequestResult::Success();
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestResult RequestHandler::TriggerMediaInputAction(const Request& request)
|
||||||
|
{
|
||||||
|
RequestStatus::RequestStatus statusCode;
|
||||||
|
std::string comment;
|
||||||
|
OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment);
|
||||||
|
if (!(input && request.ValidateString("mediaAction", statusCode, comment)))
|
||||||
|
return RequestResult::Error(statusCode, comment);
|
||||||
|
|
||||||
|
std::string mediaActionString = request.RequestData["mediaAction"];
|
||||||
|
auto mediaAction = Utils::Obs::EnumHelper::GetMediaInputAction(mediaActionString);
|
||||||
|
|
||||||
|
switch (mediaAction) {
|
||||||
|
default:
|
||||||
|
case OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE:
|
||||||
|
return RequestResult::Error(RequestStatus::InvalidRequestParameter, "You have specified an invalid media input action.");
|
||||||
|
case OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY:
|
||||||
|
// Shoutout to whoever implemented this API call like this
|
||||||
|
obs_source_media_play_pause(input, false);
|
||||||
|
break;
|
||||||
|
case OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE:
|
||||||
|
obs_source_media_play_pause(input, true);
|
||||||
|
break;
|
||||||
|
case OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP:
|
||||||
|
obs_source_media_stop(input);
|
||||||
|
break;
|
||||||
|
case OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART:
|
||||||
|
// I'm only implementing this because I'm nice. I think its a really dumb action.
|
||||||
|
obs_source_media_restart(input);
|
||||||
|
break;
|
||||||
|
case OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT:
|
||||||
|
obs_source_media_next(input);
|
||||||
|
break;
|
||||||
|
case OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS:
|
||||||
|
obs_source_media_previous(input);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RequestResult::Success();
|
||||||
|
}
|
@ -4,11 +4,13 @@ RequestResult RequestHandler::GetRecordStatus(const Request& request)
|
|||||||
{
|
{
|
||||||
OBSOutputAutoRelease recordOutput = obs_frontend_get_streaming_output();
|
OBSOutputAutoRelease recordOutput = obs_frontend_get_streaming_output();
|
||||||
|
|
||||||
|
uint64_t outputDuration = Utils::Obs::NumberHelper::GetOutputDuration(recordOutput);
|
||||||
|
|
||||||
json responseData;
|
json responseData;
|
||||||
responseData["outputActive"] = obs_output_active(recordOutput);
|
responseData["outputActive"] = obs_output_active(recordOutput);
|
||||||
responseData["outputPaused"] = obs_output_paused(recordOutput);
|
responseData["outputPaused"] = obs_output_paused(recordOutput);
|
||||||
responseData["outputTimecode"] = Utils::Obs::StringHelper::GetOutputTimecodeString(recordOutput);
|
responseData["outputTimecode"] = Utils::Obs::StringHelper::DurationToTimecode(outputDuration);
|
||||||
responseData["outputDuration"] = Utils::Obs::NumberHelper::GetOutputDuration(recordOutput);
|
responseData["outputDuration"] = outputDuration;
|
||||||
responseData["outputBytes"] = (uint64_t)obs_output_get_total_bytes(recordOutput);
|
responseData["outputBytes"] = (uint64_t)obs_output_get_total_bytes(recordOutput);
|
||||||
|
|
||||||
return RequestResult::Success(responseData);
|
return RequestResult::Success(responseData);
|
||||||
|
@ -4,11 +4,13 @@ RequestResult RequestHandler::GetStreamStatus(const Request& request)
|
|||||||
{
|
{
|
||||||
OBSOutputAutoRelease streamOutput = obs_frontend_get_streaming_output();
|
OBSOutputAutoRelease streamOutput = obs_frontend_get_streaming_output();
|
||||||
|
|
||||||
|
uint64_t outputDuration = Utils::Obs::NumberHelper::GetOutputDuration(streamOutput);
|
||||||
|
|
||||||
json responseData;
|
json responseData;
|
||||||
responseData["outputActive"] = obs_output_active(streamOutput);
|
responseData["outputActive"] = obs_output_active(streamOutput);
|
||||||
responseData["outputReconnecting"] = obs_output_reconnecting(streamOutput);
|
responseData["outputReconnecting"] = obs_output_reconnecting(streamOutput);
|
||||||
responseData["outputTimecode"] = Utils::Obs::StringHelper::GetOutputTimecodeString(streamOutput);
|
responseData["outputTimecode"] = Utils::Obs::StringHelper::DurationToTimecode(outputDuration);
|
||||||
responseData["outputDuration"] = Utils::Obs::NumberHelper::GetOutputDuration(streamOutput);
|
responseData["outputDuration"] = outputDuration;
|
||||||
responseData["outputBytes"] = (uint64_t)obs_output_get_total_bytes(streamOutput);
|
responseData["outputBytes"] = (uint64_t)obs_output_get_total_bytes(streamOutput);
|
||||||
responseData["outputSkippedFrames"] = obs_output_get_frames_dropped(streamOutput);
|
responseData["outputSkippedFrames"] = obs_output_get_frames_dropped(streamOutput);
|
||||||
responseData["outputTotalFrames"] = obs_output_get_total_frames(streamOutput);
|
responseData["outputTotalFrames"] = obs_output_get_total_frames(streamOutput);
|
||||||
|
@ -30,7 +30,7 @@ std::vector<std::string> ConvertStringArray(char **array)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Utils::Obs::StringHelper::GetObsVersionString()
|
std::string Utils::Obs::StringHelper::GetObsVersion()
|
||||||
{
|
{
|
||||||
uint32_t version = obs_get_version();
|
uint32_t version = obs_get_version();
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ std::string Utils::Obs::StringHelper::GetCurrentRecordOutputPath()
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Utils::Obs::StringHelper::GetSourceTypeString(obs_source_t *source)
|
std::string Utils::Obs::StringHelper::GetSourceType(obs_source_t *source)
|
||||||
{
|
{
|
||||||
obs_source_type sourceType = obs_source_get_type(source);
|
obs_source_type sourceType = obs_source_get_type(source);
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ std::string Utils::Obs::StringHelper::GetSourceTypeString(obs_source_t *source)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Utils::Obs::StringHelper::GetInputMonitorTypeString(obs_source_t *input)
|
std::string Utils::Obs::StringHelper::GetInputMonitorType(obs_source_t *input)
|
||||||
{
|
{
|
||||||
obs_monitoring_type monitorType = obs_source_get_monitoring_type(input);
|
obs_monitoring_type monitorType = obs_source_get_monitoring_type(input);
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ std::string Utils::Obs::StringHelper::GetInputMonitorTypeString(obs_source_t *in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Utils::Obs::StringHelper::GetMediaInputStateString(obs_source_t *input)
|
std::string Utils::Obs::StringHelper::GetMediaInputState(obs_source_t *input)
|
||||||
{
|
{
|
||||||
obs_media_state mediaState = obs_source_media_get_state(input);
|
obs_media_state mediaState = obs_source_media_get_state(input);
|
||||||
|
|
||||||
@ -130,7 +130,7 @@ std::string Utils::Obs::StringHelper::GetLastReplayBufferFilePath()
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Utils::Obs::StringHelper::GetSceneItemBoundsTypeString(enum obs_bounds_type type)
|
std::string Utils::Obs::StringHelper::GetSceneItemBoundsType(enum obs_bounds_type type)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
default:
|
default:
|
||||||
@ -144,16 +144,8 @@ std::string Utils::Obs::StringHelper::GetSceneItemBoundsTypeString(enum obs_boun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Utils::Obs::StringHelper::GetOutputTimecodeString(obs_output_t *output)
|
std::string Utils::Obs::StringHelper::DurationToTimecode(uint64_t ms)
|
||||||
{
|
{
|
||||||
if (!output || !obs_output_active(output))
|
|
||||||
return "00:00:00.000";
|
|
||||||
|
|
||||||
video_t* video = obs_output_video(output);
|
|
||||||
uint64_t frameTimeNs = video_output_get_frame_time(video);
|
|
||||||
int totalFrames = obs_output_get_total_frames(output);
|
|
||||||
|
|
||||||
uint64_t ms = util_mul_div64(totalFrames, frameTimeNs, 1000000ULL);
|
|
||||||
uint64_t secs = ms / 1000ULL;
|
uint64_t secs = ms / 1000ULL;
|
||||||
uint64_t minutes = secs / 60ULL;
|
uint64_t minutes = secs / 60ULL;
|
||||||
|
|
||||||
@ -179,6 +171,18 @@ enum obs_bounds_type Utils::Obs::EnumHelper::GetSceneItemBoundsType(std::string
|
|||||||
return OBS_BOUNDS_NONE;
|
return OBS_BOUNDS_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ObsMediaInputAction Utils::Obs::EnumHelper::GetMediaInputAction(std::string mediaAction)
|
||||||
|
{
|
||||||
|
RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY);
|
||||||
|
RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE);
|
||||||
|
RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP);
|
||||||
|
RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART);
|
||||||
|
RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT);
|
||||||
|
RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS);
|
||||||
|
|
||||||
|
return OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t Utils::Obs::NumberHelper::GetOutputDuration(obs_output_t *output)
|
uint64_t Utils::Obs::NumberHelper::GetOutputDuration(obs_output_t *output)
|
||||||
{
|
{
|
||||||
if (!output || !obs_output_active(output))
|
if (!output || !obs_output_active(output))
|
||||||
@ -288,11 +292,15 @@ std::vector<json> Utils::Obs::ListHelper::GetSceneItemList(obs_scene_t *scene, b
|
|||||||
if (!enumData->second) {
|
if (!enumData->second) {
|
||||||
OBSSource itemSource = obs_sceneitem_get_source(sceneItem);
|
OBSSource itemSource = obs_sceneitem_get_source(sceneItem);
|
||||||
item["sourceName"] = obs_source_get_name(itemSource);
|
item["sourceName"] = obs_source_get_name(itemSource);
|
||||||
item["sourceType"] = StringHelper::GetSourceTypeString(itemSource);
|
item["sourceType"] = StringHelper::GetSourceType(itemSource);
|
||||||
if (obs_source_get_type(itemSource) == OBS_SOURCE_TYPE_INPUT)
|
if (obs_source_get_type(itemSource) == OBS_SOURCE_TYPE_INPUT)
|
||||||
item["inputKind"] = obs_source_get_id(itemSource);
|
item["inputKind"] = obs_source_get_id(itemSource);
|
||||||
else if (obs_source_get_type(itemSource) == OBS_SOURCE_TYPE_SCENE)
|
else
|
||||||
|
item["inputKind"] = nullptr;
|
||||||
|
if (obs_source_get_type(itemSource) == OBS_SOURCE_TYPE_SCENE)
|
||||||
item["isGroup"] = obs_source_is_group(itemSource);
|
item["isGroup"] = obs_source_is_group(itemSource);
|
||||||
|
else
|
||||||
|
item["isGroup"] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
enumData->first.push_back(item);
|
enumData->first.push_back(item);
|
||||||
@ -433,7 +441,7 @@ json Utils::Obs::DataHelper::GetSceneItemTransform(obs_sceneitem_t *item)
|
|||||||
|
|
||||||
ret["alignment"] = osi.alignment;
|
ret["alignment"] = osi.alignment;
|
||||||
|
|
||||||
ret["boundsType"] = StringHelper::GetSceneItemBoundsTypeString(osi.bounds_type);
|
ret["boundsType"] = StringHelper::GetSceneItemBoundsType(osi.bounds_type);
|
||||||
ret["boundsAlignment"] = osi.bounds_alignment;
|
ret["boundsAlignment"] = osi.bounds_alignment;
|
||||||
ret["boundsWidth"] = osi.bounds.x;
|
ret["boundsWidth"] = osi.bounds.x;
|
||||||
ret["boundsHeight"] = osi.bounds.y;
|
ret["boundsHeight"] = osi.bounds.y;
|
||||||
|
@ -16,10 +16,11 @@ enum ObsOutputState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum ObsMediaInputAction {
|
enum ObsMediaInputAction {
|
||||||
OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE,
|
OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE,
|
||||||
OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY,
|
OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY,
|
||||||
OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART,
|
OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE,
|
||||||
OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP,
|
OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP,
|
||||||
|
OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART,
|
||||||
OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT,
|
OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT,
|
||||||
OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS
|
OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS
|
||||||
};
|
};
|
||||||
@ -27,21 +28,22 @@ enum ObsMediaInputAction {
|
|||||||
namespace Utils {
|
namespace Utils {
|
||||||
namespace Obs {
|
namespace Obs {
|
||||||
namespace StringHelper {
|
namespace StringHelper {
|
||||||
std::string GetObsVersionString();
|
std::string GetObsVersion();
|
||||||
std::string GetCurrentSceneCollection();
|
std::string GetCurrentSceneCollection();
|
||||||
std::string GetCurrentProfile();
|
std::string GetCurrentProfile();
|
||||||
std::string GetCurrentProfilePath();
|
std::string GetCurrentProfilePath();
|
||||||
std::string GetCurrentRecordOutputPath();
|
std::string GetCurrentRecordOutputPath();
|
||||||
std::string GetSourceTypeString(obs_source_t *source);
|
std::string GetSourceType(obs_source_t *source);
|
||||||
std::string GetInputMonitorTypeString(obs_source_t *input);
|
std::string GetInputMonitorType(obs_source_t *input);
|
||||||
std::string GetMediaInputStateString(obs_source_t *input);
|
std::string GetMediaInputState(obs_source_t *input);
|
||||||
std::string GetLastReplayBufferFilePath();
|
std::string GetLastReplayBufferFilePath();
|
||||||
std::string GetSceneItemBoundsTypeString(enum obs_bounds_type type);
|
std::string GetSceneItemBoundsType(enum obs_bounds_type type);
|
||||||
std::string GetOutputTimecodeString(obs_output_t *output);
|
std::string DurationToTimecode(uint64_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace EnumHelper {
|
namespace EnumHelper {
|
||||||
enum obs_bounds_type GetSceneItemBoundsType(std::string boundsType);
|
enum obs_bounds_type GetSceneItemBoundsType(std::string boundsType);
|
||||||
|
enum ObsMediaInputAction GetMediaInputAction(std::string mediaAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace NumberHelper {
|
namespace NumberHelper {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user