@@ -17,7 +17,10 @@ use crate::{
1717 player:: { Player , PlayerEvent , PlayerEventChannel , QueueTrack } ,
1818 } ,
1919 protocol:: {
20- connect:: { Cluster , ClusterUpdate , LogoutCommand , SetVolumeCommand } ,
20+ connect:: {
21+ Cluster , ClusterUpdate , ClusterUpdateReason as ServerClusterUpdateReason ,
22+ LogoutCommand , SetVolumeCommand ,
23+ } ,
2124 context:: Context ,
2225 explicit_content_pubsub:: UserAttributesUpdate ,
2326 player:: ProvidedTrack ,
@@ -36,14 +39,15 @@ use crate::{
3639use futures_util:: StreamExt ;
3740use protobuf:: MessageField ;
3841use std:: {
42+ collections:: HashMap ,
3943 future:: Future ,
4044 sync:: Arc ,
4145 sync:: atomic:: { AtomicUsize , Ordering } ,
4246 time:: { Duration , SystemTime , UNIX_EPOCH } ,
4347} ;
4448use thiserror:: Error ;
4549use tokio:: {
46- sync:: { broadcast, mpsc} ,
50+ sync:: { broadcast, mpsc, watch } ,
4751 time:: sleep,
4852} ;
4953
@@ -72,6 +76,103 @@ impl From<SpircError> for Error {
7276 }
7377}
7478
79+ /// Information about a device in the cluster
80+ #[ derive( Debug , Clone ) ]
81+ pub struct DeviceInfo {
82+ /// Unique device identifier
83+ pub device_id : String ,
84+ /// Human-readable device name
85+ pub device_alias : String ,
86+ /// Device type (e.g., "Speaker", "Phone")
87+ pub device_type : String ,
88+ /// Volume level 0-100
89+ pub volume : u32 ,
90+ /// Whether this is the currently active device
91+ pub is_active : bool ,
92+ }
93+
94+ /// Current state of the device cluster (all known devices)
95+ #[ derive( Debug , Clone ) ]
96+ pub struct ClusterState {
97+ /// Map of all known devices by device_id
98+ pub devices : HashMap < String , DeviceInfo > ,
99+ /// Currently active device ID (if any)
100+ pub active_device_id : Option < String > ,
101+ }
102+
103+ /// Queue information (previous and next tracks)
104+ #[ derive( Debug , Clone ) ]
105+ pub struct QueueList {
106+ /// Previous tracks in the queue (as URIs)
107+ pub prev_tracks : Vec < String > ,
108+ /// Next tracks in the queue (as URIs)
109+ pub next_tracks : Vec < String > ,
110+ }
111+
112+ /// Semantic reason for cluster updates
113+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
114+ pub enum ClusterUpdateReason {
115+ /// Device list changed
116+ DeviceListChanged ,
117+ /// Active device switched
118+ ActiveDeviceChanged ,
119+ /// Device state changed
120+ DeviceStateChanged ,
121+ /// Device info changed
122+ DeviceInfoChanged ,
123+ }
124+
125+ /// Event emitted when cluster state changes
126+ #[ derive( Debug , Clone ) ]
127+ pub struct ClusterUpdateEvent {
128+ /// Device ID that changed
129+ pub device_id : String ,
130+ /// Reason for the update
131+ pub reason : ClusterUpdateReason ,
132+ }
133+
134+ /// Semantic reasons for queue updates
135+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
136+ pub enum QueueUpdateReason {
137+ /// Previous tracks changed
138+ PrevTracksChanged ,
139+ /// Next tracks changed
140+ NextTracksChanged ,
141+ }
142+
143+ /// Event emitted when queue changes
144+ #[ derive( Debug , Clone ) ]
145+ pub struct QueueUpdateEvent {
146+ /// Reason for the queue update
147+ pub reason : QueueUpdateReason ,
148+ }
149+
150+ /// Semantic reasons for player state updates
151+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
152+ pub enum PlayerUpdateReason {
153+ /// Track changed
154+ TrackChanged ,
155+ /// Position changed
156+ PositionChanged ,
157+ /// Play/pause state changed
158+ PlayPauseChanged ,
159+ /// Shuffle mode changed
160+ ShuffleChanged ,
161+ /// Repeat mode changed
162+ RepeatChanged ,
163+ /// Context changed
164+ ContextChanged ,
165+ /// Other state change
166+ Other ,
167+ }
168+
169+ /// Emitted when player state changes
170+ #[ derive( Debug , Clone ) ]
171+ pub struct PlayerUpdateEvent {
172+ /// Reason for the player update
173+ pub reason : PlayerUpdateReason ,
174+ }
175+
75176struct SpircTask {
76177 player : Arc < Player > ,
77178 mixer : Arc < dyn Mixer > ,
0 commit comments