libobs_wrapper\data\output/replay_buffer.rs
1//! Provides functionality for working with OBS replay buffers.
2//!
3//! This module extends the ObsOutputRef to provide replay buffer capabilities.
4//! A replay buffer is a special type of output that continuously records
5//! the last N seconds of content, allowing the user to save this buffer on demand. This must be configured. More documentation soon.
6use std::{
7 ffi::c_char,
8 mem::MaybeUninit,
9 path::{Path, PathBuf},
10};
11
12use libobs::calldata_t;
13
14use crate::{
15 run_with_obs,
16 utils::{ObsError, ObsString},
17};
18
19use super::ObsOutputRef;
20
21/// Defines functionality specific to replay buffer outputs.
22///
23/// This trait provides methods for working with replay buffers in OBS,
24/// which are special outputs that continuously record content and allow
25/// on-demand saving of recent footage.
26pub trait ReplayBufferOutput {
27 /// Saves the current replay buffer content to disk.
28 ///
29 /// This method triggers the replay buffer to save its content to a file
30 /// and returns the path to the saved file.
31 ///
32 /// # Returns
33 /// * `Result<Box<Path>, ObsError>` - On success, returns the path to the saved
34 /// replay file. On failure, returns an error describing what went wrong.
35 fn save_buffer(&self) -> Result<Box<Path>, ObsError>;
36}
37
38/// Implementation of the ReplayBufferOutput trait for ObsOutputRef.
39///
40/// This implementation allows any ObsOutputRef configured as a replay buffer
41/// to save its content to disk via a simple API call.
42impl ReplayBufferOutput for ObsOutputRef {
43 /// Saves the current replay buffer content to disk.
44 ///
45 /// # Implementation Details
46 /// This method:
47 /// 1. Accesses the OBS procedure handler for the output
48 /// 2. Calls the "save" procedure to trigger saving the replay
49 /// 3. Calls the "get_last_replay" procedure to retrieve the saved file path
50 /// 4. Extracts the path string from the calldata and returns it
51 ///
52 /// # Returns
53 /// * `Ok(Box<Path>)` - The path to the saved replay file
54 /// * `Err(ObsError)` - Various errors that might occur during the saving process:
55 /// - Failure to get procedure handler
56 /// - Failure to call "save" procedure
57 /// - Failure to call "get_last_replay" procedure
58 /// - Failure to extract the path from calldata
59 fn save_buffer(&self) -> Result<Box<Path>, ObsError> {
60 let output_ptr = self.output.clone();
61
62 let path = run_with_obs!(self.runtime, (output_ptr), move || {
63 let ph = unsafe { libobs::obs_output_get_proc_handler(output_ptr) };
64 if ph.is_null() {
65 return Err(ObsError::OutputSaveBufferFailure(
66 "Failed to get proc handler.".to_string(),
67 ));
68 }
69
70 let name = ObsString::new("save");
71 let call_success = unsafe {
72 let mut calldata = MaybeUninit::<calldata_t>::zeroed();
73 libobs::proc_handler_call(ph, name.as_ptr().0, calldata.as_mut_ptr())
74 };
75
76 if !call_success {
77 return Err(ObsError::OutputSaveBufferFailure(
78 "Failed to call proc handler.".to_string(),
79 ));
80 }
81
82 let func_get = ObsString::new("get_last_replay");
83 let last_replay = unsafe {
84 let mut calldata = MaybeUninit::<calldata_t>::zeroed();
85 let success =
86 libobs::proc_handler_call(ph, func_get.as_ptr().0, calldata.as_mut_ptr());
87
88 if !success {
89 return Err(ObsError::OutputSaveBufferFailure(
90 "Failed to call get_last_replay.".to_string(),
91 ));
92 }
93
94 calldata.assume_init()
95 };
96
97 let path_get = ObsString::new("path");
98
99 let mut s = MaybeUninit::<*const c_char>::uninit();
100
101 let res = unsafe {
102 libobs::calldata_get_string(&last_replay, path_get.as_ptr().0, s.as_mut_ptr())
103 };
104 if !res {
105 return Err(ObsError::OutputSaveBufferFailure(
106 "Failed to get path from last replay.".to_string(),
107 ));
108 }
109
110 let s: *const c_char = unsafe { s.assume_init() };
111 let path = unsafe { std::ffi::CStr::from_ptr(s) }.to_str().unwrap();
112
113 Ok(PathBuf::from(path))
114 })??;
115
116 Ok(path.into_boxed_path())
117 }
118}