mirror of
https://github.com/Palakis/obs-websocket.git
synced 2024-08-30 18:12:16 +00:00
requesthandler: Add Outputs requests
Co-authored-by: Ruggero Tomaselli <ruggerotomaselli@gmail.com> Co-authored-by: tt2468 <tt2468@irltoolkit.com>
This commit is contained in:
parent
a22a7cf993
commit
1dd57f6140
@ -151,6 +151,13 @@ const std::unordered_map<std::string, RequestMethodHandler> RequestHandler::_han
|
|||||||
{"StopReplayBuffer", &RequestHandler::StopReplayBuffer},
|
{"StopReplayBuffer", &RequestHandler::StopReplayBuffer},
|
||||||
{"SaveReplayBuffer", &RequestHandler::SaveReplayBuffer},
|
{"SaveReplayBuffer", &RequestHandler::SaveReplayBuffer},
|
||||||
{"GetLastReplayBufferReplay", &RequestHandler::GetLastReplayBufferReplay},
|
{"GetLastReplayBufferReplay", &RequestHandler::GetLastReplayBufferReplay},
|
||||||
|
{"GetOutputList", &RequestHandler::GetOutputList},
|
||||||
|
{"GetOutputStatus", &RequestHandler::GetOutputStatus},
|
||||||
|
{"ToggleOutput", &RequestHandler::ToggleOutput},
|
||||||
|
{"StartOutput", &RequestHandler::StartOutput},
|
||||||
|
{"StopOutput", &RequestHandler::StopOutput},
|
||||||
|
{"GetOutputSettings", &RequestHandler::GetOutputSettings},
|
||||||
|
{"SetOutputSettings", &RequestHandler::SetOutputSettings},
|
||||||
|
|
||||||
// Stream
|
// Stream
|
||||||
{"GetStreamStatus", &RequestHandler::GetStreamStatus},
|
{"GetStreamStatus", &RequestHandler::GetStreamStatus},
|
||||||
|
@ -170,6 +170,13 @@ private:
|
|||||||
RequestResult StopReplayBuffer(const Request &);
|
RequestResult StopReplayBuffer(const Request &);
|
||||||
RequestResult SaveReplayBuffer(const Request &);
|
RequestResult SaveReplayBuffer(const Request &);
|
||||||
RequestResult GetLastReplayBufferReplay(const Request &);
|
RequestResult GetLastReplayBufferReplay(const Request &);
|
||||||
|
RequestResult GetOutputList(const Request &);
|
||||||
|
RequestResult GetOutputStatus(const Request &);
|
||||||
|
RequestResult ToggleOutput(const Request &);
|
||||||
|
RequestResult StartOutput(const Request &);
|
||||||
|
RequestResult StopOutput(const Request &);
|
||||||
|
RequestResult GetOutputSettings(const Request &);
|
||||||
|
RequestResult SetOutputSettings(const Request &);
|
||||||
|
|
||||||
// Stream
|
// Stream
|
||||||
RequestResult GetStreamStatus(const Request &);
|
RequestResult GetStreamStatus(const Request &);
|
||||||
|
@ -275,3 +275,214 @@ RequestResult RequestHandler::GetLastReplayBufferReplay(const Request &)
|
|||||||
responseData["savedReplayPath"] = Utils::Obs::StringHelper::GetLastReplayBufferFileName();
|
responseData["savedReplayPath"] = Utils::Obs::StringHelper::GetLastReplayBufferFileName();
|
||||||
return RequestResult::Success(responseData);
|
return RequestResult::Success(responseData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of available outputs.
|
||||||
|
*
|
||||||
|
* @requestType GetOutputList
|
||||||
|
* @complexity 4
|
||||||
|
* @rpcVersion -1
|
||||||
|
* @initialVersion 5.0.0
|
||||||
|
* @api requests
|
||||||
|
* @category outputs
|
||||||
|
*/
|
||||||
|
RequestResult RequestHandler::GetOutputList(const Request &)
|
||||||
|
{
|
||||||
|
json responseData;
|
||||||
|
responseData["outputs"] = Utils::Obs::ArrayHelper::GetOutputList();
|
||||||
|
return RequestResult::Success(responseData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the status of an output.
|
||||||
|
*
|
||||||
|
* @requestField outputName | String | Output name
|
||||||
|
*
|
||||||
|
* @responseField outputActive | Boolean | Whether the output is active
|
||||||
|
* @responseField outputReconnecting | Boolean | Whether the output is reconnecting
|
||||||
|
* @responseField outputTimecode | String | Current formatted timecode string for the output
|
||||||
|
* @responseField outputDuration | Number | Current duration in milliseconds for the output
|
||||||
|
* @responseField outputCongestion | Number | Congestion of the output
|
||||||
|
* @responseField outputBytes | Number | Number of bytes sent by the output
|
||||||
|
* @responseField outputSkippedFrames | Number | Number of frames skipped by the output's process
|
||||||
|
* @responseField outputTotalFrames | Number | Total number of frames delivered by the output's process
|
||||||
|
*
|
||||||
|
* @requestType GetOutputStatus
|
||||||
|
* @complexity 4
|
||||||
|
* @rpcVersion -1
|
||||||
|
* @initialVersion 5.0.0
|
||||||
|
* @api requests
|
||||||
|
* @category outputs
|
||||||
|
*/
|
||||||
|
RequestResult RequestHandler::GetOutputStatus(const Request &request)
|
||||||
|
{
|
||||||
|
RequestStatus::RequestStatus statusCode;
|
||||||
|
std::string comment;
|
||||||
|
OBSOutputAutoRelease output = request.ValidateOutput("outputName", statusCode, comment);
|
||||||
|
if (!output)
|
||||||
|
return RequestResult::Error(statusCode, comment);
|
||||||
|
|
||||||
|
uint64_t outputDuration = Utils::Obs::NumberHelper::GetOutputDuration(output);
|
||||||
|
|
||||||
|
json responseData;
|
||||||
|
responseData["outputActive"] = obs_output_active(output);
|
||||||
|
responseData["outputReconnecting"] = obs_output_reconnecting(output);
|
||||||
|
responseData["outputTimecode"] = Utils::Obs::StringHelper::DurationToTimecode(outputDuration);
|
||||||
|
responseData["outputDuration"] = outputDuration;
|
||||||
|
responseData["outputCongestion"] = obs_output_get_congestion(output);
|
||||||
|
responseData["outputBytes"] = obs_output_get_total_bytes(output);
|
||||||
|
responseData["outputSkippedFrames"] = obs_output_get_frames_dropped(output);
|
||||||
|
responseData["outputTotalFrames"] = obs_output_get_total_frames(output);
|
||||||
|
|
||||||
|
return RequestResult::Success(responseData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles the status of an output.
|
||||||
|
*
|
||||||
|
* @requestField outputName | String | Output name
|
||||||
|
*
|
||||||
|
* @responseField outputActive | Boolean | Whether the output is active
|
||||||
|
*
|
||||||
|
* @requestType ToggleOutput
|
||||||
|
* @complexity 4
|
||||||
|
* @rpcVersion -1
|
||||||
|
* @initialVersion 5.0.0
|
||||||
|
* @api requests
|
||||||
|
* @category outputs
|
||||||
|
*/
|
||||||
|
RequestResult RequestHandler::ToggleOutput(const Request &request)
|
||||||
|
{
|
||||||
|
RequestStatus::RequestStatus statusCode;
|
||||||
|
std::string comment;
|
||||||
|
OBSOutputAutoRelease output = request.ValidateOutput("outputName", statusCode, comment);
|
||||||
|
if (!output)
|
||||||
|
return RequestResult::Error(statusCode, comment);
|
||||||
|
|
||||||
|
bool outputActive = obs_output_active(output);
|
||||||
|
if (outputActive)
|
||||||
|
obs_output_stop(output);
|
||||||
|
else
|
||||||
|
obs_output_start(output);
|
||||||
|
|
||||||
|
json responseData;
|
||||||
|
responseData["outputActive"] = !outputActive;
|
||||||
|
return RequestResult::Success(responseData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts an output.
|
||||||
|
*
|
||||||
|
* @requestField outputName | String | Output name
|
||||||
|
*
|
||||||
|
* @requestType StartOutput
|
||||||
|
* @complexity 4
|
||||||
|
* @rpcVersion -1
|
||||||
|
* @initialVersion 5.0.0
|
||||||
|
* @api requests
|
||||||
|
* @category outputs
|
||||||
|
*/
|
||||||
|
RequestResult RequestHandler::StartOutput(const Request &request)
|
||||||
|
{
|
||||||
|
RequestStatus::RequestStatus statusCode;
|
||||||
|
std::string comment;
|
||||||
|
OBSOutputAutoRelease output = request.ValidateOutput("outputName", statusCode, comment);
|
||||||
|
if (!output)
|
||||||
|
return RequestResult::Error(statusCode, comment);
|
||||||
|
|
||||||
|
if (obs_output_active(output))
|
||||||
|
return RequestResult::Error(RequestStatus::OutputRunning);
|
||||||
|
|
||||||
|
obs_output_start(output);
|
||||||
|
|
||||||
|
return RequestResult::Success();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops an output.
|
||||||
|
*
|
||||||
|
* @requestField outputName | String | Output name
|
||||||
|
*
|
||||||
|
* @requestType StopOutput
|
||||||
|
* @complexity 4
|
||||||
|
* @rpcVersion -1
|
||||||
|
* @initialVersion 5.0.0
|
||||||
|
* @api requests
|
||||||
|
* @category outputs
|
||||||
|
*/
|
||||||
|
RequestResult RequestHandler::StopOutput(const Request &request)
|
||||||
|
{
|
||||||
|
RequestStatus::RequestStatus statusCode;
|
||||||
|
std::string comment;
|
||||||
|
OBSOutputAutoRelease output = request.ValidateOutput("outputName", statusCode, comment);
|
||||||
|
if (!output)
|
||||||
|
return RequestResult::Error(statusCode, comment);
|
||||||
|
|
||||||
|
if (!obs_output_active(output))
|
||||||
|
return RequestResult::Error(RequestStatus::OutputNotRunning);
|
||||||
|
|
||||||
|
obs_output_stop(output);
|
||||||
|
|
||||||
|
return RequestResult::Success();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the settings of an output.
|
||||||
|
*
|
||||||
|
* @requestField outputName | String | Output name
|
||||||
|
*
|
||||||
|
* @responseField outputSettings | Object | Output settings
|
||||||
|
*
|
||||||
|
* @requestType GetOutputSettings
|
||||||
|
* @complexity 4
|
||||||
|
* @rpcVersion -1
|
||||||
|
* @initialVersion 5.0.0
|
||||||
|
* @api requests
|
||||||
|
* @category outputs
|
||||||
|
*/
|
||||||
|
RequestResult RequestHandler::GetOutputSettings(const Request &request)
|
||||||
|
{
|
||||||
|
RequestStatus::RequestStatus statusCode;
|
||||||
|
std::string comment;
|
||||||
|
OBSOutputAutoRelease output = request.ValidateOutput("outputName", statusCode, comment);
|
||||||
|
if (!output)
|
||||||
|
return RequestResult::Error(statusCode, comment);
|
||||||
|
|
||||||
|
OBSDataAutoRelease outputSettings = obs_output_get_settings(output);
|
||||||
|
|
||||||
|
json responseData;
|
||||||
|
responseData["outputSettings"] = Utils::Json::ObsDataToJson(outputSettings);
|
||||||
|
return RequestResult::Success(responseData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the settings of an output.
|
||||||
|
*
|
||||||
|
* @requestField outputName | String | Output name
|
||||||
|
* @requestField outputSettings | Object | Output settings
|
||||||
|
*
|
||||||
|
* @requestType SetOutputSettings
|
||||||
|
* @complexity 4
|
||||||
|
* @rpcVersion -1
|
||||||
|
* @initialVersion 5.0.0
|
||||||
|
* @api requests
|
||||||
|
* @category outputs
|
||||||
|
*/
|
||||||
|
RequestResult RequestHandler::SetOutputSettings(const Request &request)
|
||||||
|
{
|
||||||
|
RequestStatus::RequestStatus statusCode;
|
||||||
|
std::string comment;
|
||||||
|
OBSOutputAutoRelease output = request.ValidateOutput("outputName", statusCode, comment);
|
||||||
|
if (!(output && request.ValidateObject("outputSettings", statusCode, comment, true)))
|
||||||
|
return RequestResult::Error(statusCode, comment);
|
||||||
|
|
||||||
|
OBSDataAutoRelease newSettings = Utils::Json::JsonToObsData(request.RequestData["outputSettings"]);
|
||||||
|
if (!newSettings)
|
||||||
|
// This should never happen
|
||||||
|
return RequestResult::Error(RequestStatus::RequestProcessingFailed,
|
||||||
|
"An internal data conversion operation failed. Please report this!");
|
||||||
|
|
||||||
|
obs_output_update(output, newSettings);
|
||||||
|
|
||||||
|
return RequestResult::Success();
|
||||||
|
}
|
||||||
|
@ -26,6 +26,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
|||||||
* @responseField outputReconnecting | Boolean | Whether the output is currently reconnecting
|
* @responseField outputReconnecting | Boolean | Whether the output is currently reconnecting
|
||||||
* @responseField outputTimecode | String | Current formatted timecode string for the output
|
* @responseField outputTimecode | String | Current formatted timecode string for the output
|
||||||
* @responseField outputDuration | Number | Current duration in milliseconds for the output
|
* @responseField outputDuration | Number | Current duration in milliseconds for the output
|
||||||
|
* @responseField outputCongestion | Number | Congestion of the output
|
||||||
* @responseField outputBytes | Number | Number of bytes sent by the output
|
* @responseField outputBytes | Number | Number of bytes sent by the output
|
||||||
* @responseField outputSkippedFrames | Number | Number of frames skipped by the output's process
|
* @responseField outputSkippedFrames | Number | Number of frames skipped by the output's process
|
||||||
* @responseField outputTotalFrames | Number | Total number of frames delivered by the output's process
|
* @responseField outputTotalFrames | Number | Total number of frames delivered by the output's process
|
||||||
@ -48,6 +49,7 @@ RequestResult RequestHandler::GetStreamStatus(const Request &)
|
|||||||
responseData["outputReconnecting"] = obs_output_reconnecting(streamOutput);
|
responseData["outputReconnecting"] = obs_output_reconnecting(streamOutput);
|
||||||
responseData["outputTimecode"] = Utils::Obs::StringHelper::DurationToTimecode(outputDuration);
|
responseData["outputTimecode"] = Utils::Obs::StringHelper::DurationToTimecode(outputDuration);
|
||||||
responseData["outputDuration"] = outputDuration;
|
responseData["outputDuration"] = outputDuration;
|
||||||
|
responseData["outputCongestion"] = obs_output_get_congestion(streamOutput);
|
||||||
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);
|
||||||
|
@ -232,7 +232,8 @@ RequestResult RequestHandler::OpenVideoMixProjector(const Request &request)
|
|||||||
else if (videoMixType == "OBS_WEBSOCKET_VIDEO_MIX_TYPE_MULTIVIEW")
|
else if (videoMixType == "OBS_WEBSOCKET_VIDEO_MIX_TYPE_MULTIVIEW")
|
||||||
projectorType = "Multiview";
|
projectorType = "Multiview";
|
||||||
else
|
else
|
||||||
return RequestResult::Error(RequestStatus::InvalidRequestField, "The field `videoMixType` has an invalid enum value.");
|
return RequestResult::Error(RequestStatus::InvalidRequestField,
|
||||||
|
"The field `videoMixType` has an invalid enum value.");
|
||||||
|
|
||||||
int monitorIndex = -1;
|
int monitorIndex = -1;
|
||||||
if (request.Contains("monitorIndex")) {
|
if (request.Contains("monitorIndex")) {
|
||||||
@ -246,7 +247,8 @@ RequestResult RequestHandler::OpenVideoMixProjector(const Request &request)
|
|||||||
if (!request.ValidateOptionalString("projectorGeometry", statusCode, comment))
|
if (!request.ValidateOptionalString("projectorGeometry", statusCode, comment))
|
||||||
return RequestResult::Error(statusCode, comment);
|
return RequestResult::Error(statusCode, comment);
|
||||||
if (monitorIndex != -1)
|
if (monitorIndex != -1)
|
||||||
return RequestResult::Error(RequestStatus::TooManyRequestFields, "`monitorIndex` and `projectorGeometry` are mutually exclusive.");
|
return RequestResult::Error(RequestStatus::TooManyRequestFields,
|
||||||
|
"`monitorIndex` and `projectorGeometry` are mutually exclusive.");
|
||||||
projectorGeometry = request.RequestData["projectorGeometry"];
|
projectorGeometry = request.RequestData["projectorGeometry"];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,7 +293,8 @@ RequestResult RequestHandler::OpenSourceProjector(const Request &request)
|
|||||||
if (!request.ValidateOptionalString("projectorGeometry", statusCode, comment))
|
if (!request.ValidateOptionalString("projectorGeometry", statusCode, comment))
|
||||||
return RequestResult::Error(statusCode, comment);
|
return RequestResult::Error(statusCode, comment);
|
||||||
if (monitorIndex != -1)
|
if (monitorIndex != -1)
|
||||||
return RequestResult::Error(RequestStatus::TooManyRequestFields, "`monitorIndex` and `projectorGeometry` are mutually exclusive.");
|
return RequestResult::Error(RequestStatus::TooManyRequestFields,
|
||||||
|
"`monitorIndex` and `projectorGeometry` are mutually exclusive.");
|
||||||
projectorGeometry = request.RequestData["projectorGeometry"];
|
projectorGeometry = request.RequestData["projectorGeometry"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,3 +354,21 @@ obs_sceneitem_t *Request::ValidateSceneItem(const std::string &sceneKeyName, con
|
|||||||
obs_sceneitem_addref(sceneItem);
|
obs_sceneitem_addref(sceneItem);
|
||||||
return sceneItem;
|
return sceneItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
obs_output_t *Request::ValidateOutput(const std::string &keyName, RequestStatus::RequestStatus &statusCode,
|
||||||
|
std::string &comment) const
|
||||||
|
{
|
||||||
|
if (!ValidateString(keyName, statusCode, comment))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
std::string outputName = RequestData[keyName];
|
||||||
|
|
||||||
|
obs_output_t *ret = obs_get_output_by_name(outputName.c_str());
|
||||||
|
if (!ret) {
|
||||||
|
statusCode = RequestStatus::ResourceNotFound;
|
||||||
|
comment = std::string("No output was found with the name `") + outputName + "`.";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -77,6 +77,8 @@ struct Request {
|
|||||||
obs_sceneitem_t *ValidateSceneItem(const std::string &sceneKeyName, const std::string &sceneItemIdKeyName,
|
obs_sceneitem_t *ValidateSceneItem(const std::string &sceneKeyName, const std::string &sceneItemIdKeyName,
|
||||||
RequestStatus::RequestStatus &statusCode, std::string &comment,
|
RequestStatus::RequestStatus &statusCode, std::string &comment,
|
||||||
const ObsWebSocketSceneFilter filter = OBS_WEBSOCKET_SCENE_FILTER_SCENE_ONLY) const;
|
const ObsWebSocketSceneFilter filter = OBS_WEBSOCKET_SCENE_FILTER_SCENE_ONLY) const;
|
||||||
|
obs_output_t *ValidateOutput(const std::string &keyName, RequestStatus::RequestStatus &statusCode,
|
||||||
|
std::string &comment) const;
|
||||||
|
|
||||||
std::string RequestType;
|
std::string RequestType;
|
||||||
bool HasRequestData;
|
bool HasRequestData;
|
||||||
|
@ -205,6 +205,7 @@ namespace Utils {
|
|||||||
std::vector<json> GetSceneTransitionList();
|
std::vector<json> GetSceneTransitionList();
|
||||||
std::vector<json> GetSourceFilterList(obs_source_t *source);
|
std::vector<json> GetSourceFilterList(obs_source_t *source);
|
||||||
std::vector<std::string> GetFilterKindList();
|
std::vector<std::string> GetFilterKindList();
|
||||||
|
std::vector<json> GetOutputList();
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ObjectHelper {
|
namespace ObjectHelper {
|
||||||
|
@ -327,3 +327,35 @@ std::vector<json> Utils::Obs::ArrayHelper::GetSourceFilterList(obs_source_t *sou
|
|||||||
|
|
||||||
return filters;
|
return filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<json> Utils::Obs::ArrayHelper::GetOutputList()
|
||||||
|
{
|
||||||
|
std::vector<json> outputs;
|
||||||
|
|
||||||
|
auto cb = [](void *param, obs_output_t *output) {
|
||||||
|
auto outputs = reinterpret_cast<std::vector<json> *>(param);
|
||||||
|
|
||||||
|
auto rawFlags = obs_output_get_flags(output);
|
||||||
|
json flags;
|
||||||
|
flags["OBS_OUTPUT_AUDIO"] = !!(rawFlags & OBS_OUTPUT_AUDIO);
|
||||||
|
flags["OBS_OUTPUT_VIDEO"] = !!(rawFlags & OBS_OUTPUT_VIDEO);
|
||||||
|
flags["OBS_OUTPUT_ENCODED"] = !!(rawFlags & OBS_OUTPUT_ENCODED);
|
||||||
|
flags["OBS_OUTPUT_MULTI_TRACK"] = !!(rawFlags & OBS_OUTPUT_MULTI_TRACK);
|
||||||
|
flags["OBS_OUTPUT_SERVICE"] = !!(rawFlags & OBS_OUTPUT_SERVICE);
|
||||||
|
|
||||||
|
json outputJson;
|
||||||
|
outputJson["outputName"] = obs_output_get_name(output);
|
||||||
|
outputJson["outputKind"] = obs_output_get_id(output);
|
||||||
|
outputJson["outputWidth"] = obs_output_get_width(output);
|
||||||
|
outputJson["outputHeight"] = obs_output_get_height(output);
|
||||||
|
outputJson["outputActive"] = obs_output_active(output);
|
||||||
|
outputJson["outputFlags"] = flags;
|
||||||
|
|
||||||
|
outputs->push_back(outputJson);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
obs_enum_outputs(cb, &outputs);
|
||||||
|
|
||||||
|
return outputs;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user