Skip to main content

Remote

Struct Remote 

Source
pub struct Remote { /* private fields */ }
Expand description

A client on the MX Remote network.

Create one with Remote::new, then Remote::start it. Discovery runs on threads this client owns until Remote::close, or until the Remote is dropped.

Implementations§

Source§

impl Remote

Source

pub fn select_video_source( &self, sink: BayUid, source_port: u16, ) -> Result<(), ControlError>

Routes this V2IP sink’s video to the stream a source port advertises.

Source

pub fn select_audio_source( &self, sink: BayUid, source_port: u16, ) -> Result<(), ControlError>

Routes this V2IP sink’s audio to the stream a source port advertises.

Source

pub fn select_video_source_by_name( &self, sink: BayUid, name: &str, ) -> Result<(), ControlError>

Routes this V2IP sink’s video to the input bay with the given user-assigned name.

Source

pub fn select_audio_source_addr( &self, sink: BayUid, audio_ip: Ipv4Addr, audio_port: Option<u16>, format: Option<V2ipAudioFormat>, ) -> Result<(), ControlError>

Routes this V2IP sink’s audio to a multicast address directly, leaving its video and ancillary streams alone.

An unset port is the standard V2IP audio port. A format overrides the sample rate and channel count the receiver would otherwise assume.

Source

pub fn select_audio_source_by_name( &self, sink: BayUid, name: &str, format: Option<V2ipAudioFormat>, ) -> Result<(), ControlError>

Routes this V2IP sink’s audio from the input bay with the given user-assigned name.

A format is carried on the manual switch frame, which is the only form that can override the receiver’s sample rate and channel count.

Source

pub fn set_bay_name(&self, bay: BayUid, name: &str) -> Result<(), ControlError>

Renames a bay.

Source

pub fn set_bay_hidden( &self, bay: BayUid, hidden: bool, ) -> Result<(), ControlError>

Hides a bay from the pickers that list it, or shows it again.

Source

pub fn select_edid_profile( &self, bay: BayUid, profile: EdidProfile, ) -> Result<(), ControlError>

Sets the EDID profile an input presents to the source attached to it.

Source

pub fn send_action( &self, bay: BayUid, action: RcAction, ) -> Result<(), ControlError>

Sends a remote-control action to whatever is attached to a bay.

Source

pub fn power_on(&self, bay: BayUid) -> Result<(), ControlError>

Powers on the device attached to a bay.

Source

pub fn power_off(&self, bay: BayUid) -> Result<(), ControlError>

Powers off the device attached to a bay.

Source

pub fn set_volume( &self, bay: BayUid, volume: u8, muted: Option<bool>, ) -> Result<(), ControlError>

Sets a bay’s volume, as a percentage, and optionally its mute state.

Both channels are set together: the wire carries them separately, but nothing on this surface splits them.

A bay with no volume control of its own is set through its linked_bay, so an output wired to an amplifier zone reaches that zone. volume_up, volume_down and set_muted follow the same link, and read the volume they step from through it.

Source

pub fn volume_up(&self, bay: BayUid) -> Result<(), ControlError>

Raises a bay’s volume by one percent.

Source

pub fn volume_down(&self, bay: BayUid) -> Result<(), ControlError>

Lowers a bay’s volume by one percent.

Source

pub fn set_muted(&self, bay: BayUid, muted: bool) -> Result<(), ControlError>

Mutes or unmutes a bay, keeping the volume it is set to.

Source

pub fn set_amp_zone_settings( &self, bay: BayUid, settings: AmpZoneSettings, ) -> Result<(), ControlError>

Applies amplifier settings to a zone.

Source

pub fn set_audio_endpoint_muted( &self, device: DeviceUid, endpoint: u16, muted: bool, ) -> Result<(), ControlError>

Mutes or unmutes an audio endpoint.

Source

pub fn set_audio_endpoint_trigger( &self, device: DeviceUid, endpoint: u16, active: bool, ) -> Result<(), ControlError>

Sets an audio endpoint’s trigger output.

Source

pub fn set_audio_endpoint_volume( &self, device: DeviceUid, endpoint: u16, volume: u32, ) -> Result<(), ControlError>

Sets an audio endpoint’s volume.

Source

pub fn select_audio_endpoint_input( &self, sink: DeviceUid, sink_endpoint: u16, source: DeviceUid, source_endpoint: u16, ) -> Result<(), ControlError>

Routes a source endpoint on one device to a sink endpoint on another.

Source

pub fn subscribe_v2ip_stats( &self, device: DeviceUid, subscribe: bool, ) -> Result<(), ControlError>

Starts or stops a V2IP device reporting its transport statistics.

Source

pub fn reboot(&self, device: DeviceUid) -> Result<(), ControlError>

Reboots a device.

The device is marked as rebooting once the frame is away, so the silence that follows does not read as one that went offline.

Source

pub fn send_monitoring_pulse(&self) -> Result<(), ControlError>

Asks every peer to report its monitoring data now rather than on its own schedule.

Source

pub fn set_multiviewer_view_mode( &self, device: DeviceUid, mode: MultiviewerViewMode, ) -> Result<(), ControlError>

Sets the window layout.

Source

pub fn set_multiviewer_video_source( &self, device: DeviceUid, screen: u8, source: MultiviewerSource, ) -> Result<(), ControlError>

Assigns a source to one window.

Source

pub fn set_multiviewer_audio_source( &self, device: DeviceUid, source: MultiviewerSource, ) -> Result<(), ControlError>

Selects which window’s audio is output.

Source

pub fn set_multiviewer_audio_volume( &self, device: DeviceUid, volume: u8, muted: bool, ) -> Result<(), ControlError>

Sets the output volume and mute state.

Source

pub fn set_multiviewer_edid_template( &self, device: DeviceUid, template: MultiviewerEdidTemplate, ) -> Result<(), ControlError>

Sets the EDID template presented to the sources.

Source

pub fn set_multiviewer_remote_control( &self, device: DeviceUid, source: MultiviewerSource, ) -> Result<(), ControlError>

Selects which window receives remote-control passthrough.

Source

pub fn set_multiviewer_pip_size( &self, device: DeviceUid, size: MultiviewerPipSize, ) -> Result<(), ControlError>

Sets how large the picture-in-picture window is.

Source

pub fn set_multiviewer_pip_position( &self, device: DeviceUid, position: MultiviewerPipPosition, ) -> Result<(), ControlError>

Sets which corner the picture-in-picture window sits in.

Source

pub fn set_multiviewer_aspect_ratio( &self, device: DeviceUid, aspect: MultiviewerAspectRatio, ) -> Result<(), ControlError>

Sets the aspect ratio the windows are scaled to.

Source

pub fn set_multiviewer_auto_switch( &self, device: DeviceUid, enable: bool, ) -> Result<(), ControlError>

Enables or disables switching windows on its own.

Source

pub fn set_multiviewer_output_mode( &self, device: DeviceUid, mode: MultiviewerOutputMode, ) -> Result<(), ControlError>

Sets the output resolution and refresh rate.

Source

pub fn set_multiviewer_output_itc( &self, device: DeviceUid, mode: MultiviewerItcMode, ) -> Result<(), ControlError>

Sets the IT-content flag on the output.

Source

pub fn set_multiviewer_hdcp_mode( &self, device: DeviceUid, mode: MultiviewerHdcpMode, ) -> Result<(), ControlError>

Sets the HDCP version negotiated on the output.

Source

pub fn set_multiviewer_input_source( &self, device: DeviceUid, input: u8, source: DeviceUid, ) -> Result<(), ControlError>

Maps a source device onto one of the multiviewer’s inputs.

The zero identifier clears the mapping.

Source

pub fn multiviewer_auto_route( &self, device: DeviceUid, ) -> Result<(), ControlError>

Asks the multiviewer to route its sources itself.

Source§

impl Remote

Source

pub fn new(config: Config, handler: Arc<dyn EventHandler>) -> Result<Self>

Builds a client, loading or generating its identifier.

Nothing is sent and no socket is opened until Remote::start.

Examples found in repository?
examples/discover.rs (line 68)
59fn main() -> std::io::Result<()> {
60    let mut config = Config::default();
61    config.name = Some("discover".to_owned());
62    if let Some(address) = std::env::args().nth(1) {
63        config.local_ip = Some(address.parse().map_err(|_| {
64            std::io::Error::new(std::io::ErrorKind::InvalidInput, "not an IPv4 address")
65        })?);
66    }
67
68    let remote = Arc::new(Remote::new(config, Arc::new(Printer))?);
69    let _ = CLIENT.set(Arc::clone(&remote));
70    remote.start()?;
71
72    if let Some(target) = remote.target() {
73        println!("listening, sending to {target}. Ctrl-C to stop.");
74    }
75
76    let running = Arc::new(AtomicBool::new(true));
77    let stop = Arc::clone(&running);
78    ctrl_c(move || stop.store(false, Ordering::Relaxed));
79    while running.load(Ordering::Relaxed) {
80        std::thread::sleep(Duration::from_millis(200));
81    }
82
83    let devices = remote.devices();
84    println!("\n{} device(s):", devices.len());
85    for device in devices {
86        Printer.on_device_update(device);
87    }
88
89    remote.close();
90    Ok(())
91}
Source

pub fn start(&self) -> Result<()>

Opens the socket, announces this client and begins discovery.

Returns once the receive thread is running; discovery continues in the background.

Examples found in repository?
examples/discover.rs (line 70)
59fn main() -> std::io::Result<()> {
60    let mut config = Config::default();
61    config.name = Some("discover".to_owned());
62    if let Some(address) = std::env::args().nth(1) {
63        config.local_ip = Some(address.parse().map_err(|_| {
64            std::io::Error::new(std::io::ErrorKind::InvalidInput, "not an IPv4 address")
65        })?);
66    }
67
68    let remote = Arc::new(Remote::new(config, Arc::new(Printer))?);
69    let _ = CLIENT.set(Arc::clone(&remote));
70    remote.start()?;
71
72    if let Some(target) = remote.target() {
73        println!("listening, sending to {target}. Ctrl-C to stop.");
74    }
75
76    let running = Arc::new(AtomicBool::new(true));
77    let stop = Arc::clone(&running);
78    ctrl_c(move || stop.store(false, Ordering::Relaxed));
79    while running.load(Ordering::Relaxed) {
80        std::thread::sleep(Duration::from_millis(200));
81    }
82
83    let devices = remote.devices();
84    println!("\n{} device(s):", devices.len());
85    for device in devices {
86        Printer.on_device_update(device);
87    }
88
89    remote.close();
90    Ok(())
91}
Source

pub fn close(&self)

Stops discovery, closes the socket and waits for the threads to finish.

Calling it more than once, or before Remote::start, does nothing.

Examples found in repository?
examples/discover.rs (line 89)
59fn main() -> std::io::Result<()> {
60    let mut config = Config::default();
61    config.name = Some("discover".to_owned());
62    if let Some(address) = std::env::args().nth(1) {
63        config.local_ip = Some(address.parse().map_err(|_| {
64            std::io::Error::new(std::io::ErrorKind::InvalidInput, "not an IPv4 address")
65        })?);
66    }
67
68    let remote = Arc::new(Remote::new(config, Arc::new(Printer))?);
69    let _ = CLIENT.set(Arc::clone(&remote));
70    remote.start()?;
71
72    if let Some(target) = remote.target() {
73        println!("listening, sending to {target}. Ctrl-C to stop.");
74    }
75
76    let running = Arc::new(AtomicBool::new(true));
77    let stop = Arc::clone(&running);
78    ctrl_c(move || stop.store(false, Ordering::Relaxed));
79    while running.load(Ordering::Relaxed) {
80        std::thread::sleep(Duration::from_millis(200));
81    }
82
83    let devices = remote.devices();
84    println!("\n{} device(s):", devices.len());
85    for device in devices {
86        Printer.on_device_update(device);
87    }
88
89    remote.close();
90    Ok(())
91}
Source

pub fn uid(&self) -> DeviceUid

This client’s identifier, as peers see it.

Source

pub fn name(&self) -> &str

The name this client advertises.

Source

pub fn target(&self) -> Option<SocketAddrV4>

The address frames are being sent to, once started.

Examples found in repository?
examples/discover.rs (line 72)
59fn main() -> std::io::Result<()> {
60    let mut config = Config::default();
61    config.name = Some("discover".to_owned());
62    if let Some(address) = std::env::args().nth(1) {
63        config.local_ip = Some(address.parse().map_err(|_| {
64            std::io::Error::new(std::io::ErrorKind::InvalidInput, "not an IPv4 address")
65        })?);
66    }
67
68    let remote = Arc::new(Remote::new(config, Arc::new(Printer))?);
69    let _ = CLIENT.set(Arc::clone(&remote));
70    remote.start()?;
71
72    if let Some(target) = remote.target() {
73        println!("listening, sending to {target}. Ctrl-C to stop.");
74    }
75
76    let running = Arc::new(AtomicBool::new(true));
77    let stop = Arc::clone(&running);
78    ctrl_c(move || stop.store(false, Ordering::Relaxed));
79    while running.load(Ordering::Relaxed) {
80        std::thread::sleep(Duration::from_millis(200));
81    }
82
83    let devices = remote.devices();
84    println!("\n{} device(s):", devices.len());
85    for device in devices {
86        Printer.on_device_update(device);
87    }
88
89    remote.close();
90    Ok(())
91}
Source

pub fn devices(&self) -> Vec<DeviceUid>

Every device heard from, in no particular order.

Examples found in repository?
examples/discover.rs (line 83)
59fn main() -> std::io::Result<()> {
60    let mut config = Config::default();
61    config.name = Some("discover".to_owned());
62    if let Some(address) = std::env::args().nth(1) {
63        config.local_ip = Some(address.parse().map_err(|_| {
64            std::io::Error::new(std::io::ErrorKind::InvalidInput, "not an IPv4 address")
65        })?);
66    }
67
68    let remote = Arc::new(Remote::new(config, Arc::new(Printer))?);
69    let _ = CLIENT.set(Arc::clone(&remote));
70    remote.start()?;
71
72    if let Some(target) = remote.target() {
73        println!("listening, sending to {target}. Ctrl-C to stop.");
74    }
75
76    let running = Arc::new(AtomicBool::new(true));
77    let stop = Arc::clone(&running);
78    ctrl_c(move || stop.store(false, Ordering::Relaxed));
79    while running.load(Ordering::Relaxed) {
80        std::thread::sleep(Duration::from_millis(200));
81    }
82
83    let devices = remote.devices();
84    println!("\n{} device(s):", devices.len());
85    for device in devices {
86        Printer.on_device_update(device);
87    }
88
89    remote.close();
90    Ok(())
91}
Source

pub fn device(&self, uid: DeviceUid) -> Option<DeviceInfo>

A snapshot of one device.

Examples found in repository?
examples/discover.rs (line 30)
28    fn on_device_update(&self, device: DeviceUid) {
29        let Some(remote) = CLIENT.get() else { return };
30        let Some(info) = remote.device(device) else {
31            return;
32        };
33        println!(
34            "  {device}  {:<16} {:<12} {:<16} protocol {:#04x}, {} bays{}",
35            info.model,
36            info.serial,
37            info.name,
38            info.supported_protocol,
39            info.bays.len(),
40            if info.online { "" } else { " (offline)" },
41        );
42    }
Source

pub fn device_by_serial(&self, serial: &str) -> Option<DeviceUid>

The device with the given serial number.

Source

pub fn resolve_device(&self, name: &str) -> Option<DeviceUid>

Resolves a device from its dotted-hex identifier, falling back to a serial-number match.

Source

pub fn bay(&self, uid: BayUid) -> Option<BayInfo>

A snapshot of one bay.

Examples found in repository?
examples/discover.rs (line 46)
44    fn on_bay_update(&self, bay: BayUid) {
45        let Some(remote) = CLIENT.get() else { return };
46        let Some(info) = remote.bay(bay) else { return };
47        println!(
48            "    bay {} {:<16} {}",
49            bay.port,
50            info.user_name,
51            match info.signal_detected {
52                Some(true) => "signal",
53                _ => "no signal",
54            },
55        );
56    }
Source

pub fn bay_by_name(&self, device: DeviceUid, port_name: &str) -> Option<BayUid>

The bay on device with the given port name, such as Output 1.

Source

pub fn bay_by_stream_ip(&self, ip: Ipv4Addr, audio: bool) -> Option<BayUid>

The source bay advertising the given multicast group, for the video or the audio stream.

Source

pub fn v2ip_sources(&self, uid: DeviceUid) -> Option<Vec<V2ipStreamSources>>

The V2IP streams a device advertises.

Source

pub fn v2ip_details(&self, uid: DeviceUid) -> Option<DeviceV2ipDetails>

A V2IP device’s own encoder configuration.

Source

pub fn v2ip_sink(&self, uid: DeviceUid) -> Option<DeviceV2ipSink>

The streams a V2IP sink is subscribed to.

Source

pub fn v2ip_stats(&self, uid: DeviceUid) -> Option<V2ipDeviceStats>

Transport statistics a V2IP device reports.

Source

pub fn v2ip_tiling(&self, uid: DeviceUid) -> Option<V2ipTilingConfig>

The video-wall tiling a V2IP device is configured for.

Source

pub fn audio_endpoints(&self, uid: DeviceUid) -> Option<AudioEndpoints>

The audio endpoint tree a device exposes.

Source

pub fn multiviewer_status(&self, uid: DeviceUid) -> Option<MultiviewerStatus>

The multiviewer layout a device is showing.

Source

pub fn dolby_settings(&self, uid: DeviceUid) -> Option<AmpDolbySettings>

An amplifier’s Dolby decoder settings.

Source

pub fn pdu_state(&self, uid: DeviceUid) -> Option<PduState>

A device’s power-distribution state.

Source

pub fn rc_settings(&self, uid: DeviceUid) -> Option<RcSettings>

A device’s remote-control settings.

Source

pub fn network_status(&self, uid: DeviceUid) -> Vec<NetworkPortStatus>

Every network port a device reports, in port order.

Source

pub fn topology(&self, uid: DeviceUid) -> Vec<TopologyEntry>

The mesh topology a device reports.

Source

pub fn firmware(&self, uid: DeviceUid) -> Vec<(FirmwareType, FirmwareVersion)>

Every firmware image a device reports a version for.

Source

pub fn update_config( &self, local_ip: Option<Ipv4Addr>, broadcast: bool, ) -> Result<()>

Changes the interface and the multicast/broadcast mode while running, reopening the socket when either differs from what is in use.

Source

pub fn discover(&self) -> Result<(), SendError>

Asks every device on the network to announce itself.

Trait Implementations§

Source§

impl Drop for Remote

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

§

impl !Freeze for Remote

§

impl !RefUnwindSafe for Remote

§

impl !UnwindSafe for Remote

§

impl Send for Remote

§

impl Sync for Remote

§

impl Unpin for Remote

§

impl UnsafeUnpin for Remote

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.