Whenever I run yarn tauri dev
command in my terminal, Below are the errors I'm getting in my errors, I've pasted the errors,
[{
"resource": "/m:/Projects/screen_recorder/src-tauri/src/main.rs",
"owner": "rustc",
"code": {
"value": "Click for full compiler diagnostic",
"target": {
"$mid": 1,
"path": "/diagnostic message [0]",
"scheme": "rust-analyzer-diagnostics-view",
"query": "0",
"fragment": "file:///m%3A/Projects/screen_recorder/src-tauri/src/main.rs"
}
},
"severity": 8,
"message": "failed to resolve: could not find `__cmd__start_capture` in `screen_capture`\ncould not find `__cmd__start_capture` in `screen_capture`",
"source": "rustc",
"startLineNumber": 13,
"startColumn": 29,
"endLineNumber": 13,
"endColumn": 42
},{
"resource": "/m:/Projects/screen_recorder/src-tauri/src/main.rs",
"owner": "rustc",
"code": {
"value": "Click for full compiler diagnostic",
"target": {
"$mid": 1,
"path": "/diagnostic message [1]",
"scheme": "rust-analyzer-diagnostics-view",
"query": "1",
"fragment": "file:///m%3A/Projects/screen_recorder/src-tauri/src/main.rs"
}
},
"severity": 8,
"message": "failed to resolve: could not find `__cmd__stop_capture` in `screen_capture`\ncould not find `__cmd__stop_capture` in `screen_capture`",
"source": "rustc",
"startLineNumber": 14,
"startColumn": 29,
"endLineNumber": 14,
"endColumn": 41
},{
"resource": "/m:/Projects/screen_recorder/src-tauri/src/screen_capture.rs",
"owner": "rustc",
"code": {
"value": "Click for full compiler diagnostic",
"target": {
"$mid": 1,
"path": "/diagnostic message [4]",
"scheme": "rust-analyzer-diagnostics-view",
"query": "4",
"fragment": "file:///m%3A/Projects/screen_recorder/src-tauri/src/screen_capture.rs"
}
},
"severity": 8,
"message": "mismatched types\n expected enum `Result<screen_capture::Capture, Box<(dyn std::error::Error + Send + Sync + 'static)>>`\nfound unit type `()`",
"source": "rustc",
"startLineNumber": 77,
"startColumn": 37,
"endLineNumber": 77,
"endColumn": 62,
"relatedInformation": [
{
"startLineNumber": 77,
"startColumn": 8,
"endLineNumber": 77,
"endColumn": 11,
"message": "implicitly returns `()` as its body has no tail or `return` expression",
"resource": "/m:/Projects/screen_recorder/src-tauri/src/screen_capture.rs"
}
]
},{
"resource": "/m:/Projects/screen_recorder/src-tauri/src/screen_capture.rs",
"owner": "rustc",
"code": {
"value": "Click for full compiler diagnostic",
"target": {
"$mid": 1,
"path": "/diagnostic message [6]",
"scheme": "rust-analyzer-diagnostics-view",
"query": "6",
"fragment": "file:///m%3A/Projects/screen_recorder/src-tauri/src/screen_capture.rs"
}
},
"severity": 8,
"message": "mismatched types\n expected enum `Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>`\nfound unit type `()`",
"source": "rustc",
"startLineNumber": 81,
"startColumn": 100,
"endLineNumber": 81,
"endColumn": 123,
"relatedInformation": [
{
"startLineNumber": 81,
"startColumn": 8,
"endLineNumber": 81,
"endColumn": 24,
"message": "implicitly returns `()` as its body has no tail or `return` expression",
"resource": "/m:/Projects/screen_recorder/src-tauri/src/screen_capture.rs"
}
]
},{
"resource": "/m:/Projects/screen_recorder/src-tauri/src/screen_capture.rs",
"owner": "rustc",
"code": {
"value": "E0308",
"target": {
"$mid": 1,
"path": "/stable/error_codes/E0308.html",
"scheme": "https",
"authority": "doc.rust-lang.org"
}
},
"severity": 8,
"message": "expected Result<(), Box<dyn Error + Send + Sync, Global>>, found ()",
"source": "rust-analyzer",
"startLineNumber": 83,
"startColumn": 5,
"endLineNumber": 83,
"endColumn": 6
},{
"resource": "/m:/Projects/screen_recorder/src-tauri/src/screen_capture.rs",
"owner": "rustc",
"code": {
"value": "Click for full compiler diagnostic",
"target": {
"$mid": 1,
"path": "/diagnostic message [1]",
"scheme": "rust-analyzer-diagnostics-view",
"query": "1",
"fragment": "file:///m%3A/Projects/screen_recorder/src-tauri/src/screen_capture.rs"
}
},
"severity": 4,
"message": "unused imports: `Write`, `self`\n`#[warn(unused_imports)]` on by default",
"source": "rustc",
"startLineNumber": 2,
"startColumn": 10,
"endLineNumber": 2,
"endColumn": 14,
"relatedInformation": [
{
"startLineNumber": 2,
"startColumn": 5,
"endLineNumber": 3,
"endColumn": 5,
"message": "remove the unused imports",
"resource": "/m:/Projects/screen_recorder/src-tauri/src/screen_capture.rs"
}
],
"tags": [
1
]
},{
"resource": "/m:/Projects/screen_recorder/src-tauri/src/screen_capture.rs",
"owner": "rustc",
"code": {
"value": "Click for full compiler diagnostic",
"target": {
"$mid": 1,
"path": "/diagnostic message [3]",
"scheme": "rust-analyzer-diagnostics-view",
"query": "3",
"fragment": "file:///m%3A/Projects/screen_recorder/src-tauri/src/screen_capture.rs"
}
},
"severity": 4,
"message": "unused imports: `Write`, `self`\n`#[warn(unused_imports)]` on by default",
"source": "rustc",
"startLineNumber": 2,
"startColumn": 16,
"endLineNumber": 2,
"endColumn": 21,
"relatedInformation": [
{
"startLineNumber": 2,
"startColumn": 5,
"endLineNumber": 3,
"endColumn": 5,
"message": "remove the unused imports",
"resource": "/m:/Projects/screen_recorder/src-tauri/src/screen_capture.rs"
}
],
"tags": [
1
]
}]
I've installed below two libraries, in my Cargo.toml
file
[dependencies]
windows-capture = "1.0.65"
once_cell = "1.9.0"
From the code provided by windows-capture
Link library, I copied the code and created a new file inside src-tauri/src
called screen_capture.rs
Code inside my main.rs
file (src-tauri/src/main.rs)
#![cfg_attr(
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
)]
mod screen_capture;
use tauri::Builder;
fn main() {
Builder::default()
.invoke_handler(tauri::generate_handler![
screen_capture::start_capture,
screen_capture::stop_capture
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
Code inside screen_capture.rs
file ` (src-tauri/src/screen_capture.rs )
use std::{
io::{self, Write},
sync::{Arc, Mutex},
time::Instant,
error::Error,
};
use once_cell::sync::Lazy;
use windows_capture::{
capture::GraphicsCaptureApiHandler,
encoder::{VideoEncoder, VideoEncoderQuality, VideoEncoderType},
frame::Frame,
graphics_capture_api::InternalCaptureControl,
};
static CAPTURE_SESSION: Lazy<Arc<Mutex<Option<Capture>>>> = Lazy::new(|| Arc::new(Mutex::new(None)));
pub struct Capture {
encoder: Option<VideoEncoder>,
start: Instant,
}
impl Capture {
// Assuming a new method for initialization
pub fn new(message: String) -> Result<Self, Box<dyn Error>> {
println!("Got flag: {}", message);
let encoder = VideoEncoder::new(
VideoEncoderType::Mp4,
VideoEncoderQuality::HD1080p,
1920,
1080,
"video.mp4",
)?;
Ok(Self {
encoder: Some(encoder),
start: Instant::now(),
})
}
pub fn stop(&mut self) -> Result<(), Box<dyn Error>> {
// Placeholder for actual stop logic
if let Some(encoder) = self.encoder.take() {
encoder.finish()?;
println!("Capture stopped.");
}
Ok(())
}
}
pub fn start_capture() -> Result<(), Box<dyn Error>> {
let capture_session = CAPTURE_SESSION.clone();
let mut session = capture_session.lock().unwrap();
if session.is_none() {
let capture = Capture::new("Start Message".into())?;
*session = Some(capture);
println!("Capture started.");
} else {
println!("Capture is already running.");
}
Ok(())
}
pub fn stop_capture() -> Result<(), Box<dyn Error>> {
let capture_session = CAPTURE_SESSION.clone();
let mut session = capture_session.lock().unwrap();
if let Some(mut capture) = session.take() {
capture.stop()?;
} else {
println!("No capture is running.");
}
Ok(())
}
impl GraphicsCaptureApiHandler for Capture {
type Flags = String;
type Error = Box<dyn std::error::Error + Send + Sync>;
fn new(message: Self::Flags) -> Result<Self, Self::Error> {
// Your existing implementation...
}
fn on_frame_arrived(&mut self, frame: &mut Frame, capture_control: InternalCaptureControl,) -> Result<(), Self::Error> {
// Your existing implementation...
}
fn on_closed(&mut self) -> Result<(), Self::Error> {
println!("Capture session closed");
Ok(())
}
}
tauri.conf.json file
{
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
"build": {
"beforeBuildCommand": "npm run build",
"beforeDevCommand": "npm run dev",
"devPath": "http://localhost:3000",
"distDir": "../out",
"withGlobalTauri": true
},
"package": {
"productName": "screen_recorder",
"version": "0.1.0"
},
"tauri": {
"allowlist": {
"all": false
},
"bundle": {
"active": true,
"category": "DeveloperTool",
"copyright": "",
"deb": {
"depends": []
},
"externalBin": [],
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
],
"identifier": "com.tauri.dev",
"longDescription": "",
"macOS": {
"entitlements": null,
"exceptionDomain": "",
"frameworks": [],
"providerShortName": null,
"signingIdentity": null
},
"resources": [],
"shortDescription": "",
"targets": "all",
"windows": {
"certificateThumbprint": null,
"digestAlgorithm": "sha256",
"timestampUrl": ""
}
},
"security": {
"csp": null
},
"updater": {
"active": false
},
"windows": [
{
"fullscreen": false,
"height": 600,
"resizable": true,
"title": "Screen Recorder",
"width": 800
}
]
}
}
Below is my frontend code:
import {invoke} from "@tauri-apps/api/tauri";
export default function Home() {
const startRecording = () => {
invoke("start_capture").catch(console.error);
};
const stopRecording = () => {
invoke("stop_capture").catch(console.error);
};
return (
<div className="flex flex-col items-center justify-center h-screen">
<div>
<button onClick={startRecording}>Start Recording</button>
<button onClick={stopRecording}>Stop Recording</button>
</div>
</div>
);
};
Looks like you need to add #[tauri::command]
macro for each function you want to invoke:
#[tauri::command]
pub fn start_capture() -> Result<(), Error> {
let capture_session = CAPTURE_SESSION.clone();
let mut session = capture_session.lock().unwrap();
if session.is_none() {
let capture = Capture::new("Start Message".into())?;
*session = Some(capture);
println!("Capture started.");
} else {
println!("Capture is already running.");
}
}
#[tauri::command]
pub fn stop_capture() -> Result<(), Error> {
let capture_session = CAPTURE_SESSION.clone();
let mut session = capture_session.lock().unwrap();
if let Some(mut capture) = session.take() {
capture.stop()?;
} else {
println!("No capture is running.");
}
}
And don't forget to make sure you serialize your Errors from Capture
:
#[derive(Debug, thiserror::Error)]
enum Error {
#[error(transparent)]
Io(#[from] std::io::Error)
}
// we must manually implement serde::Serialize
impl serde::Serialize for Error {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
serializer.serialize_str(self.to_string().as_ref())
}
}
Last thing you want to do is to align your Capture and Encoder error types from dyn Error
to a serializable Error
from the above.