Skip to main content

StateManager

Struct StateManager 

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

Core state manager with sync-first API

All public methods are synchronous. Background event processing happens in a dedicated thread.

Implementations§

Source§

impl StateManager

Source

pub fn new() -> Result<Self>

Create a new StateManager with default settings (sync)

§Example
let manager = StateManager::new()?;
Source

pub fn builder() -> StateManagerBuilder

Create a StateManager builder for custom configuration

Source

pub fn add_devices(&self, devices: Vec<Device>) -> Result<()>

Add discovered devices (sync)

§Example
let devices = sonos_discovery::get();
manager.add_devices(devices)?;
Source

pub fn speaker_infos(&self) -> Vec<SpeakerInfo>

Get all speaker info

Source

pub fn speaker_info(&self, speaker_id: &SpeakerId) -> Option<SpeakerInfo>

Get a specific speaker info by ID

Source

pub fn get_speaker_ip(&self, speaker_id: &SpeakerId) -> Option<IpAddr>

Get speaker IP by ID

Source

pub fn get_boot_seq(&self, speaker_id: &SpeakerId) -> Option<u32>

Get boot_seq for a speaker (used by GroupManagement AddMember)

Source

pub fn update_speaker_ip(&self, speaker_id: &SpeakerId, new_ip: IpAddr)

Update a speaker’s IP address in both the store and the reverse map.

Source

pub fn get_satellite_ids(&self) -> Vec<SpeakerId>

Get all satellite speaker IDs from topology data.

Source

pub fn set_satellite_ids(&self, ids: Vec<SpeakerId>)

Store satellite speaker IDs from topology data.

Source

pub fn iter(&self) -> ChangeIterator

Create a blocking iterator over change events

Only emits events for properties that have been watched.

Each call returns an independent iterator: every iterator receives every event, so two event loops both see the whole stream instead of splitting it between them. An iterator only receives events emitted after it was created, so take it before the writes you want to observe.

Each iterator owns an unbounded queue, so a slow consumer never loses an event and never blocks a fast one — and never drains means never bounded.

§Example
// First, watch some properties
speaker.volume.watch()?;

// Then iterate over changes — the new value rides along on the event
for event in manager.iter() {
    match &event.change {
        PropertyChange::Volume(v) => println!("volume -> {}%", v.value()),
        other => println!("{} changed", other.key()),
    }
}
Source

pub fn get_property<P: SonosProperty>( &self, speaker_id: &SpeakerId, ) -> Option<P>

Get current property value (sync, no subscription)

For PerCoordinator speaker-scoped properties, this transparently reads from the coordinator’s store, so group members see the coordinator’s value.

Source

pub fn get_group_property<P: Property>(&self, group_id: &GroupId) -> Option<P>

Get current group property value (sync, no subscription)

Source

pub fn set_property<P: SonosProperty>(&self, speaker_id: &SpeakerId, value: P)

Set a property value

Updates the property value in the store and emits a change event if the property is being watched.

The write is routed the same way Self::get_property reads: for a PerCoordinator speaker-scoped property, the value lands in the coordinator’s bag, because get_resolved reads it from there. Writing the raw speaker_id instead put the value in a bag nothing ever reads — so speaker.play() on a grouped member updated a cache entry that playback_state.get() could not see, and the UI kept showing the old state until an event arrived.

The notification is still keyed on the requesting speaker, so a member watching the property is woken by its own write. The coordinator’s own watchers are reached by the worker’s group fan-out on the next event.

Stamped ChangeSource::LocalAction as of now. Use Self::set_property_stamped for a fetch() result, whose observation predates the write by a full network round trip.

Source

pub fn set_property_stamped<P: SonosProperty>( &self, speaker_id: &SpeakerId, value: P, stamp: WriteStamp, ) -> WriteOutcome

Set a property value with explicit write provenance.

Rejected without effect if stamp is older than the observation already stored — see WriteStamp. Returns the outcome so a caller can tell a rejected write from an accepted one.

Source

pub fn set_group_property<P: SonosProperty>(&self, group_id: &GroupId, value: P)

Set a group property value

Updates the group property value in the store and emits a change event if the property is being watched (keyed on the coordinator’s speaker ID). Used by the SDK layer to store group-scoped values fetched via API calls.

Stamped ChangeSource::LocalAction; see Self::set_group_property_stamped for fetch() results.

Source

pub fn set_group_property_stamped<P: SonosProperty>( &self, group_id: &GroupId, value: P, stamp: WriteStamp, ) -> WriteOutcome

Set a group property value with explicit write provenance.

Rejected without effect if stamp is older than the observation already stored — see WriteStamp.

Source

pub fn register_watch(&self, speaker_id: &SpeakerId, property_key: &'static str)

Register a property as watched (called by PropertyHandle::watch)

Adds one reference. Balanced by Self::unregister_watch; the property keeps emitting until every registration has been unregistered.

Source

pub fn unregister_watch( &self, speaker_id: &SpeakerId, property_key: &'static str, )

Unregister a property watch

Releases one reference taken by Self::register_watch. The property stops being watched only when the last reference is released, so one watcher going away cannot silence its siblings. Unregistering something that was never registered is a no-op.

Source

pub fn watch_property_with_subscription<P: SonosProperty>( &self, speaker_id: &SpeakerId, ) -> Result<Option<P>>

Watch a property with automatic UPnP subscription (recommended API)

This is the preferred method for watching properties as it:

  1. Registers the property for change notifications
  2. Subscribes to the UPnP service via the event manager

Returns the current cached value if available.

Source

pub fn unwatch_property_with_subscription<P: SonosProperty>( &self, speaker_id: &SpeakerId, )

Unwatch a property and release UPnP subscription

Source

pub fn is_watched( &self, speaker_id: &SpeakerId, property_key: &'static str, ) -> bool

Check if a property is being watched

Source

pub fn initialize(&self, topology: Topology)

Initialize from topology data

Source

pub fn is_initialized(&self) -> bool

Check if initialized with any speakers

Source

pub fn speaker_count(&self) -> usize

Get number of speakers

Source

pub fn group_count(&self) -> usize

Get number of groups

Source

pub fn groups(&self) -> Vec<GroupInfo>

Get all current groups

Returns all groups in the system. Every speaker is always in a group, so a single speaker forms a group of one.

Source

pub fn get_group(&self, group_id: &GroupId) -> Option<GroupInfo>

Get a specific group by ID

Source

pub fn get_group_for_speaker(&self, speaker_id: &SpeakerId) -> Option<GroupInfo>

Get the group a speaker belongs to

Uses the speaker_to_group mapping for quick lookup.

Source

pub fn resolve_subscription_target( &self, speaker_id: &SpeakerId, speaker_ip: IpAddr, service: Service, ) -> (SpeakerId, IpAddr)

Resolve the subscription target for a PerCoordinator service.

For PerCoordinator services, returns the coordinator’s (SpeakerId, IpAddr) so the SDK can route UPnP subscriptions to the coordinator speaker. Falls back to the speaker itself if no group data exists.

For non-PerCoordinator services, returns the speaker’s own identity.

Source

pub fn event_manager(&self) -> Option<&Arc<SonosEventManager>>

Get access to the event manager (if configured)

This allows PropertyHandle::watch() to trigger UPnP subscriptions via the event manager’s ensure_service_subscribed() method.

Source

pub fn set_event_manager(&self, em: Arc<SonosEventManager>) -> Result<()>

Wire an event manager into this StateManager after construction.

Spawns the event worker thread and registers all known devices. Can only be called once — subsequent calls are no-ops.

Source

pub fn set_event_init(&self, f: EventInitFn)

Set the lazy event manager initialization closure.

Called once by SonosSystem::from_devices_inner() after construction. Subsequent calls are no-ops (OnceLock semantics).

Source

pub fn event_init(&self) -> Option<&EventInitFn>

Get the event init closure (if set).

Used by PropertyHandle::watch() and GroupPropertyHandle::watch() to trigger lazy event manager creation on first use.

Trait Implementations§

Source§

impl Clone for StateManager

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

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

Source§

type Error = Infallible

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.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more