use std::ffi::c_char;
use mx_remote::{
EdidProfile, MultiviewerAspectRatio, MultiviewerEdidTemplate, MultiviewerHdcpMode,
MultiviewerItcMode, MultiviewerOutputMode, MultiviewerPipPosition, MultiviewerPipSize,
MultiviewerSource, MultiviewerViewMode, RcAction, V2ipAudioFormat,
};
use crate::abi::{
fail, from_control, mxr_bay_uid_t, mxr_result_t, mxr_tribool_t, mxr_uid_t, req_str,
};
use crate::info::mxr_amp_zone_settings_t;
use crate::remote::{mxr_remote_t, with};
#[repr(C)]
#[derive(Clone, Copy)]
pub struct mxr_audio_format_t {
pub sample_rate: u32,
pub channels: u8,
}
impl From<mxr_audio_format_t> for V2ipAudioFormat {
fn from(f: mxr_audio_format_t) -> Self {
Self {
sample_rate: f.sample_rate,
channels: f.channels,
}
}
}
#[no_mangle]
pub unsafe extern "C" fn mxr_select_video_source(
remote: *const mxr_remote_t,
sink: mxr_bay_uid_t,
source_port: u16,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(r.remote.select_video_source(sink.into(), source_port))
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_select_audio_source(
remote: *const mxr_remote_t,
sink: mxr_bay_uid_t,
source_port: u16,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(r.remote.select_audio_source(sink.into(), source_port))
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_select_video_source_by_name(
remote: *const mxr_remote_t,
sink: mxr_bay_uid_t,
name: *const c_char,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
match unsafe { req_str(name) } {
Ok(name) => from_control(r.remote.select_video_source_by_name(sink.into(), name)),
Err(code) => code,
}
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_select_audio_source_by_name(
remote: *const mxr_remote_t,
sink: mxr_bay_uid_t,
name: *const c_char,
format: *const mxr_audio_format_t,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
let name = match unsafe { req_str(name) } {
Ok(name) => name,
Err(code) => return code,
};
let format = unsafe { format.as_ref() }.map(|f| (*f).into());
from_control(
r.remote
.select_audio_source_by_name(sink.into(), name, format),
)
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_select_audio_source_addr(
remote: *const mxr_remote_t,
sink: mxr_bay_uid_t,
audio_ip: *const c_char,
audio_port: u16,
format: *const mxr_audio_format_t,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
let text = match unsafe { req_str(audio_ip) } {
Ok(text) => text,
Err(code) => return code,
};
let Ok(ip) = text.parse() else {
return fail(
mxr_result_t::MXR_ERR_INVALID_ARGUMENT,
&format!("audio_ip is not an IPv4 address: {text:?}"),
);
};
let format = unsafe { format.as_ref() }.map(|f| (*f).into());
from_control(r.remote.select_audio_source_addr(
sink.into(),
ip,
(audio_port != 0).then_some(audio_port),
format,
))
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_set_bay_name(
remote: *const mxr_remote_t,
bay: mxr_bay_uid_t,
name: *const c_char,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
match unsafe { req_str(name) } {
Ok(name) => from_control(r.remote.set_bay_name(bay.into(), name)),
Err(code) => code,
}
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_set_bay_hidden(
remote: *const mxr_remote_t,
bay: mxr_bay_uid_t,
hidden: bool,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(r.remote.set_bay_hidden(bay.into(), hidden))
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_select_edid_profile(
remote: *const mxr_remote_t,
bay: mxr_bay_uid_t,
profile: u16,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(
r.remote
.select_edid_profile(bay.into(), EdidProfile::from_wire(profile)),
)
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_send_action(
remote: *const mxr_remote_t,
bay: mxr_bay_uid_t,
action: u16,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(
r.remote
.send_action(bay.into(), RcAction::from_wire(action)),
)
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_power_on(
remote: *const mxr_remote_t,
bay: mxr_bay_uid_t,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| from_control(r.remote.power_on(bay.into())))
}
#[no_mangle]
pub unsafe extern "C" fn mxr_power_off(
remote: *const mxr_remote_t,
bay: mxr_bay_uid_t,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| from_control(r.remote.power_off(bay.into())))
}
#[no_mangle]
pub unsafe extern "C" fn mxr_set_volume(
remote: *const mxr_remote_t,
bay: mxr_bay_uid_t,
volume: u8,
muted: mxr_tribool_t,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(r.remote.set_volume(
bay.into(),
volume,
match muted {
mxr_tribool_t::MXR_UNKNOWN => None,
mxr_tribool_t::MXR_FALSE => Some(false),
mxr_tribool_t::MXR_TRUE => Some(true),
},
))
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_volume_up(
remote: *const mxr_remote_t,
bay: mxr_bay_uid_t,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| from_control(r.remote.volume_up(bay.into())))
}
#[no_mangle]
pub unsafe extern "C" fn mxr_volume_down(
remote: *const mxr_remote_t,
bay: mxr_bay_uid_t,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| from_control(r.remote.volume_down(bay.into())))
}
#[no_mangle]
pub unsafe extern "C" fn mxr_set_muted(
remote: *const mxr_remote_t,
bay: mxr_bay_uid_t,
muted: bool,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(r.remote.set_muted(bay.into(), muted))
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_set_amp_zone_settings(
remote: *const mxr_remote_t,
bay: mxr_bay_uid_t,
settings: *const mxr_amp_zone_settings_t,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
let Some(settings) = (unsafe { settings.as_ref() }) else {
return fail(
mxr_result_t::MXR_ERR_INVALID_ARGUMENT,
"the amp zone settings pointer is null",
);
};
from_control(
r.remote
.set_amp_zone_settings(bay.into(), (*settings).into()),
)
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_set_audio_endpoint_muted(
remote: *const mxr_remote_t,
device: mxr_uid_t,
endpoint: u16,
muted: bool,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(
r.remote
.set_audio_endpoint_muted(device.into(), endpoint, muted),
)
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_set_audio_endpoint_trigger(
remote: *const mxr_remote_t,
device: mxr_uid_t,
endpoint: u16,
active: bool,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(
r.remote
.set_audio_endpoint_trigger(device.into(), endpoint, active),
)
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_set_audio_endpoint_volume(
remote: *const mxr_remote_t,
device: mxr_uid_t,
endpoint: u16,
volume: u32,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(
r.remote
.set_audio_endpoint_volume(device.into(), endpoint, volume),
)
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_select_audio_endpoint_input(
remote: *const mxr_remote_t,
sink: mxr_uid_t,
sink_endpoint: u16,
source: mxr_uid_t,
source_endpoint: u16,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(r.remote.select_audio_endpoint_input(
sink.into(),
sink_endpoint,
source.into(),
source_endpoint,
))
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_subscribe_v2ip_stats(
remote: *const mxr_remote_t,
device: mxr_uid_t,
subscribe: bool,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(r.remote.subscribe_v2ip_stats(device.into(), subscribe))
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_reboot(
remote: *const mxr_remote_t,
device: mxr_uid_t,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| from_control(r.remote.reboot(device.into())))
}
#[no_mangle]
pub unsafe extern "C" fn mxr_send_monitoring_pulse(remote: *const mxr_remote_t) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| from_control(r.remote.send_monitoring_pulse()))
}
#[no_mangle]
pub unsafe extern "C" fn mxr_set_multiviewer_view_mode(
remote: *const mxr_remote_t,
device: mxr_uid_t,
mode: u8,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(
r.remote
.set_multiviewer_view_mode(device.into(), MultiviewerViewMode::from_wire(mode)),
)
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_set_multiviewer_video_source(
remote: *const mxr_remote_t,
device: mxr_uid_t,
screen: u8,
source: u8,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(r.remote.set_multiviewer_video_source(
device.into(),
screen,
MultiviewerSource::from_wire(source),
))
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_set_multiviewer_audio_source(
remote: *const mxr_remote_t,
device: mxr_uid_t,
source: u8,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(
r.remote
.set_multiviewer_audio_source(device.into(), MultiviewerSource::from_wire(source)),
)
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_set_multiviewer_audio_volume(
remote: *const mxr_remote_t,
device: mxr_uid_t,
volume: u8,
muted: bool,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(
r.remote
.set_multiviewer_audio_volume(device.into(), volume, muted),
)
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_set_multiviewer_edid_template(
remote: *const mxr_remote_t,
device: mxr_uid_t,
template: u8,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(r.remote.set_multiviewer_edid_template(
device.into(),
MultiviewerEdidTemplate::from_wire(template),
))
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_set_multiviewer_remote_control(
remote: *const mxr_remote_t,
device: mxr_uid_t,
source: u8,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(
r.remote.set_multiviewer_remote_control(
device.into(),
MultiviewerSource::from_wire(source),
),
)
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_set_multiviewer_pip_size(
remote: *const mxr_remote_t,
device: mxr_uid_t,
size: u8,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(
r.remote
.set_multiviewer_pip_size(device.into(), MultiviewerPipSize::from_wire(size)),
)
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_set_multiviewer_pip_position(
remote: *const mxr_remote_t,
device: mxr_uid_t,
position: u8,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(r.remote.set_multiviewer_pip_position(
device.into(),
MultiviewerPipPosition::from_wire(position),
))
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_set_multiviewer_aspect_ratio(
remote: *const mxr_remote_t,
device: mxr_uid_t,
aspect: u8,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(
r.remote.set_multiviewer_aspect_ratio(
device.into(),
MultiviewerAspectRatio::from_wire(aspect),
),
)
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_set_multiviewer_auto_switch(
remote: *const mxr_remote_t,
device: mxr_uid_t,
enable: bool,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(r.remote.set_multiviewer_auto_switch(device.into(), enable))
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_set_multiviewer_output_mode(
remote: *const mxr_remote_t,
device: mxr_uid_t,
mode: u8,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(
r.remote
.set_multiviewer_output_mode(device.into(), MultiviewerOutputMode::from_wire(mode)),
)
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_set_multiviewer_output_itc(
remote: *const mxr_remote_t,
device: mxr_uid_t,
mode: u8,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(
r.remote
.set_multiviewer_output_itc(device.into(), MultiviewerItcMode::from_wire(mode)),
)
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_set_multiviewer_hdcp_mode(
remote: *const mxr_remote_t,
device: mxr_uid_t,
mode: u8,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(
r.remote
.set_multiviewer_hdcp_mode(device.into(), MultiviewerHdcpMode::from_wire(mode)),
)
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_set_multiviewer_input_source(
remote: *const mxr_remote_t,
device: mxr_uid_t,
input: u8,
source: mxr_uid_t,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(
r.remote
.set_multiviewer_input_source(device.into(), input, source.into()),
)
})
}
#[no_mangle]
pub unsafe extern "C" fn mxr_multiviewer_auto_route(
remote: *const mxr_remote_t,
device: mxr_uid_t,
) -> mxr_result_t {
let handle = unsafe { remote.as_ref() };
with(handle, |r| {
from_control(r.remote.multiviewer_auto_route(device.into()))
})
}