Skip to main content

sonos_api/
lib.rs

1//! High-level Sonos API for device control
2//!
3//! This crate provides a type-safe, trait-based API for controlling Sonos devices.
4//! It uses the private `soap-client` crate for low-level SOAP communication.
5//!
6//! # UPnP Architecture
7//!
8//! This API correctly implements the UPnP architecture used by Sonos devices:
9//!
10//! - **Control Operations**: Commands like Play, Pause, SetVolume are sent to `/Control` endpoints
11//! - **Event Subscriptions**: Subscriptions for state change notifications are sent to `/Event` endpoints
12//!
13//! These are completely separate and independent concepts that work together to provide
14//! both control and monitoring capabilities.
15//!
16//! # Enhanced Operation Framework
17//!
18//! The operation framework provides composable, declarative UPnP operations with validation,
19//! retry policies, and timeouts:
20//!
21//! ```rust,ignore
22//! use sonos_api::{SonosClient, services::av_transport, services::rendering_control};
23//! use sonos_api::operation::ValidationLevel;
24//!
25//! let client = SonosClient::new();
26//!
27//! // Simple operation execution
28//! let play_op = av_transport::play("1".to_string())
29//!     .with_validation(ValidationLevel::Comprehensive)
30//!     .build()?;
31//!
32//! client.execute_enhanced("192.168.1.100", play_op)?;
33//!
34//! // Composed operations
35//! let sequence = av_transport::play("1".to_string())
36//!     .build()?
37//!     .and_then(rendering_control::set_volume("Master".to_string(), 75).build()?);
38//!
39//! client.execute_sequence("192.168.1.100", sequence)?;
40//! ```
41//!
42//! # Event Subscription Management
43//!
44//! UPnP event subscriptions allow you to receive real-time state change notifications
45//! from Sonos devices. Subscriptions are managed separately from control operations:
46//!
47//! ## Client-Level Subscriptions
48//!
49//! Subscribe directly to any service using the client:
50//!
51//! ```rust,ignore
52//! use sonos_api::{SonosClient, Service};
53//!
54//! let client = SonosClient::new();
55//!
56//! // Subscribe to AVTransport events (play/pause state changes)
57//! let av_subscription = client.subscribe(
58//!     "192.168.1.100",
59//!     Service::AVTransport,
60//!     "http://192.168.1.50:8080/callback"
61//! )?;
62//!
63//! // Subscribe to RenderingControl events (volume changes)
64//! let rc_subscription = client.subscribe(
65//!     "192.168.1.100",
66//!     Service::RenderingControl,
67//!     "http://192.168.1.50:8080/callback"
68//! )?;
69//!
70//! // Custom timeout (default is 1800 seconds)
71//! let long_subscription = client.subscribe_with_timeout(
72//!     "192.168.1.100",
73//!     Service::AVTransport,
74//!     "http://192.168.1.50:8080/callback",
75//!     7200  // 2 hours
76//! )?;
77//! ```
78//!
79//! ## Service-Level Subscription Helpers
80//!
81//! Each service module provides convenient subscription helpers:
82//!
83//! ```rust,ignore
84//! use sonos_api::{SonosClient, services::av_transport, services::rendering_control};
85//!
86//! let client = SonosClient::new();
87//!
88//! // Subscribe to specific services using module helpers
89//! let av_subscription = av_transport::subscribe(
90//!     &client,
91//!     "192.168.1.100",
92//!     "http://192.168.1.50:8080/callback"
93//! )?;
94//!
95//! let rc_subscription = rendering_control::subscribe(
96//!     &client,
97//!     "192.168.1.100",
98//!     "http://192.168.1.50:8080/callback"
99//! )?;
100//!
101//! // With custom timeout
102//! let long_av_subscription = av_transport::subscribe_with_timeout(
103//!     &client,
104//!     "192.168.1.100",
105//!     "http://192.168.1.50:8080/callback",
106//!     3600
107//! )?;
108//! ```
109//!
110//! ## Subscription Lifecycle Management
111//!
112//! All subscriptions return a `ManagedSubscription` that handles lifecycle management:
113//!
114//! ```rust,ignore
115//! let subscription = client.subscribe(
116//!     "192.168.1.100",
117//!     Service::AVTransport,
118//!     "http://192.168.1.50:8080/callback"
119//! )?;
120//!
121//! // Check if renewal is needed and renew if so
122//! if subscription.needs_renewal() {
123//!     subscription.renew()?;
124//! }
125//!
126//! // Clean up when done
127//! subscription.unsubscribe()?;
128//! ```
129//!
130//! The `ManagedSubscription` handles all lifecycle management including expiration tracking,
131//! renewal logic, and proper cleanup.
132//!
133//! ## Control Operations and Subscriptions Together
134//!
135//! Control operations and subscriptions work independently but can be used together:
136//!
137//! ```rust,ignore
138//! use sonos_api::{SonosClient, Service, services::av_transport};
139//!
140//! let client = SonosClient::new();
141//!
142//! // Set up event subscription first
143//! let subscription = client.subscribe(
144//!     "192.168.1.100",
145//!     Service::AVTransport,
146//!     "http://192.168.1.50:8080/callback"
147//! )?;
148//!
149//! // Execute control operations
150//! let play_op = av_transport::play("1".to_string()).build()?;
151//! client.execute_enhanced("192.168.1.100", play_op)?;
152//!
153//! // The subscription will receive events about state changes
154//! // caused by the control operations
155//! ```
156
157// This workspace contains no `unsafe` code. Asserted here so a future
158// addition is a hard compile error, not a silent change in guarantees.
159#![forbid(unsafe_code)]
160
161pub mod client;
162pub mod error;
163pub mod events;
164pub mod operation; // Enhanced operation framework
165pub mod service;
166pub mod services; // Enhanced services
167pub mod subscription; // New event handling framework
168pub mod types;
169
170// Common types shared across the workspace
171pub use types::{GroupId, SpeakerId};
172
173// Legacy exports for backward compatibility
174pub use client::SonosClient;
175pub use error::{ApiError, Result};
176pub use operation::SonosOperation; // Legacy trait
177pub use service::{Service, ServiceInfo, ServiceScope};
178pub use subscription::ManagedSubscription;
179
180// New enhanced operation framework exports
181pub use operation::{
182    OperationBuilder, OperationMetadata, UPnPOperation, Validate, ValidationError, ValidationLevel,
183};
184
185// New event handling framework exports
186pub use events::{EnrichedEvent, EventParser, EventParserRegistry, EventProcessor, EventSource};
187
188// Enhanced services are available through the services module