added scene request states
This commit is contained in:
parent
a20b3fff6c
commit
984f4d2bad
6 changed files with 194 additions and 22 deletions
16
notes.md
Normal file
16
notes.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
|
||||
|
||||
Active camera and screen scene,
|
||||
augmented scene
|
||||
|
||||
timer state
|
||||
timer length
|
||||
clicker can change scene
|
||||
time can run
|
||||
start/stop stream/recording
|
||||
|
||||
override RPC for:
|
||||
- volume up and down
|
||||
- next/prev slide
|
||||
|
||||
If I can make all the scenes dynamic, it gets rid of a lot of the states and state management, so if I can declare the types and names of scenes, and save those to config files, then that
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
use futures_util::{
|
||||
stream::{SplitSink, SplitStream},
|
||||
SinkExt, StreamExt,
|
||||
|
@ -20,7 +19,7 @@ pub struct ConnectionCoreParam {
|
|||
pub shutdown_rx: watch::Receiver<bool>,
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
#[instrument(skip(params, on_connection_oneshot))]
|
||||
pub async fn connect_to_core(
|
||||
params: ConnectionCoreParam,
|
||||
on_connection_oneshot: oneshot::Sender<mpsc::Sender<Message>>,
|
||||
|
|
100
src/external_state/mod.rs
Normal file
100
src/external_state/mod.rs
Normal file
|
@ -0,0 +1,100 @@
|
|||
mod timer;
|
||||
use obws::{requests::scenes::SceneId, responses::scenes::Scene, Client};
|
||||
use timer::Timer;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ExternalState {
|
||||
pub scene_timer: Timer,
|
||||
|
||||
pub is_recording: bool,
|
||||
pub is_streaming: bool,
|
||||
|
||||
pub scenes: Vec<SceneState>,
|
||||
}
|
||||
|
||||
|
||||
impl ExternalState {
|
||||
pub async fn update_obs(&mut self, client: &Client) {
|
||||
self.is_recording = client
|
||||
.recording()
|
||||
.status()
|
||||
.await
|
||||
.map(|res| res.active)
|
||||
.unwrap_or(false);
|
||||
|
||||
self.is_streaming = client
|
||||
.streaming()
|
||||
.status()
|
||||
.await
|
||||
.map(|res| res.active)
|
||||
.unwrap_or(false);
|
||||
|
||||
let src_scenes = client
|
||||
.scenes()
|
||||
.list()
|
||||
.await
|
||||
.unwrap_or(obws::responses::scenes::Scenes::default())
|
||||
.scenes;
|
||||
|
||||
let mut scenes = Vec::<SceneState>::with_capacity(src_scenes.len());
|
||||
for scene in src_scenes {
|
||||
scenes.push(SceneState::new(scene, &client).await);
|
||||
}
|
||||
self.scenes = scenes;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct SceneState {
|
||||
pub scene: Scene,
|
||||
pub scene_items: Vec<SceneItem>,
|
||||
}
|
||||
|
||||
impl SceneState {
|
||||
async fn new(source: Scene, client: &Client) -> Self {
|
||||
let scene_id = obws::requests::scenes::SceneId::Name(&source.name);
|
||||
let items = client.scene_items().list(scene_id).await;
|
||||
|
||||
|
||||
if let Ok(items) = items {
|
||||
let mut scene_items = Vec::<SceneItem>::with_capacity(items.len());
|
||||
for item in items {
|
||||
scene_items.push(SceneItem::new(item, scene_id, client).await);
|
||||
}
|
||||
|
||||
SceneState {
|
||||
scene: source,
|
||||
scene_items
|
||||
}
|
||||
} else {
|
||||
SceneState {
|
||||
scene: source,
|
||||
scene_items: vec![]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SceneItem {
|
||||
pub scene_item: obws::responses::scene_items::SceneItem,
|
||||
pub transform: obws::responses::scene_items::SceneItemTransform,
|
||||
}
|
||||
|
||||
impl SceneItem {
|
||||
async fn new<'a>(source: obws::responses::scene_items::SceneItem, id: SceneId<'a>, client: &Client) -> Self {
|
||||
let transform = client.scene_items().transform(id, source.id).await;
|
||||
|
||||
if let Ok(transform) = transform {
|
||||
SceneItem {
|
||||
scene_item: source,
|
||||
transform,
|
||||
}
|
||||
} else {
|
||||
SceneItem {
|
||||
scene_item: source,
|
||||
transform: obws::responses::scene_items::SceneItemTransform::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
42
src/external_state/timer.rs
Normal file
42
src/external_state/timer.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
use std::time::{Duration, Instant};
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Timer {
|
||||
timer_start: Option<Instant>,
|
||||
timer_len: Duration,
|
||||
}
|
||||
|
||||
impl Timer {
|
||||
pub fn set_len(&mut self, new_len: Duration) {
|
||||
self.timer_len = new_len;
|
||||
}
|
||||
pub fn start(&mut self) {
|
||||
self.timer_start = Some(Instant::now());
|
||||
}
|
||||
pub fn stop(&mut self) {
|
||||
self.timer_start = None;
|
||||
}
|
||||
|
||||
/// Returns true if the time_start + timer_len > Instant::now
|
||||
/// or if the timer is stopped
|
||||
pub fn is_complete(&mut self) -> bool {
|
||||
if let Some(start) = self.timer_start {
|
||||
start + self.timer_len > Instant::now()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the time left, or None if the timer is complete
|
||||
pub fn time_left(&mut self) -> Option<Duration> {
|
||||
if self.is_complete() {
|
||||
None
|
||||
} else {
|
||||
if let Some(start) = self.timer_start {
|
||||
Some((start + self.timer_len) - Instant::now())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
src/main.rs
22
src/main.rs
|
@ -1,13 +1,17 @@
|
|||
|
||||
use std::time::Duration;
|
||||
|
||||
use tokio::sync::{mpsc::{self, error::TryRecvError}, watch};
|
||||
use tokio::sync::{
|
||||
mpsc::{self, error::TryRecvError},
|
||||
watch,
|
||||
};
|
||||
use tracing::{error, info, warn};
|
||||
|
||||
mod config;
|
||||
mod core;
|
||||
mod external_state;
|
||||
mod satellite_state;
|
||||
|
||||
use external_state::ExternalState;
|
||||
use satellite_state::SatelliteState;
|
||||
|
||||
pub enum AppEvent {
|
||||
|
@ -38,6 +42,7 @@ async fn main() {
|
|||
let (tx, rx) = mpsc::channel::<AppEvent>(10);
|
||||
|
||||
let mut state = SatelliteState {
|
||||
ext_state: ExternalState::default(),
|
||||
config,
|
||||
shutdown_tx,
|
||||
shutdown_rx,
|
||||
|
@ -53,23 +58,18 @@ async fn main() {
|
|||
state.check_sockets().await;
|
||||
|
||||
match state.events_rx.try_recv() {
|
||||
Err(e) => {
|
||||
match e {
|
||||
Err(e) => match e {
|
||||
TryRecvError::Empty => {
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
},
|
||||
}
|
||||
TryRecvError::Disconnected => {
|
||||
error!("events mpsc was closed! Exiting main thread");
|
||||
break;
|
||||
}
|
||||
},
|
||||
Ok(res) => {}
|
||||
}
|
||||
}
|
||||
Ok(res) => {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// let version = client.general().version().await.unwrap();
|
||||
// info!("Connected to OBS version: {:?}", version);
|
||||
|
|
|
@ -4,9 +4,16 @@ use tokio::sync::{mpsc, oneshot, watch};
|
|||
use tokio_tungstenite::tungstenite::Message;
|
||||
use tracing::{info, instrument, warn};
|
||||
|
||||
use crate::{config::AppConfig, core::{connect_to_core, ConnectionCoreParam}, AppEvent};
|
||||
use crate::{
|
||||
config::AppConfig,
|
||||
core::{connect_to_core, ConnectionCoreParam},
|
||||
external_state::ExternalState,
|
||||
AppEvent,
|
||||
};
|
||||
|
||||
pub struct SatelliteState {
|
||||
pub ext_state: ExternalState,
|
||||
|
||||
pub config: AppConfig,
|
||||
pub obs_client: Option<Client>,
|
||||
|
||||
|
@ -22,6 +29,7 @@ pub struct SatelliteState {
|
|||
|
||||
impl SatelliteState {
|
||||
pub async fn check_sockets(&mut self) {
|
||||
|
||||
if self.obs_client.is_none() {
|
||||
self.obs_client = match Client::connect(
|
||||
self.config.obs_ip.clone(),
|
||||
|
@ -34,7 +42,11 @@ impl SatelliteState {
|
|||
info!("Failed to connect to obs: {e}");
|
||||
None
|
||||
}
|
||||
Ok(client) => Some(client),
|
||||
Ok(client) => {
|
||||
self.ext_state.update_obs(&client).await;
|
||||
info!("{:#?}", self.ext_state);
|
||||
Some(client)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,7 +67,11 @@ impl SatelliteState {
|
|||
let param = ConnectionCoreParam {
|
||||
shutdown_rx: self.shutdown_rx.clone(),
|
||||
event_loop_tx: self.events_tx.clone(),
|
||||
connection_string: format!("ws://{}:{}", self.config.core_ip, self.config.core_port.to_string()),
|
||||
connection_string: format!(
|
||||
"ws://{}:{}",
|
||||
self.config.core_ip,
|
||||
self.config.core_port.to_string()
|
||||
),
|
||||
};
|
||||
|
||||
let (tx, rx) = oneshot::channel::<mpsc::Sender<Message>>();
|
||||
|
@ -63,7 +79,6 @@ impl SatelliteState {
|
|||
self.to_core_oneshot = Some(rx);
|
||||
|
||||
tokio::spawn(connect_to_core(param, tx));
|
||||
|
||||
}
|
||||
|
||||
#[instrument(skip(obs_client, event_tx))]
|
||||
|
|
Loading…
Reference in a new issue