#![cfg(feature = "ffi")]
mod common;
use phostt::ffi::{
PhosttEngine, phostt_engine_free, phostt_stream_flush, phostt_stream_free, phostt_stream_new,
phostt_stream_process_chunk, phostt_string_free,
};
use std::ffi::CString;
#[test]
#[ignore = "Requires model download"]
fn test_ffi_streaming_happy_path() {
let model_dir = common::model_dir();
let engine = phostt::inference::Engine::load(&model_dir).unwrap();
let original_available = engine.pool.available();
let engine_ptr = Box::into_raw(Box::new(PhosttEngine::new(engine)));
let stream_ptr = unsafe { phostt_stream_new(engine_ptr) };
assert!(!stream_ptr.is_null(), "stream_new should succeed");
let engine_ref = unsafe { (*engine_ptr).engine() };
assert_eq!(
engine_ref.pool.available(),
original_available.saturating_sub(1),
"pool slot should be checked out"
);
let pcm16 = common::generate_pcm16_tone(1.0, 16000, 440.0);
let cstring = unsafe {
phostt_stream_process_chunk(engine_ptr, stream_ptr, pcm16.as_ptr(), pcm16.len(), 16000)
};
assert!(
!cstring.is_null(),
"process_chunk should return a JSON string"
);
let json_str = unsafe { CString::from_raw(cstring) }
.to_string_lossy()
.to_string();
let json: serde_json::Value = serde_json::from_str(&json_str).expect("JSON should parse");
assert!(
json.is_array(),
"process_chunk output should be a JSON array"
);
let cstring = unsafe { phostt_stream_flush(engine_ptr, stream_ptr) };
assert!(!cstring.is_null(), "flush should return a JSON string");
let json_str = unsafe { CString::from_raw(cstring) }
.to_string_lossy()
.to_string();
let json: serde_json::Value = serde_json::from_str(&json_str).expect("JSON should parse");
assert!(json.is_array(), "flush output should be a JSON array");
unsafe { phostt_stream_free(stream_ptr) };
assert_eq!(
engine_ref.pool.available(),
original_available,
"pool slot should be returned after stream_free"
);
unsafe { phostt_engine_free(engine_ptr) };
}
#[test]
#[ignore = "Requires model download"]
fn test_ffi_streaming_resample_48k() {
let model_dir = common::model_dir();
let engine = phostt::inference::Engine::load(&model_dir).unwrap();
let engine_ptr = Box::into_raw(Box::new(PhosttEngine::new(engine)));
let stream_ptr = unsafe { phostt_stream_new(engine_ptr) };
assert!(!stream_ptr.is_null());
let pcm16 = common::generate_pcm16_tone(0.5, 48000, 440.0);
let cstring = unsafe {
phostt_stream_process_chunk(engine_ptr, stream_ptr, pcm16.as_ptr(), pcm16.len(), 48000)
};
assert!(
!cstring.is_null(),
"process_chunk with 48 kHz should succeed"
);
unsafe { phostt_string_free(cstring) };
let cstring = unsafe { phostt_stream_flush(engine_ptr, stream_ptr) };
assert!(!cstring.is_null());
unsafe { phostt_string_free(cstring) };
unsafe { phostt_stream_free(stream_ptr) };
unsafe { phostt_engine_free(engine_ptr) };
}