oww_rs/
lib.rs

1use crate::mic::converters::i16_to_f32;
2use crate::mic::mic_cpal::MicHandlerCpal;
3use crate::model::{Detection, Model, new_model};
4use hound::{SampleFormat, WavReader};
5use log::{debug, info, warn};
6use std::env;
7use std::error::Error;
8use std::fs::File;
9use std::io::BufReader;
10use std::path::{Path, PathBuf};
11use std::sync::{Arc, Mutex};
12use std::thread::sleep;
13use std::time::Duration;
14use tokio::sync::broadcast;
15use tokio_util::sync::CancellationToken;
16use tract_core::internal::{Graph, RunnableModel, TypedFact, TypedOp};
17use crate::chunk::ChunkType;
18use crate::config::UnlockConfig;
19
20pub mod config;
21pub mod info;
22mod model;
23pub mod oww;
24pub mod rms;
25pub mod save;
26mod tests;
27
28pub mod mic;
29pub mod chunk;
30
31pub const VOICE_SAMPLE_RATE: usize = 16000;
32pub const BUFFER_SECS: usize = 4;
33
34pub const RMS_BUFFER_SIZE: usize = 16; // 1 secs+ buffer size
35
36type ModelType = RunnableModel<TypedFact, Box<dyn TypedOp>, Graph<TypedFact, Box<dyn TypedOp>>>;
37
38pub struct Models {
39    pub(crate) model1: Box<dyn Model>,
40    pub(crate) model2: Box<dyn Model>,
41}
42
43impl Models {
44    pub(crate) fn new(model1: Box<dyn Model>, model2: Box<dyn Model>) -> Self {
45        Models { model1, model2 }
46    }
47    pub(crate) fn frame_length(&self) -> usize {
48        self.model1.frame_length() as usize
49    }
50
51    pub fn detect1(&mut self, data: Vec<f32>) -> Option<Detection> {
52        self.model1.detect(data)
53    }
54
55    pub fn detect2(&mut self, data: Vec<f32>) -> Option<Detection> {
56        self.model2.detect(data)
57    }
58
59    pub fn detect1_i16(&mut self, data: Vec<i16>) -> Option<Detection> {
60        self.model1.detect_i16(data)
61    }
62
63    pub fn detect2_i16(&mut self, data: Vec<i16>) -> Option<Detection> {
64        self.model2.detect_i16(data)
65    }
66}
67
68pub fn create_unlock_task_sync(
69    running: CancellationToken,
70    chunks_sender: broadcast::Sender<ChunkType>,
71) -> Result<bool, String> {
72    let running2 = running.clone();
73    let mut mic_failing = false;
74    while !running2.is_cancelled() {
75        let config = UnlockConfig::default(); // load_config(config_file_name.clone());
76        let model1 = new_model(config.clone());
77        let model2 = new_model(config.clone());
78
79        let models = match (model1, model2) {
80            (Ok(model1), Ok(model2)) => (model1, model2),
81            _ => {
82                panic!("Unable to create unlock model");
83            }
84        };
85
86        let mic_loop = MicHandlerCpal::new(
87            Arc::new(Mutex::new(Models::new(models.0, models.1))),
88            &config,
89            chunks_sender.clone(),
90        );
91
92        match mic_loop {
93            Ok(mut mic) => {
94                mic_failing = false;
95                if let Err(e) = mic.loop_now_sync(running.clone()) {
96                    warn!("Mic loop error {:?}. Reloading mic loop", e)
97                }
98                debug!("Mic loop successful");
99            }
100            Err(e) => {
101                if !mic_failing {
102                    warn!("Mic init error {:?}", e);
103                    mic_failing = true;
104                } else {
105                    debug!("Mic err loop successful {:?}", e);
106                }
107            }
108        }
109        sleep(Duration::from_secs(1));
110    }
111    Ok(false)
112}
113
114/// loads all wav file as Vec<f32> with conversion from Int format as well
115pub fn load_wav(filename: &str) -> Result<Vec<f32>, Box<dyn Error>> {
116    let based_dir = env!("CARGO_MANIFEST_DIR");
117    let path = Path::new(based_dir).join(filename);
118    info!("Reading file {:?}", &path);
119    let reader: WavReader<BufReader<File>> = hound::WavReader::open(path)?;
120
121    match reader.spec().sample_format {
122        SampleFormat::Float => match load_wav_f32(reader) {
123            Ok(d) => Ok(d),
124            Err(e) => Err(e),
125        },
126        SampleFormat::Int => load_wav_i16(reader).map(|d| d.iter().map(i16_to_f32).collect()),
127    }
128}
129
130/// loads all wav file as vec<i16>
131fn load_wav_i16(mut reader: WavReader<BufReader<File>>) -> Result<Vec<i16>, Box<dyn Error>> {
132    let mut data = vec![];
133    for s in reader.samples::<i16>() {
134        data.push(s.unwrap());
135    }
136    Ok(data)
137}
138
139/// loads all wav file as vec<f32>
140fn load_wav_f32(mut reader: WavReader<BufReader<File>>) -> Result<Vec<f32>, Box<dyn Error>> {
141    let mut data = vec![];
142    for s in reader.samples::<f32>() {
143        data.push(s.unwrap());
144    }
145    Ok(data)
146}
147
148pub fn get_exec_dir() -> PathBuf {
149    let exec_dir = match env::current_exe() {
150        Ok(exe) => match exe.parent() {
151            None => {
152                panic!("No exec directory found");
153            }
154            Some(p) => p.to_path_buf(),
155        },
156        Err(e) => {
157            panic!("No exec directory found, error {:?}", e);
158        }
159    };
160    exec_dir
161}