making obs scene switching more coherent, but still not functional

This commit is contained in:
Chris Cochrun 2024-04-07 06:56:44 -05:00
parent c96f188c70
commit 00fcf565ef
5 changed files with 133 additions and 46 deletions

View file

@ -67,6 +67,8 @@ Once the model of OBS scenes is created, we can select a scene to add it to the
*** TODO This should be ported to slides rather than service_items. *** TODO This should be ported to slides rather than service_items.
Since sometimes in a presentation you'd possibly want different obs scenes, lets instead make these changes on the slides rather than on the service_items. That way each slide can have an associated obs scene and do some trickerydo to determine if we need to change it. Since sometimes in a presentation you'd possibly want different obs scenes, lets instead make these changes on the slides rather than on the service_items. That way each slide can have an associated obs scene and do some trickerydo to determine if we need to change it.
I need to properly update them yet, it would seem I never assigned the obs scene to the slides and then obs wouldn't have anything to change to. I'm trying to change it now.
*** TODO OBWS setting scenes *** TODO OBWS setting scenes
This has been really tricky since there is something of a bug when using =runtime.block_on()= rather than having a single cohesive tokio runtime. So, perhaps I need to figure out if I can't make a runtime that works for the whole app so that I can manage these a little better. This has been really tricky since there is something of a bug when using =runtime.block_on()= rather than having a single cohesive tokio runtime. So, perhaps I need to figure out if I can't make a runtime that works for the whole app so that I can manage these a little better.

View file

@ -314,7 +314,7 @@ Controls.Page {
editMode = false; editMode = false;
refocusPresentation(); refocusPresentation();
footerFirstText = presenting ? "Presenting..." : "Presentation Preview"; footerFirstText = presenting ? "Presenting..." : "Presentation Preview";
footerSecondText = ""; footerSecondText = ObsModel.currentProgramScene;
} }
} else { } else {
videoEditor.visible = false; videoEditor.visible = false;
@ -327,7 +327,7 @@ Controls.Page {
editMode = false; editMode = false;
refocusPresentation(); refocusPresentation();
footerFirstText = presenting ? "Presenting..." : "Presentation Preview" footerFirstText = presenting ? "Presenting..." : "Presentation Preview"
footerSecondText = ""; footerSecondText = ObsModel.currentProgramScene;
} }
} }

View file

@ -11,6 +11,7 @@ Item {
implicitHeight: Kirigami.Units.gridUnit * 6.5 implicitHeight: Kirigami.Units.gridUnit * 6.5
implicitWidth: Kirigami.Units.gridUnit * 9 implicitWidth: Kirigami.Units.gridUnit * 9
property bool showVidBG property bool showVidBG
property var rootModel: model
/* property var previewSlidesList: parent */ /* property var previewSlidesList: parent */
/* Component.onCompleted: { */ /* Component.onCompleted: { */
/* if (model.videoBackground != "") */ /* if (model.videoBackground != "") */
@ -75,14 +76,23 @@ Item {
Controls.Label { Controls.Label {
id: obsSceneLabel id: obsSceneLabel
width: previewHighlight.width anchors.top: previewHighlight.top
anchors.top: previewHighlight.bottom anchors.right: previewHighlight.right
anchors.left: previewHighlight.left
anchors.topMargin: Kirigami.Units.smallSpacing anchors.topMargin: Kirigami.Units.smallSpacing
anchors.rightMargin: Kirigami.Units.smallSpacing * 2 anchors.rightMargin: Kirigami.Units.smallSpacing
elide: Text.ElideRight /* elide: Text.ElideRight */
text: model.obsScene background: Rectangle {
font.bold: true visible: model.obsScene.length > 0
color: Qt.lighter(Kirigami.Theme.backgroundColor, 1.2)
radius: 3
}
horizontalAlignment: Text.AlignRight
text: model.obsScene.length > 0 ? "OBS Scene: " + model.obsScene : ""
font.pointSize: 8
rightPadding: 4
leftPadding: 4
color: Kirigami.Theme.highlightColor
} }
MouseArea { MouseArea {
@ -101,9 +111,9 @@ Item {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
propagateComposedEvents: true propagateComposedEvents: true
Controls.ToolTip { /* Controls.ToolTip { */
text: model.obsScene /* text: model.obsScene.length > 0 ? "OBS Scene: " + model.obsScene : "" */
} /* } */
} }
@ -119,10 +129,10 @@ Item {
Kirigami.Action { Kirigami.Action {
text: modelData text: modelData
onTriggered: { onTriggered: {
Utils.dbg("setting: " + modelData) Utils.dbg("setting: " + modelData + " on index: " + rootModel.index);
Utils.dbg(model.obsScene); Utils.dbg(rootModel.obsScene);
SlideModel.updateObsScene(modelData); SlideModel.updateObsScene(rootModel.index, modelData);
/* ObsModel.setScene(modelData); */ ObsModel.setScene(modelData);
} }
} }
onObjectAdded: obsMenu.insertAction(index, object) onObjectAdded: obsMenu.insertAction(index, object)

View file

@ -75,31 +75,33 @@ impl Obs {
} }
pub fn set_scene( pub fn set_scene(
self, &self,
scene: String, scene: String,
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
debug!("Starting function"); // debug!("Starting function");
if let Some(client) = self.client { if let Some(client) = &self.client {
debug!("Starting to set"); debug!(scene, "setting scene in obs");
let runtime =
tokio::runtime::Builder::new_current_thread()
.thread_keep_alive(Duration::from_secs(1))
.enable_all()
.build()
.unwrap();
let client = make_client(); let client = make_client();
let handle = runtime.spawn(async move { let runtime = tokio::runtime::Runtime::new()?;
debug!(scene, "working in thread"); let handle = runtime.spawn(async move {
client.scenes() debug!("in spawn: before setting");
.set_current_program_scene(&scene) let res = client.scenes().set_current_program_scene(&scene).await;
.await match res {
}); Ok(o) => debug!("in spawn: after setting: success"),
loop { Err(e) => error!(?e, "in spawn: after setting")
sleep(Duration::from_millis(100));
if handle.is_finished() {
break;
} }
} });
debug!("after spawn");
// loop {
// sleep(Duration::from_millis(100));
// if handle.is_finished() {
// break;
// }
// }
Ok(()) Ok(())
} else { } else {
Err("There is no client".to_owned())? Err("There is no client".to_owned())?
@ -180,13 +182,13 @@ impl obs_model::ObsModel {
tokio::runtime::Runtime::new().unwrap().block_on(async { tokio::runtime::Runtime::new().unwrap().block_on(async {
match Obs::new().await { match Obs::new().await {
Ok(o) => { Ok(o) => {
if let Some(scene) = &o.current_program_scene {
let scene = QString::from(scene);
self.as_mut().set_current_program_scene(scene);
}
self.as_mut().set_connected(true); self.as_mut().set_connected(true);
self.as_mut().rust_mut().obs = Some(o); self.as_mut().rust_mut().obs = Some(o);
self.as_mut().update_scenes(); self.as_mut().update_scenes();
if let Some(scene) = o.current_program_scene {
let scene = QString::from(&scene);
self.as_mut().set_current_program_scene(scene);
}
} }
Err(e) => { Err(e) => {
error!(e); error!(e);
@ -220,6 +222,11 @@ mod test {
#[test] #[test]
pub fn test_obs_setting_scene() { pub fn test_obs_setting_scene() {
assert_eq!(true, true) let runtime = tokio::runtime::Runtime::new().unwrap();
let future = Client::connect("localhost", 4455, Some(""));
let client = runtime.block_on(future).unwrap();
let scene = String::from("me");
let res = runtime.block_on(client.scenes().set_current_program_scene(&scene));
debug_assert!(res.is_ok());
} }
} }

View file

@ -47,6 +47,7 @@ mod slide_model {
VideoStartTime, VideoStartTime,
VideoEndTime, VideoEndTime,
Html, Html,
ObsScene,
} }
unsafe extern "RustQt" { unsafe extern "RustQt" {
@ -123,6 +124,13 @@ mod slide_model {
#[qinvokable] #[qinvokable]
fn activate(self: Pin<&mut SlideModel>, index: i32) -> bool; fn activate(self: Pin<&mut SlideModel>, index: i32) -> bool;
#[qinvokable]
fn update_obs_scene(
self: Pin<&mut SlideModel>,
index: i32,
obs_scene: QString,
);
} }
impl cxx_qt::Threading for SlideModel {} impl cxx_qt::Threading for SlideModel {}
@ -271,7 +279,7 @@ impl Default for Slide {
} }
} }
#[derive(Default, Debug)] #[derive(Debug)]
pub struct SlideModelRust { pub struct SlideModelRust {
id: i32, id: i32,
slides: Vec<Slide>, slides: Vec<Slide>,
@ -279,6 +287,28 @@ pub struct SlideModelRust {
count: i32, count: i32,
} }
impl Default for SlideModelRust {
fn default() -> Self {
let obs =
tokio::runtime::Runtime::new().unwrap().block_on(async {
match Obs::new().await {
Ok(o) => Some(o),
Err(e) => {
error!(e);
None
}
}
});
Self {
id: 0,
slides: Vec::new(),
obs,
count: 0,
}
}
}
impl slide_model::SlideModel { impl slide_model::SlideModel {
pub fn add_video_thumbnail( pub fn add_video_thumbnail(
mut self: Pin<&mut Self>, mut self: Pin<&mut Self>,
@ -1154,25 +1184,26 @@ impl slide_model::SlideModel {
slide.active = false; slide.active = false;
} }
let obs = self.as_mut().obs.clone();
if let Some(slide) = if let Some(slide) =
self.as_mut().rust_mut().slides.get_mut(index as usize) self.as_mut().rust_mut().slides.get_mut(index as usize)
{ {
debug!( debug!(
slide = index, slide = index,
service_item = slide.service_item_id, service_item = slide.service_item_id,
obs = slide.obs_scene.to_string(),
"This slide is activating" "This slide is activating"
); );
let obs_scene = slide.obs_scene.to_string(); let obs_scene = slide.obs_scene.to_string();
slide.active = true; slide.active = true;
self.as_mut().data_changed(tl, br, &vector_roles); self.as_mut().data_changed(tl, br, &vector_roles);
if let Some(obs) = obs { if let Some(obs) = self.as_ref().obs.clone() {
match obs.set_scene(obs_scene) { match obs.set_scene(obs_scene) {
Ok(()) => debug!("Successfully set scene"), Ok(()) => debug!("Successfully set scene"),
Err(e) => error!(e), Err(e) => error!(e),
} }
} else {
debug!("Obs isn't connected");
} }
// We use this signal generated by our signals enum to tell QML that // We use this signal generated by our signals enum to tell QML that
@ -1184,6 +1215,24 @@ impl slide_model::SlideModel {
} }
} }
pub fn update_obs_scene(
mut self: Pin<&mut Self>,
index: i32,
obs_scene: QString,
) {
let rc = self.as_ref().count() - 1;
let tl = &self.as_ref().index(0, 0, &QModelIndex::default());
let br = &self.as_ref().index(rc, 0, &QModelIndex::default());
let mut vector_roles = QVector_i32::default();
vector_roles.append(self.get_role(SlideRoles::ObsScene));
if let Some(slide) =
self.as_mut().rust_mut().slides.get_mut(index as usize)
{
slide.obs_scene = obs_scene;
self.as_mut().data_changed(tl, br, &vector_roles);
}
}
fn get_role(&self, role: SlideRoles) -> i32 { fn get_role(&self, role: SlideRoles) -> i32 {
match role { match role {
SlideRoles::Text => 1, SlideRoles::Text => 1,
@ -1193,6 +1242,8 @@ impl slide_model::SlideModel {
SlideRoles::VideoThumbnail => 15, SlideRoles::VideoThumbnail => 15,
SlideRoles::VideoStartTime => 16, SlideRoles::VideoStartTime => 16,
SlideRoles::VideoEndTime => 17, SlideRoles::VideoEndTime => 17,
SlideRoles::Html => 18,
SlideRoles::ObsScene => 19,
_ => 0, _ => 0,
} }
} }
@ -1247,6 +1298,9 @@ impl slide_model::SlideModel {
QVariant::from(&slide.video_end_time) QVariant::from(&slide.video_end_time)
} }
SlideRoles::Html => QVariant::from(&slide.html), SlideRoles::Html => QVariant::from(&slide.html),
SlideRoles::ObsScene => {
QVariant::from(&slide.obs_scene)
}
_ => QVariant::default(), _ => QVariant::default(),
}; };
} }
@ -1325,6 +1379,10 @@ impl slide_model::SlideModel {
QByteArray::from("videoEndTime"), QByteArray::from("videoEndTime"),
); );
roles.insert(SlideRoles::Html.repr, QByteArray::from("html")); roles.insert(SlideRoles::Html.repr, QByteArray::from("html"));
roles.insert(
SlideRoles::ObsScene.repr,
QByteArray::from("obsScene"),
);
roles roles
} }
@ -1334,3 +1392,13 @@ impl slide_model::SlideModel {
cnt cnt
} }
} }
#[cfg(test)]
mod test {
use super::*;
#[test]
pub fn test_obs_setting_scene() {
assert_eq!(true, true)
}
}