diff --git a/Cargo.lock b/Cargo.lock index 535c7716..e68590ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4090,11 +4090,10 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.12.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2c2416fdedca8443ae44b4527de1ea633af61d8f7169ffa6e72c5b53d24efcc" +checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838" dependencies = [ - "autocfg", "bytes", "libc", "memchr", diff --git a/Cargo.toml b/Cargo.toml index cd10e056..5da11da3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ gtk-macros = "0.3" once_cell = "1.5" serde = "1.0.130" serde_json = "1.0" -tokio = { version = "1.2", features = ["rt", "rt-multi-thread"] } +tokio = { version = "1.15", features = ["rt", "rt-multi-thread", "sync"] } url = "2.2" secret-service = "2.0" html2pango = "0.4" diff --git a/src/contrib/qr_code_scanner/camera_paintable.rs b/src/contrib/qr_code_scanner/camera_paintable.rs index e4d7c9b1..4279c68e 100644 --- a/src/contrib/qr_code_scanner/camera_paintable.rs +++ b/src/contrib/qr_code_scanner/camera_paintable.rs @@ -212,7 +212,6 @@ mod imp { pub struct CameraPaintable { pub sink: camera_sink::CameraSink, - pub detector: QrCodeDetector, pub pipeline: RefCell>, pub sender: Sender, pub image: RefCell>, @@ -227,7 +226,6 @@ mod imp { Self { pipeline: RefCell::default(), sink: camera_sink::CameraSink::new(sender.clone()), - detector: QrCodeDetector::new(sender.clone()), image: RefCell::new(None), sender, receiver, @@ -337,6 +335,7 @@ impl Default for CameraPaintable { impl CameraPaintable { pub fn set_pipewire_fd(&self, fd: F, node_id: u32) { + self.close_pipeline(); let pipewire_element = gst::ElementFactory::make("pipewiresrc", None).unwrap(); pipewire_element .set_property("fd", &fd.as_raw_fd()) @@ -350,6 +349,7 @@ impl CameraPaintable { fn init_pipeline(&self, pipewire_src: gst::Element) { let self_ = imp::CameraPaintable::from_instance(self); let pipeline = gst::Pipeline::new(None); + let detector = QrCodeDetector::new(self_.sender.clone()).upcast(); let tee = gst::ElementFactory::make("tee", None).unwrap(); let queue = gst::ElementFactory::make("queue", None).unwrap(); @@ -377,21 +377,14 @@ impl CameraPaintable { &tee, &queue, &videoconvert1, - self_.detector.upcast_ref(), + &detector, &queue2, &videoconvert2, self_.sink.upcast_ref(), ]) .unwrap(); - gst::Element::link_many(&[ - &pipewire_src, - &tee, - &queue, - &videoconvert1, - self_.detector.upcast_ref(), - ]) - .unwrap(); + gst::Element::link_many(&[&pipewire_src, &tee, &queue, &videoconvert1, &detector]).unwrap(); tee.link_pads(None, &queue2, None).unwrap(); gst::Element::link_many(&[&queue2, &videoconvert2, self_.sink.upcast_ref()]).unwrap(); diff --git a/src/contrib/qr_code_scanner/mod.rs b/src/contrib/qr_code_scanner/mod.rs index e5a646f3..3e484b5a 100644 --- a/src/contrib/qr_code_scanner/mod.rs +++ b/src/contrib/qr_code_scanner/mod.rs @@ -20,6 +20,7 @@ mod imp { use gtk::CompositeTemplate; use once_cell::sync::Lazy; use std::cell::Cell; + use tokio::sync::OnceCell; use super::*; @@ -29,8 +30,8 @@ mod imp { pub paintable: CameraPaintable, #[template_child] pub picture: TemplateChild, + pub connection: OnceCell, pub has_camera: Cell, - pub is_started: Cell, } #[glib::object_subclass] @@ -116,47 +117,51 @@ impl QrCodeScanner { glib::Object::new(&[]).expect("Failed to create a QrCodeScanner") } + async fn connection(&self) -> Result<&zbus::Connection, ashpd::Error> { + let priv_ = imp::QrCodeScanner::from_instance(self); + + Ok(priv_ + .connection + .get_or_try_init(|| zbus::Connection::session()) + .await?) + } + pub fn stop(&self) { let self_ = imp::QrCodeScanner::from_instance(self); self_.paintable.close_pipeline(); } - async fn start_internal(&self) -> bool { - let self_ = imp::QrCodeScanner::from_instance(self); - if let Ok(Some(stream_fd)) = stream().await { + pub async fn start(&self) -> bool { + let priv_ = imp::QrCodeScanner::from_instance(self); + if let Ok(stream_fd) = self.stream().await { if let Ok(node_id) = camera::pipewire_node_id(stream_fd).await { - self_.paintable.set_pipewire_fd(stream_fd, node_id); - self_.has_camera.set(true); - self.notify("has-camera"); + priv_.paintable.set_pipewire_fd(stream_fd, node_id); + self.set_has_camera(true); return true; } } - self_.has_camera.set(false); - self.notify("has-camera"); - false + + self.set_has_camera(false); + return false; } - pub async fn start(&self) -> bool { - let priv_ = imp::QrCodeScanner::from_instance(self); - let is_started = self.start_internal().await; - priv_.is_started.set(is_started); - is_started + async fn has_camera_internal(&self) -> Result { + let proxy = camera::CameraProxy::new(self.connection().await?).await?; + + proxy.is_camera_present().await + } + + async fn stream(&self) -> Result { + let proxy = camera::CameraProxy::new(self.connection().await?).await?; + + proxy.access_camera().await?; + proxy.open_pipe_wire_remote().await } fn init_has_camera(&self) { spawn!(clone!(@weak self as obj => async move { - let priv_ = imp::QrCodeScanner::from_instance(&obj); - let has_camera = if obj.start_internal().await { - if !priv_.is_started.get() { - obj.stop(); - } - true - } else { - false - }; - priv_.has_camera.set(has_camera); - obj.notify("has-camera"); + obj.set_has_camera(obj.has_camera_internal().await.unwrap_or_default()); })); } @@ -165,6 +170,17 @@ impl QrCodeScanner { priv_.has_camera.get() } + fn set_has_camera(&self, has_camera: bool) { + let priv_ = imp::QrCodeScanner::from_instance(self); + + if has_camera == self.has_camera() { + return; + } + + priv_.has_camera.set(has_camera); + self.notify("has-camera"); + } + /// Connects the prepared signals to the function f given in input pub fn connect_code_detected( &self, @@ -182,18 +198,6 @@ impl QrCodeScanner { } } -async fn stream() -> Result, ashpd::Error> { - let connection = zbus::Connection::session().await?; - let proxy = camera::CameraProxy::new(&connection).await?; - - if proxy.is_camera_present().await? { - proxy.access_camera().await?; - Ok(Some(proxy.open_pipe_wire_remote().await?)) - } else { - Ok(None) - } -} - #[derive(Clone, Debug, PartialEq, glib::GBoxed)] #[gboxed(type_name = "QrVerificationDataBoxed")] struct QrVerificationDataBoxed(QrVerificationData);