mirror of https://github.com/dnaka91/obws
commit
a96db636f6
@ -0,0 +1,4 @@
|
||||
/target
|
||||
|
||||
.env
|
||||
Cargo.lock
|
@ -0,0 +1,32 @@
|
||||
[package]
|
||||
name = "obws"
|
||||
version = "0.1.0"
|
||||
authors = ["Dominik Nakamura <dnaka91@gmail.com>"]
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
readme = "README.md"
|
||||
description = "The obws (obvious) remote control library for OBS."
|
||||
homepage = "https://github.com/dnaka91/obws"
|
||||
repository = "https://github.com/dnaka91/obws"
|
||||
categories = ["api-bindings", "web-programming"]
|
||||
keywords = ["async", "obs", "obs-websocket", "remote-control", "tokio"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.36"
|
||||
async-stream = "0.3.0"
|
||||
base64 = "0.13.0"
|
||||
either = { version = "1.6.1", features = ["serde"] }
|
||||
futures-util = { version = "0.3.8", features = ["sink"] }
|
||||
log = "0.4.11"
|
||||
serde = { version = "1.0.118", features = ["derive"] }
|
||||
serde_json = "1.0.60"
|
||||
serde_with = "1.6.0"
|
||||
sha2 = "0.9.2"
|
||||
tokio = { version = "0.3.6", features = ["net", "sync"] }
|
||||
tokio-tungstenite = "0.12.0"
|
||||
tungstenite = { version = "0.11.1", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
dotenv = "0.15.0"
|
||||
pretty_env_logger = "0.4.0"
|
||||
tokio = { version = "0.3.6", features = ["fs", "macros", "rt-multi-thread", "time"] }
|
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2020 Dominik Nakamura
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
@ -0,0 +1,9 @@
|
||||
# OBWS - The obws (obvious) remote control library for OBS
|
||||
|
||||
Library to remote control OBS with the [obs-websocket] plugin.
|
||||
|
||||
[obs-websocket]: https://github.com/Palakis/obs-websocket
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under [MIT License](LICENSE) (or <http://opensource.org/licenses/MIT>).
|
@ -0,0 +1,12 @@
|
||||
# Examples
|
||||
|
||||
These are several examples that show how to use `obws`. If you require authentication for your OBS
|
||||
instance, create a `.env` file in the project root and add a `OBS_PASSWORD` entry in it. The
|
||||
examples will pick up the password and authenticate automatically.
|
||||
|
||||
- `simple` A very basic example showing how to connect, login and print out current version
|
||||
information and the list of scenes.
|
||||
- `iter_scenes` Get a list of all scenes and endlessly iterate through them with a small pause
|
||||
between each change.
|
||||
- `screenshot` Take a screenshot of the currently visible scene and save it as `screenshot.png`.
|
||||
- `events` Shows how to get a stream of user events and simply print them out to the terminal.
|
@ -0,0 +1,27 @@
|
||||
use std::env;
|
||||
|
||||
use anyhow::Result;
|
||||
use futures_util::{pin_mut, StreamExt};
|
||||
|
||||
use obws::client::Client;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
dotenv::dotenv().ok();
|
||||
|
||||
env::set_var("RUST_LOG", "obws=debug");
|
||||
pretty_env_logger::init();
|
||||
|
||||
let client = Client::connect("localhost", 4444).await?;
|
||||
|
||||
client.login(env::var("OBS_PASSWORD").ok()).await?;
|
||||
|
||||
let events = client.events();
|
||||
pin_mut!(events);
|
||||
|
||||
while let Some(event) = events.next().await {
|
||||
println!("{:#?}", event);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
use std::{env, time::Duration};
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use obws::client::Client;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
dotenv::dotenv().ok();
|
||||
|
||||
env::set_var("RUST_LOG", "obws=debug");
|
||||
pretty_env_logger::init();
|
||||
|
||||
let client = Client::connect("localhost", 4444).await?;
|
||||
|
||||
client.login(env::var("OBS_PASSWORD").ok()).await?;
|
||||
|
||||
let scene_list = client.scenes().get_scene_list().await?;
|
||||
|
||||
for scene in scene_list.scenes.iter().cycle() {
|
||||
client
|
||||
.scenes()
|
||||
.set_current_scene(scene.name.clone())
|
||||
.await?;
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
use std::env;
|
||||
|
||||
use anyhow::Result;
|
||||
use tokio::fs;
|
||||
|
||||
use obws::{client::Client, requests::SourceScreenshot};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
dotenv::dotenv().ok();
|
||||
|
||||
env::set_var("RUST_LOG", "obws=debug");
|
||||
pretty_env_logger::init();
|
||||
|
||||
let client = Client::connect("localhost", 4444).await?;
|
||||
|
||||
client.login(env::var("OBS_PASSWORD").ok()).await?;
|
||||
|
||||
let screenshot = client
|
||||
.sources()
|
||||
.take_source_screenshot(SourceScreenshot {
|
||||
source_name: Some("Start".to_owned()),
|
||||
embed_picture_format: Some("png".to_owned()),
|
||||
save_to_file_path: None,
|
||||
file_format: None,
|
||||
compress_quality: None,
|
||||
width: None,
|
||||
height: None,
|
||||
})
|
||||
.await?;
|
||||
|
||||
let image = screenshot.img.unwrap();
|
||||
let pos = image.find("base64,").unwrap();
|
||||
let image = base64::decode(&image[pos + 7..])?;
|
||||
|
||||
fs::write("screenshot.png", &image).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
use std::env;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use obws::client::Client;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
dotenv::dotenv().ok();
|
||||
|
||||
env::set_var("RUST_LOG", "obws=debug");
|
||||
pretty_env_logger::init();
|
||||
|
||||
let client = Client::connect("localhost", 4444).await?;
|
||||
|
||||
let version = client.general().get_version().await?;
|
||||
println!("{:#?}", version);
|
||||
|
||||
client.login(env::var("OBS_PASSWORD").ok()).await?;
|
||||
|
||||
let scene_list = client.scenes().get_scene_list().await?;
|
||||
println!("{:#?}", scene_list);
|
||||
|
||||
Ok(())
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
use anyhow::Result;
|
||||
use serde::Serialize;
|
||||
|
||||
use super::Client;
|
||||
use crate::requests::{Projector, RequestType};
|
||||
use crate::responses;
|
||||
|
||||
/// General functions of the API.
|
||||
pub struct General<'a> {
|
||||
pub(super) client: &'a Client,
|
||||
}
|
||||
|
||||
impl<'a> General<'a> {
|
||||
/// Returns the latest version of the plugin and the API.
|
||||
pub async fn get_version(&self) -> Result<responses::Version> {
|
||||
self.client.send_message(RequestType::GetVersion).await
|
||||
}
|
||||
|
||||
/// Tells the client if authentication is required. If so, returns authentication parameters
|
||||
/// `challenge` and `salt`.
|
||||
pub async fn get_auth_required(&self) -> Result<responses::AuthRequired> {
|
||||
self.client.send_message(RequestType::GetAuthRequired).await
|
||||
}
|
||||
|
||||
/// Attempt to authenticate the client to the server.
|
||||
///
|
||||
/// - `auth`: Response to the auth challenge.
|
||||
pub async fn authenticate(&self, auth: String) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::Authenticate { auth })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Set the filename formatting string.
|
||||
///
|
||||
/// - `filename_formatting`: Filename formatting string to set.
|
||||
pub async fn set_filename_formatting(&self, filename_formatting: String) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetFilenameFormatting {
|
||||
filename_formatting,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get the filename formatting string.
|
||||
pub async fn get_filename_formatting(&self) -> Result<String> {
|
||||
self.client
|
||||
.send_message::<responses::FilenameFormatting>(RequestType::GetFilenameFormatting)
|
||||
.await
|
||||
.map(|ff| ff.filename_formatting)
|
||||
}
|
||||
|
||||
/// Get OBS stats (almost the same info as provided in OBS' stats window).
|
||||
pub async fn get_stats(&self) -> Result<responses::ObsStats> {
|
||||
self.client
|
||||
.send_message::<responses::Stats>(RequestType::GetStats)
|
||||
.await
|
||||
.map(|s| s.stats)
|
||||
}
|
||||
|
||||
/// Broadcast custom message to all connected WebSocket clients.
|
||||
///
|
||||
/// - `realm`: Identifier to be choosen by the client.
|
||||
/// - `data`: User-defined data.
|
||||
pub async fn broadcast_custom_message<T>(&self, realm: String, data: T) -> Result<()>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
self.client
|
||||
.send_message(RequestType::BroadcastCustomMessage {
|
||||
realm,
|
||||
data: serde_json::to_value(&data)?,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get basic OBS video information.
|
||||
pub async fn get_video_info(&self) -> Result<responses::VideoInfo> {
|
||||
self.client.send_message(RequestType::GetVideoInfo).await
|
||||
}
|
||||
|
||||
/// Open a projector window or create a projector on a monitor. Requires OBS v24.0.4 or newer.
|
||||
pub async fn open_projector(&self, projector: Projector) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::OpenProjector(projector))
|
||||
.await
|
||||
}
|
||||
}
|
@ -0,0 +1,265 @@
|
||||
//! The client to the obs-websocket API and main entry point.
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{atomic::AtomicU64, Arc},
|
||||
};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use futures_util::{
|
||||
sink::SinkExt,
|
||||
stream::{SplitSink, Stream, StreamExt},
|
||||
};
|
||||
use log::{debug, error, trace};
|
||||
use serde::de::DeserializeOwned;
|
||||
use tokio::{
|
||||
net::TcpStream,
|
||||
sync::{broadcast, oneshot, Mutex},
|
||||
};
|
||||
use tokio_tungstenite::{tungstenite::Message, WebSocketStream};
|
||||
|
||||
use crate::{
|
||||
events::Event,
|
||||
requests::{Request, RequestType},
|
||||
responses::{AuthRequired, Response},
|
||||
};
|
||||
|
||||
pub use self::{
|
||||
general::General, outputs::Outputs, profiles::Profiles, recording::Recording,
|
||||
replay_buffer::ReplayBuffer, scene_collections::SceneCollections, scene_items::SceneItems,
|
||||
scenes::Scenes, sources::Sources, streaming::Streaming, studio_mode::StudioMode,
|
||||
transitions::Transitions,
|
||||
};
|
||||
|
||||
mod general;
|
||||
mod outputs;
|
||||
mod profiles;
|
||||
mod recording;
|
||||
mod replay_buffer;
|
||||
mod scene_collections;
|
||||
mod scene_items;
|
||||
mod scenes;
|
||||
mod sources;
|
||||
mod streaming;
|
||||
mod studio_mode;
|
||||
mod transitions;
|
||||
|
||||
/// The client is the main entry point to access the obs-websocket API. It allows to call various
|
||||
/// functions to remote control an OBS instance as well as to listen to events caused by the user
|
||||
/// by interacting with OBS.
|
||||
pub struct Client {
|
||||
write: Mutex<MessageWriter>,
|
||||
id_counter: AtomicU64,
|
||||
receivers: Arc<Mutex<HashMap<String, oneshot::Sender<serde_json::Value>>>>,
|
||||
event_sender: broadcast::Sender<Event>,
|
||||
}
|
||||
|
||||
type MessageWriter = SplitSink<WebSocketStream<TcpStream>, Message>;
|
||||
|
||||
impl Client {
|
||||
/// Connect to a obs-websocket instance on the given host and port.
|
||||
pub async fn connect(host: impl AsRef<str>, port: u16) -> Result<Self> {
|
||||
let (socket, _) =
|
||||
tokio_tungstenite::connect_async(format!("ws://{}:{}", host.as_ref(), port)).await?;
|
||||
let (write, mut read) = socket.split();
|
||||
let receivers = Arc::new(Mutex::new(HashMap::<
|
||||
String,
|
||||
oneshot::Sender<serde_json::Value>,
|
||||
>::new()));
|
||||
let receivers2 = Arc::clone(&receivers);
|
||||
let (event_sender, _) = broadcast::channel(100);
|
||||
let events_tx = event_sender.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
while let Some(Ok(msg)) = read.next().await {
|
||||
trace!("{}", msg);
|
||||
let temp: Result<()> = async {
|
||||
let json = serde_json::from_str::<serde_json::Value>(&msg.into_text()?)?;
|
||||
|
||||
if let Some(message_id) = json
|
||||
.as_object()
|
||||
.and_then(|obj| obj.get("message-id"))
|
||||
.and_then(|id| id.as_str())
|
||||
{
|
||||
debug!("got message with id {}", message_id);
|
||||
if let Some(tx) = receivers2.lock().await.remove(message_id) {
|
||||
tx.send(json).ok();
|
||||
}
|
||||
} else {
|
||||
let event = serde_json::from_value(json)?;
|
||||
events_tx.send(event).ok();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
.await;
|
||||
|
||||
if let Err(e) = temp {
|
||||
error!("{:?}", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let write = Mutex::new(write);
|
||||
let id_counter = AtomicU64::new(1);
|
||||
|
||||
Ok(Self {
|
||||
write,
|
||||
id_counter,
|
||||
receivers,
|
||||
event_sender,
|
||||
})
|
||||
}
|
||||
|
||||
async fn send_message<T>(&self, req: RequestType) -> Result<T>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
let id = self
|
||||
.id_counter
|
||||
.fetch_add(1, std::sync::atomic::Ordering::SeqCst)
|
||||
.to_string();
|
||||
let req = Request {
|
||||
message_id: id.clone(),
|
||||
ty: req,
|
||||
};
|
||||
let json = serde_json::to_string(&req)?;
|
||||
|
||||
let (tx, rx) = oneshot::channel();
|
||||
self.receivers.lock().await.insert(id, tx);
|
||||
|
||||
debug!("sending message: {}", json);
|
||||
self.write.lock().await.send(Message::Text(json)).await?;
|
||||
|
||||
let resp = rx.await?;
|
||||
|
||||
if let Some(error) = resp
|
||||
.as_object()
|
||||
.and_then(|o| o.get("error"))
|
||||
.and_then(|e| e.as_str())
|
||||
{
|
||||
bail!("{}", error);
|
||||
}
|
||||
|
||||
serde_json::from_value::<Response<T>>(resp)
|
||||
.map(|r| r.details)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Login to the OBS websocket if an authentication is required.
|
||||
pub async fn login(&self, password: Option<impl AsRef<str>>) -> Result<()> {
|
||||
let auth_required = self.general().get_auth_required().await?;
|
||||
|
||||
if let AuthRequired {
|
||||
auth_required: true,
|
||||
challenge: Some(challenge),
|
||||
salt: Some(salt),
|
||||
} = auth_required
|
||||
{
|
||||
match password {
|
||||
Some(password) => {
|
||||
let auth = Self::create_auth_response(&challenge, &salt, password.as_ref());
|
||||
self.general().authenticate(auth).await?;
|
||||
}
|
||||
None => bail!("authentication required but no password provided"),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_auth_response(challenge: &str, salt: &str, password: &str) -> String {
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(password.as_bytes());
|
||||
hasher.update(salt.as_bytes());
|
||||
|
||||
let mut auth = String::with_capacity(Sha256::output_size() * 4 / 3 + 4);
|
||||
|
||||
base64::encode_config_buf(hasher.finalize_reset(), base64::STANDARD, &mut auth);
|
||||
|
||||
hasher.update(auth.as_bytes());
|
||||
hasher.update(challenge.as_bytes());
|
||||
auth.clear();
|
||||
|
||||
base64::encode_config_buf(hasher.finalize(), base64::STANDARD, &mut auth);
|
||||
|
||||
auth
|
||||
}
|
||||
|
||||
/// Get a stream of events. Each call to this function creates a new listener, therefore it's
|
||||
/// recommended to keep the stream around and iterate over it.
|
||||
///
|
||||
/// **Note**: To be able to iterate over the stream you have to pin it with
|
||||
/// [`futures_util::pin_mut`] for example.
|
||||
pub fn events(&self) -> impl Stream<Item = Event> {
|
||||
let mut receiver = self.event_sender.subscribe();
|
||||
|
||||
async_stream::stream! {
|
||||
while let Ok(event) = receiver.recv().await {
|
||||
yield event;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Access general API functions.
|
||||
pub fn general(&self) -> General<'_> {
|
||||
General { client: self }
|
||||
}
|
||||
|
||||
/// Access API functions related to sources.
|
||||
pub fn sources(&self) -> Sources<'_> {
|
||||
Sources { client: self }
|
||||
}
|
||||
|
||||
/// Access API functions related to outputs.
|
||||
pub fn outputs(&self) -> Outputs<'_> {
|
||||
Outputs { client: self }
|
||||
}
|
||||
|
||||
/// Access API functions related to profiles.
|
||||
pub fn profiles(&self) -> Profiles<'_> {
|
||||
Profiles { client: self }
|
||||
}
|
||||
|
||||
/// Access API functions related to recording.
|
||||
pub fn recording(&self) -> Recording<'_> {
|
||||
Recording { client: self }
|
||||
}
|
||||
|
||||
/// Access API functions related to the replay buffer.
|
||||
pub fn replay_buffer(&self) -> ReplayBuffer<'_> {
|
||||
ReplayBuffer { client: self }
|
||||
}
|
||||
|
||||
/// Access API functions related to scene collections.
|
||||
pub fn scene_collections(&self) -> SceneCollections<'_> {
|
||||
SceneCollections { client: self }
|
||||
}
|
||||
|
||||
/// Access API functions related to scene items.
|
||||
pub fn scene_items(&self) -> SceneItems<'_> {
|
||||
SceneItems { client: self }
|
||||
}
|
||||
|
||||
/// Access API functions related to scenes.
|
||||
pub fn scenes(&self) -> Scenes<'_> {
|
||||
Scenes { client: self }
|
||||
}
|
||||
|
||||
/// Access API functions related to streaming.
|
||||
pub fn streaming(&self) -> Streaming<'_> {
|
||||
Streaming { client: self }
|
||||
}
|
||||
|
||||
/// Access API functions related to the studio mode.
|
||||
pub fn studio_mode(&self) -> StudioMode<'_> {
|
||||
StudioMode { client: self }
|
||||
}
|
||||
|
||||
/// Access API functions related to transitions.
|
||||
pub fn transitions(&self) -> Transitions<'_> {
|
||||
Transitions { client: self }
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use super::Client;
|
||||
use crate::requests::RequestType;
|
||||
use crate::responses;
|
||||
|
||||
/// API functions related to outputs.
|
||||
pub struct Outputs<'a> {
|
||||
pub(super) client: &'a Client,
|
||||
}
|
||||
|
||||
impl<'a> Outputs<'a> {
|
||||
/// List existing outputs.
|
||||
pub async fn list_outputs(&self) -> Result<Vec<responses::Output>> {
|
||||
self.client
|
||||
.send_message::<responses::Outputs>(RequestType::ListOutputs)
|
||||
.await
|
||||
.map(|o| o.outputs)
|
||||
}
|
||||
|
||||
/// Get information about a single output.
|
||||
///
|
||||
/// - `output_name`: Output name.
|
||||
pub async fn get_output_info(&self, output_name: String) -> Result<responses::Output> {
|
||||
self.client
|
||||
.send_message::<responses::OutputInfo>(RequestType::GetOutputInfo { output_name })
|
||||
.await
|
||||
.map(|o| o.output_info)
|
||||
}
|
||||
|
||||
/// Note: Controlling outputs is an experimental feature of obs-websocket. Some plugins which
|
||||
/// add outputs to OBS may not function properly when they are controlled in this way.
|
||||
///
|
||||
/// - `output_name`: Output name.
|
||||
pub async fn start_output(&self, output_name: String) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::StartOutput { output_name })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Note: Controlling outputs is an experimental feature of obs-websocket. Some plugins which
|
||||
/// add outputs to OBS may not function properly when they are controlled in this way.
|
||||
///
|
||||
/// - `output_name`: Output name.
|
||||
/// - `force`: Force stop (default: false).
|
||||
pub async fn stop_output(&self, output_name: String, force: Option<bool>) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::StopOutput { output_name, force })
|
||||
.await
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use super::Client;
|
||||
use crate::requests::RequestType;
|
||||
use crate::responses;
|
||||
|
||||
/// API functions related to profiles.
|
||||
pub struct Profiles<'a> {
|
||||
pub(super) client: &'a Client,
|
||||
}
|
||||
|
||||
impl<'a> Profiles<'a> {
|
||||
/// Set the currently active profile.
|
||||
///
|
||||
/// - `profile_name`: Name of the desired profile.
|
||||
pub async fn set_current_profile(&self, profile_name: String) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetCurrentProfile { profile_name })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get the name of the current profile.
|
||||
pub async fn get_current_profile(&self) -> Result<String> {
|
||||
self.client
|
||||
.send_message::<responses::CurrentProfile>(RequestType::GetCurrentProfile)
|
||||
.await
|
||||
.map(|cp| cp.profile_name)
|
||||
}
|
||||
|
||||
/// Get a list of available profiles.
|
||||
pub async fn list_profiles(&self) -> Result<Vec<responses::Profile>> {
|
||||
self.client
|
||||
.send_message::<responses::Profiles>(RequestType::ListProfiles)
|
||||
.await
|
||||
.map(|cp| cp.profiles)
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use super::Client;
|
||||
use crate::requests::RequestType;
|
||||
use crate::responses;
|
||||
|
||||
/// API functions related to recording.
|
||||
pub struct Recording<'a> {
|
||||
pub(super) client: &'a Client,
|
||||
}
|
||||
|
||||
impl<'a> Recording<'a> {
|
||||
/// Toggle recording on or off (depending on the current recording state).
|
||||
pub async fn start_stop_recording(&self) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::StartStopRecording)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Start recording. Will return an `error` if recording is already active.
|
||||
pub async fn start_recording(&self) -> Result<()> {
|
||||
self.client.send_message(RequestType::StartRecording).await
|
||||
}
|
||||
|
||||
/// Stop recording. Will return an `error` if recording is not active.
|
||||
pub async fn stop_recording(&self) -> Result<()> {
|
||||
self.client.send_message(RequestType::StopRecording).await
|
||||
}
|
||||
|
||||
/// Pause the current recording. Returns an `error` if recording is not active or already
|
||||
/// paused.
|
||||
pub async fn pause_recording(&self) -> Result<()> {
|
||||
self.client.send_message(RequestType::PauseRecording).await
|
||||
}
|
||||
|
||||
/// Resume/unpause the current recording (if paused). Returns an error if recording is not
|
||||
/// active or not paused.
|
||||
pub async fn resume_recording(&self) -> Result<()> {
|
||||
self.client.send_message(RequestType::ResumeRecording).await
|
||||
}
|
||||
|
||||
/// Please note: if this is called while a recording is in progress, the change won't be applied
|
||||
/// immediately and will be effective on the next recording.
|
||||
///
|
||||
/// - `rec_folder`: Path of the recording folder.
|
||||
pub async fn set_recording_folder(&self, rec_folder: String) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetRecordingFolder { rec_folder })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get the path of the current recording folder.
|
||||
pub async fn get_recording_folder(&self) -> Result<String> {
|
||||
self.client
|
||||
.send_message::<responses::RecordingFolder>(RequestType::GetRecordingFolder)
|
||||
.await
|
||||
.map(|rf| rf.rec_folder)
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use super::Client;
|
||||
use crate::requests::RequestType;
|
||||
|
||||
/// API functions related to the replay buffer.
|
||||
pub struct ReplayBuffer<'a> {
|
||||
pub(super) client: &'a Client,
|
||||
}
|
||||
|
||||
impl<'a> ReplayBuffer<'a> {
|
||||
/// Toggle the Replay Buffer on/off (depending on the current state of the replay buffer).
|
||||
pub async fn start_stop_replay_buffer(&self) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::StartStopReplayBuffer)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Start recording into the Replay Buffer. Will return an `error` if the Replay Buffer is
|
||||
/// already active or if the "Save Replay Buffer" hotkey is not set in OBS' settings. Setting
|
||||
/// this hotkey is mandatory, even when triggering saves only through obs-websocket.
|
||||
pub async fn start_replay_buffer(&self) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::StartReplayBuffer)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Stop recording into the Replay Buffer. Will return an `error` if the Replay Buffer is not
|
||||
/// active.
|
||||
pub async fn stop_replay_buffer(&self) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::StopReplayBuffer)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Flush and save the contents of the Replay Buffer to disk. This is basically the same as
|
||||
/// triggering the "Save Replay Buffer" hotkey. Will return an `error` if the Replay Buffer is
|
||||
/// not active.
|
||||
pub async fn save_replay_buffer(&self) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SaveReplayBuffer)
|
||||
.await
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use super::Client;
|
||||
use crate::requests::RequestType;
|
||||
use crate::responses;
|
||||
|
||||
/// API functions related to scene collections.
|
||||
pub struct SceneCollections<'a> {
|
||||
pub(super) client: &'a Client,
|
||||
}
|
||||
|
||||
impl<'a> SceneCollections<'a> {
|
||||
/// Change the active scene collection.
|
||||
///
|
||||
/// - `sc_name`: Name of the desired scene collection.
|
||||
pub async fn set_current_scene_collection(&self, sc_name: String) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetCurrentSceneCollection { sc_name })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get the name of the current scene collection.
|
||||
pub async fn get_current_scene_collection(&self) -> Result<String> {
|
||||
self.client
|
||||
.send_message::<responses::CurrentSceneCollection>(
|
||||
RequestType::GetCurrentSceneCollection,
|
||||
)
|
||||
.await
|
||||
.map(|csc| csc.sc_name)
|
||||
}
|
||||
|
||||
/// List available scene collections.
|
||||
pub async fn list_scene_collections(&self) -> Result<Vec<responses::SceneCollection>> {
|
||||
self.client
|
||||
.send_message::<responses::SceneCollections>(RequestType::ListSceneCollections)
|
||||
.await
|
||||
.map(|sc| sc.scene_collections)
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
use anyhow::Result;
|
||||
use either::Either;
|
||||
|
||||
use super::Client;
|
||||
use crate::requests::{
|
||||
AddSceneItem, DuplicateSceneItem, RequestType, SceneItemProperties, SceneItemRender,
|
||||
SceneItemSpecification,
|
||||
};
|
||||
use crate::responses;
|
||||
|
||||
/// API functions related to scene items.
|
||||
pub struct SceneItems<'a> {
|
||||
pub(super) client: &'a Client,
|
||||
}
|
||||
|
||||
impl<'a> SceneItems<'a> {
|
||||
/// Gets the scene specific properties of the specified source item. Coordinates are relative to
|
||||
/// the item's parent (the scene or group it belongs to).
|
||||
///
|
||||
/// - `scene_name`: Name of the scene the scene item belongs to. Defaults to the current scene.
|
||||
/// - `item`: Scene Item name (if this field is a string) or specification (if it is an object).
|
||||
pub async fn get_scene_item_properties(
|
||||
&self,
|
||||
scene_name: Option<String>,
|
||||
item: Either<String, SceneItemSpecification>,
|
||||
) -> Result<Vec<responses::SceneItemProperties>> {
|
||||
self.client
|
||||
.send_message(RequestType::GetSceneItemProperties { scene_name, item })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Sets the scene specific properties of a source. Unspecified properties will remain
|
||||
/// unchanged. Coordinates are relative to the item's parent (the scene or group it belongs to).
|
||||
pub async fn set_scene_item_properties(&self, properties: SceneItemProperties) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetSceneItemProperties(properties))
|
||||
.await
|
||||
}
|
||||
|
||||
/// Reset a scene item.
|
||||
///
|
||||
/// - `scene_name`: Name of the scene the scene item belongs to. Defaults to the current scene.
|
||||
/// - `item`: Scene Item name (if this field is a string) or specification (if it is an object).
|
||||
pub async fn reset_scene_item(
|
||||
&self,
|
||||
scene_name: Option<String>,
|
||||
item: Either<String, SceneItemSpecification>,
|
||||
) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::ResetSceneItem { scene_name, item })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Show or hide a specified source item in a specified scene.
|
||||
pub async fn set_scene_item_render(&self, scene_item_render: SceneItemRender) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetSceneItemRender(scene_item_render))
|
||||
.await
|
||||
}
|
||||
|
||||
/// Deletes a scene item.
|
||||
///
|
||||
/// - `scene`: Name of the scene the scene item belongs to. Defaults to the current scene.
|
||||
/// - `item`: Scene item to delete.
|
||||
pub async fn delete_scene_item(
|
||||
&self,
|
||||
scene: Option<String>,
|
||||
item: SceneItemSpecification,
|
||||
) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::DeleteSceneItem { scene, item })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Creates a scene item in a scene. In other words, this is how you add a source into a scene.
|
||||
pub async fn add_scene_item(&self, scene_item: AddSceneItem) -> Result<i64> {
|
||||
self.client
|
||||
.send_message::<responses::AddSceneItem>(RequestType::AddSceneItem(scene_item))
|
||||
.await
|
||||
.map(|asi| asi.item_id)
|
||||
}
|
||||
|
||||
/// Duplicates a scene item.
|
||||
pub async fn duplicate_scene_item(
|
||||
&self,
|
||||
scene_item: DuplicateSceneItem,
|
||||
) -> Result<responses::DuplicateSceneItem> {
|
||||
self.client
|
||||
.send_message(RequestType::DuplicateSceneItem(scene_item))
|
||||
.await
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use super::Client;
|
||||
use crate::requests::{RequestType, Scene, SceneTransitionOverride};
|
||||
use crate::responses;
|
||||
|
||||
/// API functions related to scenes.
|
||||
pub struct Scenes<'a> {
|
||||
pub(super) client: &'a Client,
|
||||
}
|
||||
|
||||
impl<'a> Scenes<'a> {
|
||||
/// Switch to the specified scene.
|
||||
///
|
||||
/// - `scene_name`: Name of the scene to switch to.
|
||||
pub async fn set_current_scene(&self, scene_name: String) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetCurrentScene { scene_name })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get the current scene's name and source items.
|
||||
pub async fn get_current_scene(&self) -> Result<responses::CurrentScene> {
|
||||
self.client.send_message(RequestType::GetCurrentScene).await
|
||||
}
|
||||
|
||||
/// Get a list of scenes in the currently active profile.
|
||||
pub async fn get_scene_list(&self) -> Result<responses::SceneList> {
|
||||
self.client.send_message(RequestType::GetSceneList).await
|
||||
}
|
||||
|
||||
/// Create a new scene scene.
|
||||
///
|
||||
/// - `scene_name`: Name of the scene to create.
|
||||
pub async fn create_scene(&self, scene_name: String) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::CreateScene { scene_name })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Changes the order of scene items in the requested scene.
|
||||
///
|
||||
/// - `scene`: Name of the scene to reorder (defaults to current).
|
||||
/// - `items`: Ordered list of objects with name and/or id specified. Id preferred due to
|
||||
/// uniqueness per scene
|
||||
pub async fn reorder_scene_items(
|
||||
&self,
|
||||
scene: Option<String>,
|
||||
items: Vec<Scene>,
|
||||
) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::ReorderSceneItems { scene, items })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Set a scene to use a specific transition override.
|
||||
pub async fn set_scene_transition_override(
|
||||
&self,
|
||||
scene_transition: SceneTransitionOverride,
|
||||
) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetSceneTransitionOverride(scene_transition))
|
||||
.await
|
||||
}
|
||||
|
||||
/// Remove any transition override on a scene.
|
||||
///
|
||||
/// - `scene_name`: Name of the scene to remove the override from.
|
||||
pub async fn remove_scene_transition_override(&self, scene_name: String) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::RemoveSceneTransitionOverride { scene_name })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get the current scene transition override.
|
||||
///
|
||||
/// - `scene_name`: Name of the scene to get the override for.
|
||||
pub async fn get_scene_transition_override(
|
||||
&self,
|
||||
scene_name: String,
|
||||
) -> Result<responses::SceneTransitionOverride> {
|
||||
self.client
|
||||
.send_message(RequestType::GetSceneTransitionOverride { scene_name })
|
||||
.await
|
||||
}
|
||||
}
|
@ -0,0 +1,348 @@
|
||||
use anyhow::Result;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
use super::Client;
|
||||
use crate::requests::{
|
||||
AddFilter, MoveFilter, ReorderFilter, RequestType, SourceFilterSettings,
|
||||
SourceFilterVisibility, SourceScreenshot, SourceSettings, TextFreetype2Properties,
|
||||
TextGdiPlusProperties, Volume,
|
||||
};
|
||||
use crate::responses;
|
||||
|
||||
/// API functions related to sources.
|
||||
pub struct Sources<'a> {
|
||||
pub(super) client: &'a Client,
|
||||
}
|
||||
|
||||
impl<'a> Sources<'a> {
|
||||
/// List all sources available in the running OBS instance.
|
||||
pub async fn get_sources_list(&self) -> Result<Vec<responses::SourceListItem>> {
|
||||
self.client
|
||||
.send_message::<responses::SourcesList>(RequestType::GetSourcesList)
|
||||
.await
|
||||
.map(|sl| sl.sources)
|
||||
}
|
||||
|
||||
/// Get a list of all available sources types.
|
||||
pub async fn get_sources_types_list(&self) -> Result<Vec<responses::SourceTypeItem>> {
|
||||
self.client
|
||||
.send_message::<responses::SourceTypesList>(RequestType::GetSourceTypesList)
|
||||
.await
|
||||
.map(|stl| stl.types)
|
||||
}
|
||||
|
||||
/// Get the volume of the specified source. Default response uses mul format, NOT SLIDER
|
||||
/// PERCENTAGE.
|
||||
///
|
||||
/// - `source`: Source name.
|
||||
/// - `use_decibel`: Output volume in decibels of attenuation instead of amplitude/mul.
|
||||
pub async fn get_volume(
|
||||
&self,
|
||||
source: String,
|
||||
use_decibel: Option<bool>,
|
||||
) -> Result<responses::Volume> {
|
||||
self.client
|
||||
.send_message(RequestType::GetVolume {
|
||||
source,
|
||||
use_decibel,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Set the volume of the specified source. Default request format uses mul, NOT SLIDER
|
||||
/// PERCENTAGE.
|
||||
pub async fn set_volume(&self, volume: Volume) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetVolume(volume))
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get the mute status of a specified source.
|
||||
///
|
||||
/// - `source`: Source name.
|
||||
pub async fn get_mute(&self, source: String) -> Result<responses::Mute> {
|
||||
self.client
|
||||
.send_message(RequestType::GetMute { source })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Sets the mute status of a specified source.
|
||||
///
|
||||
/// - `source`: Source name.
|
||||
/// - `mute`: Desired mute status.
|
||||
pub async fn set_mute(&self, source: String, mute: bool) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetMute { source, mute })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Inverts the mute status of a specified source.
|
||||
///
|
||||
/// - `source`: Source name.
|
||||
pub async fn toggle_mute(&self, source: String) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::ToggleMute { source })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get the audio's active status of a specified source.
|
||||
///
|
||||
/// - `source_name`: Source name.
|
||||
pub async fn get_audio_active(&self, source_name: String) -> Result<bool> {
|
||||
self.client
|
||||
.send_message::<responses::AudioActive>(RequestType::GetAudioActive { source_name })
|
||||
.await
|
||||
.map(|aa| aa.audio_active)
|
||||
}
|
||||
|
||||
/// Note: If the new name already exists as a source, obs-websocket will return an error.
|
||||
///
|
||||
/// - `source_name`: Source name.
|
||||
/// - `new_name`: New source name.
|
||||
pub async fn set_source_name(&self, source_name: String, new_name: String) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetSourceName {
|
||||
source_name,
|
||||
new_name,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Set the audio sync offset of a specified source.
|
||||
///
|
||||
/// - `source`: Source name.
|
||||
/// - `offset`: The desired audio sync offset (in nanoseconds).
|
||||
pub async fn set_sync_offset(&self, source: String, offset: i64) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetSyncOffset { source, offset })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get the audio sync offset of a specified source.
|
||||
///
|
||||
/// - `source`: Source name.
|
||||
pub async fn get_sync_offset(&self, source: String) -> Result<responses::SyncOffset> {
|
||||
self.client
|
||||
.send_message(RequestType::GetSyncOffset { source })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get settings of the specified source.
|
||||
///
|
||||
/// - `source_name`: Source name.
|
||||
/// - `source_type`: Type of the specified source. Useful for type-checking if you expect a
|
||||
/// specific settings schema.
|
||||
pub async fn get_source_settings<T>(
|
||||
&self,
|
||||
source_name: String,
|
||||
source_type: Option<String>,
|
||||
) -> Result<responses::SourceSettings<T>>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
self.client
|
||||
.send_message(RequestType::GetSourceSettings {
|
||||
source_name,
|
||||
source_type,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Set settings of the specified source.
|
||||
pub async fn set_source_settings<T>(
|
||||
&self,
|
||||
source_settings: SourceSettings,
|
||||
) -> Result<responses::SourceSettings<T>>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
self.client
|
||||
.send_message(RequestType::SetSourceSettings(source_settings))
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get the current properties of a Text GDI Plus source.
|
||||
///
|
||||
/// - `source`: Source name.
|
||||
pub async fn get_text_gdi_plus_properties(
|
||||
&self,
|
||||
source: String,
|
||||
) -> Result<responses::TextGdiPlusProperties> {
|
||||
self.client
|
||||
.send_message(RequestType::GetTextGDIPlusProperties { source })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Set the current properties of a Text GDI Plus source.
|
||||
pub async fn set_text_gdi_plus_properties(
|
||||
&self,
|
||||
properties: TextGdiPlusProperties,
|
||||
) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetTextGDIPlusProperties(Box::new(properties)))
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get the current properties of a Text Freetype 2 source.
|
||||
///
|
||||
/// - `source`: Source name.
|
||||
pub async fn get_text_freetype2_properties(
|
||||
&self,
|
||||
source: String,
|
||||
) -> Result<responses::TextFreetype2Properties> {
|
||||
self.client
|
||||
.send_message(RequestType::GetTextFreetype2Properties { source })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Set the current properties of a Text Freetype 2 source.
|
||||
pub async fn set_text_freetype2_properties(
|
||||
&self,
|
||||
properties: TextFreetype2Properties,
|
||||
) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetTextFreetype2Properties(properties))
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get configured special sources like Desktop Audio and Mic/Aux sources.
|
||||
pub async fn get_special_sources(&self) -> Result<responses::SpecialSources> {
|
||||
self.client
|
||||
.send_message(RequestType::GetSpecialSources)
|
||||
.await
|
||||
}
|
||||
|
||||
/// List filters applied to a source
|
||||
///
|
||||
/// - `source_name`: Source name.
|
||||
pub async fn get_source_filters(
|
||||
&self,
|
||||
source_name: String,
|
||||
) -> Result<Vec<responses::SourceFilter>> {
|
||||
self.client
|
||||
.send_message::<responses::SourceFilters>(RequestType::GetSourceFilters { source_name })
|
||||
.await
|
||||
.map(|sf| sf.filters)
|
||||
}
|
||||
|
||||
/// List filters applied to a source.
|
||||
///
|
||||
/// - `source_name`: Source name.
|
||||
/// - `filter_name`: Source filter name.
|
||||
pub async fn get_source_filter_info<T>(
|
||||
&self,
|
||||
source_name: String,
|
||||
filter_name: String,
|
||||
) -> Result<responses::SourceFilterInfo<T>>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
self.client
|
||||
.send_message(RequestType::GetSourceFilterInfo {
|
||||
source_name,
|
||||
filter_name,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Add a new filter to a source. Available source types along with their settings properties
|
||||
/// are available from [`get_sources_types_list`](Self::get_sources_types_list).
|
||||
pub async fn add_filter_to_source(&self, add_filter: AddFilter) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::AddFilterToSource(add_filter))
|
||||
.await
|
||||
}
|
||||
|
||||
/// Remove a filter from a source.
|
||||
///
|
||||
/// - `source_name`: Name of the source from which the specified filter is removed.
|
||||
/// - `filter_name`: Name of the filter to remove.
|
||||
pub async fn remove_filter_from_source(
|
||||
&self,
|
||||
source_name: String,
|
||||
filter_name: String,
|
||||
) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::RemoveFilterFromSource {
|
||||
source_name,
|
||||
filter_name,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Move a filter in the chain (absolute index positioning).
|
||||
pub async fn reorder_source_filter(&self, reorder_filter: ReorderFilter) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::ReorderSourceFilter(reorder_filter))
|
||||
.await
|
||||
}
|
||||
|
||||
/// Move a filter in the chain (relative positioning).
|
||||
pub async fn move_source_filter(&self, move_filter: MoveFilter) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::MoveSourceFilter(move_filter))
|
||||
.await
|
||||
}
|
||||
|
||||
/// Update settings of a filter.
|
||||
pub async fn set_source_filter_settings(&self, settings: SourceFilterSettings) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetSourceFilterSettings(settings))
|
||||
.await
|
||||
}
|
||||
|
||||
/// Change the visibility/enabled state of a filter.
|
||||
pub async fn set_source_filter_visibility(
|
||||
&self,
|
||||
visibility: SourceFilterVisibility,
|
||||
) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetSourceFilterVisibility(visibility))
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get the audio monitoring type of the specified source.
|
||||
///
|
||||
/// - `source_name`: Source name.
|
||||
pub async fn get_audio_monitor_type(&self, source_name: String) -> Result<String> {
|
||||
self.client
|
||||
.send_message::<responses::AudioMonitorType>(RequestType::GetAudioMonitorType {
|
||||
source_name,
|
||||
})
|
||||
.await
|
||||
.map(|amt| amt.monitor_type)
|
||||
}
|
||||
|
||||
/// Set the audio monitoring type of the specified source.
|
||||
///
|
||||
/// - `source_name`: Source name.
|
||||
/// - `monitor_type`: The monitor type to use. Options: `none`, `monitorOnly`,
|
||||
/// `monitorAndOutput`.
|
||||
pub async fn set_audio_monitor_type(
|
||||
&self,
|
||||
source_name: String,
|
||||
monitor_type: String,
|
||||
) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetAudioMonitorType {
|
||||
source_name,
|
||||
monitor_type,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// At least [`embed_picture_format`](SourceScreenshot::embed_picture_format) or
|
||||
/// [`save_to_file_path`](SourceScreenshot::save_to_file_path) must be specified.
|
||||
///
|
||||
/// Clients can specify [`width`](SourceScreenshot::width) and
|
||||
/// [`height`](SourceScreenshot::height) parameters to receive scaled pictures. Aspect ratio is
|
||||
/// preserved if only one of these two parameters is specified.
|
||||
pub async fn take_source_screenshot(
|
||||
&self,
|
||||
source_screenshot: SourceScreenshot,
|
||||
) -> Result<responses::SourceScreenshot> {
|
||||
self.client
|
||||
.send_message(RequestType::TakeSourceScreenshot(source_screenshot))
|
||||
.await
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use super::Client;
|
||||
use crate::requests::{RequestType, SetStreamSettings, Stream};
|
||||
use crate::responses;
|
||||
|
||||
/// API functions related to streaming.
|
||||
pub struct Streaming<'a> {
|
||||
pub(super) client: &'a Client,
|
||||
}
|
||||
|
||||
impl<'a> Streaming<'a> {
|
||||
/// Get current streaming and recording status.
|
||||
pub async fn get_streaming_status(&self) -> Result<responses::StreamingStatus> {
|
||||
self.client
|
||||
.send_message(RequestType::GetStreamingStatus)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Toggle streaming on or off (depending on the current stream state).
|
||||
pub async fn start_stop_streaming(&self) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::StartStopStreaming)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Start streaming. Will return an `error` if streaming is already active.
|
||||
///
|
||||
/// - `stream`: Special stream configuration. Please note: these won't be saved to OBS'
|
||||
/// configuration.
|
||||
pub async fn start_streaming(&self, stream: Option<Stream>) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::StartStreaming { stream })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Stop streaming. Will return an `error` if streaming is not active.
|
||||
pub async fn stop_streaming(&self) -> Result<()> {
|
||||
self.client.send_message(RequestType::StopStreaming).await
|
||||
}
|
||||
|
||||
/// Sets one or more attributes of the current streaming server settings. Any options not passed
|
||||
/// will remain unchanged. Returns the updated settings in response. If 'type' is different than
|
||||
/// the current streaming service type, all settings are required. Returns the full settings of
|
||||
/// the stream (the same as GetStreamSettings).
|
||||
pub async fn set_stream_settings(&self, settings: SetStreamSettings) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetStreamSettings(settings))
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get the current streaming server settings.
|
||||
pub async fn get_stream_settings(&self) -> Result<responses::GetStreamSettings> {
|
||||
self.client
|
||||
.send_message(RequestType::GetStreamSettings)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Save the current streaming server settings to disk.
|
||||
pub async fn save_stream_settings(&self) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SaveStreamSettings)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Send the provided text as embedded CEA-608 caption data.
|
||||
///
|
||||
/// - `text`: Captions text.
|
||||
pub async fn send_captions(&self, text: String) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SendCaptions { text })
|
||||
.await
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use super::Client;
|
||||
use crate::requests::{RequestType, Transition};
|
||||
use crate::responses;
|
||||
|
||||
/// API functions related to the studio mode.
|
||||
pub struct StudioMode<'a> {
|
||||
pub(super) client: &'a Client,
|
||||
}
|
||||
|
||||
impl<'a> StudioMode<'a> {
|
||||
/// Indicates if Studio Mode is currently enabled.
|
||||
pub async fn get_studio_mode_status(&self) -> Result<bool> {
|
||||
self.client
|
||||
.send_message::<responses::StudioModeStatus>(RequestType::GetStudioModeStatus)
|
||||
.await
|
||||
.map(|sms| sms.studio_mode)
|
||||
}
|
||||
|
||||
/// Get the name of the currently previewed scene and its list of sources. Will return an
|
||||
/// `error` if Studio Mode is not enabled.
|
||||
pub async fn get_preview_scene(&self) -> Result<responses::PreviewScene> {
|
||||
self.client.send_message(RequestType::GetPreviewScene).await
|
||||
}
|
||||
|
||||
/// Set the active preview scene. Will return an `error` if Studio Mode is not enabled.
|
||||
///
|
||||
/// - `scene_name`: The name of the scene to preview.
|
||||
pub async fn set_preview_scene(&self, scene_name: String) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetPreviewScene { scene_name })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Transitions the currently previewed scene to the main output. Will return an `error` if
|
||||
/// Studio Mode is not enabled.
|
||||
///
|
||||
/// - `with_transition`: Change the active transition before switching scenes. Defaults to the
|
||||
/// active transition.
|
||||
pub async fn transition_to_program(&self, with_transition: Option<Transition>) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::TransitionToProgram { with_transition })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Enables Studio Mode.
|
||||
pub async fn enable_studio_mode(&self) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::EnableStudioMode)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Disables Studio Mode.
|
||||
pub async fn disable_studio_mode(&self) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::DisableStudioMode)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Toggles Studio Mode (depending on the current state of studio mode).
|
||||
pub async fn toggle_studio_mode(&self) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::ToggleStudioMode)
|
||||
.await
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use super::Client;
|
||||
use crate::requests::RequestType;
|
||||
use crate::responses;
|
||||
|
||||
/// API functions related to transitions.
|
||||
pub struct Transitions<'a> {
|
||||
pub(super) client: &'a Client,
|
||||
}
|
||||
|
||||
impl<'a> Transitions<'a> {
|
||||
/// List of all transitions available in the frontend's dropdown menu.
|
||||
pub async fn get_transition_list(&self) -> Result<responses::TransitionList> {
|
||||
self.client
|
||||
.send_message(RequestType::GetTransitionList)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get the name of the currently selected transition in the frontend's dropdown menu.
|
||||
pub async fn get_current_transition(&self) -> Result<responses::CurrentTransition> {
|
||||
self.client
|
||||
.send_message(RequestType::GetCurrentTransition)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Set the active transition.
|
||||
///
|
||||
/// - `transition_name`: The name of the transition.
|
||||
pub async fn set_current_transition(&self, transition_name: String) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetCurrentTransition { transition_name })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Set the duration of the currently selected transition if supported.
|
||||
///
|
||||
/// - `duration`: Desired duration of the transition (in milliseconds).
|
||||
pub async fn set_transition_duration(&self, duration: u64) -> Result<()> {
|
||||
self.client
|
||||
.send_message(RequestType::SetTransitionDuration { duration })
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get the duration of the currently selected transition if supported.
|
||||
pub async fn get_transition_duration(&self) -> Result<u64> {
|
||||
self.client
|
||||
.send_message::<responses::TransitionDuration>(RequestType::GetTransitionDuration)
|
||||
.await
|
||||
.map(|td| td.transition_duration)
|
||||
}
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
//! Common data structures shared between [`requests`](crate::requests),
|
||||
//! [`responses`](crate::responses) and [`events`](crate::events).
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
/// Response value for [`get_current_scene`](crate::client::Scenes::get_current_scene) as part of
|
||||
/// [`CurrentScene`](crate::responses::CurrentScene),
|
||||
/// [`get_scene_list`](crate::client::Scenes::get_scene_list) as part of
|
||||
/// [`Scene`](crate::responses::Scene),
|
||||
/// [`get_preview_scene`](crate::client::StudioMode::get_preview_scene) as part of
|
||||
/// [`PreviewScene`](crate::responses::PreviewScene),
|
||||
/// [`EventType::SwitchScenes`](crate::events::EventType::SwitchScenes),
|
||||
/// [`EventType::PreviewSceneChanged`](crate::events::EventType::PreviewSceneChanged),
|
||||
/// and **itself**.
|
||||
#[allow(missing_docs)] // Docs missing in the obs-websocket spec.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct SceneItem {
|
||||
pub cy: f64,
|
||||
pub cx: f64,
|
||||
/// The point on the source that the item is manipulated from. The sum of 1=Left or 2=Right, and
|
||||
/// 4=Top or 8=Bottom, or omit to center on that axis.
|
||||
pub alignment: u8,
|
||||
/// The name of this Scene Item.
|
||||
pub name: String,
|
||||
/// Scene item ID.
|
||||
pub id: i64,
|
||||
/// Whether or not this Scene Item is set to "visible".
|
||||
pub render: bool,
|
||||
/// Whether or not this Scene Item is muted.
|
||||
pub muted: bool,
|
||||
/// Whether or not this Scene Item is locked and can't be moved around
|
||||
pub locked: bool,
|
||||
pub source_cx: f64,
|
||||
pub source_cy: f64,
|
||||
/// Source type. Value is one of the following: "input", "filter", "transition", "scene" or
|
||||
/// "unknown".
|
||||
#[serde(rename = "type")]
|
||||
pub ty: String,
|
||||
pub volume: f64,
|
||||
pub x: f64,
|
||||
pub y: f64,
|
||||
/// Name of the item's parent (if this item belongs to a group).
|
||||
#[serde(rename = "parentGroupName")]
|
||||
pub parent_group_name: Option<String>,
|
||||
/// List of children (if this item is a group).
|
||||
#[serde(rename = "groupChildren", default)]
|
||||
pub group_children: Vec<SceneItem>,
|
||||
}
|
||||
|
||||
/// Response value for
|
||||
/// [`get_scene_item_properties`](crate::client::SceneItems::get_scene_item_properties) as part of
|
||||
/// [`SceneItemProperties`](crate::responses::SceneItemProperties),
|
||||
/// [`EventType::SceneItemTransformChanged`](crate::events::EventType::SceneItemTransformChanged)
|
||||
/// and **itself**.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SceneItemTransform {
|
||||
/// Position of the scene item.
|
||||
pub position: Position,
|
||||
/// The clockwise rotation of the scene item in degrees around the point of alignment.
|
||||
pub rotation: f64,
|
||||
/// Scaling factor of the scene item.
|
||||
pub scale: Scale,
|
||||
/// Pixel cropping of the scene item before scaling.
|
||||
pub crop: Crop,
|
||||
/// If the scene item is visible.
|
||||
pub visible: bool,
|
||||
/// If the scene item is locked in position.
|
||||
pub locked: bool,
|
||||
/// Bounding box of the source item.
|
||||
pub bounds: Bounds,
|
||||
/// Base width (without scaling) of the source.
|
||||
pub source_width: u64,
|
||||
/// Base source (without scaling) of the source.
|
||||
pub source_height: u64,
|
||||
/// Scene item width (base source width multiplied by the horizontal scaling factor).
|
||||
pub width: f64,
|
||||
/// Scene item height (base source height multiplied by the vertical scaling factor).
|
||||
pub height: f64,
|
||||
/// Name of the item's parent (if this item belongs to a group).
|
||||
pub parent_group_name: Option<String>,
|
||||
/// List of children (if this item is a group).
|
||||
#[serde(default)]
|
||||
pub group_children: Vec<SceneItemTransform>,
|
||||
}
|
||||
|
||||
/// Response value for
|
||||
/// [`get_scene_item_properties`](crate::client::SceneItems::get_scene_item_properties) as part of
|
||||
/// [`SceneItemProperties`](crate::responses::SceneItemProperties).
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct Position {
|
||||
/// The x position of the source from the left.
|
||||
pub x: f64,
|
||||
/// The y position of the source from the top.
|
||||
pub y: f64,
|
||||
/// The point on the source that the item is manipulated from. The sum of 1=Left or 2=Right, and
|
||||
/// 4=Top or 8=Bottom, or omit to center on that axis.
|
||||
pub alignment: u8,
|
||||
}
|
||||
|
||||
/// Response value for
|
||||
/// [`get_scene_item_properties`](crate::client::SceneItems::get_scene_item_properties) as part of
|
||||
/// [`SceneItemProperties`](crate::responses::SceneItemProperties) and [`SceneItemTransform`].
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct Scale {
|
||||
/// The x-scale factor of the source.
|
||||
pub x: f64,
|
||||
/// The y-scale factor of the source.
|
||||
pub y: f64,
|
||||
}
|
||||
|
||||
/// Response value for
|
||||
/// [`get_scene_item_properties`](crate::client::SceneItems::get_scene_item_properties) as part of
|
||||
/// [`SceneItemProperties`](crate::responses::SceneItemProperties) and [`SceneItemTransform`].
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct Crop {
|
||||
/// The number of pixels cropped off the top of the source before scaling.
|
||||
pub top: i64,
|
||||
/// The number of pixels cropped off the right of the source before scaling.
|
||||
pub right: i64,
|
||||
/// The number of pixels cropped off the bottom of the source before scaling.
|
||||
pub bottom: i64,
|
||||
/// The number of pixels cropped off the left of the source before scaling.
|
||||
pub left: i64,
|
||||
}
|
||||
|
||||
/// Response value for
|
||||
/// [`get_scene_item_properties`](crate::client::SceneItems::get_scene_item_properties) as part of
|
||||
/// [`SceneItemProperties`](crate::responses::SceneItemProperties) and [`SceneItemTransform`].
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct Bounds {
|
||||
/// Type of bounding box. Can be "OBS_BOUNDS_STRETCH", "OBS_BOUNDS_SCALE_INNER",
|
||||
/// "OBS_BOUNDS_SCALE_OUTER", "OBS_BOUNDS_SCALE_TO_WIDTH", "OBS_BOUNDS_SCALE_TO_HEIGHT",
|
||||
/// "OBS_BOUNDS_MAX_ONLY" or "OBS_BOUNDS_NONE".
|
||||
#[serde(rename = "type")]
|
||||
pub ty: String,
|
||||
/// Alignment of the bounding box.
|
||||
pub alignment: u8,
|
||||
/// Width of the bounding box.
|
||||
pub x: f64,
|
||||
/// Height of the bounding box.
|
||||
pub y: f64,
|
||||
}
|
@ -0,0 +1,511 @@
|
||||
//! All events that can be received from the API.
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::common::{SceneItem, SceneItemTransform};
|
||||
|
||||
/// Events are sent when a recognized action occurs within OBS.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct Event {
|
||||
/// Time elapsed between now and stream start (only present if OBS Studio is streaming).
|
||||
pub stream_timecode: Option<String>,
|
||||
/// Time elapsed between now and recording start (only present if OBS Studio is recording).
|
||||
pub rec_timecode: Option<String>,
|
||||
/// The type of event.
|
||||
#[serde(flatten)]
|
||||
pub ty: EventType,
|
||||
}
|
||||
|
||||
/// All possible event types that can occur while the user interacts with OBS.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(tag = "update-type")]
|
||||
pub enum EventType {
|
||||
// --------------------------------
|
||||
// Scenes
|
||||
// --------------------------------
|
||||
/// Indicates a scene change.
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
SwitchScenes {
|
||||
/// The new scene.
|
||||
scene_name: String,
|
||||
/// List of scene items in the new scene.
|
||||
sources: Vec<SceneItem>,
|
||||
},
|
||||
/// Note: This event is not fired when the scenes are reordered.
|
||||
ScenesChanged,
|
||||
/// Triggered when switching to another scene collection or when renaming the current scene
|
||||
/// collection.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SceneCollectionChanged {
|
||||
/// Name of the new current scene collection.
|
||||
scene_collection: String,
|
||||
},
|
||||
/// Triggered when a scene collection is created, added, renamed, or removed.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SceneCollectionListChanged {
|
||||
/// Scene collections list.
|
||||
scene_collections: Vec<SceneCollection>,
|
||||
},
|
||||
// --------------------------------
|
||||
// Transitions
|
||||
// --------------------------------
|
||||
/// The active transition has been changed.
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
SwitchTransition {
|
||||
/// The name of the new active transition.
|
||||
transition_name: String,
|
||||
},
|
||||
/// The list of available transitions has been modified. Transitions have been added, removed,
|
||||
/// or renamed.
|
||||
TransitionListChanged,
|
||||
/// The active transition duration has been changed.
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
TransitionDurationChanged {
|
||||
/// New transition duration.
|
||||
new_duration: u64,
|
||||
},
|
||||
/// A transition (other than "cut") has begun.
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
TransitionBegin {
|
||||
/// Transition name.
|
||||
name: String,
|
||||
/// Transition type.
|
||||
#[serde(rename = "type")]
|
||||
ty: String,
|
||||
/// Transition duration (in milliseconds). Will be -1 for any transition with a fixed
|
||||
/// duration, such as a Stinger, due to limitations of the OBS API.
|
||||
duration: u64,
|
||||
/// Source scene of the transition.
|
||||
from_scene: String,
|
||||
/// Destination scene of the transition.
|
||||
to_scene: String,
|
||||
},
|
||||
/// A transition (other than "cut") has ended. Please note that the `from_scene` field is not
|
||||
/// available in TransitionEnd.
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
TransitionEnd {
|
||||
/// Transition name.
|
||||
name: String,
|
||||
/// Transition type.
|
||||
#[serde(rename = "type")]
|
||||
ty: String,
|
||||
/// Transition duration (in milliseconds).
|
||||
duration: u64,
|
||||
/// Destination scene of the transition.
|
||||
to_scene: String,
|
||||
},
|
||||
/// A stinger transition has finished playing its video.
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
TransitionVideoEnd {
|
||||
/// Transition name.
|
||||
name: String,
|
||||
/// Transition type.
|
||||
#[serde(rename = "type")]
|
||||
ty: String,
|
||||
/// Transition duration (in milliseconds).
|
||||
duration: u64,
|
||||
/// Source scene of the transition.
|
||||
from_scene: String,
|
||||
/// Destination scene of the transition.
|
||||
to_scene: String,
|
||||
},
|
||||
// --------------------------------
|
||||
// Profiles
|
||||
// --------------------------------
|
||||
/// Triggered when switching to another profile or when renaming the current profile.
|
||||
ProfileChanged,
|
||||
/// Triggered when a profile is created, added, renamed, or removed.
|
||||
ProfileListChanged,
|
||||
// --------------------------------
|
||||
// Streaming
|
||||
// --------------------------------
|
||||
/// A request to start streaming has been issued.
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
StreamStarting {
|
||||
/// Always false (retrocompatibility).
|
||||
#[serde(default)]
|
||||
preview_only: bool,
|
||||
},
|
||||
/// Streaming started successfully.
|
||||
StreamStarted,
|
||||
/// A request to stop streaming has been issued.
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
StreamStopping {
|
||||
/// Always false (retrocompatibility).
|
||||
#[serde(default)]
|
||||
preview_only: bool,
|
||||
},
|
||||
/// Streaming stopped successfully.
|
||||
StreamStopped,
|
||||
/// Emitted every 2 seconds when stream is active.
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
StreamStatus {
|
||||
/// Current streaming state.
|
||||
streaming: bool,
|
||||
/// Current recording state.
|
||||
recording: bool,
|
||||
/// Replay Buffer status.
|
||||
replay_buffer_active: bool,
|
||||
/// Amount of data per second (in bytes) transmitted by the stream encoder.
|
||||
bytes_per_sec: u64,
|
||||
/// Amount of data per second (in kilobits) transmitted by the stream encoder.
|
||||
kbits_per_sec: u64,
|
||||
/// Percentage of dropped frames.
|
||||
strain: f64,
|
||||
/// Total time (in seconds) since the stream started.
|
||||
total_stream_time: u64,
|
||||
/// Total number of frames transmitted since the stream started.
|
||||
num_total_frames: u64,
|
||||
/// Number of frames dropped by the encoder since the stream started.
|
||||
num_dropped_frames: u64,
|
||||
/// Current framerate.
|
||||
fps: f64,
|
||||
/// Number of frames rendered.
|
||||
render_total_frames: u64,
|
||||
/// Number of frames missed due to rendering lag.
|
||||
render_missed_frames: u64,
|
||||
/// Number of frames outputted.
|
||||
output_total_frames: u64,
|
||||
/// Number of frames skipped due to encoding lag.
|
||||
output_skipped_frames: u64,
|
||||
/// Average frame time (in milliseconds).
|
||||
average_frame_time: f64,
|
||||
/// Current CPU usage (percentage).
|
||||
cpu_usage: f64,
|
||||
/// Current RAM usage (in megabytes).
|
||||
memory_usage: f64,
|
||||
/// Free recording disk space (in megabytes).
|
||||
free_disk_space: f64,
|
||||
/// Always false (retrocompatibility).
|
||||
#[serde(default)]
|
||||
preview_only: bool,
|
||||
},
|
||||
// --------------------------------
|
||||
// Recording
|
||||
// --------------------------------
|
||||
/// Note: `recording_filename` is not provided in this event because this information is not
|
||||
/// available at the time this event is emitted.
|
||||
RecordingStarting,
|
||||
/// Recording started successfully.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
RecordingStarted {
|
||||
/// Absolute path to the file of the current recording.
|
||||
recording_filename: String,
|
||||
},
|
||||
/// A request to stop recording has been issued.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
RecordingStopping {
|
||||
/// Absolute path to the file of the current recording.
|
||||
recording_filename: String,
|
||||
},
|
||||
/// Recording stopped successfully.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
RecordingStopped {
|
||||
/// Absolute path to the file of the current recording.
|
||||
recording_filename: String,
|
||||
},
|
||||
/// Current recording paused.
|
||||
RecordingPaused,
|
||||
/// Current recording resumed.
|
||||
RecordingResumed,
|
||||
// --------------------------------
|
||||
// Replay Buffer
|
||||
// --------------------------------
|
||||
/// A request to start the replay buffer has been issued.
|
||||
ReplayStarting,
|
||||
/// Replay Buffer started successfully.
|
||||
ReplayStarted,
|
||||
/// A request to stop the replay buffer has been issued.
|
||||
ReplayStopping,
|
||||
/// Replay Buffer stopped successfully.
|
||||
ReplayStopped,
|
||||
// --------------------------------
|
||||
// Other
|
||||
// --------------------------------
|
||||
/// OBS is exiting.
|
||||
Exiting,
|
||||
// --------------------------------
|
||||
// General
|
||||
// --------------------------------
|
||||
/// A custom broadcast message, sent by the server, requested by one of the websocket clients.
|
||||
BroadcastCustomMessage {
|
||||
/// Identifier provided by the sender.
|
||||
realm: String,
|
||||
/// User-defined data.
|
||||
data: serde_json::Value,
|
||||
},
|
||||
// --------------------------------
|
||||
// Sources
|
||||
// --------------------------------
|
||||
/// A source has been created. A source can be an input, a scene or a transition.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SourceCreated {
|
||||
/// Source name.
|
||||
source_name: String,
|
||||
/// Source type. Can be "input", "scene", "transition" or "filter".
|
||||
source_type: String,
|
||||
/// Source kind.
|
||||
source_kind: String,
|
||||
/// Source settings.
|
||||
source_settings: serde_json::Value,
|
||||
},
|
||||
/// A source has been destroyed/removed. A source can be an input, a scene or a transition.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SourceDestroyed {
|
||||
/// Source name.
|
||||
source_name: String,
|
||||
/// Source type. Can be "input", "scene", "transition" or "filter".
|
||||
source_type: String,
|
||||
/// Source kind.
|
||||
source_kind: String,
|
||||
},
|
||||
/// The volume of a source has changed.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SourceVolumeChanged {
|
||||
/// Source name.
|
||||
source_name: String,
|
||||
/// Source volume.
|
||||
volume: f32,
|
||||
},
|
||||
/// A source has been muted or unmuted.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SourceMuteStateChanged {
|
||||
/// Source name.
|
||||
source_name: String,
|
||||
/// Mute status of the source.
|
||||
muted: bool,
|
||||
},
|
||||
/// A source has removed audio.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SourceAudioDeactivated {
|
||||
/// Source name.
|
||||
source_name: String,
|
||||
},
|
||||
/// A source has added audio.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SourceAudioActivated {
|
||||
/// Source name.
|
||||
source_name: String,
|
||||
},
|
||||
/// The audio sync offset of a source has changed.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SourceAudioSyncOffsetChanged {
|
||||
/// Source name.
|
||||
source_name: String,
|
||||
/// Audio sync offset of the source (in nanoseconds).
|
||||
sync_offset: i64,
|
||||
},
|
||||
/// Audio mixer routing changed on a source.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SourceAudioMixersChanged {
|
||||
/// Source name.
|
||||
source_name: String,
|
||||
/// Routing status of the source for each audio mixer (array of 6 values).
|
||||
mixers: [AudioMixer; 6],
|
||||
/// Raw mixer flags (little-endian, one bit per mixer) as an hexadecimal value.
|
||||
hex_mixers_value: String,
|
||||
},
|
||||
/// A source has been renamed.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SourceRenamed {
|
||||
/// Previous source name.
|
||||
previous_name: String,
|
||||
/// New source name.
|
||||
new_name: String,
|
||||
/// Type of source (input, scene, filter, transition).
|
||||
source_type: String,
|
||||
},
|
||||
/// A filter was added to a source.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SourceFilterAdded {
|
||||
/// Source name.
|
||||
source_name: String,
|
||||
/// Filter name.
|
||||
filter_name: String,
|
||||
/// Filter type.
|
||||
filter_type: String,
|
||||
/// Filter settings.
|
||||
filter_settings: serde_json::Value,
|
||||
},
|
||||
/// A filter was removed from a source.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SourceFilterRemoved {
|
||||
/// Source name.
|
||||
source_name: String,
|
||||
/// Filter name.
|
||||
filter_name: String,
|
||||
/// Filter type.
|
||||
filter_type: String,
|
||||
},
|
||||
/// The visibility/enabled state of a filter changed.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SourceFilterVisibilityChanged {
|
||||
/// Source name.
|
||||
source_name: String,
|
||||
/// Filter name.
|
||||
filter_name: String,
|
||||
/// New filter state.
|
||||
filter_enabled: bool,
|
||||
},
|
||||
/// Filters in a source have been reordered.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SourceFiltersReordered {
|
||||
/// Source name.
|
||||
source_name: String,
|
||||
/// Ordered Filters list.
|
||||
filters: Vec<SourceFilter>,
|
||||
},
|
||||
// --------------------------------
|
||||
// Scene Items
|
||||
// --------------------------------
|
||||
/// Scene items within a scene have been reordered.
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
SourceOrderChanged {
|
||||
/// Name of the scene where items have been reordered.
|
||||
scene_name: String,
|
||||
/// Ordered list of scene items.
|
||||
scene_items: Vec<SourceOrderSceneItem>,
|
||||
},
|
||||
/// A scene item has been added to a scene.
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
SceneItemAdded {
|
||||
/// Name of the scene.
|
||||
scene_name: String,
|
||||
/// Name of the item added to the scene.
|
||||
item_name: String,
|
||||
/// Scene item ID.
|
||||
item_id: i64,
|
||||
},
|
||||
/// A scene item has been removed from a scene.
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
SceneItemRemoved {
|
||||
/// Name of the scene.
|
||||
scene_name: String,
|
||||
/// Name of the item removed from the scene.
|
||||
item_name: String,
|
||||
/// Scene item ID.
|
||||
item_id: i64,
|
||||
},
|
||||
/// A scene item's visibility has been toggled.
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
SceneItemVisibilityChanged {
|
||||
/// Name of the scene.
|
||||
scene_name: String,
|
||||
/// Name of the item in the scene.
|
||||
item_name: String,
|
||||
/// Scene item ID.
|
||||
item_id: i64,
|
||||
/// New visibility state of the item.
|
||||
item_visible: bool,
|
||||
},
|
||||
/// A scene item's locked status has been toggled.
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
SceneItemLockChanged {
|
||||
/// Name of the scene.
|
||||
scene_name: String,
|
||||
/// Name of the item in the scene.
|
||||
item_name: String,
|
||||
/// Scene item ID.
|
||||
item_id: i64,
|
||||
/// New locked state of the item.
|
||||
item_locked: bool,
|
||||
},
|
||||
/// A scene item's transform has been changed.
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
SceneItemTransformChanged {
|
||||
/// Name of the scene.
|
||||
scene_name: String,
|
||||
/// Name of the item in the scene.
|
||||
item_name: String,
|
||||
/// Scene item ID.
|
||||
item_id: i64,
|
||||
/// Scene item transform properties.
|
||||
transform: SceneItemTransform,
|
||||
},
|
||||
/// A scene item is selected.
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
SceneItemSelected {
|
||||
/// Name of the scene.
|
||||
scene_name: String,
|
||||
/// Name of the item in the scene.
|
||||
item_name: String,
|
||||
/// ID of the item in the scene.
|
||||
item_id: i64,
|
||||
},
|
||||
/// A scene item is deselected.
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
SceneItemDeselected {
|
||||
/// Name of the scene.
|
||||
scene_name: String,
|
||||
/// Name of the item in the scene.
|
||||
item_name: String,
|
||||
/// ID of the item in the scene.
|
||||
item_id: i64,
|
||||
},
|
||||
// --------------------------------
|
||||
// Studio Mode
|
||||
// --------------------------------
|
||||
/// The selected preview scene has changed (only available in Studio Mode).
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
PreviewSceneChanged {
|
||||
/// Name of the scene being previewed.
|
||||
scene_name: String,
|
||||
/// List of sources composing the scene.
|
||||
soruces: Vec<SceneItem>,
|
||||
},
|
||||
/// Studio Mode has been enabled or disabled.
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
StudioModeSwitched {
|
||||
/// The new enabled state of Studio Mode.
|
||||
new_state: bool,
|
||||
},
|
||||
/// Fallback value for any unknown event type.
|
||||
#[serde(other)]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
/// Part of [`EventType::SceneCollectionListChanged`].
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct SceneCollection {
|
||||
/// Scene collection name.
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
/// Part of [`EventType::ProfileListChanged`].
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct Profile {
|
||||
/// Profile name.
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
/// Part of [`EventType::SourceAudioMixersChanged`].
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct AudioMixer {
|
||||
/// Mixer number.
|
||||
pub id: i64,
|
||||
/// Routing status.
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
/// Part of [`EventType::SourceFiltersReordered`].
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct SourceFilter {
|
||||
/// Filter name.
|
||||
pub name: String,
|
||||
/// Filter type.
|
||||
#[serde(rename = "type")]
|
||||
pub ty: String,
|
||||
/// Filter visibility status.
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
/// Part of [`EventType::SourceOrderChanged`].
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct SourceOrderSceneItem {
|
||||
/// Item source name.
|
||||
pub source_name: String,
|
||||
/// Scene item unique ID.
|
||||
pub item_id: i64,
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
//! # OBSWS - The obws (obvious) remote control library for OBS
|
||||
|
||||
#![deny(missing_docs, rust_2018_idioms, clippy::all)]
|
||||
|
||||
pub mod client;
|
||||
pub mod common;
|
||||
pub mod events;
|
||||
pub mod requests;
|
||||
pub mod responses;
|
@ -0,0 +1,810 @@
|
||||
//! All requests that can be send to the API.
|
||||
|
||||
use either::Either;
|
||||
use serde::Serialize;
|
||||
use serde_with::skip_serializing_none;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub(crate) struct Request {
|
||||
pub message_id: String,
|
||||
#[serde(flatten)]
|
||||
pub ty: RequestType,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(tag = "request-type")]
|
||||
pub(crate) enum RequestType {
|
||||
// --------------------------------
|
||||
// General
|
||||
// --------------------------------
|
||||
GetVersion,
|
||||
GetAuthRequired,
|
||||
Authenticate {
|
||||
/// Response to the auth challenge.
|
||||
auth: String,
|
||||
},
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
SetFilenameFormatting {
|
||||
/// Filename formatting string to set.
|
||||
filename_formatting: String,
|
||||
},
|
||||
GetFilenameFormatting,
|
||||
GetStats,
|
||||
BroadcastCustomMessage {
|
||||
/// Identifier to be choosen by the client.
|
||||
realm: String,
|
||||
/// User-defined data.
|
||||
data: serde_json::Value,
|
||||
},
|
||||
GetVideoInfo,
|
||||
OpenProjector(Projector),
|
||||
// --------------------------------
|
||||
// Sources
|
||||
// --------------------------------
|
||||
GetSourcesList,
|
||||
GetSourceTypesList,
|
||||
#[serde(rename_all = "camelCase")]
|
||||
GetVolume {
|
||||
/// Source name.
|
||||
source: String,
|
||||
/// Output volume in decibels of attenuation instead of amplitude/mul.
|
||||
use_decibel: Option<bool>,
|
||||
},
|
||||
SetVolume(Volume),
|
||||
GetMute {
|
||||
/// Source name.
|
||||
source: String,
|
||||
},
|
||||
SetMute {
|
||||
/// Source name.
|
||||
source: String,
|
||||
/// Desired mute status.
|
||||
mute: bool,
|
||||
},
|
||||
ToggleMute {
|
||||
/// Source name.
|
||||
source: String,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
GetAudioActive {
|
||||
/// Source name.
|
||||
source_name: String,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SetSourceName {
|
||||
/// Source name.
|
||||
source_name: String,
|
||||
/// New source name.
|
||||
new_name: String,
|
||||
},
|
||||
SetSyncOffset {
|
||||
/// Source name.
|
||||
source: String,
|
||||
/// The desired audio sync offset (in nanoseconds).
|
||||
offset: i64,
|
||||
},
|
||||
GetSyncOffset {
|
||||
/// Source name.
|
||||
source: String,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
GetSourceSettings {
|
||||
/// Source name.
|
||||
source_name: String,
|
||||
/// Type of the specified source. Useful for type-checking if you expect a specific settings
|
||||
/// schema.
|
||||
source_type: Option<String>,
|
||||
},
|
||||
SetSourceSettings(SourceSettings),
|
||||
GetTextGDIPlusProperties {
|
||||
/// Source name.
|
||||
source: String,
|
||||
},
|
||||
SetTextGDIPlusProperties(Box<TextGdiPlusProperties>),
|
||||
GetTextFreetype2Properties {
|
||||
/// Source name.
|
||||
source: String,
|
||||
},
|
||||
SetTextFreetype2Properties(TextFreetype2Properties),
|
||||
GetSpecialSources,
|
||||
#[serde(rename_all = "camelCase")]
|
||||
GetSourceFilters {
|
||||
/// Source name.
|
||||
source_name: String,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
GetSourceFilterInfo {
|
||||
/// Source name.
|
||||
source_name: String,
|
||||
/// Source filter name.
|
||||
filter_name: String,
|
||||
},
|
||||
AddFilterToSource(AddFilter),
|
||||
#[serde(rename_all = "camelCase")]
|
||||
RemoveFilterFromSource {
|
||||
/// Name of the source from which the specified filter is removed.
|
||||
source_name: String,
|
||||
/// Name of the filter to remove.
|
||||
filter_name: String,
|
||||
},
|
||||
ReorderSourceFilter(ReorderFilter),
|
||||
MoveSourceFilter(MoveFilter),
|
||||
SetSourceFilterSettings(SourceFilterSettings),
|
||||
SetSourceFilterVisibility(SourceFilterVisibility),
|
||||
#[serde(rename_all = "camelCase")]
|
||||
GetAudioMonitorType {
|
||||
/// Source name.
|
||||
source_name: String,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SetAudioMonitorType {
|
||||
/// Source name.
|
||||
source_name: String,
|
||||
/// The monitor type to use. Options: `none`, `monitorOnly`, `monitorAndOutput`.
|
||||
monitor_type: String,
|
||||
},
|
||||
TakeSourceScreenshot(SourceScreenshot),
|
||||
// --------------------------------
|
||||
// Outputs
|
||||
// --------------------------------
|
||||
ListOutputs,
|
||||
#[serde(rename_all = "camelCase")]
|
||||
GetOutputInfo {
|
||||
/// Output name.
|
||||
output_name: String,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
StartOutput {
|
||||
/// Output name.
|
||||
output_name: String,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
StopOutput {
|
||||
/// Output name.
|
||||
output_name: String,
|
||||
/// Force stop (default: false).
|
||||
force: Option<bool>,
|
||||
},
|
||||
// --------------------------------
|
||||
// Profiles
|
||||
// --------------------------------
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
SetCurrentProfile {
|
||||
/// Name of the desired profile.
|
||||
profile_name: String,
|
||||
},
|
||||
GetCurrentProfile,
|
||||
ListProfiles,
|
||||
// --------------------------------
|
||||
// Recording
|
||||
// --------------------------------
|
||||
StartStopRecording,
|
||||
StartRecording,
|
||||
StopRecording,
|
||||
PauseRecording,
|
||||
ResumeRecording,
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
SetRecordingFolder {
|
||||
/// Path of the recording folder.
|
||||
rec_folder: String,
|
||||
},
|
||||
GetRecordingFolder,
|
||||
// --------------------------------
|
||||
// Replay Buffer
|
||||
// --------------------------------
|
||||
StartStopReplayBuffer,
|
||||
StartReplayBuffer,
|
||||
StopReplayBuffer,
|
||||
SaveReplayBuffer,
|
||||
// --------------------------------
|
||||
// Scene Collections
|
||||
// --------------------------------
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
SetCurrentSceneCollection {
|
||||
/// Name of the desired scene collection.
|
||||
sc_name: String,
|
||||
},
|
||||
GetCurrentSceneCollection,
|
||||
ListSceneCollections,
|
||||
// --------------------------------
|
||||
// Scene Items
|
||||
// --------------------------------
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
GetSceneItemProperties {
|
||||
/// Name of the scene the scene item belongs to. Defaults to the current scene.
|
||||
scene_name: Option<String>,
|
||||
/// Scene Item name (if this field is a string) or specification (if it is an object).
|
||||
#[serde(with = "either::serde_untagged")]
|
||||
item: Either<String, SceneItemSpecification>,
|
||||
},
|
||||
SetSceneItemProperties(SceneItemProperties),
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
ResetSceneItem {
|
||||
/// Name of the scene the scene item belongs to. Defaults to the current scene.
|
||||
scene_name: Option<String>,
|
||||
/// Scene Item name (if this field is a string) or specification (if it is an object).
|
||||
#[serde(with = "either::serde_untagged")]
|
||||
item: Either<String, SceneItemSpecification>,
|
||||
},
|
||||
SetSceneItemRender(SceneItemRender),
|
||||
DeleteSceneItem {
|
||||
/// Name of the scene the scene item belongs to. Defaults to the current scene.
|
||||
scene: Option<String>,
|
||||
/// Scene item to delete.
|
||||
item: SceneItemSpecification, // TODO: fields are actually not optional
|
||||
},
|
||||
AddSceneItem(AddSceneItem),
|
||||
DuplicateSceneItem(DuplicateSceneItem),
|
||||
// --------------------------------
|
||||
// Scenes
|
||||
// --------------------------------
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
SetCurrentScene {
|
||||
/// Name of the scene to switch to.
|
||||
scene_name: String,
|
||||
},
|
||||
GetCurrentScene,
|
||||
GetSceneList,
|
||||
#[serde(rename_all = "camelCase")]
|
||||
CreateScene {
|
||||
/// Name of the scene to create.
|
||||
scene_name: String,
|
||||
},
|
||||
ReorderSceneItems {
|
||||
/// Name of the scene to reorder (defaults to current).
|
||||
scene: Option<String>,
|
||||
/// Ordered list of objects with name and/or id specified. Id preferred due to uniqueness
|
||||
/// per scene.
|
||||
items: Vec<Scene>,
|
||||
},
|
||||
SetSceneTransitionOverride(SceneTransitionOverride),
|
||||
#[serde(rename_all = "camelCase")]
|
||||
RemoveSceneTransitionOverride {
|
||||
/// Name of the scene to remove the override from.
|
||||
scene_name: String,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
GetSceneTransitionOverride {
|
||||
/// Name of the scene to get the override for.
|
||||
scene_name: String,
|
||||
},
|
||||
// --------------------------------
|
||||
// Streaming
|
||||
// --------------------------------
|
||||
GetStreamingStatus,
|
||||
StartStopStreaming,
|
||||
StartStreaming {
|
||||
/// Special stream configuration. Please note: these won't be saved to OBS' configuration.
|
||||
stream: Option<Stream>,
|
||||
},
|
||||
StopStreaming,
|
||||
SetStreamSettings(SetStreamSettings),
|
||||
GetStreamSettings,
|
||||
SaveStreamSettings,
|
||||
SendCaptions {
|
||||
/// Captions text.
|
||||
text: String,
|
||||
},
|
||||
// --------------------------------
|
||||
// Studio Mode
|
||||
// --------------------------------
|
||||
GetStudioModeStatus,
|
||||
GetPreviewScene,
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
SetPreviewScene {
|
||||
/// The name of the scene to preview.
|
||||
scene_name: String,
|
||||
},
|
||||
TransitionToProgram {
|
||||
/// Change the active transition before switching scenes. Defaults to the active transition.
|
||||
with_transition: Option<Transition>,
|
||||
},
|
||||
EnableStudioMode,
|
||||
DisableStudioMode,
|
||||
ToggleStudioMode,
|
||||
// --------------------------------
|
||||
// Transitions
|
||||
// --------------------------------
|
||||
GetTransitionList,
|
||||
GetCurrentTransition,
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
SetCurrentTransition {
|
||||
/// The name of the transition.
|
||||
transition_name: String,
|
||||
},
|
||||
SetTransitionDuration {
|
||||
/// Desired duration of the transition (in milliseconds).
|
||||
duration: u64,
|
||||
},
|
||||
GetTransitionDuration,
|
||||
}
|
||||
|
||||
/// Request information for [`open_projector`](crate::client::General::open_projector).
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Projector {
|
||||
/// Type of projector: `Preview` (default), `Source`, `Scene`, `StudioProgram`, or `Multiview`
|
||||
/// (case insensitive).
|
||||
#[serde(rename = "type")]
|
||||
pub ty: Option<String>,
|
||||
/// Monitor to open the projector on. If -1 or omitted, opens a window.
|
||||
pub monitor: Option<i64>,
|
||||
/// Size and position of the projector window (only if monitor is -1). Encoded in Base64 using
|
||||
/// [Qt's geometry encoding](https://doc.qt.io/qt-5/qwidget.html#saveGeometry). Corresponds to
|
||||
/// OBS's saved projectors.
|
||||
pub geometry: Option<String>,
|
||||
/// Name of the source or scene to be displayed (ignored for other projector types).
|
||||
pub name: Option<String>,
|
||||
}
|
||||
|
||||
/// Request information for [`set_volume`](crate::client::Sources::set_volume).
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Volume {
|
||||
/// Source name.
|
||||
pub source: String,
|
||||
/// Desired volume. Must be between `0.0` and `20.0` for mul, and under 26.0 for dB. OBS will
|
||||
/// interpret dB values under -100.0 as Inf. Note: The OBS volume sliders only reach a maximum
|
||||
/// of 1.0mul/0.0dB, however OBS actually supports larger values.
|
||||
pub volume: f64,
|
||||
/// Interperet `volume` data as decibels instead of amplitude/mul.
|
||||
pub use_decibel: Option<bool>,
|
||||
}
|
||||
|
||||
/// Request information for [`set_source_settings`](crate::client::Sources::set_source_settings).
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SourceSettings {
|
||||
/// Source name.
|
||||
pub source_name: String,
|
||||
/// Type of the specified source. Useful for type-checking to avoid settings a set of settings
|
||||
/// incompatible with the actual source's type.
|
||||
pub source_type: Option<String>,
|
||||
/// Source settings (varies between source types, may require some probing around).
|
||||
pub source_settings: serde_json::Value,
|
||||
}
|
||||
|
||||
/// Request information for
|
||||
/// [`set_text_gdi_plus_properties`](crate::client::Sources::set_text_gdi_plus_properties).
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct TextGdiPlusProperties {
|
||||
/// Name of the source.
|
||||
pub source: String,
|
||||
/// Text Alignment ("left", "center", "right").
|
||||
pub align: Option<String>,
|
||||
/// Background color.
|
||||
pub bk_color: Option<u32>,
|
||||
/// Background opacity (0-100).
|
||||
pub bk_opacity: Option<u8>,
|
||||
/// Chat log.
|
||||
pub chatlog: Option<bool>,
|
||||
/// Chat log lines.
|
||||
pub chatlog_lines: Option<u64>,
|
||||
/// Text color.
|
||||
pub color: Option<u32>,
|
||||
/// Extents wrap.
|
||||
pub extents: Option<bool>,
|
||||
/// Extents cx.
|
||||
pub extents_cx: Option<i64>,
|
||||
/// Extents cy.
|
||||
pub extents_cy: Option<i64>,
|
||||
/// File path name.
|
||||
pub file: Option<String>,
|
||||
/// Read text from the specified file.
|
||||
pub read_from_file: Option<bool>,
|
||||
/// Holds data for the font. Ex:
|
||||
/// `"font": { "face": "Arial", "flags": 0, "size": 150, "style": "" }`.
|
||||
pub font: Option<Font>,
|
||||
/// Gradient enabled.
|
||||
pub gradient: Option<bool>,
|
||||
/// Gradient color.
|
||||
pub gradient_color: Option<u32>,
|
||||
/// Gradient direction.
|
||||
pub gradient_dir: Option<f32>,
|
||||
/// Gradient opacity (0-100).
|
||||
pub gradient_opacity: Option<u8>,
|
||||
/// Outline.
|
||||
pub outline: Option<bool>,
|
||||
/// Outline color.
|
||||
pub outline_color: Option<u32>,
|
||||
/// Outline size.
|
||||
pub outline_size: Option<u64>,
|
||||
/// Outline opacity (0-100).
|
||||
pub outline_opacity: Option<u8>,
|
||||
/// Text content to be displayed.
|
||||
pub text: Option<String>,
|
||||
/// Text vertical alignment ("top", "center", "bottom").
|
||||
pub valign: Option<String>,
|
||||
/// Vertical text enabled.
|
||||
pub vertical: Option<bool>,
|
||||
/// Visibility of the scene item.
|
||||
pub render: Option<bool>,
|
||||
}
|
||||
|
||||
/// Request information for
|
||||
/// [`set_text_freetype2_properties`](crate::client::Sources::set_text_freetype2_properties).
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct TextFreetype2Properties {
|
||||
/// Source name.
|
||||
pub source: String,
|
||||
/// Gradient top color.
|
||||
pub color1: Option<u32>,
|
||||
/// Gradient bottom color.
|
||||
pub color2: Option<u32>,
|
||||
/// Custom width (0 to disable).
|
||||
pub custom_width: Option<u32>,
|
||||
/// Drop shadow.
|
||||
pub drop_shadow: Option<bool>,
|
||||
/// Holds data for the font. Ex:
|
||||
/// `"font": { "face": "Arial", "flags": 0, "size": 150, "style": "" }`.
|
||||
pub font: Option<Font>,
|
||||
/// Read text from the specified file.
|
||||
pub from_file: Option<bool>,
|
||||
/// Chat log.
|
||||
pub log_mode: Option<bool>,
|
||||
/// Outline.
|
||||
pub outline: Option<bool>,
|
||||
/// Text content to be displayed.
|
||||
pub text: Option<String>,
|
||||
/// File path.
|
||||
pub text_file: Option<String>,
|
||||
/// Word wrap.
|
||||
pub word_wrap: Option<bool>,
|
||||
}
|
||||
|
||||
/// Request information for [`add_filter_to_source`](crate::client::Sources::add_filter_to_source).
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AddFilter {
|
||||
/// Name of the source on which the filter is added.
|
||||
pub source_name: String,
|
||||
/// Name of the new filter.
|
||||
pub filter_name: String,
|
||||
/// Filter type.
|
||||
pub filter_type: String,
|
||||
/// Filter settings.
|
||||
pub filter_settings: serde_json::Value,
|
||||
}
|
||||
|
||||
/// Request information for
|
||||
/// [`reorder_source_filter`](crate::client::Sources::reorder_source_filter).
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ReorderFilter {
|
||||
/// Name of the source to which the filter belongs.
|
||||
pub source_name: String,
|
||||
/// Name of the filter to reorder.
|
||||
pub filter_name: String,
|
||||
/// Desired position of the filter in the chain.
|
||||
pub new_index: u32,
|
||||
}
|
||||
|
||||
/// Request information for [`move_source_filter`](crate::client::Sources::move_source_filter).
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MoveFilter {
|
||||
/// Name of the source to which the filter belongs.
|
||||
pub source_name: String,
|
||||
/// Name of the filter to reorder.
|
||||
pub filter_name: String,
|
||||
/// How to move the filter around in the source's filter chain. Either "up", "down", "top" or
|
||||
/// "bottom".
|
||||
pub movement_type: String,
|
||||
}
|
||||
|
||||
/// Request information for
|
||||
/// [`set_source_filter_settings`](crate::client::Sources::set_source_filter_settings).
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SourceFilterSettings {
|
||||
/// Name of the source to which the filter belongs.
|
||||
pub source_name: String,
|
||||
/// Name of the filter to reconfigure.
|
||||
pub filter_name: String,
|
||||
/// New settings. These will be merged to the current filter settings.
|
||||
pub filter_settings: serde_json::Value,
|
||||
}
|
||||
|
||||
/// Request information for
|
||||
/// [`set_source_filter_visibility`](crate::client::Sources::set_source_filter_visibility).
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SourceFilterVisibility {
|
||||
/// Source name.
|
||||
pub source_name: String,
|
||||
/// Source filter name.
|
||||
pub filter_name: String,
|
||||
/// New filter state.
|
||||
pub filter_enabled: bool,
|
||||
}
|
||||
|
||||
/// Request information for
|
||||
/// [`take_source_screenshot`](crate::client::Sources::take_source_screenshot).
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SourceScreenshot {
|
||||
/// Source name. Note that, since scenes are also sources, you can also provide a scene name. If
|
||||
/// not provided, the currently active scene is used.
|
||||
pub source_name: Option<String>,
|
||||
/// Format of the Data URI encoded picture. Can be "png", "jpg", "jpeg" or "bmp" (or any other
|
||||
/// value supported by Qt's Image module).
|
||||
pub embed_picture_format: Option<String>,
|
||||
/// Full file path (file extension included) where the captured image is to be saved. Can be in
|
||||
/// a format different from [`embed_picture_format`](SourceScreenshot::embed_picture_format).
|
||||
/// Can be a relative path.
|
||||
pub save_to_file_path: Option<String>,
|
||||
/// Format to save the image file as (one of the values provided in the
|
||||
/// [`supported_image_export_formats`](crate::responses::Version::supported_image_export_formats)
|
||||
/// response field of [`get_version`](crate::client::General::get_version)). If not specified,
|
||||
/// tries to guess based on file extension.
|
||||
pub file_format: Option<String>,
|
||||
/// Compression ratio between -1 and 100 to write the image with. -1 is automatic, 1 is smallest
|
||||
/// file/most compression, 100 is largest file/least compression. Varies with image type.
|
||||
pub compress_quality: Option<i8>,
|
||||
/// Screenshot width. Defaults to the source's base width.
|
||||
pub width: Option<u32>,
|
||||
/// Screenshot height. Defaults to the source's base height.
|
||||
pub height: Option<u32>,
|
||||
}
|
||||
|
||||
/// Request information for
|
||||
/// [`set_scene_item_properties`](crate::client::SceneItems::set_scene_item_properties).
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct SceneItemProperties {
|
||||
/// Name of the scene the source item belongs to. Defaults to the current scene.
|
||||
pub scene_name: Option<String>,
|
||||
/// Scene Item name (if this field is a string) or specification (if it is an object).
|
||||
#[serde(with = "either::serde_untagged")]
|
||||
pub item: Either<String, SceneItemSpecification>,
|
||||
/// Position of the scene item.
|
||||
pub position: Option<Position>,
|
||||
/// The new clockwise rotation of the item in degrees.
|
||||
pub rotation: Option<f64>,
|
||||
/// Scaling factor of the scene item.
|
||||
pub scale: Option<Scale>,
|
||||
/// Pixel cropping of the scene item before scaling.
|
||||
pub crop: Option<Crop>,
|
||||
/// The new visibility of the source. 'true' shows source, 'false' hides source.
|
||||
pub visible: Option<bool>,
|
||||
/// The new locked status of the source. 'true' keeps it in its current position, 'false' allows
|
||||
/// movement.
|
||||
pub locked: Option<bool>,
|
||||
/// Bounding box of the scene item.
|
||||
pub bounds: Option<Bounds>,
|
||||
}
|
||||
|
||||
/// Request information for
|
||||
/// [`set_scene_item_render`](crate::client::SceneItems::set_scene_item_render).
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct SceneItemRender {
|
||||
/// Name of the scene the scene item belongs to. Defaults to the currently active scene.
|
||||
pub scene_name: Option<String>,
|
||||
/// Scene Item name.
|
||||
pub source: String,
|
||||
/// true = shown ; false = hidden.
|
||||
pub render: bool,
|
||||
}
|
||||
|
||||
/// Request information for [`add_scene_item`](crate::client::SceneItems::add_scene_item).
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AddSceneItem {
|
||||
/// Name of the scene to create the scene item in.
|
||||
pub scene_name: String,
|
||||
/// Name of the source to be added.
|
||||
pub source_name: String,
|
||||
/// Whether to make the sceneitem visible on creation or not. Default `true`.
|
||||
pub set_visible: bool,
|
||||
}
|
||||
|
||||
/// Request information for
|
||||
/// [`duplicate_scene_item`](crate::client::SceneItems::duplicate_scene_item).
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DuplicateSceneItem {
|
||||
/// Name of the scene to copy the item from. Defaults to the current scene.
|
||||
pub from_scene: Option<String>,
|
||||
/// Name of the scene to create the item in. Defaults to the current scene.
|
||||
pub to_scene: Option<String>,
|
||||
/// Scene Item to duplicate from the source scene.
|
||||
pub item: SceneItemSpecification, // TODO: fields are actually not optional
|
||||
}
|
||||
|
||||
/// Request information for
|
||||
/// [`set_scene_transition_override`](crate::client::Scenes::set_scene_transition_override).
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SceneTransitionOverride {
|
||||
/// Name of the scene to switch to.
|
||||
pub scene_name: String,
|
||||
/// Name of the transition to use.
|
||||
pub transition_name: String,
|
||||
/// Duration in milliseconds of the transition if transition is not fixed. Defaults to the
|
||||
/// current duration specified in the UI if there is no current override and this value is not
|
||||
/// given.
|
||||
pub transition_duration: Option<i64>,
|
||||
}
|
||||
|
||||
/// Request information for [`set_stream_settings`](crate::client::Streaming::set_stream_settings).
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct SetStreamSettings {
|
||||
/// The type of streaming service configuration, usually `rtmp_custom` or `rtmp_common`.
|
||||
#[serde(rename = "type")]
|
||||
pub ty: String,
|
||||
/// The actual settings of the stream.
|
||||
pub settings: StreamSettings,
|
||||
/// Persist the settings to disk.
|
||||
pub save: bool,
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// Request information for
|
||||
/// [`set_text_gdi_plus_properties`](crate::client::Sources::set_text_gdi_plus_properties) as part
|
||||
/// of [`TextGdiPlusProperties`] and
|
||||
/// [`set_text_freetype2_properties`](crate::client::Sources::set_text_freetype2_properties) as part
|
||||
/// of [`TextFreetype2Properties`].
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Font {
|
||||
/// Font face.
|
||||
pub face: Option<String>,
|
||||
/// Font text styling flag. `Bold=1, Italic=2, Bold Italic=3, Underline=5, Strikeout=8`.
|
||||
pub flags: Option<u8>,
|
||||
/// Font text size.
|
||||
pub size: Option<u32>,
|
||||
/// Font Style (unknown function).
|
||||
pub style: Option<String>,
|
||||
}
|
||||
|
||||
/// Request information for
|
||||
/// [`get_scene_item_properties`](crate::client::SceneItems::get_scene_item_properties),
|
||||
/// [`set_scene_item_properties`](crate::client::SceneItems::set_scene_item_properties) as part of
|
||||
/// [`SceneItemProperties`], [`reset_scene_item`](crate::client::SceneItems::reset_scene_item),
|
||||
/// [`delete_scene_item`](crate::client::SceneItems::delete_scene_item) and
|
||||
/// [`duplicate_scene_item`](crate::client::SceneItems::duplicate_scene_item) as part of
|
||||
/// [`DuplicateSceneItem`].
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct SceneItemSpecification {
|
||||
/// Scene Item name.
|
||||
pub name: Option<String>,
|
||||
/// Scene Item ID.
|
||||
pub id: Option<i64>,
|
||||
}
|
||||
|
||||
/// Request information for
|
||||
/// [`set_scene_item_properties`](crate::client::SceneItems::set_scene_item_properties) as part of
|
||||
/// [`SceneItemProperties`].
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Position {
|
||||
/// The new x position of the source.
|
||||
pub x: Option<f64>,
|
||||
/// The new y position of the source.
|
||||
pub y: Option<f64>,
|
||||
/// The new alignment of the source.
|
||||
pub alignment: Option<u8>,
|
||||
}
|
||||
|
||||
/// Request information for
|
||||
/// [`set_scene_item_properties`](crate::client::SceneItems::set_scene_item_properties) as part of
|
||||
/// [`SceneItemProperties`].
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Scale {
|
||||
/// The new x scale of the item.
|
||||
pub x: Option<f64>,
|
||||
/// The new y scale of the item.
|
||||
pub y: Option<f64>,
|
||||
}
|
||||
|
||||
/// Request information for
|
||||
/// [`set_scene_item_properties`](crate::client::SceneItems::set_scene_item_properties) as part of
|
||||
/// [`SceneItemProperties`].
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Crop {
|
||||
/// The new amount of pixels cropped off the top of the source before scaling.
|
||||
pub top: Option<i64>,
|
||||
/// The new amount of pixels cropped off the bottom of the source before scaling.
|
||||
pub bottom: Option<i64>,
|
||||
/// The new amount of pixels cropped off the left of the source before scaling.
|
||||
pub left: Option<i64>,
|
||||
/// The new amount of pixels cropped off the right of the source before scaling.
|
||||
pub right: Option<i64>,
|
||||
}
|
||||
|
||||
/// Request information for
|
||||
/// [`set_scene_item_properties`](crate::client::SceneItems::set_scene_item_properties) as part of
|
||||
/// [`SceneItemProperties`].
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Bounds {
|
||||
/// The new bounds type of the source. Can be "OBS_BOUNDS_STRETCH", "OBS_BOUNDS_SCALE_INNER",
|
||||
/// "OBS_BOUNDS_SCALE_OUTER", "OBS_BOUNDS_SCALE_TO_WIDTH", "OBS_BOUNDS_SCALE_TO_HEIGHT",
|
||||
/// "OBS_BOUNDS_MAX_ONLY" or "OBS_BOUNDS_NONE".
|
||||
#[serde(rename = "type")]
|
||||
pub ty: Option<String>,
|
||||
/// The new alignment of the bounding box. (0-2, 4-6, 8-10).
|
||||
pub alignment: Option<u8>,
|
||||
/// The new width of the bounding box.
|
||||
pub x: Option<f64>,
|
||||
/// The new height of the bounding box.
|
||||
pub y: Option<f64>,
|
||||
}
|
||||
|
||||
/// Request information for
|
||||
/// [`reorder_scene_items`](crate::client::Scenes::reorder_scene_items) as part of
|
||||
/// [`ReorderLineItems`](RequestType::ReorderSceneItems).
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Scene {
|
||||
/// Id of a specific scene item. Unique on a scene by scene basis.
|
||||
id: Option<i64>,
|
||||
/// Name of a scene item. Sufficiently unique if no scene items share sources within the scene.
|
||||
name: Option<String>,
|
||||
}
|
||||
|
||||
/// Request information for [`start_streaming`](crate::client::Streaming::start_streaming).
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Stream {
|
||||
/// If specified ensures the type of stream matches the given type (usually 'rtmp_custom' or
|
||||
/// 'rtmp_common'). If the currently configured stream type does not match the given stream
|
||||
/// type, all settings must be specified in the `settings` object or an error will occur when
|
||||
/// starting the stream.
|
||||
#[serde(rename = "type")]
|
||||
ty: Option<String>,
|
||||
/// Adds the given object parameters as encoded query string parameters to the 'key' of the RTMP
|
||||
/// stream. Used to pass data to the RTMP service about the streaming. May be any String,
|
||||
/// Numeric, or Boolean field.
|
||||
metadata: Option<serde_json::Value>,
|
||||
/// Settings for the stream.
|
||||
settings: Option<StreamSettings>,
|
||||
}
|
||||
|
||||
/// Request information for [`start_streaming`](crate::client::Streaming::start_streaming) as part
|
||||
/// of [`Stream`] and [`set_stream_settings`](crate::client::Streaming::set_stream_settings) as part
|
||||
/// of [`SetStreamSettings`].
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct StreamSettings {
|
||||
/// The publish URL.
|
||||
server: Option<String>,
|
||||
/// The publish key of the stream.
|
||||
key: Option<String>,
|
||||
/// Indicates whether authentication should be used when connecting to the streaming server.
|
||||
use_auth: Option<bool>,
|
||||
/// If authentication is enabled, the username for the streaming server. Ignored if
|
||||
/// [`use_auth`](Self::use_auth) is not set to `true`.
|
||||
username: Option<String>,
|
||||
/// If authentication is enabled, the password for the streaming server. Ignored if
|
||||
/// [`use_auth`](Self::use_auth) is not set to `true`.
|
||||
password: Option<String>,
|
||||
}
|
||||
|
||||
/// Request information for
|
||||
/// [`transition_to_program`](crate::client::StudioMode::transition_to_program).
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Transition {
|
||||
/// Name of the transition.
|
||||
name: String,
|
||||
/// Transition duration (in milliseconds).
|
||||
duration: Option<u64>,
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
use std::iter::FromIterator;
|
||||
|
||||
use serde::de::{Deserialize, Deserializer};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn string_comma_list<'de, D, T>(deserializer: D) -> Result<T, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: FromIterator<String>,
|
||||
{
|
||||
let s = <&str>::deserialize(deserializer)?;
|
||||
|
||||
Ok(s.split(',').map(|s| s.to_owned()).collect())
|
||||
}
|
@ -0,0 +1,751 @@
|
||||
//! All responses that can be received from the API.
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::common::{Bounds, Crop, Position, Scale, SceneItem, SceneItemTransform};
|
||||
|
||||
mod de;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub(crate) struct Response<T> {
|
||||
pub message_id: String,
|
||||
pub status: Status,
|
||||
pub error: Option<String>,
|
||||
#[serde(flatten)]
|
||||
pub details: T,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub(crate) enum Status {
|
||||
Ok,
|
||||
Error,
|
||||
}
|
||||
|
||||
/// Response value for [`get_version`](crate::client::General::get_version).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct Version {
|
||||
/// OBSRemote compatible API version. Fixed to 1.1 for retrocompatibility.
|
||||
pub version: f64,
|
||||
/// obs-websocket plugin version.
|
||||
pub obs_websocket_version: String,
|
||||
/// OBS Studio program version.
|
||||
pub obs_studio_version: String,
|
||||
/// List of available request types, formatted as a comma-separated list string (e.g. :
|
||||
/// "Method1,Method2,Method3").
|
||||
pub available_requests: String,
|
||||
/// List of supported formats for features that use image export (like the
|
||||
/// [`TakeSourceScreenshot`](crate::requests::RequestType::TakeSourceScreenshot) request type)
|
||||
/// formatted as a comma-separated list string.
|
||||
pub supported_image_export_formats: String,
|
||||
}
|
||||
|
||||
/// Response value for [`get_auth_required`](crate::client::General::get_auth_required).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AuthRequired {
|
||||
/// Indicates whether authentication is required.
|
||||
pub auth_required: bool,
|
||||
/// A random string that will be used to generate the auth response.
|
||||
pub challenge: Option<String>,
|
||||
/// Applied to the password when generating the auth response.
|
||||
pub salt: Option<String>,
|
||||
}
|
||||
|
||||
/// Response value for [`get_filename_formatting`](crate::client::General::get_filename_formatting).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub(crate) struct FilenameFormatting {
|
||||
/// Current filename formatting string.
|
||||
pub filename_formatting: String,
|
||||
}
|
||||
|
||||
/// Response value for [`get_stats`](crate::client::General::get_stats).
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub(crate) struct Stats {
|
||||
/// See [`ObsStats`].
|
||||
pub stats: ObsStats,
|
||||
}
|
||||
|
||||
/// Response value for [`get_video_info`](crate::client::General::get_video_info).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct VideoInfo {
|
||||
/// Base (canvas) width.
|
||||
pub base_width: u64,
|
||||
/// Base (canvas) height.
|
||||
pub base_height: u64,
|
||||
/// Output width.
|
||||
pub output_width: u64,
|
||||
/// Output height.
|
||||
pub output_height: u64,
|
||||
/// Scaling method used if output size differs from base size.
|
||||
pub scale_type: String,
|
||||
/// Frames rendered per second.
|
||||
pub fps: f64,
|
||||
/// Video color format.
|
||||
pub video_format: String,
|
||||
/// Color space for YUV.
|
||||
pub color_space: String,
|
||||
/// Color range (full or partial).
|
||||
pub color_range: String,
|
||||
}
|
||||
|
||||
/// Response value for [`get_sources_list`](crate::client::Sources::get_sources_list).
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub(crate) struct SourcesList {
|
||||
/// Array of sources.
|
||||
pub sources: Vec<SourceListItem>,
|
||||
}
|
||||
|
||||
/// Response value for [`get_sources_types_list`](crate::client::Sources::get_sources_types_list).
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub(crate) struct SourceTypesList {
|
||||
/// Array of source types.
|
||||
pub types: Vec<SourceTypeItem>,
|
||||
}
|
||||
|
||||
/// Response value for [`get_volume`](crate::client::Sources::get_volume).
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Volume {
|
||||
/// Source name.
|
||||
pub name: String,
|
||||
/// Volume of the source. Between `0.0` and `20.0` if using mul, under `26.0` if using dB.
|
||||
pub volume: f64,
|
||||
/// Indicates whether the source is muted.
|
||||
pub muted: bool,
|
||||
}
|
||||
|
||||
/// Response value for [`get_mute`](crate::client::Sources::get_mute).
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Mute {
|
||||
/// Source name.
|
||||
pub name: String,
|
||||
/// Mute status of the source.
|
||||
pub muted: bool,
|
||||
}
|
||||
|
||||
/// Response value for [`get_audio_active`](crate::client::Sources::get_audio_active).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct AudioActive {
|
||||
/// Audio active status of the source.
|
||||
pub audio_active: bool,
|
||||
}
|
||||
|
||||
/// Response value for [`get_sync_offset`](crate::client::Sources::get_sync_offset).
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct SyncOffset {
|
||||
/// Source name.
|
||||
pub name: String,
|
||||
/// The audio sync offset (in nanoseconds).
|
||||
pub offset: i64,
|
||||
}
|
||||
|
||||
/// Response value for [`get_source_settings`](crate::client::Sources::get_source_settings) and
|
||||
/// [`set_source_settings`](crate::client::Sources::set_source_settings).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SourceSettings<T> {
|
||||
/// Source name.
|
||||
pub source_name: String,
|
||||
/// Type of the specified source.
|
||||
pub source_type: String,
|
||||
/// Source settings (varies between source types, may require some probing around).
|
||||
pub source_settings: T,
|
||||
}
|
||||
|
||||
/// Response value for
|
||||
/// [`get_text_gdi_plus_properties`](crate::client::Sources::get_text_gdi_plus_properties).
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct TextGdiPlusProperties {
|
||||
/// Source name.
|
||||
pub source: String,
|
||||
/// Text Alignment ("left", "center", "right").
|
||||
pub align: String,
|
||||
/// Background color.
|
||||
pub bk_color: u32,
|
||||
/// Background opacity (0-100).
|
||||
pub bk_opacity: u8,
|
||||
/// Chat log.
|
||||
pub chatlog: bool,
|
||||
/// Chat log lines.
|
||||
pub chatlog_lines: u64,
|
||||
/// Text color.
|
||||
pub color: u32,
|
||||
/// Extents wrap.
|
||||
pub extents: bool,
|
||||
/// Extents cx.
|
||||
pub extents_cx: i64,
|
||||
/// Extents cy.
|
||||
pub extents_cy: i64,
|
||||
/// File path name.
|
||||
pub file: String,
|
||||
/// Read text from the specified file.
|
||||
pub read_from_file: bool,
|
||||
/// Holds data for the font. Ex:
|
||||
/// `"font": { "face": "Arial", "flags": 0, "size": 150, "style": "" }`.
|
||||
pub font: Font,
|
||||
/// Gradient enabled.
|
||||
pub gradient: bool,
|
||||
/// Gradient color.
|
||||
pub gradient_color: u32,
|
||||
/// Gradient direction.
|
||||
pub gradient_dir: f32,
|
||||
/// Gradient opacity (0-100).
|
||||
pub gradient_opacity: u8,
|
||||
/// Outline.
|
||||
pub outline: bool,
|
||||
/// Outline color.
|
||||
pub outline_color: u32,
|
||||
/// Outline size.
|
||||
pub outline_size: u64,
|
||||
/// Outline opacity (0-100).
|
||||
pub outline_opacity: u8,
|
||||
/// Text content to be displayed.
|
||||
pub text: String,
|
||||
/// Text vertical alignment ("top", "center", "bottom").
|
||||
pub valign: String,
|
||||
/// Vertical text enabled.
|
||||
pub vertical: bool,
|
||||
}
|
||||
|
||||
/// Response value for
|
||||
/// [`get_text_freetype2_properties`](crate::client::Sources::get_text_freetype2_properties).
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct TextFreetype2Properties {
|
||||
/// Source name.
|
||||
pub source: String,
|
||||
/// Gradient top color.
|
||||
pub color1: u32,
|
||||
/// Gradient bottom color.
|
||||
pub color2: u32,
|
||||
/// Custom width (0 to disable).
|
||||
pub custom_width: u32,
|
||||
/// Drop shadow.
|
||||
pub drop_shadow: bool,
|
||||
/// Holds data for the font. Ex:
|
||||
/// `"font": { "face": "Arial", "flags": 0, "size": 150, "style": "" }`.
|
||||
pub font: Font,
|
||||
/// Read text from the specified file.
|
||||
pub from_file: bool,
|
||||
/// Chat log.
|
||||
pub log_mode: bool,
|
||||
/// Outline.
|
||||
pub outline: bool,
|
||||
/// Text content to be displayed.
|
||||
pub text: String,
|
||||
/// File path.
|
||||
pub text_file: String,
|
||||
/// Word wrap.
|
||||
pub word_wrap: bool,
|
||||
}
|
||||
|
||||
/// Response value for [`get_special_sources`](crate::client::Sources::get_special_sources).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct SpecialSources {
|
||||
/// Name of the first Desktop Audio capture source.
|
||||
pub desktop_1: Option<String>,
|
||||
/// Name of the second Desktop Audio capture source.
|
||||
pub desktop_2: Option<String>,
|
||||
/// Name of the first Mic/Aux input source.
|
||||
pub mic_1: Option<String>,
|
||||
/// Name of the second Mic/Aux input source.
|
||||
pub mic_2: Option<String>,
|
||||
/// Name of the third Mic/Aux input source.
|
||||
pub mic_3: Option<String>,
|
||||
}
|
||||
|
||||
/// Response value for [`get_source_filters`](crate::client::Sources::get_source_filters).
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub(crate) struct SourceFilters {
|
||||
/// List of filters for the specified source.
|
||||
pub filters: Vec<SourceFilter>,
|
||||
}
|
||||
|
||||
/// Response value for [`get_source_filter_info`](crate::client::Sources::get_source_filter_info).
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct SourceFilterInfo<T> {
|
||||
/// Filter status (enabled or not).
|
||||
pub enabled: bool,
|
||||
/// Filter type.
|
||||
#[serde(rename = "type")]
|
||||
pub ty: String,
|
||||
/// Filter name.
|
||||
pub name: String,
|
||||
/// Filter settings.
|
||||
pub settings: T,
|
||||
}
|
||||
|
||||
/// Response value for [`get_audio_monitor_type`](crate::client::Sources::get_audio_monitor_type).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct AudioMonitorType {
|
||||
/// The monitor type in use. Options: `none`, `monitorOnly`, `monitorAndOutput`.
|
||||
pub monitor_type: String,
|
||||
}
|
||||
|
||||
/// Response value for [`take_source_screenshot`](crate::client::Sources::take_source_screenshot).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SourceScreenshot {
|
||||
/// Source name.
|
||||
pub source_name: String,
|
||||
/// Image Data URI (if
|
||||
/// [`embed_picture_format`](crate::requests::SourceScreenshot::embed_picture_format) was
|
||||
/// specified in the request).
|
||||
pub img: Option<String>,
|
||||
/// Absolute path to the saved image file (if
|
||||
/// [`save_to_file_path`](crate::requests::SourceScreenshot::save_to_file_path) was specified in
|
||||
/// the request).
|
||||
pub image_file: Option<String>,
|
||||
}
|
||||
|
||||
/// Response value for [`list_outputs`](crate::client::Outputs::list_outputs).
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub(crate) struct Outputs {
|
||||
/// Outputs list.
|
||||
pub outputs: Vec<Output>,
|
||||
}
|
||||
|
||||
/// Response value for [`get_output_info`](crate::client::Outputs::get_output_info).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct OutputInfo {
|
||||
/// Output info.
|
||||
pub output_info: Output,
|
||||
}
|
||||
|
||||
/// Response value for [`get_current_profile`](crate::client::Profiles::get_current_profile).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub(crate) struct CurrentProfile {
|
||||
/// Name of the currently active profile.
|
||||
pub profile_name: String,
|
||||
}
|
||||
|
||||
/// Response value for [`list_profiles`](crate::client::Profiles::list_profiles).
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub(crate) struct Profiles {
|
||||
/// List of available profiles.
|
||||
pub profiles: Vec<Profile>,
|
||||
}
|
||||
|
||||
/// Response value for [`get_recording_folder`](crate::client::Recording::get_recording_folder).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub(crate) struct RecordingFolder {
|
||||
/// Path of the recording folder.
|
||||
pub rec_folder: String,
|
||||
}
|
||||
|
||||
/// Response value for
|
||||
/// [`get_current_scene_collection`](crate::client::SceneCollections::get_current_scene_collection).
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub(crate) struct CurrentSceneCollection {
|
||||
/// Name of the currently active scene collection.
|
||||
pub sc_name: String,
|
||||
}
|
||||
|
||||
/// Response value for
|
||||
/// [`list_scene_collections`](crate::client::SceneCollections::list_scene_collections).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub(crate) struct SceneCollections {
|
||||
/// Scene collections list.
|
||||
pub scene_collections: Vec<SceneCollection>,
|
||||
}
|
||||
|
||||
/// Response value for
|
||||
/// [`get_scene_item_properties`](crate::client::SceneItems::get_scene_item_properties).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SceneItemProperties {
|
||||
/// Scene Item name.
|
||||
pub name: String,
|
||||
/// Scene Item ID.
|
||||
pub item_id: i64,
|
||||
/// Position of the source.
|
||||
pub position: Position,
|
||||
/// The clockwise rotation of the item in degrees around the point of alignment.
|
||||
pub rotation: f64,
|
||||
/// Scaling factor of the source.
|
||||
pub scale: Scale,
|
||||
/// Pixel cropping of the source before scaling.
|
||||
pub crop: Crop,
|
||||
/// If the source is visible.
|
||||
pub visible: bool,
|
||||
/// If the source is muted.
|
||||
pub muted: bool,
|
||||
/// If the source's transform is locked.
|
||||
pub locked: bool,
|
||||
/// Bounding box of the source.
|
||||
pub bounds: Bounds,
|
||||
/// Base width (without scaling) of the source.
|
||||
pub source_width: u32,
|
||||
/// Base source (without scaling) of the source.
|
||||
pub source_height: u32,
|
||||
/// Scene item width (base source width multiplied by the horizontal scaling factor).
|
||||
pub width: f64,
|
||||
/// Scene item height (base source height multiplied by the vertical scaling factor).
|
||||
pub height: f64,
|
||||
// pub alignment: u8,
|
||||
/// Name of the item's parent (if this item belongs to a group).
|
||||
pub parent_group_name: Option<String>,
|
||||
/// List of children (if this item is a group).
|
||||
#[serde(default)]
|
||||
pub group_children: Vec<SceneItemTransform>,
|
||||
}
|
||||
|
||||
/// Response value for [`add_scene_item`](crate::client::SceneItems::add_scene_item).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct AddSceneItem {
|
||||
/// Numerical ID of the created scene item.
|
||||
pub item_id: i64,
|
||||
}
|
||||
|
||||
/// Response value for [`duplicate_scene_item`](crate::client::SceneItems::duplicate_scene_item).
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct DuplicateSceneItem {
|
||||
/// Name of the scene where the new item was created.
|
||||
pub scene: String,
|
||||
/// New item info.
|
||||
pub item: SceneItemSpecification,
|
||||
}
|
||||
|
||||
/// Response value for [`get_current_scene`](crate::client::Scenes::get_current_scene).
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct CurrentScene {
|
||||
/// Name of the currently active scene.
|
||||
pub name: String,
|
||||
/// Ordered list of the current scene's source items.
|
||||
pub sources: Vec<SceneItem>,
|
||||
}
|
||||
|
||||
/// Response value for [`get_scene_list`](crate::client::Scenes::get_scene_list).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct SceneList {
|
||||
/// Name of the currently active scene.
|
||||
pub current_scene: String,
|
||||
/// Ordered list of the current profile's scenes.
|
||||
pub scenes: Vec<Scene>,
|
||||
}
|
||||
|
||||
/// Response value for
|
||||
/// [`get_scene_transition_override`](crate::client::Scenes::get_scene_transition_override).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SceneTransitionOverride {
|
||||
/// Name of the current overriding transition. Empty string if no override is set.
|
||||
pub transition_name: String,
|
||||
/// Transition duration. `-1` if no override is set.
|
||||
pub transition_duration: i64,
|
||||
}
|
||||
|
||||
/// Response value for [`get_streaming_status`](crate::client::Streaming::get_streaming_status).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct StreamingStatus {
|
||||
/// Current streaming status.
|
||||
pub streaming: bool,
|
||||
/// Current recording status.
|
||||
pub recording: bool,
|
||||
/// Time elapsed since streaming started (only present if currently streaming).
|
||||
pub stream_timecode: Option<String>,
|
||||
/// Time elapsed since recording started (only present if currently recording).
|
||||
pub rec_timecode: Option<String>,
|
||||
/// Always false. Retrocompatibility with OBSRemote.
|
||||
#[serde(default)]
|
||||
pub preview_only: bool,
|
||||
}
|
||||
|
||||
/// Response value for [`get_stream_settings`](crate::client::Streaming::get_stream_settings).
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct GetStreamSettings {
|
||||
/// The type of streaming service configuration. Possible values: `rtmp_custom` or
|
||||
/// `rtmp_common`.
|
||||
#[serde(rename = "type")]
|
||||
pub ty: String,
|
||||
/// Stream settings object.
|
||||
pub settings: StreamSettings,
|
||||
}
|
||||
|
||||
/// Response value for
|
||||
/// [`get_studio_mode_status`](crate::client::StudioMode::get_studio_mode_status).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub(crate) struct StudioModeStatus {
|
||||
/// Indicates if Studio Mode is enabled.
|
||||
pub studio_mode: bool,
|
||||
}
|
||||
|
||||
/// Response value for [`get_preview_scene`](crate::client::StudioMode::get_preview_scene).
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct PreviewScene {
|
||||
/// The name of the active preview scene.
|
||||
pub name: String,
|
||||
/// Array of scene items of the active preview scene.
|
||||
pub sources: Vec<SceneItem>,
|
||||
}
|
||||
|
||||
/// Response value for [`get_transition_list`](crate::client::Transitions::get_transition_list).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct TransitionList {
|
||||
/// Name of the currently active transition.
|
||||
pub current_transition: String,
|
||||
/// List of transitions.
|
||||
pub transitions: Vec<Transition>,
|
||||
}
|
||||
|
||||
/// Response value for
|
||||
/// [`get_current_transition`](crate::client::Transitions::get_current_transition).
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct CurrentTransition {
|
||||
/// Name of the selected transition.
|
||||
pub name: String,
|
||||
/// Transition duration (in milliseconds) if supported by the transition.
|
||||
pub duration: Option<u64>,
|
||||
}
|
||||
|
||||
/// Response value for
|
||||
/// [`get_transition_duration`](crate::client::Transitions::get_transition_duration).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub(crate) struct TransitionDuration {
|
||||
/// Duration of the current transition (in milliseconds).
|
||||
pub transition_duration: u64,
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// Response value for [`get_stats`](crate::client::General::get_stats).
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct ObsStats {
|
||||
/// Current framerate.
|
||||
pub fps: f64,
|
||||
/// Number of frames rendered.
|
||||
pub render_total_frames: u64,
|
||||
/// Number of frames missed due to rendering lag.
|
||||
pub render_missed_frames: u64,
|
||||
/// Number of frames outputted.
|
||||
pub output_total_frames: u64,
|
||||
/// Number of frames skipped due to encoding lag.
|
||||
pub output_skipped_frames: u64,
|
||||
/// Average frame render time (in milliseconds).
|
||||
pub average_frame_time: f64,
|
||||
/// Current CPU usage (percentage).
|
||||
pub cpu_usage: f64,
|
||||
/// Current RAM usage (in megabytes).
|
||||
pub memory_usage: f64,
|
||||
/// Free recording disk space (in megabytes)
|
||||
pub free_disk_space: f64,
|
||||
}
|
||||
|
||||
/// Response value for [`get_sources_list`](crate::client::Sources::get_sources_list).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SourceListItem {
|
||||
/// Unique source name.
|
||||
pub name: String,
|
||||
/// Non-unique source internal type (a.k.a kind).
|
||||
pub type_id: String,
|
||||
/// Source type. Value is one of the following: "input", "filter", "transition", "scene" or
|
||||
/// "unknown".
|
||||
#[serde(rename = "type")]
|
||||
pub ty: String,
|
||||
}
|
||||
|
||||
/// Response value for [`get_sources_types_list`](crate::client::Sources::get_sources_types_list).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SourceTypeItem {
|
||||
/// Non-unique internal source type ID.
|
||||
pub type_id: String,
|
||||
/// Display name of the source type.
|
||||
pub display_name: String,
|
||||
/// Type. Value is one of the following: "input", "filter", "transition" or "other".
|
||||
#[serde(rename = "type")]
|
||||
pub ty: String,
|
||||
/// Default settings of this source type.
|
||||
pub default_settings: serde_json::Value,
|
||||
/// Source type capabilities.
|
||||
pub caps: Caps,
|
||||
}
|
||||
|
||||
/// Response value for [`get_sources_types_list`](crate::client::Sources::get_sources_types_list) as
|
||||
/// part of [`SourceTypeItem`].
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Caps {
|
||||
/// True if source of this type provide frames asynchronously.
|
||||
pub is_async: bool,
|
||||
/// True if sources of this type provide video.
|
||||
pub has_video: bool,
|
||||
/// True if sources of this type provide audio.
|
||||
pub has_audio: bool,
|
||||
/// True if interaction with this sources of this type is possible.
|
||||
pub can_interact: bool,
|
||||
/// True if sources of this type composite one or more sub-sources.
|
||||
pub is_composite: bool,
|
||||
/// True if sources of this type should not be fully duplicated.
|
||||
pub do_not_duplicate: bool,
|
||||
/// True if sources of this type may cause a feedback loop if it's audio is monitored and
|
||||
/// shouldn't be.
|
||||
pub do_not_self_monitor: bool,
|
||||
}
|
||||
|
||||
/// Response value for
|
||||
/// [`get_text_gdi_plus_properties`](crate::client::Sources::get_text_gdi_plus_properties) as part
|
||||
/// of [`TextGdiPlusProperties`] and
|
||||
/// [`get_text_freetype2_properties`](crate::client::Sources::get_text_freetype2_properties) as part
|
||||
/// of [`TextFreetype2Properties`].
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Font {
|
||||
/// Font face.
|
||||
pub face: String,
|
||||
/// Font text styling flag. `Bold=1, Italic=2, Bold Italic=3, Underline=5, Strikeout=8`.
|
||||
pub flags: u8,
|
||||
/// Font text size.
|
||||
pub size: u32,
|
||||
/// Font Style (unknown function).
|
||||
pub style: String,
|
||||
}
|
||||
|
||||
/// Response value for [`get_source_filters`](crate::client::Sources::get_source_filters).
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct SourceFilter {
|
||||
/// Filter status (enabled or not).
|
||||
pub enabled: bool,
|
||||
/// Filter type.
|
||||
#[serde(rename = "type")]
|
||||
pub ty: String,
|
||||
/// Filter name.
|
||||
pub name: String,
|
||||
/// Filter settings.
|
||||
pub settings: serde_json::Value,
|
||||
}
|
||||
|
||||
/// Response value for [`list_outputs`](crate::client::Outputs::list_outputs) and
|
||||
/// [`get_output_info`](crate::client::Outputs::get_output_info).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Output {
|
||||
/// Output name.
|
||||
pub name: String,
|
||||
/// Output type/kind.
|
||||
#[serde(rename = "type")]
|
||||
pub ty: String,
|
||||
/// Video output width.
|
||||
pub width: u32,
|
||||
/// Video output height.
|
||||
pub height: u32,
|
||||
/// Output flags.
|
||||
pub flags: OutputFlags,
|
||||
/// Output settings.
|
||||
pub settings: serde_json::Value,
|
||||
/// Output status (active or not).
|
||||
pub active: bool,
|
||||
/// Output reconnection status (reconnecting or not).
|
||||
pub reconnecting: bool,
|
||||
/// Output congestion.
|
||||
pub congestion: f64,
|
||||
/// Number of frames sent.
|
||||
pub total_frames: u64,
|
||||
/// Number of frames dropped.
|
||||
pub dropped_frames: u64,
|
||||
/// Total bytes sent.
|
||||
pub total_bytes: u64,
|
||||
}
|
||||
|
||||
/// Response value for [`list_outputs`](crate::client::Outputs::list_outputs) and
|
||||
/// [`get_output_info`](crate::client::Outputs::get_output_info) as part of [`Output`].
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct OutputFlags {
|
||||
/// Raw flags value.
|
||||
pub raw_value: u64,
|
||||
/// Output uses audio.
|
||||
pub audio: bool,
|
||||
/// Output uses video.
|
||||
pub video: bool,
|
||||
/// Output is encoded.
|
||||
pub encoded: bool,
|
||||
/// Output uses several audio tracks.
|
||||
pub multi_track: bool,
|
||||
/// Output uses a service.
|
||||
pub service: bool,
|
||||
}
|
||||
|
||||
/// Response value for [`list_profiles`](crate::client::Profiles::list_profiles).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct Profile {
|
||||
/// Profile name.
|
||||
pub profile_name: String,
|
||||
}
|
||||
|
||||
/// Response value for
|
||||
/// [`list_scene_collections`](crate::client::SceneCollections::list_scene_collections).
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct SceneCollection {
|
||||
/// Scene collection name.
|
||||
pub sc_name: String,
|
||||
}
|
||||
|
||||
/// Response value for [`duplicate_scene_item`](crate::client::SceneItems::duplicate_scene_item) as
|
||||
/// part of [`DuplicateSceneItem`].
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct SceneItemSpecification {
|
||||
/// New item ID.
|
||||
pub id: i64,
|
||||
/// New item name.
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
/// Response value for [`get_scene_list`](crate::client::Scenes::get_scene_list) as part of
|
||||
/// [`SceneList`].
|
||||
// TODO: actually the same as `CurrentScene`.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct Scene {
|
||||
/// Name of the scene.
|
||||
pub name: String,
|
||||
/// Ordered list of the scene's source items.
|
||||
pub sources: Vec<SceneItem>,
|
||||
}
|
||||
|
||||
/// Response value for [`get_stream_settings`](crate::client::Streaming::get_stream_settings) as
|
||||
/// part of [`GetStreamSettings`].
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct StreamSettings {
|
||||
/// The publish URL.
|
||||
pub server: String,
|
||||
/// The publish key of the stream.
|
||||
pub key: String,
|
||||
/// Indicates whether authentication should be used when connecting to the streaming server.
|
||||
pub use_auth: bool,
|
||||
/// The username to use when accessing the streaming server. Only present if
|
||||
/// [`use_auth`](Self::use_auth) is `true`.
|
||||
pub username: Option<String>,
|
||||
/// The password to use when accessing the streaming server. Only present if
|
||||
/// [`use_auth`](Self::use_auth) is `true`.
|
||||
pub password: Option<String>,
|
||||
}
|
||||
|
||||
/// Response value for [`get_transition_list`](crate::client::Transitions::get_transition_list) as
|
||||
/// part of [`TransitionList`].
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Transition {
|
||||
/// Name of the transition.
|
||||
pub name: String,
|
||||
}
|
Loading…
Reference in New Issue