Skip to main content

adamo_sys/
lib.rs

1//! Raw FFI bindings to the Adamo SDK.
2//!
3//! This crate is a thin, `unsafe` interface — prefer the safe wrappers in
4//! [`adamo`](https://docs.rs/adamo) for normal use.
5//!
6//! All declarations match the C header generated by `cbindgen` for the
7//! `adamo-c` crate (`include/adamo/adamo.h`). Keep them in sync.
8
9#![allow(non_camel_case_types)]
10#![allow(clippy::missing_safety_doc)]
11
12use std::os::raw::{c_char, c_int, c_void};
13
14pub type adamo_protocol_t = u32;
15pub const ADAMO_PROTOCOL_UDP: adamo_protocol_t = 0;
16pub const ADAMO_PROTOCOL_QUIC: adamo_protocol_t = 1;
17pub const ADAMO_PROTOCOL_TCP: adamo_protocol_t = 2;
18
19pub type adamo_regime_t = u32;
20pub const ADAMO_REGIME_STABLE: adamo_regime_t = 0;
21pub const ADAMO_REGIME_DEGRADING: adamo_regime_t = 1;
22pub const ADAMO_REGIME_VOLATILE: adamo_regime_t = 2;
23pub const ADAMO_REGIME_RECOVERING: adamo_regime_t = 3;
24
25pub type adamo_video_backend_t = i32;
26pub const ADAMO_VIDEO_BACKEND_AUTO: adamo_video_backend_t = 0;
27pub const ADAMO_VIDEO_BACKEND_GSTREAMER: adamo_video_backend_t = 1;
28pub const ADAMO_VIDEO_BACKEND_HW_PIPELINE: adamo_video_backend_t = 2;
29
30// Opaque handles. Zero-sized placeholders — callers only ever see pointers
31// to them. `PhantomData<*mut ()>` keeps them `!Send + !Sync` by default;
32// the safe wrapper re-asserts thread-safety where the C API documents it.
33#[repr(C)]
34pub struct adamo_session_t {
35    _priv: [u8; 0],
36    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
37}
38#[repr(C)]
39pub struct adamo_publisher_t {
40    _priv: [u8; 0],
41    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
42}
43#[repr(C)]
44pub struct adamo_subscriber_t {
45    _priv: [u8; 0],
46    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
47}
48#[repr(C)]
49pub struct adamo_cb_sub_t {
50    _priv: [u8; 0],
51    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
52}
53#[repr(C)]
54pub struct adamo_liveliness_token_t {
55    _priv: [u8; 0],
56    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
57}
58#[repr(C)]
59pub struct adamo_liveliness_sub_t {
60    _priv: [u8; 0],
61    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
62}
63#[repr(C)]
64pub struct adamo_state_t {
65    _priv: [u8; 0],
66    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
67}
68#[repr(C)]
69pub struct adamo_task_runner_t {
70    _priv: [u8; 0],
71    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
72}
73#[repr(C)]
74pub struct adamo_robot_t {
75    _priv: [u8; 0],
76    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
77}
78#[repr(C)]
79pub struct adamo_video_track_t {
80    _priv: [u8; 0],
81    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
82}
83
84#[repr(C)]
85pub struct adamo_sample_t {
86    pub key: *mut c_char,
87    pub payload: *mut u8,
88    pub payload_len: usize,
89    pub is_delete: i32,
90    pub timestamp_us: u64,
91}
92
93#[repr(C)]
94pub struct adamo_latency_stats_t {
95    pub regime: adamo_regime_t,
96    pub jitter_hint_ms: f32,
97    pub garch_sigma_ms: f32,
98    pub target_bitrate_kbps: u32,
99    pub loss_rate: f32,
100    pub queuing_delay_ms: f32,
101    pub timestamp_ms: u64,
102}
103
104#[repr(C)]
105#[derive(Clone, Copy)]
106pub struct adamo_video_options_t {
107    pub width: u32,
108    pub height: u32,
109    pub pixel_format: *const c_char,
110    pub codec: *const c_char,
111    pub encoder: *const c_char,
112    pub bitrate_kbps: u32,
113    pub adaptive_bitrate: i32,
114    pub min_bitrate_kbps: u32,
115    pub max_bitrate_kbps: u32,
116    pub bitrate_priority: f32,
117    pub fps: u32,
118    pub keyframe_distance: f64,
119    pub stereo: i32,
120    pub backend: adamo_video_backend_t,
121    /// Optional iceoryx2 service name to also publish every raw captured
122    /// frame to (V4L2 tracks only; null = disabled).
123    pub shm_publish: *const c_char,
124    /// Per-track video protocol (null = adamo default).
125    pub reliability: *const c_char,
126    /// Forward an already-encoded H.264/H.265 bitstream without re-encoding
127    /// (0 = off). Appended last to keep prior field offsets ABI-stable.
128    pub passthrough: i32,
129    /// Keep the robot running when this track fails (0 = required/default).
130    /// Appended last to keep prior field offsets ABI-stable.
131    pub allow_missing: i32,
132}
133
134/// Audio send options — mirrors the C ABI `adamo_audio_options_t`. Note the
135/// flag fields are `bool` (C `_Bool`) and `channels` is `u8`, matching the
136/// header cbindgen generates — unlike `adamo_video_options_t`, whose flags are
137/// `i32`.
138#[repr(C)]
139#[derive(Clone, Copy)]
140pub struct adamo_audio_options_t {
141    pub source_type: *const c_char,
142    pub device: *const c_char,
143    pub pipeline: *const c_char,
144    pub codec: *const c_char,
145    pub bitrate_kbps: u32,
146    pub sample_rate: u32,
147    pub channels: u8,
148    pub frame_ms: u32,
149    pub inband_fec: bool,
150    pub dtx: bool,
151    pub allow_missing: bool,
152}
153
154pub type adamo_sample_cb_t =
155    Option<unsafe extern "C" fn(sample: *const adamo_sample_t, user: *mut c_void)>;
156pub type adamo_liveliness_cb_t =
157    Option<unsafe extern "C" fn(key: *const c_char, alive: c_int, user: *mut c_void)>;
158
159// docs.rs builds can't link libadamo; stub the extern block out there so
160// rustdoc still succeeds.
161#[cfg(not(docsrs))]
162unsafe extern "C" {
163    pub fn adamo_last_error() -> *const c_char;
164
165    /// Category of the last error on this thread. 0 = OK, 1 = auth,
166    /// 2 = network, 3 = timeout, 4 = invalid argument, 5 = video,
167    /// 6 = internal, 7 = audio. Stable across releases.
168    pub fn adamo_last_error_code() -> core::ffi::c_int;
169    pub fn adamo_last_stream_error_code() -> *const c_char;
170    pub fn adamo_last_stream_error_stage() -> *const c_char;
171    pub fn adamo_last_stream_error_track() -> *const c_char;
172    pub fn adamo_last_stream_error_backend() -> *const c_char;
173    pub fn adamo_last_stream_error_source() -> *const c_char;
174
175    pub fn adamo_sample_free(sample: *mut adamo_sample_t);
176
177    pub fn adamo_open(api_key: *const c_char, protocol: adamo_protocol_t) -> *mut adamo_session_t;
178    pub fn adamo_open_default(api_key: *const c_char) -> *mut adamo_session_t;
179    pub fn adamo_open_mtls(
180        api_key: *const c_char,
181        protocol: adamo_protocol_t,
182    ) -> *mut adamo_session_t;
183    pub fn adamo_session_free(sess: *mut adamo_session_t);
184    pub fn adamo_session_org(sess: *const adamo_session_t) -> *const c_char;
185    pub fn adamo_session_org_len(sess: *const adamo_session_t) -> usize;
186
187    pub fn adamo_put(
188        sess: *const adamo_session_t,
189        key: *const c_char,
190        payload: *const u8,
191        payload_len: usize,
192        priority: u8,
193        express: i32,
194    ) -> i32;
195
196    pub fn adamo_publisher(
197        sess: *const adamo_session_t,
198        key: *const c_char,
199        priority: u8,
200        express: i32,
201        reliable: i32,
202    ) -> *mut adamo_publisher_t;
203    pub fn adamo_publisher_put(
204        pub_: *const adamo_publisher_t,
205        payload: *const u8,
206        payload_len: usize,
207    ) -> i32;
208    pub fn adamo_publisher_free(pub_: *mut adamo_publisher_t);
209
210    pub fn adamo_subscribe(
211        sess: *const adamo_session_t,
212        key: *const c_char,
213    ) -> *mut adamo_subscriber_t;
214    pub fn adamo_sub_recv(
215        sub: *const adamo_subscriber_t,
216        timeout_ms: u64,
217    ) -> *mut adamo_sample_t;
218    pub fn adamo_sub_try_recv(sub: *const adamo_subscriber_t) -> *mut adamo_sample_t;
219    pub fn adamo_sub_free(sub: *mut adamo_subscriber_t);
220
221    pub fn adamo_subscribe_cb(
222        sess: *const adamo_session_t,
223        key: *const c_char,
224        cb: adamo_sample_cb_t,
225        user: *mut c_void,
226    ) -> *mut adamo_cb_sub_t;
227    pub fn adamo_cb_sub_free(sub: *mut adamo_cb_sub_t);
228
229    pub fn adamo_get(
230        sess: *const adamo_session_t,
231        key: *const c_char,
232        timeout_ms: u64,
233        count_out: *mut usize,
234    ) -> *mut *mut adamo_sample_t;
235    pub fn adamo_get_replies_free(replies: *mut *mut adamo_sample_t, count: usize);
236
237    pub fn adamo_state_declare(
238        sess: *const adamo_session_t,
239        robot: *const c_char,
240    ) -> *mut adamo_state_t;
241    pub fn adamo_state_set(
242        state: *const adamo_state_t,
243        key: *const c_char,
244        payload: *const u8,
245        payload_len: usize,
246    ) -> i32;
247    pub fn adamo_state_get(
248        state: *const adamo_state_t,
249        key: *const c_char,
250        out_payload: *mut *mut u8,
251        out_len: *mut usize,
252    ) -> i32;
253    pub fn adamo_state_delete(state: *const adamo_state_t, key: *const c_char) -> i32;
254    pub fn adamo_state_bytes_free(payload: *mut u8, payload_len: usize);
255    pub fn adamo_state_free(state: *mut adamo_state_t);
256
257    pub fn adamo_task_runner_declare(
258        sess: *const adamo_session_t,
259        robot: *const c_char,
260    ) -> *mut adamo_task_runner_t;
261    pub fn adamo_task_runner_select(
262        runner: *const adamo_task_runner_t,
263        task_set_id: *const c_char,
264        name: *const c_char,
265        ids: *const *const c_char,
266        names: *const *const c_char,
267        count: usize,
268    ) -> i32;
269    pub fn adamo_task_runner_advance(runner: *const adamo_task_runner_t) -> i32;
270    pub fn adamo_task_runner_reset(runner: *const adamo_task_runner_t) -> i32;
271    pub fn adamo_task_runner_free(runner: *mut adamo_task_runner_t);
272
273    pub fn adamo_liveliness_declare(
274        sess: *const adamo_session_t,
275        token_key: *const c_char,
276    ) -> *mut adamo_liveliness_token_t;
277    pub fn adamo_liveliness_token_free(tok: *mut adamo_liveliness_token_t);
278    pub fn adamo_liveliness_get(
279        sess: *const adamo_session_t,
280        pattern: *const c_char,
281        count_out: *mut usize,
282    ) -> *mut *mut c_char;
283    pub fn adamo_liveliness_tokens_free(tokens: *mut *mut c_char, count: usize);
284    pub fn adamo_liveliness_subscribe(
285        sess: *const adamo_session_t,
286        pattern: *const c_char,
287        history: c_int,
288        cb: adamo_liveliness_cb_t,
289        user: *mut c_void,
290    ) -> *mut adamo_liveliness_sub_t;
291    pub fn adamo_liveliness_sub_free(sub: *mut adamo_liveliness_sub_t);
292
293    pub fn adamo_robot_new(
294        api_key: *const c_char,
295        name: *const c_char,
296        protocol: adamo_protocol_t,
297    ) -> *mut adamo_robot_t;
298    pub fn adamo_robot_new_default(
299        api_key: *const c_char,
300        name: *const c_char,
301    ) -> *mut adamo_robot_t;
302    pub fn adamo_video_options_default() -> adamo_video_options_t;
303    pub fn adamo_robot_video(
304        robot: *mut adamo_robot_t,
305        name: *const c_char,
306        width: u32,
307        height: u32,
308        pixel_format: *const c_char,
309        fps: u32,
310        bitrate_kbps: u32,
311        stereo: bool,
312    ) -> *mut adamo_video_track_t;
313    pub fn adamo_robot_video_with_options(
314        robot: *mut adamo_robot_t,
315        name: *const c_char,
316        width: u32,
317        height: u32,
318        pixel_format: *const c_char,
319        fps: u32,
320        bitrate_kbps: u32,
321        stereo: bool,
322        encoder: *const c_char,
323        hw_pipeline: bool,
324    ) -> *mut adamo_video_track_t;
325    pub fn adamo_robot_video_configured(
326        robot: *mut adamo_robot_t,
327        name: *const c_char,
328        opts: *const adamo_video_options_t,
329    ) -> *mut adamo_video_track_t;
330    pub fn adamo_robot_attach_video_v4l2(
331        robot: *mut adamo_robot_t,
332        name: *const c_char,
333        device: *const c_char,
334        width: u32,
335        height: u32,
336        fps: u32,
337        bitrate_kbps: u32,
338        stereo: bool,
339    ) -> i32;
340    pub fn adamo_robot_attach_video_v4l2_configured(
341        robot: *mut adamo_robot_t,
342        name: *const c_char,
343        device: *const c_char,
344        opts: *const adamo_video_options_t,
345    ) -> i32;
346    pub fn adamo_robot_attach_video_gst(
347        robot: *mut adamo_robot_t,
348        name: *const c_char,
349        pipeline: *const c_char,
350        width: u32,
351        height: u32,
352        fps: u32,
353        bitrate_kbps: u32,
354        stereo: bool,
355    ) -> i32;
356    pub fn adamo_robot_attach_video_gst_with_format(
357        robot: *mut adamo_robot_t,
358        name: *const c_char,
359        pipeline: *const c_char,
360        width: u32,
361        height: u32,
362        fps: u32,
363        bitrate_kbps: u32,
364        stereo: bool,
365        source_format: *const c_char,
366    ) -> i32;
367    pub fn adamo_robot_attach_video_gst_configured(
368        robot: *mut adamo_robot_t,
369        name: *const c_char,
370        pipeline: *const c_char,
371        opts: *const adamo_video_options_t,
372    ) -> i32;
373    pub fn adamo_robot_attach_video_shm(
374        robot: *mut adamo_robot_t,
375        name: *const c_char,
376        service: *const c_char,
377        width: u32,
378        height: u32,
379        pixel_format: *const c_char,
380        fps: u32,
381        bitrate_kbps: u32,
382        stereo: bool,
383    ) -> i32;
384    pub fn adamo_robot_attach_video_shm_configured(
385        robot: *mut adamo_robot_t,
386        name: *const c_char,
387        service: *const c_char,
388        opts: *const adamo_video_options_t,
389    ) -> i32;
390
391    // -- Audio send (source-driven). Requires libadamo built with `audio`. --
392    pub fn adamo_audio_options_default() -> adamo_audio_options_t;
393    pub fn adamo_robot_attach_audio_alsa(
394        robot: *mut adamo_robot_t,
395        name: *const c_char,
396        device: *const c_char,
397        bitrate_kbps: u32,
398        channels: u8,
399        sample_rate: u32,
400        frame_ms: u32,
401    ) -> i32;
402    pub fn adamo_robot_attach_audio_test(
403        robot: *mut adamo_robot_t,
404        name: *const c_char,
405    ) -> i32;
406    pub fn adamo_robot_attach_audio_gst(
407        robot: *mut adamo_robot_t,
408        name: *const c_char,
409        pipeline: *const c_char,
410    ) -> i32;
411    pub fn adamo_robot_attach_audio_configured(
412        robot: *mut adamo_robot_t,
413        name: *const c_char,
414        opts: *const adamo_audio_options_t,
415    ) -> i32;
416
417    pub fn adamo_video_track_send(
418        track: *mut adamo_video_track_t,
419        payload: *const u8,
420        payload_len: usize,
421    ) -> i32;
422    pub fn adamo_video_track_free(track: *mut adamo_video_track_t);
423    pub fn adamo_robot_run(robot: *mut adamo_robot_t) -> i32;
424    pub fn adamo_robot_stop(robot: *mut adamo_robot_t) -> i32;
425    pub fn adamo_robot_free(robot: *mut adamo_robot_t);
426
427    pub fn adamo_detect_encoder() -> *const c_char;
428
429    pub fn adamo_fabric_now_us() -> u64;
430    pub fn adamo_fabric_synced() -> i32;
431    pub fn adamo_relay_rtt_us(sess: *const adamo_session_t, out_us: *mut u64) -> i32;
432
433    pub fn adamo_parse_heartbeat(
434        payload: *const u8,
435        payload_len: usize,
436        out: *mut adamo_latency_stats_t,
437    ) -> i32;
438    pub fn adamo_heartbeat_topic(
439        robot: *const c_char,
440        out: *mut c_char,
441        out_cap: usize,
442    ) -> isize;
443    pub fn adamo_ping_topic(
444        robot: *const c_char,
445        out: *mut c_char,
446        out_cap: usize,
447    ) -> isize;
448    pub fn adamo_pong_topic(
449        robot: *const c_char,
450        out: *mut c_char,
451        out_cap: usize,
452    ) -> isize;
453    pub fn adamo_measure_rtt(
454        sess: *const adamo_session_t,
455        robot: *const c_char,
456        timeout_ms: u64,
457        out_us: *mut u64,
458    ) -> i32;
459}
460
461// Silence `unused_imports` if someone pulls in the crate without calling
462// anything (e.g. docs builds).
463#[doc(hidden)]
464pub const _IMPORTS: (Option<c_int>, Option<*mut c_void>) = (None, None);