use crabcamera::audio::list_audio_devices;
use crabcamera::headless::{
list_devices, list_formats, AudioMode, BufferPolicy, CaptureConfig, HeadlessSession,
};
use crabcamera::types::CameraFormat;
use std::fs;
use std::time::Duration;
fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::init();
println!("đĻ CrabCamera Headless Capture Example");
println!("=====================================");
println!("\nđ Discovering available cameras...");
let devices = list_devices()?;
if devices.is_empty() {
eprintln!("â No cameras found!");
return Ok(());
}
for (i, device) in devices.iter().enumerate() {
println!(" {}. {} ({})", i + 1, device.name, device.id);
}
let device = &devices[0];
println!("\nđˇ Using camera: {} ({})", device.name, device.id);
println!("\nđ¤ Available audio devices...");
match list_audio_devices() {
Ok(devices) => {
if devices.is_empty() {
println!(" â No audio devices found!");
} else {
for (i, dev) in devices.iter().enumerate() {
println!(" {}. {} ({})", i + 1, dev.name, dev.id);
}
}
}
Err(e) => {
println!(" â Error listing audio devices: {}", e);
}
}
println!("\nđ Available formats:");
let formats = list_formats(&device.id)?;
if formats.is_empty() {
eprintln!("â No formats found!");
return Ok(());
}
for (i, format) in formats.iter().enumerate() {
println!(
" {}. {}x{}@{} {}",
i + 1,
format.width,
format.height,
format.fps,
format.format_type
);
}
let format = &formats[0];
println!(
"\nđĨ Using format: {}x{}@{} {}",
format.width, format.height, format.fps, format.format_type
);
let config = CaptureConfig {
device_id: device.id.clone(),
format: CameraFormat {
width: format.width,
height: format.height,
fps: format.fps,
format_type: format.format_type.clone(),
},
buffer_policy: BufferPolicy::DropOldest { capacity: 10 },
audio_mode: AudioMode::Enabled,
audio_device_id: Some("audio_0_87a48c3e".to_string()),
};
println!("\nđ Opening headless session...");
let session = HeadlessSession::open(config)?;
println!("âļī¸ Starting capture...");
session.start()?;
println!("\nđ¸ Capturing frames...");
let mut frame_count = 0;
let start_time = std::time::Instant::now();
let mut audio_count = 0;
let mut frame_saved = false;
while frame_count < 10 && start_time.elapsed() < Duration::from_secs(10) {
match session.get_frame(Duration::from_millis(1000)) {
Ok(Some(frame)) => {
frame_count += 1;
println!(
" Frame {}: {}x{} {} seq:{} size:{} bytes",
frame_count,
frame.width,
frame.height,
frame.format,
frame.sequence,
frame.data.len()
);
if !frame_saved {
fs::write("captured_frame.raw", &frame.data)?;
println!(" đž Saved frame to captured_frame.raw");
frame_saved = true;
}
}
Ok(None) => {
println!(" Timeout waiting for frame");
}
Err(e) => {
eprintln!(" Error getting frame: {}", e);
break;
}
}
match session.get_audio_packet(Duration::from_millis(100)) {
Ok(Some(packet)) => {
audio_count += 1;
println!(
" Audio {}: {} samples seq:{} size:{} bytes channels:{}",
audio_count,
packet.data.len() / 4,
packet.sequence,
packet.data.len(),
packet.channels
);
use std::fs::OpenOptions;
use std::io::Write;
let mut file = OpenOptions::new()
.create(true)
.append(true)
.open("captured_audio.raw")?;
file.write_all(&packet.data)?;
println!(" đĩ Appended audio to captured_audio.raw");
}
Ok(None) => {
}
Err(e) => {
eprintln!(" Error getting audio: {}", e);
}
}
}
let dropped = session.dropped_frames()?;
println!(
"\nđ Captured {} frames, {} audio packets, {} dropped",
frame_count, audio_count, dropped
);
println!("âšī¸ Stopping capture...");
match session.stop(Duration::from_millis(10000)) {
Ok(()) => {}
Err(e) => {
eprintln!(
"Warning: Stop timed out, but session may still be stopping: {:?}",
e
);
}
}
println!("đ Closing session...");
session.close(Duration::from_millis(5000))?;
println!("\nâ
Headless capture example completed successfully!");
Ok(())
}