1#![allow(non_upper_case_globals)]
27#![allow(non_camel_case_types)]
28#![allow(non_snake_case)]
29#![allow(dead_code)]
30#![allow(clippy::all)]
31
32include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
33
34#[cfg(not(feature = "runtime-linking"))]
35unsafe extern "C" {
36 pub fn aic_set_sdk_wrapper_id(id: u32);
40}
41
42#[cfg(feature = "runtime-linking")]
43mod runtime_linking {
44 use super::*;
45 use libloading::Library;
46 use std::{
47 ffi::{c_char, c_float, c_uint},
48 fmt,
49 path::{Path, PathBuf},
50 sync::OnceLock,
51 };
52
53 static AIC_LIBRARY: OnceLock<LoadedLibrary> = OnceLock::new();
54
55 #[derive(Debug)]
57 pub enum DynamicLoadingError {
58 AlreadyLoaded,
60 OpenLibrary {
62 path: PathBuf,
64 source: libloading::Error,
66 },
67 LoadSymbol {
69 symbol: &'static str,
71 source: libloading::Error,
73 },
74 }
75
76 impl fmt::Display for DynamicLoadingError {
77 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78 match self {
79 Self::AlreadyLoaded => write!(f, "the AIC dynamic library is already loaded"),
80 Self::OpenLibrary { path, source } => write!(
81 f,
82 "failed to load AIC dynamic library '{}': {source}",
83 path.display()
84 ),
85 Self::LoadSymbol { symbol, source } => {
86 write!(f, "failed to load AIC symbol '{symbol}': {source}")
87 }
88 }
89 }
90 }
91
92 impl std::error::Error for DynamicLoadingError {
93 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
94 match self {
95 Self::AlreadyLoaded => None,
96 Self::OpenLibrary { source, .. } | Self::LoadSymbol { source, .. } => Some(source),
97 }
98 }
99 }
100
101 struct LoadedLibrary {
102 _library: Library,
103 symbols: Symbols,
104 }
105
106 impl LoadedLibrary {
107 unsafe fn load(path: &Path) -> Result<Self, DynamicLoadingError> {
108 let library = unsafe { Library::new(path) }.map_err(|source| {
109 DynamicLoadingError::OpenLibrary {
110 path: path.to_path_buf(),
111 source,
112 }
113 })?;
114 let symbols = unsafe { Symbols::load(&library)? };
115
116 Ok(Self {
117 _library: library,
118 symbols,
119 })
120 }
121 }
122
123 fn symbols() -> &'static Symbols {
124 &AIC_LIBRARY
125 .get_or_init(|| {
126 let name = libloading::library_filename("aic");
129 unsafe { LoadedLibrary::load(Path::new(&name)) }.unwrap_or_else(|err| {
132 panic!(
133 "{err}. Make it discoverable on the dynamic loader search path (e.g. \
134 LD_LIBRARY_PATH, rpath, or a system install), or call \
135 `aic_sdk_sys::load_library` with an explicit path before using the SDK."
136 )
137 })
138 })
139 .symbols
140 }
141
142 macro_rules! aic_symbols {
143 ($(
144 fn $name:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret:ty)?;
145 )+) => {
146 struct Symbols {
147 $(
148 $name: unsafe extern "C" fn($($arg_ty),*) $(-> $ret)?,
149 )+
150 }
151
152 impl Symbols {
153 unsafe fn load(library: &Library) -> Result<Self, DynamicLoadingError> {
154 $(
155 let $name = *unsafe {
156 library.get(concat!(stringify!($name), "\0").as_bytes())
157 }
158 .map_err(|source| DynamicLoadingError::LoadSymbol {
159 symbol: stringify!($name),
160 source,
161 })?;
162 )+
163
164 Ok(Self { $($name,)+ })
165 }
166 }
167
168 $(
169 pub unsafe fn $name($($arg: $arg_ty),*) $(-> $ret)? {
170 unsafe { (symbols().$name)($($arg),*) }
171 }
172 )+
173 };
174 }
175
176 aic_symbols! {
183 fn aic_get_sdk_version() -> *const c_char;
184 fn aic_get_compatible_model_version() -> c_uint;
185 fn aic_model_create_from_file(model: *mut *mut AicModel, file_path: *const c_char) -> AicErrorCode::Type;
186 fn aic_model_create_from_buffer(model: *mut *mut AicModel, buffer: *const u8, buffer_len: usize) -> AicErrorCode::Type;
187 fn aic_model_destroy(model: *mut AicModel);
188 fn aic_model_get_id(model: *const AicModel) -> *const c_char;
189 fn aic_model_get_optimal_sample_rate(model: *const AicModel, sample_rate: *mut c_uint) -> AicErrorCode::Type;
190 fn aic_model_get_optimal_num_frames(model: *const AicModel, sample_rate: c_uint, num_frames: *mut usize) -> AicErrorCode::Type;
191 fn aic_processor_create(processor: *mut *mut AicProcessor, model: *const AicModel, license_key: *const c_char, otel_config: *const AicOtelConfig) -> AicErrorCode::Type;
192 fn aic_processor_destroy(processor: *mut AicProcessor);
193 fn aic_processor_initialize(processor: *mut AicProcessor, sample_rate: c_uint, num_channels: u16, num_frames: usize, allow_variable_frames: bool) -> AicErrorCode::Type;
194 fn aic_processor_process_planar(processor: *mut AicProcessor, audio: *const *mut c_float, num_channels: u16, num_frames: usize) -> AicErrorCode::Type;
195 fn aic_processor_process_interleaved(processor: *mut AicProcessor, audio: *mut c_float, num_channels: u16, num_frames: usize) -> AicErrorCode::Type;
196 fn aic_processor_process_sequential(processor: *mut AicProcessor, audio: *mut c_float, num_channels: u16, num_frames: usize) -> AicErrorCode::Type;
197 fn aic_processor_context_create(context: *mut *mut AicProcessorContext, processor: *const AicProcessor) -> AicErrorCode::Type;
198 fn aic_processor_context_destroy(context: *mut AicProcessorContext);
199 fn aic_processor_context_reset(context: *const AicProcessorContext) -> AicErrorCode::Type;
200 fn aic_processor_context_set_parameter(context: *const AicProcessorContext, parameter: AicProcessorParameter::Type, value: c_float) -> AicErrorCode::Type;
201 fn aic_processor_context_get_parameter(context: *const AicProcessorContext, parameter: AicProcessorParameter::Type, value: *mut c_float) -> AicErrorCode::Type;
202 fn aic_processor_context_get_output_delay(context: *const AicProcessorContext, delay: *mut usize) -> AicErrorCode::Type;
203 fn aic_processor_context_update_bearer_token(context: *const AicProcessorContext, token: *const c_char) -> AicErrorCode::Type;
204 fn aic_vad_context_create(context: *mut *mut AicVadContext, processor: *const AicProcessor) -> AicErrorCode::Type;
205 fn aic_vad_context_destroy(context: *mut AicVadContext);
206 fn aic_vad_context_is_speech_detected(context: *const AicVadContext, value: *mut bool) -> AicErrorCode::Type;
207 fn aic_vad_context_set_parameter(context: *const AicVadContext, parameter: AicVadParameter::Type, value: c_float) -> AicErrorCode::Type;
208 fn aic_vad_context_get_parameter(context: *const AicVadContext, parameter: AicVadParameter::Type, value: *mut c_float) -> AicErrorCode::Type;
209 fn aic_set_sdk_wrapper_id(id: c_uint);
210 }
211
212 pub unsafe fn load_library<P: AsRef<Path>>(path: P) -> Result<(), DynamicLoadingError> {
228 let loaded = unsafe { LoadedLibrary::load(path.as_ref())? };
229 AIC_LIBRARY
230 .set(loaded)
231 .map_err(|_| DynamicLoadingError::AlreadyLoaded)
232 }
233
234 pub fn is_library_loaded() -> bool {
236 AIC_LIBRARY.get().is_some()
237 }
238}
239
240#[cfg(feature = "runtime-linking")]
241pub use runtime_linking::*;