mirror of https://github.com/dnaka91/obws
Adjust to latest v5 changes and fix minor mistakes
parent
825315b0bf
commit
3093734a4e
@ -0,0 +1,66 @@
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
|
||||
use super::Client;
|
||||
use crate::{requests::outputs::Request, responses::outputs as responses, Error, Result};
|
||||
|
||||
/// API functions related to outputs.
|
||||
pub struct Outputs<'a> {
|
||||
pub(super) client: &'a Client,
|
||||
}
|
||||
|
||||
impl<'a> Outputs<'a> {
|
||||
/// Gets the list of available outputs.
|
||||
pub async fn list(&self) -> Result<Vec<responses::Output>> {
|
||||
self.client
|
||||
.send_message::<_, responses::OutputList>(Request::List)
|
||||
.await
|
||||
.map(|ol| ol.outputs)
|
||||
}
|
||||
|
||||
/// Gets the status of an output.
|
||||
pub async fn status(&self, name: &str) -> Result<responses::OutputStatus> {
|
||||
self.client.send_message(Request::Status { name }).await
|
||||
}
|
||||
|
||||
/// Toggles the status of an output.
|
||||
pub async fn toggle(&self, name: &str) -> Result<bool> {
|
||||
self.client
|
||||
.send_message::<_, responses::OutputActive>(Request::Toggle { name })
|
||||
.await
|
||||
.map(|oa| oa.active)
|
||||
}
|
||||
|
||||
/// Starts an output.
|
||||
pub async fn start(&self, name: &str) -> Result<()> {
|
||||
self.client.send_message(Request::Start { name }).await
|
||||
}
|
||||
|
||||
/// Stops an output.
|
||||
pub async fn stop(&self, name: &str) -> Result<()> {
|
||||
self.client.send_message(Request::Stop { name }).await
|
||||
}
|
||||
|
||||
/// Gets the settings of an output.
|
||||
pub async fn settings<T>(&self, name: &str) -> Result<T>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
self.client
|
||||
.send_message::<_, responses::OutputSettings<T>>(Request::Settings { name })
|
||||
.await
|
||||
.map(|os| os.settings)
|
||||
}
|
||||
|
||||
/// Sets the settings of an output.
|
||||
pub async fn set_settings<T>(&self, name: &str, settings: T) -> Result<()>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
self.client
|
||||
.send_message(Request::SetSettings {
|
||||
name,
|
||||
settings: serde_json::to_value(&settings).map_err(Error::SerializeCustomData)?,
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
//! Requests related to outputs.
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(tag = "requestType", content = "requestData")]
|
||||
pub(crate) enum Request<'a> {
|
||||
#[serde(rename = "GetOutputList")]
|
||||
List,
|
||||
#[serde(rename = "GetOutputStatus")]
|
||||
Status {
|
||||
/// Output name.
|
||||
#[serde(rename = "outputName")]
|
||||
name: &'a str,
|
||||
},
|
||||
#[serde(rename = "ToggleOutput")]
|
||||
Toggle {
|
||||
/// Output name.
|
||||
#[serde(rename = "outputName")]
|
||||
name: &'a str,
|
||||
},
|
||||
#[serde(rename = "StartOutput")]
|
||||
Start {
|
||||
/// Output name.
|
||||
#[serde(rename = "outputName")]
|
||||
name: &'a str,
|
||||
},
|
||||
#[serde(rename = "StopOutput")]
|
||||
Stop {
|
||||
/// Output name.
|
||||
#[serde(rename = "outputName")]
|
||||
name: &'a str,
|
||||
},
|
||||
#[serde(rename = "GetOutputSettings")]
|
||||
Settings {
|
||||
/// Output name.
|
||||
#[serde(rename = "outputName")]
|
||||
name: &'a str,
|
||||
},
|
||||
#[serde(rename = "SetOutputSettings")]
|
||||
SetSettings {
|
||||
/// Output name.
|
||||
#[serde(rename = "outputName")]
|
||||
name: &'a str,
|
||||
/// Output settings.
|
||||
#[serde(rename = "outputSettings")]
|
||||
settings: serde_json::Value,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> From<Request<'a>> for super::RequestType<'a> {
|
||||
fn from(value: Request<'a>) -> Self {
|
||||
super::RequestType::Outputs(value)
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
//! Responses related to outputs.
|
||||
|
||||
use serde::Deserialize;
|
||||
use time::Duration;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub(crate) struct OutputList {
|
||||
pub outputs: Vec<Output>,
|
||||
}
|
||||
|
||||
/// Response value for [`crate::client::Outputs::list`].
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Output {
|
||||
/// Name of this output.
|
||||
#[serde(rename = "outputName")]
|
||||
pub name: String,
|
||||
/// The kind of output.
|
||||
#[serde(rename = "outputKind")]
|
||||
pub kind: String,
|
||||
/// Horizontal dimension of the output (if it is a video output).
|
||||
#[serde(rename = "outputWidth")]
|
||||
pub width: u32,
|
||||
/// Vertical dimension of the output (if it is a video output).
|
||||
#[serde(rename = "outputHeight")]
|
||||
pub height: u32,
|
||||
/// Whether this output is currently active.
|
||||
#[serde(rename = "outputActive")]
|
||||
pub active: bool,
|
||||
/// Additional flags to describe capabilities of the output.
|
||||
#[serde(rename = "outputFlags")]
|
||||
pub flags: OutputFlags,
|
||||
}
|
||||
|
||||
/// Response value for [`crate::client::Outputs::list`] as part of [`Output`].
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct OutputFlags {
|
||||
/// Output supports audio.
|
||||
#[serde(rename = "OBS_OUTPUT_AUDIO")]
|
||||
pub audio: bool,
|
||||
/// Output supports video.
|
||||
#[serde(rename = "OBS_OUTPUT_VIDEO")]
|
||||
pub video: bool,
|
||||
/// Output encodes data.
|
||||
#[serde(rename = "OBS_OUTPUT_ENCODED")]
|
||||
pub encoded: bool,
|
||||
/// Output supports multiple audio/video tracks.
|
||||
#[serde(rename = "OBS_OUTPUT_MULTI_TRACK")]
|
||||
pub multi_track: bool,
|
||||
/// Output is a service.
|
||||
#[serde(rename = "OBS_OUTPUT_SERVICE")]
|
||||
pub service: bool,
|
||||
}
|
||||
|
||||
/// Response value for [`crate::client::Outputs::status`].
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct OutputStatus {
|
||||
/// Whether the output is active.
|
||||
#[serde(rename = "outputActive")]
|
||||
pub active: bool,
|
||||
/// Whether the output is currently reconnecting.
|
||||
#[serde(rename = "outputReconnecting")]
|
||||
pub reconnecting: bool,
|
||||
/// Current time code for the output.
|
||||
#[serde(rename = "outputTimecode", with = "crate::serde::duration_timecode")]
|
||||
pub timecode: Duration,
|
||||
/// Current duration for the output.
|
||||
#[serde(rename = "outputDuration", with = "crate::serde::duration_millis")]
|
||||
pub duration: Duration,
|
||||
/// Congestion of the output.
|
||||
#[serde(rename = "outputCongestion")]
|
||||
pub congestion: f32,
|
||||
/// Number of bytes sent by the output.
|
||||
#[serde(rename = "outputBytes")]
|
||||
pub bytes: u64,
|
||||
/// Number of frames skipped by the output's process.
|
||||
#[serde(rename = "outputSkippedFrames")]
|
||||
pub skipped_frames: u32,
|
||||
/// Total number of frames delivered by the output's process.
|
||||
#[serde(rename = "outputTotalFrames")]
|
||||
pub total_frames: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub(crate) struct OutputActive {
|
||||
/// New state of the stream output.
|
||||
#[serde(rename = "outputActive")]
|
||||
pub active: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub(crate) struct OutputSettings<T> {
|
||||
#[serde(rename = "outputSettings")]
|
||||
pub settings: T,
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
#![cfg(feature = "test-integration")]
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::Result;
|
||||
use obws::events::{Event, OutputState};
|
||||
use tokio::time;
|
||||
|
||||
use crate::{common, wait_for};
|
||||
|
||||
const OUTPUT_VIRTUALCAM: &str = "virtualcam_output";
|
||||
|
||||
#[tokio::test]
|
||||
async fn outputs() -> Result<()> {
|
||||
let client = common::new_client().await?;
|
||||
let events = client.events()?;
|
||||
let client = client.outputs();
|
||||
|
||||
tokio::pin!(events);
|
||||
|
||||
client.list().await?;
|
||||
client.status(OUTPUT_VIRTUALCAM).await?;
|
||||
|
||||
client.toggle(OUTPUT_VIRTUALCAM).await?;
|
||||
wait_for!(
|
||||
events,
|
||||
Event::VirtualcamStateChanged {
|
||||
state: OutputState::Started,
|
||||
..
|
||||
}
|
||||
);
|
||||
time::sleep(Duration::from_secs(1)).await;
|
||||
client.toggle(OUTPUT_VIRTUALCAM).await?;
|
||||
wait_for!(
|
||||
events,
|
||||
Event::VirtualcamStateChanged {
|
||||
state: OutputState::Stopped,
|
||||
..
|
||||
}
|
||||
);
|
||||
time::sleep(Duration::from_secs(1)).await;
|
||||
client.start(OUTPUT_VIRTUALCAM).await?;
|
||||
wait_for!(
|
||||
events,
|
||||
Event::VirtualcamStateChanged {
|
||||
state: OutputState::Started,
|
||||
..
|
||||
}
|
||||
);
|
||||
time::sleep(Duration::from_secs(1)).await;
|
||||
client.stop(OUTPUT_VIRTUALCAM).await?;
|
||||
wait_for!(
|
||||
events,
|
||||
Event::VirtualcamStateChanged {
|
||||
state: OutputState::Stopped,
|
||||
..
|
||||
}
|
||||
);
|
||||
time::sleep(Duration::from_secs(1)).await;
|
||||
|
||||
let settings = client
|
||||
.settings::<serde_json::Value>(OUTPUT_VIRTUALCAM)
|
||||
.await?;
|
||||
client.set_settings(OUTPUT_VIRTUALCAM, &settings).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue