1extern crate libc;
7use libc::c_int;
8
9mod c;
10
11use std::ffi::{CStr, CString};
13use std::fmt::{self, Display};
14use std::ptr;
15
16#[derive(Debug)]
18pub enum Status {
19 Success = 0,
20 OutOfMemory = 1,
21 IOError = 2,
22 InvalidArgument = 3,
23 Unknown = 4,
24}
25
26pub unsafe fn sample_rate() -> usize {
28 c::pv_sample_rate() as usize
29}
30
31pub unsafe fn version() -> &'static str {
33 CStr::from_ptr(c::pv_porcupine_version()).to_str().unwrap()
34}
35
36pub unsafe fn frame_length() -> usize {
38 c::pv_porcupine_frame_length() as usize
39}
40
41pub struct Object {
42 _object: *mut c::pv_porcupine_object_t,
43}
44
45unsafe impl Send for Object {}
46
47impl Object {
48 pub unsafe fn new(
50 model_file_path: &str,
51 keyword_file_path: &str,
52 sensitivity: f32,
53 ) -> Result<Self, Status> {
54 let mut _object: *mut c::pv_porcupine_object_t = ptr::null_mut();
55 let _model_file_path = CString::new(model_file_path).unwrap().into_raw();
56 let _keyword_file_path = CString::new(keyword_file_path).unwrap().into_raw();
57
58 let status = c::pv_porcupine_init(
59 _model_file_path,
60 _keyword_file_path,
61 sensitivity,
62 &mut _object,
63 );
64 if status != 0 {
65 return Err(status.into());
66 }
67
68 Ok(Object { _object })
69 }
70
71 pub unsafe fn new_multiple_keywords(
73 model_file_path: &str,
74 keyword_file_paths: &[&str],
75 sensitivities: &[f32],
76 ) -> Result<Self, Status> {
77 let mut _object: *mut c::pv_porcupine_object_t = ptr::null_mut();
78 let _model_file_path = CString::new(model_file_path).unwrap().into_raw();
79 let _number_keywords = keyword_file_paths.len() as c_int;
80 let _keyword_file_paths: Vec<CString> = keyword_file_paths
81 .iter()
82 .map(|p| CString::new(*p).unwrap())
83 .collect();
84 let _keyword_file_paths: Vec<_> = _keyword_file_paths.iter().map(|p| p.as_ptr()).collect();
85
86 let status = c::pv_porcupine_multiple_keywords_init(
87 _model_file_path,
88 _number_keywords,
89 _keyword_file_paths.as_ptr() as *const *const i8,
90 sensitivities.as_ptr(),
91 &mut _object,
92 );
93 if status != 0 {
94 return Err(status.into());
95 }
96
97 Ok(Object { _object })
98 }
99
100 pub unsafe fn delete(&mut self) {
102 c::pv_porcupine_delete(self._object);
103 }
104
105 pub unsafe fn process(&self, pcm: &[i16]) -> Result<bool, Status> {
107 let mut detected = false;
108
109 let status = c::pv_porcupine_process(self._object, pcm.as_ptr(), &mut detected);
110 if status != 0 {
111 return Err(status.into());
112 }
113
114 Ok(detected)
115 }
116
117 pub unsafe fn process_multiple_keywords(&self, pcm: &[i16]) -> Result<isize, Status> {
119 let mut keyword_index: c_int = -1;
120
121 let status = c::pv_porcupine_multiple_keywords_process(
122 self._object,
123 pcm.as_ptr(),
124 &mut keyword_index,
125 );
126 if status != 0 {
127 return Err(status.into());
128 }
129
130 Ok(keyword_index as isize)
131 }
132}
133
134impl From<c::pv_status_t> for Status {
135 fn from(status: c::pv_status_t) -> Self {
136 match status {
137 0 => Status::Success,
138 1 => Status::OutOfMemory,
139 2 => Status::IOError,
140 3 => Status::InvalidArgument,
141 _ => Status::Unknown,
142 }
143 }
144}
145
146impl Display for Status {
147 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
148 match self {
149 Status::Success => write!(f, "Success"),
150 Status::OutOfMemory => write!(f, "Out Of Memory"),
151 Status::IOError => write!(f, "I/O Error"),
152 Status::InvalidArgument => write!(f, "Invalid Argument"),
153 _ => write!(f, "Unknown"),
154 }
155 }
156}