streamkit_plugin_sdk_native/types.rs
1// SPDX-FileCopyrightText: © 2025 StreamKit Contributors
2//
3// SPDX-License-Identifier: MPL-2.0
4
5//! C ABI types for native plugins
6//!
7//! These types define the stable binary interface between the host and native plugins.
8//! The layout of these structs must remain stable across versions.
9
10use std::os::raw::{c_char, c_void};
11
12/// API version number. Plugins and host check compatibility via this field.
13pub const NATIVE_PLUGIN_API_VERSION: u32 = 2;
14
15/// Opaque handle to a plugin instance
16pub type CPluginHandle = *mut c_void;
17
18/// Log level for plugin logging
19#[repr(C)]
20#[derive(Debug, Copy, Clone, PartialEq, Eq)]
21pub enum CLogLevel {
22 Trace = 0,
23 Debug = 1,
24 Info = 2,
25 Warn = 3,
26 Error = 4,
27}
28
29/// Callback function type for plugin logging
30/// Parameters: (level, target, message, user_data)
31/// - level: The log level
32/// - target: Module path (e.g., "kokoro_plugin_native::kokoro_node")
33/// - message: The log message
34/// - user_data: Opaque pointer passed by host
35pub type CLogCallback = extern "C" fn(CLogLevel, *const c_char, *const c_char, *mut c_void);
36
37/// Result type for C ABI functions
38#[repr(C)]
39#[derive(Debug, Copy, Clone)]
40pub struct CResult {
41 pub success: bool,
42 /// Optional null-terminated error message.
43 ///
44 /// # Ownership
45 ///
46 /// This pointer is **borrowed** and must not be freed by the caller.
47 /// Callers should copy it immediately if they need to keep it.
48 pub error_message: *const c_char,
49}
50
51impl CResult {
52 pub const fn success() -> Self {
53 Self { success: true, error_message: std::ptr::null() }
54 }
55
56 pub const fn error(msg: *const c_char) -> Self {
57 Self { success: false, error_message: msg }
58 }
59}
60
61/// Audio sample format
62#[repr(C)]
63#[derive(Debug, Copy, Clone, PartialEq, Eq)]
64pub enum CSampleFormat {
65 F32 = 0,
66 S16Le = 1,
67}
68
69/// Audio format specification
70#[repr(C)]
71#[derive(Debug, Copy, Clone)]
72pub struct CAudioFormat {
73 pub sample_rate: u32,
74 pub channels: u16,
75 pub sample_format: CSampleFormat,
76}
77
78/// Packet type discriminant
79#[repr(C)]
80#[derive(Debug, Copy, Clone, PartialEq, Eq)]
81pub enum CPacketType {
82 RawAudio = 0,
83 OpusAudio = 1,
84 Text = 2,
85 Transcription = 3,
86 Custom = 4,
87 Binary = 5,
88 Any = 6,
89 Passthrough = 7,
90}
91
92/// Encoding for Custom packets.
93#[repr(C)]
94#[derive(Debug, Copy, Clone, PartialEq, Eq)]
95pub enum CCustomEncoding {
96 Json = 0,
97}
98
99/// Optional timing and sequencing metadata for packets.
100#[repr(C)]
101#[derive(Debug, Copy, Clone, Default)]
102pub struct CPacketMetadata {
103 pub timestamp_us: u64,
104 pub has_timestamp_us: bool,
105 pub duration_us: u64,
106 pub has_duration_us: bool,
107 pub sequence: u64,
108 pub has_sequence: bool,
109}
110
111/// Custom packet payload passed across the C ABI boundary.
112///
113/// `data_json` points to UTF-8 encoded JSON (not null-terminated).
114#[repr(C)]
115pub struct CCustomPacket {
116 pub type_id: *const c_char,
117 pub encoding: CCustomEncoding,
118 pub data_json: *const u8,
119 pub data_len: usize,
120 /// Optional metadata pointer (may be null).
121 pub metadata: *const CPacketMetadata,
122}
123
124/// Full packet type with optional format information
125/// For RawAudio, includes the audio format details
126#[repr(C)]
127#[derive(Debug, Copy, Clone)]
128pub struct CPacketTypeInfo {
129 pub type_discriminant: CPacketType,
130 /// For RawAudio: pointer to CAudioFormat, otherwise null
131 pub audio_format: *const CAudioFormat,
132 /// For Custom: pointer to a null-terminated type id string, otherwise null
133 pub custom_type_id: *const c_char,
134}
135
136/// Audio frame data (for RawAudio packets)
137#[repr(C)]
138pub struct CAudioFrame {
139 pub sample_rate: u32,
140 pub channels: u16,
141 pub samples: *const f32,
142 pub sample_count: usize,
143}
144
145/// Generic packet container
146/// The data field interpretation depends on packet_type
147#[repr(C)]
148pub struct CPacket {
149 pub packet_type: CPacketType,
150 pub data: *const c_void,
151 pub len: usize,
152}
153
154/// Input pin definition
155#[repr(C)]
156pub struct CInputPin {
157 pub name: *const c_char,
158 /// Array of accepted packet types with format info
159 pub accepts_types: *const CPacketTypeInfo,
160 pub accepts_types_count: usize,
161}
162
163/// Output pin definition
164#[repr(C)]
165pub struct COutputPin {
166 pub name: *const c_char,
167 pub produces_type: CPacketTypeInfo,
168}
169
170/// Node metadata returned by plugin
171#[repr(C)]
172pub struct CNodeMetadata {
173 pub kind: *const c_char,
174 /// Optional description of the node (null-terminated string, can be null)
175 pub description: *const c_char,
176 pub inputs: *const CInputPin,
177 pub inputs_count: usize,
178 pub outputs: *const COutputPin,
179 pub outputs_count: usize,
180 /// JSON schema for parameters (null-terminated string)
181 pub param_schema: *const c_char,
182 /// Array of category strings
183 pub categories: *const *const c_char,
184 pub categories_count: usize,
185}
186
187/// Callback function type for sending output packets
188/// Parameters: (pin_name, packet, user_data) -> CResult
189pub type COutputCallback = extern "C" fn(*const c_char, *const CPacket, *mut c_void) -> CResult;
190
191/// Callback function type for emitting telemetry events to the host.
192///
193/// Parameters:
194/// - `event_type`: null-terminated UTF-8 string (e.g., "vad.speech_start")
195/// - `data_json`: UTF-8 JSON bytes (not null-terminated)
196/// - `data_len`: length of `data_json`
197/// - `metadata`: optional packet-style metadata (may be null)
198/// - `user_data`: opaque pointer provided by the host
199pub type CTelemetryCallback = Option<
200 extern "C" fn(*const c_char, *const u8, usize, *const CPacketMetadata, *mut c_void) -> CResult,
201>;
202
203/// The main plugin API structure
204/// Plugins export a function that returns a pointer to this struct
205#[repr(C)]
206pub struct CNativePluginAPI {
207 /// API version for compatibility checking
208 pub version: u32,
209
210 /// Get metadata about the node type
211 /// Returns: Pointer to CNodeMetadata (must remain valid for plugin lifetime)
212 pub get_metadata: extern "C" fn() -> *const CNodeMetadata,
213
214 /// Create a new plugin instance
215 /// params: JSON string with initialization parameters (nullable)
216 /// log_callback: Callback for plugin to send log messages to host
217 /// log_user_data: Opaque pointer to pass to log callback
218 /// Returns: Opaque handle to the instance, or null on error
219 pub create_instance: extern "C" fn(*const c_char, CLogCallback, *mut c_void) -> CPluginHandle,
220
221 /// Process an incoming packet
222 /// handle: Plugin instance handle
223 /// input_pin: Name of the input pin
224 /// packet: The packet to process
225 /// output_callback: Callback to send output packets
226 /// callback_data: User data to pass to output callback
227 /// telemetry_callback: Callback to emit telemetry events
228 /// telemetry_user_data: User data to pass to telemetry callback
229 pub process_packet: extern "C" fn(
230 CPluginHandle,
231 *const c_char,
232 *const CPacket,
233 COutputCallback,
234 *mut c_void,
235 CTelemetryCallback,
236 *mut c_void,
237 ) -> CResult,
238
239 /// Update runtime parameters
240 /// handle: Plugin instance handle
241 /// params: JSON string with new parameters (nullable)
242 pub update_params: extern "C" fn(CPluginHandle, *const c_char) -> CResult,
243
244 /// Flush any buffered data (called when input stream ends)
245 /// handle: Plugin instance handle
246 /// output_callback: Callback to send output packets
247 /// callback_data: User data to pass to output callback
248 /// telemetry_callback: Callback to emit telemetry events
249 /// telemetry_user_data: User data to pass to telemetry callback
250 pub flush: extern "C" fn(
251 CPluginHandle,
252 COutputCallback,
253 *mut c_void,
254 CTelemetryCallback,
255 *mut c_void,
256 ) -> CResult,
257
258 /// Destroy a plugin instance
259 /// handle: Plugin instance handle
260 pub destroy_instance: extern "C" fn(CPluginHandle),
261}
262
263/// Symbol name that plugins must export
264pub const PLUGIN_API_SYMBOL: &[u8] = b"streamkit_native_plugin_api\0";