realsense_rust/pipeline/
inactive.rs

1//! Type for representing an "inactive" pipeline which is unconfigured and cannot acquire frames.
2
3use super::{active::ActivePipeline, profile::PipelineProfile};
4use crate::{check_rs2_error, config::Config, context::Context, kind::Rs2Exception};
5use anyhow::Result;
6use realsense_sys as sys;
7use std::{convert::TryFrom, ptr::NonNull};
8use thiserror::Error;
9
10/// Enumeration of possible errors that can occur during pipeline construction.
11#[derive(Error, Debug)]
12pub enum PipelineConstructionError {
13    /// The pipeline could not be created from the context.
14    #[error("Could not create the pipeline from the provided context. Type: {0}; Reason {1}")]
15    CouldNotCreatePipelineFromContext(Rs2Exception, String),
16}
17
18/// Enumeration of possible errors that can occur when trying to start the pipeline.
19#[derive(Error, Debug)]
20pub enum PipelineActivationError {
21    /// The pipeline could not be started due to an internal exception.
22    #[error("Could not successfully start the pipeline. Type: {0}; Reason: {1}")]
23    CouldNotStartPipelineError(Rs2Exception, String),
24    /// The configuration cannot be resolved.
25    ///
26    /// See [`InactivePipeline::can_resolve`] for more information.
27    #[error("Config cannot be resolved by any active devices / stream combinations.")]
28    ConfigCannotBeResolved,
29}
30
31/// A type describing an "inactive" pipeline which is unconfigured and cannot acquire frames.
32#[derive(Debug)]
33pub struct InactivePipeline {
34    /// A (non-null) pointer to the pipeline.
35    pipeline_ptr: NonNull<sys::rs2_pipeline>,
36}
37
38impl Drop for InactivePipeline {
39    fn drop(&mut self) {
40        unsafe {
41            sys::rs2_delete_pipeline(self.pipeline_ptr.as_ptr());
42        }
43    }
44}
45
46unsafe impl Send for InactivePipeline {}
47
48impl TryFrom<&Context> for InactivePipeline {
49    type Error = anyhow::Error;
50
51    fn try_from(context: &Context) -> Result<Self, Self::Error> {
52        unsafe {
53            let mut err = std::ptr::null_mut::<sys::rs2_error>();
54            let context_ptr = context.get_raw();
55
56            let pipeline_ptr = sys::rs2_create_pipeline(context_ptr.as_ptr(), &mut err);
57            check_rs2_error!(
58                err,
59                PipelineConstructionError::CouldNotCreatePipelineFromContext
60            )?;
61
62            Ok(Self::new(NonNull::new(pipeline_ptr).unwrap()))
63        }
64    }
65}
66
67impl InactivePipeline {
68    /// Constructs a new inactive pipeline from the constituent components
69    ///
70    /// This is only to be used / called from the [`ActivePipeline`] type.
71    pub(crate) fn new(pipeline_ptr: NonNull<sys::rs2_pipeline>) -> Self {
72        Self { pipeline_ptr }
73    }
74
75    /// Start the pipeline with an optional config.
76    ///
77    /// The method consumes inactive pipeline itself, and returns the started pipeine.
78    pub fn start(self, config: Option<Config>) -> Result<ActivePipeline> {
79        unsafe {
80            let mut err = std::ptr::null_mut::<sys::rs2_error>();
81            let profile_ptr = if let Some(conf) = config {
82                if !self.can_resolve(&conf) {
83                    return Err(anyhow::anyhow!(
84                        PipelineActivationError::ConfigCannotBeResolved
85                    ));
86                }
87
88                sys::rs2_pipeline_start_with_config(
89                    self.pipeline_ptr.as_ptr(),
90                    conf.get_raw().as_ptr(),
91                    &mut err,
92                )
93            } else {
94                sys::rs2_pipeline_start(self.pipeline_ptr.as_ptr(), &mut err)
95            };
96            check_rs2_error!(err, PipelineActivationError::CouldNotStartPipelineError)?;
97
98            let profile = PipelineProfile::try_from(NonNull::new(profile_ptr).unwrap())?;
99            let active = ActivePipeline::new(self.pipeline_ptr, profile);
100
101            std::mem::forget(self);
102            Ok(active)
103        }
104    }
105
106    /// Resolve a configuration and get the corresponding pipeline profile.
107    ///
108    /// This function checks the pipeline to see if this config can be used to start the pipeline,
109    /// and if this configuration can be used it returns the pipeline profile (device and streams)
110    /// that will be used as the active profile when the pipeline is started. Otherwise, if this
111    /// configuration cannot resolve, this will return `None`.
112    pub fn resolve(&self, config: &Config) -> Option<PipelineProfile> {
113        if !self.can_resolve(config) {
114            return None;
115        }
116
117        unsafe {
118            let mut err = std::ptr::null_mut::<sys::rs2_error>();
119            let profile_ptr = sys::rs2_config_resolve(
120                config.get_raw().as_ptr(),
121                self.pipeline_ptr.as_ptr(),
122                &mut err,
123            );
124
125            if err.as_ref().is_none() {
126                PipelineProfile::try_from(NonNull::new(profile_ptr).unwrap()).ok()
127            } else {
128                sys::rs2_free_error(err);
129                None
130            }
131        }
132    }
133
134    /// Predicate to check if a pipeline profile exists for a given configuration.
135    ///
136    /// This predicate evaluates whether or not a configuration can be resolved to a device and set
137    /// of streams (which constitute a pipeline profile) that can be used by the pipeline to start
138    /// streaming.
139    ///
140    /// Returns true iff the configuration can be satisfied and a pipeline profile can be
141    /// constructed.
142    pub fn can_resolve(&self, config: &Config) -> bool {
143        unsafe {
144            let mut err = std::ptr::null_mut::<sys::rs2_error>();
145            let can_resolve = sys::rs2_config_can_resolve(
146                config.get_raw().as_ptr(),
147                self.pipeline_ptr.as_ptr(),
148                &mut err,
149            );
150
151            if err.as_ref().is_none() {
152                can_resolve != 0
153            } else {
154                sys::rs2_free_error(err);
155                false
156            }
157        }
158    }
159}