use std::fmt;
use std::os::raw::c_int;
use std::ptr::NonNull;
use crate::error::{Result, SpanDspError};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct T38Indicator(pub spandsp_sys::t30_indicator_types_e);
impl T38Indicator {
pub const NO_SIGNAL: Self = Self(spandsp_sys::t30_indicator_types_e::T38_IND_NO_SIGNAL);
pub const CNG: Self = Self(spandsp_sys::t30_indicator_types_e::T38_IND_CNG);
pub const CED: Self = Self(spandsp_sys::t30_indicator_types_e::T38_IND_CED);
pub const V21_PREAMBLE: Self = Self(spandsp_sys::t30_indicator_types_e::T38_IND_V21_PREAMBLE);
}
impl fmt::Display for T38Indicator {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use spandsp_sys::t30_indicator_types_e::*;
let name = match self.0 {
T38_IND_NO_SIGNAL => "no-signal",
T38_IND_CNG => "CNG",
T38_IND_CED => "CED",
T38_IND_V21_PREAMBLE => "V.21-preamble",
T38_IND_V27TER_2400_TRAINING => "V.27ter-2400-training",
T38_IND_V27TER_4800_TRAINING => "V.27ter-4800-training",
T38_IND_V29_7200_TRAINING => "V.29-7200-training",
T38_IND_V29_9600_TRAINING => "V.29-9600-training",
T38_IND_V17_7200_SHORT_TRAINING => "V.17-7200-short",
T38_IND_V17_7200_LONG_TRAINING => "V.17-7200-long",
T38_IND_V17_9600_SHORT_TRAINING => "V.17-9600-short",
T38_IND_V17_9600_LONG_TRAINING => "V.17-9600-long",
T38_IND_V17_12000_SHORT_TRAINING => "V.17-12000-short",
T38_IND_V17_12000_LONG_TRAINING => "V.17-12000-long",
T38_IND_V17_14400_SHORT_TRAINING => "V.17-14400-short",
T38_IND_V17_14400_LONG_TRAINING => "V.17-14400-long",
T38_IND_V8_ANSAM => "V.8-ansam",
T38_IND_V8_SIGNAL => "V.8-signal",
T38_IND_V34_CNTL_CHANNEL_1200 => "V.34-cc-1200",
T38_IND_V34_PRI_CHANNEL => "V.34-pri-channel",
T38_IND_V34_CC_RETRAIN => "V.34-cc-retrain",
T38_IND_V33_12000_TRAINING => "V.33-12000-training",
T38_IND_V33_14400_TRAINING => "V.33-14400-training",
};
f.write_str(name)
}
}
impl From<spandsp_sys::t30_indicator_types_e> for T38Indicator {
fn from(v: spandsp_sys::t30_indicator_types_e) -> Self {
Self(v)
}
}
impl From<T38Indicator> for i32 {
fn from(v: T38Indicator) -> Self {
v.0 as i32
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct T38DataType(pub spandsp_sys::t38_data_types_e);
impl T38DataType {
pub const V21: Self = Self(spandsp_sys::t38_data_types_e::T38_DATA_V21);
pub const V27TER_2400: Self = Self(spandsp_sys::t38_data_types_e::T38_DATA_V27TER_2400);
pub const V27TER_4800: Self = Self(spandsp_sys::t38_data_types_e::T38_DATA_V27TER_4800);
pub const V29_7200: Self = Self(spandsp_sys::t38_data_types_e::T38_DATA_V29_7200);
pub const V29_9600: Self = Self(spandsp_sys::t38_data_types_e::T38_DATA_V29_9600);
pub const V17_7200: Self = Self(spandsp_sys::t38_data_types_e::T38_DATA_V17_7200);
pub const V17_9600: Self = Self(spandsp_sys::t38_data_types_e::T38_DATA_V17_9600);
pub const V17_12000: Self = Self(spandsp_sys::t38_data_types_e::T38_DATA_V17_12000);
pub const V17_14400: Self = Self(spandsp_sys::t38_data_types_e::T38_DATA_V17_14400);
}
impl fmt::Display for T38DataType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use spandsp_sys::t38_data_types_e::*;
let name = match self.0 {
T38_DATA_NONE => "none",
T38_DATA_V21 => "V.21",
T38_DATA_V27TER_2400 => "V.27ter-2400",
T38_DATA_V27TER_4800 => "V.27ter-4800",
T38_DATA_V29_7200 => "V.29-7200",
T38_DATA_V29_9600 => "V.29-9600",
T38_DATA_V17_7200 => "V.17-7200",
T38_DATA_V17_9600 => "V.17-9600",
T38_DATA_V17_12000 => "V.17-12000",
T38_DATA_V17_14400 => "V.17-14400",
T38_DATA_V8 => "V.8",
T38_DATA_V34_PRI_RATE => "V.34-pri-rate",
T38_DATA_V34_CC_1200 => "V.34-cc-1200",
T38_DATA_V34_PRI_CH => "V.34-pri-ch",
T38_DATA_V33_12000 => "V.33-12000",
T38_DATA_V33_14400 => "V.33-14400",
};
f.write_str(name)
}
}
impl From<spandsp_sys::t38_data_types_e> for T38DataType {
fn from(v: spandsp_sys::t38_data_types_e) -> Self {
Self(v)
}
}
impl From<T38DataType> for i32 {
fn from(v: T38DataType) -> Self {
v.0 as i32
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct T38FieldType(pub spandsp_sys::t38_field_types_e);
impl T38FieldType {
pub const HDLC_DATA: Self = Self(spandsp_sys::t38_field_types_e::T38_FIELD_HDLC_DATA);
pub const HDLC_SIG_END: Self = Self(spandsp_sys::t38_field_types_e::T38_FIELD_HDLC_SIG_END);
pub const HDLC_FCS_OK: Self = Self(spandsp_sys::t38_field_types_e::T38_FIELD_HDLC_FCS_OK);
pub const HDLC_FCS_BAD: Self = Self(spandsp_sys::t38_field_types_e::T38_FIELD_HDLC_FCS_BAD);
pub const T4_NON_ECM_DATA: Self =
Self(spandsp_sys::t38_field_types_e::T38_FIELD_T4_NON_ECM_DATA);
pub const T4_NON_ECM_SIG_END: Self =
Self(spandsp_sys::t38_field_types_e::T38_FIELD_T4_NON_ECM_SIG_END);
}
impl fmt::Display for T38FieldType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use spandsp_sys::t38_field_types_e::*;
let name = match self.0 {
T38_FIELD_HDLC_DATA => "HDLC-data",
T38_FIELD_HDLC_SIG_END => "HDLC-sig-end",
T38_FIELD_HDLC_FCS_OK => "HDLC-FCS-OK",
T38_FIELD_HDLC_FCS_BAD => "HDLC-FCS-bad",
T38_FIELD_HDLC_FCS_OK_SIG_END => "HDLC-FCS-OK-sig-end",
T38_FIELD_HDLC_FCS_BAD_SIG_END => "HDLC-FCS-bad-sig-end",
T38_FIELD_T4_NON_ECM_DATA => "T4-non-ECM-data",
T38_FIELD_T4_NON_ECM_SIG_END => "T4-non-ECM-sig-end",
T38_FIELD_CM_MESSAGE => "CM-message",
T38_FIELD_JM_MESSAGE => "JM-message",
T38_FIELD_CI_MESSAGE => "CI-message",
T38_FIELD_V34RATE => "V34-rate",
};
f.write_str(name)
}
}
impl From<spandsp_sys::t38_field_types_e> for T38FieldType {
fn from(v: spandsp_sys::t38_field_types_e) -> Self {
Self(v)
}
}
impl From<T38FieldType> for i32 {
fn from(v: T38FieldType) -> Self {
v.0 as i32
}
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct T38TerminalOptions: i32 {
const NO_PACING = 0x01;
const REGULAR_INDICATORS = 0x02;
const REPEATING_INDICATORS_2S = 0x04;
const NO_INDICATORS = 0x08;
}
}
impl Default for T38TerminalOptions {
fn default() -> Self {
Self::empty()
}
}
impl fmt::Display for T38TerminalOptions {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
bitflags::parser::to_writer(self, f)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum T38PacketCategory {
Indicator = spandsp_sys::t38_packet_categories_e_T38_PACKET_CATEGORY_INDICATOR,
ControlData = spandsp_sys::t38_packet_categories_e_T38_PACKET_CATEGORY_CONTROL_DATA,
ControlDataEnd = spandsp_sys::t38_packet_categories_e_T38_PACKET_CATEGORY_CONTROL_DATA_END,
ImageData = spandsp_sys::t38_packet_categories_e_T38_PACKET_CATEGORY_IMAGE_DATA,
ImageDataEnd = spandsp_sys::t38_packet_categories_e_T38_PACKET_CATEGORY_IMAGE_DATA_END,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(i32)]
pub enum T38Version {
V0 = 0,
V1 = 1,
V2 = 2,
V3 = 3,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(i32)]
pub enum T38DataRateManagement {
LocalTcf = 1,
TransferredTcf = 2,
}
pub struct T38Core {
inner: NonNull<spandsp_sys::t38_core_state_t>,
owned: bool,
}
impl T38Core {
pub unsafe fn new_raw(
rx_indicator_handler: spandsp_sys::t38_rx_indicator_handler_t,
rx_data_handler: spandsp_sys::t38_rx_data_handler_t,
rx_missing_handler: spandsp_sys::t38_rx_missing_handler_t,
rx_user_data: *mut std::ffi::c_void,
tx_packet_handler: spandsp_sys::t38_tx_packet_handler_t,
tx_packet_user_data: *mut std::ffi::c_void,
) -> Result<Self> {
unsafe {
let ptr = spandsp_sys::t38_core_init(
std::ptr::null_mut(),
rx_indicator_handler,
rx_data_handler,
rx_missing_handler,
rx_user_data,
tx_packet_handler,
tx_packet_user_data,
);
let inner = NonNull::new(ptr).ok_or(SpanDspError::InitFailed)?;
Ok(Self { inner, owned: true })
}
}
pub unsafe fn from_raw(ptr: *mut spandsp_sys::t38_core_state_t) -> Result<Self> {
let inner = NonNull::new(ptr).ok_or(SpanDspError::InitFailed)?;
Ok(Self {
inner,
owned: false,
})
}
pub fn as_ptr(&self) -> *mut spandsp_sys::t38_core_state_t {
self.inner.as_ptr()
}
pub fn restart(&self) -> Result<()> {
let rc = unsafe { spandsp_sys::t38_core_restart(self.inner.as_ptr()) };
if rc != 0 {
return Err(SpanDspError::ErrorCode(rc));
}
Ok(())
}
pub fn send_indicator(&self, indicator: T38Indicator) -> i32 {
unsafe { spandsp_sys::t38_core_send_indicator(self.inner.as_ptr(), i32::from(indicator)) }
}
pub fn send_data(
&self,
data_type: T38DataType,
field_type: T38FieldType,
field: &[u8],
category: T38PacketCategory,
) -> Result<()> {
let rc = unsafe {
spandsp_sys::t38_core_send_data(
self.inner.as_ptr(),
i32::from(data_type),
i32::from(field_type),
field.as_ptr(),
field.len() as c_int,
category as c_int,
)
};
if rc != 0 {
return Err(SpanDspError::ErrorCode(rc));
}
Ok(())
}
pub fn rx_ifp_packet(&self, buf: &[u8], seq_no: u16) -> Result<()> {
let rc = unsafe {
spandsp_sys::t38_core_rx_ifp_packet(
self.inner.as_ptr(),
buf.as_ptr(),
buf.len() as i32,
seq_no,
)
};
if rc != 0 {
return Err(SpanDspError::ErrorCode(rc));
}
Ok(())
}
pub fn set_t38_version(&self, version: T38Version) {
unsafe {
spandsp_sys::t38_set_t38_version(self.inner.as_ptr(), version as c_int);
}
}
pub fn set_data_rate_management_method(&self, method: T38DataRateManagement) {
unsafe {
spandsp_sys::t38_set_data_rate_management_method(self.inner.as_ptr(), method as c_int);
}
}
pub fn set_redundancy_control(&self, category: T38PacketCategory, setting: i32) {
unsafe {
spandsp_sys::t38_set_redundancy_control(
self.inner.as_ptr(),
category as c_int,
setting as c_int,
);
}
}
}
unsafe impl Send for T38Core {}
impl Drop for T38Core {
fn drop(&mut self) {
if self.owned {
unsafe {
spandsp_sys::t38_core_free(self.inner.as_ptr());
}
}
}
}