cvkg_render_native/
audio.rs1use std::sync::Arc;
2
3pub struct RodioAudioEngine {
11 _stream: rodio::OutputStream,
12}
13
14unsafe impl Send for RodioAudioEngine {}
18unsafe impl Sync for RodioAudioEngine {}
19
20impl RodioAudioEngine {
21 pub fn new() -> Option<Self> {
23 match rodio::OutputStreamBuilder::open_default_stream() {
24 Ok(stream) => {
25 log::info!("[Native] Audio engine initialized (rodio)");
26 Some(Self { _stream: stream })
27 }
28 Err(e) => {
29 log::warn!("[Native] Audio init failed (no sound): {}", e);
30 None
31 }
32 }
33 }
34}
35
36impl cvkg_core::AudioEngine for RodioAudioEngine {
37 fn play_sound(&self, name: &str, volume: f32) {
38 let data: &[u8] = match name {
39 "nav_tick" => cvkg_core::sounds::NAVIGATION_TICK,
40 "success_chime" => cvkg_core::sounds::SUCCESS_CHIME,
41 "warning_tone" => cvkg_core::sounds::WARNING_TONE,
42 _ => {
43 log::warn!("[Native] Unknown sound: {}", name);
44 return;
45 }
46 };
47 self.play_buffer(data, volume);
48 }
49
50 fn play_buffer(&self, data: &[u8], _volume: f32) {
51 use std::io::Cursor;
52 let cursor = Cursor::new(data.to_vec());
53 let mixer = self._stream.mixer();
54 match rodio::play(mixer, cursor) {
55 Ok(_sink) => {}
56 Err(e) => log::warn!("[Native] Audio play failed: {}", e),
57 }
58 }
59
60 fn play_spatial(&self, name: &str, _position: [f32; 3], volume: f32) {
61 self.play_sound(name, volume);
63 }
64}
65
66pub struct VisualHapticEngine {
69 last_impact: std::sync::Mutex<std::time::Instant>,
70}
71
72impl Default for VisualHapticEngine {
73 fn default() -> Self {
74 Self::new()
75 }
76}
77
78impl VisualHapticEngine {
79 pub fn new() -> Self {
80 Self {
81 last_impact: std::sync::Mutex::new(std::time::Instant::now()),
82 }
83 }
84}
85
86impl cvkg_core::HapticEngine for VisualHapticEngine {
87 fn impact(&self, intensity: cvkg_core::HapticIntensity) {
88 let _ = intensity;
89 *self.last_impact.lock().unwrap_or_else(|p| p.into_inner()) = std::time::Instant::now();
90 }
91 fn selection(&self) {
92 self.impact(cvkg_core::HapticIntensity::Light);
93 }
94 fn success(&self) {
95 self.impact(cvkg_core::HapticIntensity::Medium);
96 }
97 fn warning(&self) {
98 self.impact(cvkg_core::HapticIntensity::Medium);
99 }
100 fn error(&self) {
101 self.impact(cvkg_core::HapticIntensity::Heavy);
102 }
103 fn visual_tick(&self, _intensity: f32) {
104 *self.last_impact.lock().unwrap_or_else(|p| p.into_inner()) = std::time::Instant::now();
105 }
106}