mirror of
https://github.com/dnaka91/obws
synced 2024-11-13 19:12:03 +00:00
Implement transition commands
This commit is contained in:
parent
a2e189b355
commit
7dc39a98ef
@ -31,7 +31,7 @@ use tracing::{debug, error, trace};
|
||||
pub use self::{
|
||||
config::Config, general::General, inputs::Inputs, media_inputs::MediaInputs, outputs::Outputs,
|
||||
recording::Recording, scene_items::SceneItems, scenes::Scenes, sources::Sources,
|
||||
streaming::Streaming,
|
||||
streaming::Streaming, transitions::Transitions,
|
||||
};
|
||||
#[cfg(feature = "events")]
|
||||
use crate::events::Event;
|
||||
@ -51,6 +51,7 @@ mod scene_items;
|
||||
mod scenes;
|
||||
mod sources;
|
||||
mod streaming;
|
||||
mod transitions;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
enum InnerError {
|
||||
@ -442,6 +443,11 @@ impl Client {
|
||||
pub fn streaming(&self) -> Streaming<'_> {
|
||||
Streaming { client: self }
|
||||
}
|
||||
|
||||
/// Access API functions related to transitions.
|
||||
pub fn transitions(&self) -> Transitions<'_> {
|
||||
Transitions { client: self }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Client {
|
||||
|
@ -7,7 +7,7 @@ pub struct Streaming<'a> {
|
||||
}
|
||||
|
||||
impl<'a> Streaming<'a> {
|
||||
/// Gets the status of the stream output..
|
||||
/// Gets the status of the stream output.
|
||||
pub async fn get_stream_status(&self) -> Result<responses::StreamStatus> {
|
||||
self.client.send_message(RequestType::GetStreamStatus).await
|
||||
}
|
||||
|
115
src/client/transitions.rs
Normal file
115
src/client/transitions.rs
Normal file
@ -0,0 +1,115 @@
|
||||
use serde::Serialize;
|
||||
use time::Duration;
|
||||
|
||||
use super::Client;
|
||||
use crate::{requests::RequestType, responses, Error, Result};
|
||||
|
||||
/// API functions related to transitions.
|
||||
pub struct Transitions<'a> {
|
||||
pub(super) client: &'a Client,
|
||||
}
|
||||
|
||||
impl<'a> Transitions<'a> {
|
||||
/// Gets an array of all available transition kinds.
|
||||
pub async fn get_transition_kind_list(&self) -> Result<Vec<String>> {
|
||||
self.client
|
||||
.send_message::<responses::TransitionKinds>(RequestType::GetTransitionKindList)
|
||||
.await
|
||||
.map(|tk| tk.transition_kinds)
|
||||
}
|
||||
|
||||
/// Gets an array of all scene transitions in OBS.
|
||||
pub async fn get_scene_transition_list(&self) -> Result<responses::SceneTransitionList> {
|
||||
self.client
|
||||
.send_message(RequestType::GetSceneTransitionList)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Gets information about the current scene transition.
|
||||
pub async fn get_current_scene_transition(&self) -> Result<responses::CurrentSceneTransition> {
|
||||
self.client
|
||||
.send_message(RequestType::GetCurrentSceneTransition)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Sets the current scene transition.
|
||||
///
|
||||
/// **Small note:** While the namespace of scene transitions is generally unique, that
|
||||
/// uniqueness is not a guarantee as it is with other resources like inputs.
|
||||
///
|
||||
/// - `transition_name`: Name of the transition to make active.
|
||||
pub async fn set_current_scene_transition(&self, transition_name: &str) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetCurrentSceneTransition { transition_name })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Sets the duration of the current scene transition, if it is not fixed.
|
||||
///
|
||||
/// - `transition_duration`: Duration in milliseconds.
|
||||
pub async fn set_current_scene_transition_duration(
|
||||
&self,
|
||||
transition_duration: Duration,
|
||||
) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetCurrentSceneTransitionDuration {
|
||||
transition_duration,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Sets the settings of the current scene transition.
|
||||
///
|
||||
/// - `transition_settings`: Settings object to apply to the transition.
|
||||
/// - `overlay`: Whether to overlay over the current settings or replace them.
|
||||
pub async fn set_current_scene_transition_settings<T>(
|
||||
&self,
|
||||
transition_settings: T,
|
||||
overlay: Option<bool>,
|
||||
) -> Result<()>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
self.client
|
||||
.send_message(RequestType::SetCurrentSceneTransitionSettings {
|
||||
transition_settings: serde_json::to_value(&transition_settings)
|
||||
.map_err(Error::SerializeCustomData)?,
|
||||
overlay,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Gets the cursor position of the current scene transition.
|
||||
///
|
||||
/// **Note:** `transitionCursor` will return `1.0` when the transition is inactive.
|
||||
pub async fn get_current_scene_transition_cursor(&self) -> Result<f32> {
|
||||
self.client
|
||||
.send_message::<responses::TransitionCursor>(
|
||||
RequestType::GetCurrentSceneTransitionCursor,
|
||||
)
|
||||
.await
|
||||
.map(|tc| tc.transition_cursor)
|
||||
}
|
||||
|
||||
/// Triggers the current scene transition. Same functionality as the `Transition` button in
|
||||
/// studio mode.
|
||||
pub async fn trigger_studio_mode_transition(&self) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::TriggerStudioModeTransition)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Sets the position of the TBar.
|
||||
///
|
||||
/// **Very important note:** This will be deprecated and replaced in a future version of
|
||||
/// `obs-websocket`.
|
||||
///
|
||||
/// - `position`: New position.
|
||||
/// - `release`: Whether to release the TBar. Only set `false` if you know that you will be
|
||||
/// sending another position update.
|
||||
pub async fn set_tbar_position(&self, position: f32, release: Option<bool>) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetTbarPosition { position, release })
|
||||
.await
|
||||
}
|
||||
}
|
@ -288,6 +288,7 @@ pub(crate) enum RequestType<'a> {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
GetInputList {
|
||||
/// Restrict the array to only inputs of the specified kind.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
input_kind: Option<&'a str>,
|
||||
},
|
||||
GetInputKindList {
|
||||
@ -559,6 +560,42 @@ pub(crate) enum RequestType<'a> {
|
||||
/// Caption text.
|
||||
caption_text: &'a str,
|
||||
},
|
||||
// --------------------------------
|
||||
// Transitions
|
||||
// --------------------------------
|
||||
GetTransitionKindList,
|
||||
GetSceneTransitionList,
|
||||
GetCurrentSceneTransition,
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SetCurrentSceneTransition {
|
||||
/// Name of the transition to make active.
|
||||
transition_name: &'a str,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SetCurrentSceneTransitionDuration {
|
||||
/// Duration in milliseconds.
|
||||
#[serde(serialize_with = "ser::duration_millis")]
|
||||
transition_duration: Duration,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SetCurrentSceneTransitionSettings {
|
||||
/// Settings object to apply to the transition.
|
||||
transition_settings: serde_json::Value,
|
||||
/// Whether to overlay over the current settings or replace them.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
overlay: Option<bool>,
|
||||
},
|
||||
GetCurrentSceneTransitionCursor,
|
||||
TriggerStudioModeTransition,
|
||||
#[serde(rename_all = "camelCase", rename = "SetTBarPosition")]
|
||||
SetTbarPosition {
|
||||
/// New position.
|
||||
position: f32,
|
||||
/// Whether to release the TBar. Only set `false` if you know that you will be sending
|
||||
/// another position update.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
release: Option<bool>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Serialize)]
|
||||
@ -580,6 +617,7 @@ pub struct SetPersistentData<'a> {
|
||||
pub slot_value: &'a serde_json::Value,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Default, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SetProfileParameter<'a> {
|
||||
@ -591,6 +629,7 @@ pub struct SetProfileParameter<'a> {
|
||||
pub parameter_value: Option<&'a str>,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Default, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SetVideoSettings {
|
||||
@ -663,6 +702,7 @@ pub struct SetInputSettings<'a, T> {
|
||||
pub overlay: Option<bool>,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Default, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct SetInputSettingsInternal<'a> {
|
||||
@ -698,6 +738,7 @@ pub struct CreateInput<'a, T> {
|
||||
pub scene_item_enabled: Option<bool>,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Default, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct CreateInputInternal<'a> {
|
||||
@ -708,6 +749,7 @@ pub(crate) struct CreateInputInternal<'a> {
|
||||
pub scene_item_enabled: Option<bool>,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Default, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateSceneItem<'a> {
|
||||
@ -719,6 +761,7 @@ pub struct CreateSceneItem<'a> {
|
||||
pub scene_item_enabled: Option<bool>,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Default, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DuplicateSceneItem<'a> {
|
||||
@ -741,6 +784,7 @@ pub struct SetSceneItemTransform<'a> {
|
||||
pub scene_item_transform: SceneItemTransform,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Default, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SceneItemTransform {
|
||||
@ -814,6 +858,7 @@ pub struct SetSceneItemIndex<'a> {
|
||||
pub scene_item_index: u32,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Default, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SetSceneSceneTransitionOverride<'a> {
|
||||
@ -826,6 +871,7 @@ pub struct SetSceneSceneTransitionOverride<'a> {
|
||||
pub transition_duration: Option<Duration>,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Default, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GetSourceScreenshot<'a> {
|
||||
@ -844,6 +890,7 @@ pub struct GetSourceScreenshot<'a> {
|
||||
pub image_compression_quality: Option<i32>,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SaveSourceScreenshot<'a> {
|
||||
|
@ -668,3 +668,59 @@ pub struct StreamStatus {
|
||||
/// Total number of frames delivered by the output's process.
|
||||
pub output_total_frames: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct TransitionKinds {
|
||||
/// Array of transition kinds.
|
||||
pub transition_kinds: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SceneTransitionList {
|
||||
/// Name of the current scene transition.
|
||||
pub current_scene_transition_name: Option<String>,
|
||||
/// Kind of the current scene transition.
|
||||
pub current_scene_transition_kind: Option<String>,
|
||||
/// Array of transitions.
|
||||
pub transitions: Vec<Transition>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Transition {
|
||||
/// Name of the transition.
|
||||
pub transition_name: String,
|
||||
/// Kind of the transition.
|
||||
pub transition_kind: String,
|
||||
/// Whether the transition uses a fixed (unconfigurable) duration.
|
||||
pub transition_fixed: bool,
|
||||
/// Whether the transition supports being configured.
|
||||
pub transition_configurable: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CurrentSceneTransition {
|
||||
/// Name of the transition.
|
||||
pub transition_name: String,
|
||||
/// Kind of the transition.
|
||||
pub transition_kind: String,
|
||||
/// Whether the transition uses a fixed (unconfigurable) duration.
|
||||
pub transition_fixed: bool,
|
||||
/// Configured transition duration in milliseconds.
|
||||
#[serde(deserialize_with = "crate::de::duration_millis_opt")]
|
||||
pub transition_duration: Option<Duration>,
|
||||
/// Whether the transition supports being configured.
|
||||
pub transition_configurable: bool,
|
||||
/// Object of settings for the transition.
|
||||
pub transition_settings: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct TransitionCursor {
|
||||
/// Cursor position, between `0.0` and `1.0`.
|
||||
pub transition_cursor: f32,
|
||||
}
|
||||
|
@ -11,3 +11,4 @@ mod scene_items;
|
||||
mod scenes;
|
||||
mod sources;
|
||||
mod streaming;
|
||||
mod transitions;
|
||||
|
33
tests/integration/transitions.rs
Normal file
33
tests/integration/transitions.rs
Normal file
@ -0,0 +1,33 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::common::{self, TEST_TRANSITION};
|
||||
|
||||
#[tokio::test]
|
||||
async fn transitions() -> Result<()> {
|
||||
let client = common::new_client().await?;
|
||||
let general = client.general();
|
||||
let client = client.transitions();
|
||||
|
||||
client.get_transition_kind_list().await?;
|
||||
client.get_scene_transition_list().await?;
|
||||
|
||||
client.set_current_scene_transition(TEST_TRANSITION).await?;
|
||||
let transition = client.get_current_scene_transition().await?;
|
||||
|
||||
client
|
||||
.set_current_scene_transition_duration(transition.transition_duration.unwrap())
|
||||
.await?;
|
||||
client
|
||||
.set_current_scene_transition_settings(transition.transition_settings.unwrap(), None)
|
||||
.await?;
|
||||
client.get_current_scene_transition_cursor().await?;
|
||||
|
||||
general.set_studio_mode_enabled(true).await?;
|
||||
|
||||
client.trigger_studio_mode_transition().await?;
|
||||
client.set_tbar_position(0.5, None).await?;
|
||||
|
||||
general.set_studio_mode_enabled(false).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue
Block a user