1use crate::{
7 types::{Position3D, SpatialResult},
8 Error, Result,
9};
10use serde::{Deserialize, Serialize};
11use std::collections::HashMap;
12use tracing::{info, warn};
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct SmartSpeaker {
17 pub id: String,
19 pub position: Position3D,
21 pub capabilities: SpeakerCapabilities,
23 pub network_info: NetworkInfo,
25 pub calibration: CalibrationStatus,
27 pub audio_specs: AudioSpecs,
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct SpeakerCapabilities {
34 pub frequency_range: (f32, f32),
36 pub max_spl: f32,
38 pub driver_count: u8,
40 pub directivity: DirectivityPattern,
42 pub dsp_features: Vec<DspFeature>,
44 pub supported_formats: Vec<AudioFormat>,
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct NetworkInfo {
51 pub ip_address: String,
53 pub mac_address: String,
55 pub protocol: NetworkProtocol,
57 pub signal_strength: u8,
59 pub latency_ms: f32,
61 pub bandwidth_mbps: f32,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct CalibrationStatus {
68 pub is_calibrated: bool,
70 pub calibrated_at: Option<chrono::DateTime<chrono::Utc>>,
72 pub room_correction: Option<RoomCorrection>,
74 pub inter_speaker_distances: HashMap<String, f32>,
76 pub delay_compensation_ms: f32,
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct AudioSpecs {
83 pub sample_rate: u32,
85 pub bit_depth: u16,
87 pub channels: u8,
89 pub buffer_size: usize,
91 pub codec_latency_ms: f32,
93}
94
95#[derive(Debug, Clone, Serialize, Deserialize)]
97pub enum DirectivityPattern {
98 Omnidirectional,
100 Cardioid,
102 Bidirectional,
104 Supercardioid,
106 Custom(Vec<(f32, f32)>), }
109
110#[derive(Debug, Clone, Serialize, Deserialize)]
112pub enum DspFeature {
113 RoomCorrection,
115 Compression,
117 ParametricEQ,
119 BassManagement,
121 Crossover,
123 TimeAlignment,
125 Beamforming,
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize)]
131pub enum AudioFormat {
132 PCM {
134 sample_rate: u32,
136 bit_depth: u16,
138 },
139 FLAC,
141 AAC {
143 bitrate_kbps: u32,
145 },
146 Opus {
148 bitrate_kbps: u32,
150 },
151 Custom(String),
153}
154
155#[derive(Debug, Clone, Serialize, Deserialize)]
157pub enum NetworkProtocol {
158 WiFi,
160 Ethernet,
162 Bluetooth,
164 AirPlay,
166 Chromecast,
168 Sonos,
170 Custom(String),
172}
173
174#[derive(Debug, Clone, Serialize, Deserialize)]
176pub struct RoomCorrection {
177 pub frequency_response: Vec<(f32, f32)>, pub impulse_response: Vec<f32>,
181 pub eq_filters: Vec<EQFilter>,
183 pub measurement_position: Position3D,
185}
186
187#[derive(Debug, Clone, Serialize, Deserialize)]
189pub struct EQFilter {
190 pub filter_type: FilterType,
192 pub frequency: f32,
194 pub q_factor: f32,
196 pub gain_db: f32,
198}
199
200#[derive(Debug, Clone, Serialize, Deserialize)]
202pub enum FilterType {
203 LowPass,
205 HighPass,
207 BandPass,
209 BandStop,
211 Peaking,
213 LowShelf,
215 HighShelf,
217}
218
219#[derive(Debug, Clone, Serialize, Deserialize)]
221pub struct SpeakerArrayConfig {
222 pub name: String,
224 pub room_dimensions: (f32, f32, f32),
226 pub listening_position: Position3D,
228 pub topology: ArrayTopology,
230 pub sync_config: SyncConfig,
232 pub processing_config: ProcessingConfig,
234 pub network_config: NetworkConfig,
236}
237
238#[derive(Debug, Clone, Serialize, Deserialize)]
240pub enum ArrayTopology {
241 Stereo {
243 separation_m: f32,
245 },
246 Surround5_1,
248 Surround7_1,
250 Atmos {
252 height_speakers: u8,
254 },
255 Distributed {
257 min_speakers: u8,
259 max_speakers: u8,
261 },
262 LineArray {
264 speaker_spacing_m: f32,
266 },
267 CircularArray {
269 radius_m: f32,
271 },
272 Custom,
274}
275
276#[derive(Debug, Clone, Serialize, Deserialize)]
278pub struct SyncConfig {
279 pub clock_source: ClockSource,
281 pub sync_tolerance_us: u32,
283 pub sync_buffer_size: usize,
285 pub jitter_compensation: bool,
287 pub auto_correction: bool,
289}
290
291#[derive(Debug, Clone, Serialize, Deserialize)]
293pub enum ClockSource {
294 NTP,
296 PTP,
298 SystemClock,
300 AudioClock,
302 WordClock,
304}
305
306#[derive(Debug, Clone, Serialize, Deserialize)]
308pub struct ProcessingConfig {
309 pub crossover_frequencies: Vec<f32>,
311 pub time_alignment: HashMap<String, f32>,
313 pub speaker_eq: HashMap<String, Vec<EQFilter>>,
315 pub compression: CompressionConfig,
317 pub limiting: LimitingConfig,
319 pub room_correction_enabled: bool,
321}
322
323#[derive(Debug, Clone, Serialize, Deserialize)]
325pub struct CompressionConfig {
326 pub enabled: bool,
328 pub threshold_db: f32,
330 pub ratio: f32,
332 pub attack_ms: f32,
334 pub release_ms: f32,
336 pub makeup_gain_db: f32,
338}
339
340#[derive(Debug, Clone, Serialize, Deserialize)]
342pub struct LimitingConfig {
343 pub enabled: bool,
345 pub ceiling_db: f32,
347 pub release_ms: f32,
349 pub lookahead_ms: f32,
351}
352
353#[derive(Debug, Clone, Serialize, Deserialize)]
355pub struct NetworkConfig {
356 pub multicast_group: String,
358 pub base_port: u16,
360 pub qos_priority: u8,
362 pub max_latency_ms: f32,
364 pub packet_size: usize,
366 pub buffer_size: usize,
368}
369
370#[derive(Debug)]
372pub struct SpeakerArrayManager {
373 speakers: HashMap<String, SmartSpeaker>,
375 arrays: HashMap<String, SpeakerArrayConfig>,
377 discovery: DiscoveryService,
379 calibration: CalibrationEngine,
381 router: AudioRouter,
383 metrics: ArrayMetrics,
385}
386
387#[derive(Debug)]
389pub struct DiscoveryService {
390 protocols: Vec<DiscoveryProtocol>,
392 discovery_interval: u64,
394 auto_add: bool,
396 device_filters: Vec<DeviceFilter>,
398}
399
400#[derive(Debug, Clone, Serialize, Deserialize)]
402pub enum DiscoveryProtocol {
403 UPnP,
405 Bonjour,
407 Chromecast,
409 AirPlay,
411 Sonos,
413 IPScan {
415 start_ip: String,
417 end_ip: String,
419 },
420}
421
422#[derive(Debug, Clone, Serialize, Deserialize)]
424pub struct DeviceFilter {
425 pub manufacturer: Option<String>,
427 pub model_pattern: Option<String>,
429 pub min_capabilities: Option<SpeakerCapabilities>,
431 pub network_requirements: Option<NetworkRequirements>,
433}
434
435#[derive(Debug, Clone, Serialize, Deserialize)]
437pub struct NetworkRequirements {
438 pub min_bandwidth_mbps: f32,
440 pub max_latency_ms: f32,
442 pub required_protocols: Vec<NetworkProtocol>,
444}
445
446#[derive(Debug, Clone, Serialize, Deserialize)]
448pub struct DiscoveredDevice {
449 pub id: String,
451 pub name: String,
453 pub manufacturer: String,
455 pub model: String,
457 pub ip_address: String,
459 pub mac_address: String,
461 pub protocol: NetworkProtocol,
463 pub capabilities: SpeakerCapabilities,
465 pub services: Vec<String>,
467}
468
469#[derive(Debug)]
471pub struct CalibrationEngine {
472 methods: Vec<CalibrationMethod>,
474 signal_generator: TestSignalGenerator,
476 analyzer: MeasurementAnalyzer,
478 optimizer: ArrayOptimizer,
480}
481
482#[derive(Debug, Clone, Serialize, Deserialize)]
484pub enum CalibrationMethod {
485 SweepTone {
487 start_hz: f32,
489 end_hz: f32,
491 duration_s: f32,
493 },
494 WhiteNoise {
496 duration_s: f32,
498 },
499 PinkNoise {
501 duration_s: f32,
503 },
504 MLS {
506 length: usize,
508 },
509 Chirp {
511 start_hz: f32,
513 end_hz: f32,
515 duration_s: f32,
517 },
518}
519
520#[derive(Debug)]
522pub struct TestSignalGenerator {
523 sample_rate: u32,
525 bit_depth: u16,
527 signal_level_db: f32,
529}
530
531#[derive(Debug)]
533pub struct MeasurementAnalyzer {
534 fft_size: usize,
536 window_function: WindowFunction,
538 smoothing_factor: f32,
540}
541
542#[derive(Debug, Clone, Serialize, Deserialize)]
544pub enum WindowFunction {
545 Rectangular,
547 Hanning,
549 Hamming,
551 Blackman,
553 Kaiser {
555 beta: f32,
557 },
558}
559
560#[derive(Debug)]
562pub struct ArrayOptimizer {
563 goals: Vec<OptimizationGoal>,
565 constraints: Vec<OptimizationConstraint>,
567 algorithm: OptimizationAlgorithm,
569}
570
571#[derive(Debug, Clone, Serialize, Deserialize)]
573pub enum OptimizationGoal {
574 FlatFrequencyResponse,
576 MaximizeSweetSpot,
578 MinimizeDelays,
580 MaximizeDynamicRange,
582 MinimizePower,
584 Custom(String),
586}
587
588#[derive(Debug, Clone, Serialize, Deserialize)]
590pub enum OptimizationConstraint {
591 MaxDelay(f32),
593 FrequencyResponseLimits {
595 min_db: f32,
597 max_db: f32,
599 },
600 PowerLimits(f32),
602 PhaseCoherence {
604 max_phase_error_deg: f32,
606 },
607}
608
609#[derive(Debug, Clone, Serialize, Deserialize)]
611pub enum OptimizationAlgorithm {
612 LeastSquares,
614 GeneticAlgorithm {
616 population_size: usize,
618 generations: usize,
620 },
621 SimulatedAnnealing {
623 initial_temp: f32,
625 cooling_rate: f32,
627 },
628 ParticleSwarm {
630 particles: usize,
632 iterations: usize,
634 },
635}
636
637#[derive(Debug)]
639pub struct AudioRouter {
640 routes: HashMap<String, AudioRoute>,
642 matrix: RoutingMatrix,
644 stream_manager: StreamManager,
646}
647
648#[derive(Debug, Clone, Serialize, Deserialize)]
650pub struct AudioRoute {
651 pub id: String,
653 pub source: AudioSource,
655 pub destinations: Vec<String>,
657 pub processing: Vec<ProcessingStep>,
659 pub mix_settings: MixSettings,
661}
662
663#[derive(Debug, Clone, Serialize, Deserialize)]
665pub enum AudioSource {
666 File {
668 path: String,
670 },
671 Stream {
673 url: String,
675 },
676 Microphone {
678 device_id: String,
680 },
681 LineIn {
683 channel: u8,
685 },
686 Bluetooth {
688 device_id: String,
690 },
691 AirPlay,
693 Chromecast,
695}
696
697#[derive(Debug, Clone, Serialize, Deserialize)]
699pub enum ProcessingStep {
700 Volume {
702 gain_db: f32,
704 },
705 EQ {
707 filters: Vec<EQFilter>,
709 },
710 Delay {
712 delay_ms: f32,
714 },
715 Compression(CompressionConfig),
717 Limiting(LimitingConfig),
719 SpatialUpmix {
721 target_channels: u8,
723 },
724 CustomDSP {
726 plugin_id: String,
728 parameters: HashMap<String, f32>,
730 },
731}
732
733#[derive(Debug, Clone, Serialize, Deserialize)]
735pub struct MixSettings {
736 pub level: f32,
738 pub pan: f32,
740 pub muted: bool,
742 pub solo: bool,
744 pub crossover_assignment: Option<CrossoverAssignment>,
746}
747
748#[derive(Debug, Clone, Serialize, Deserialize)]
750pub struct CrossoverAssignment {
751 pub low_freq_speakers: Vec<String>,
753 pub mid_freq_speakers: Vec<String>,
755 pub high_freq_speakers: Vec<String>,
757 pub crossover_frequencies: Vec<f32>,
759}
760
761#[derive(Debug)]
763pub struct RoutingMatrix {
764 matrix: Vec<Vec<f32>>, input_count: usize,
768 output_count: usize,
770}
771
772#[derive(Debug)]
774pub struct StreamManager {
775 streams: HashMap<String, AudioStream>,
777 stats: StreamStats,
779 buffer_manager: BufferManager,
781}
782
783#[derive(Debug)]
785pub struct AudioStream {
786 pub id: String,
788 pub format: AudioFormat,
790 pub speakers: Vec<String>,
792 pub state: StreamState,
794 pub metrics: StreamMetrics,
796}
797
798#[derive(Debug, Clone, Serialize, Deserialize)]
800pub enum StreamState {
801 Starting,
803 Running,
805 Buffering,
807 Paused,
809 Stopped,
811 Error(String),
813}
814
815#[derive(Debug, Clone, Serialize, Deserialize)]
817pub struct StreamMetrics {
818 pub bitrate_kbps: f32,
820 pub packet_loss_rate: f32,
822 pub jitter_ms: f32,
824 pub buffer_level: f32,
826 pub dropouts: u32,
828}
829
830#[derive(Debug, Clone, Serialize, Deserialize)]
832pub struct StreamStats {
833 pub total_streams: u64,
835 pub active_streams: u32,
837 pub total_bytes: u64,
839 pub avg_bitrate_kbps: f32,
841}
842
843#[derive(Debug)]
845pub struct BufferManager {
846 pools: HashMap<String, Vec<AudioBuffer>>,
848 stats: BufferStats,
850}
851
852#[derive(Debug)]
854pub struct AudioBuffer {
855 pub data: Vec<f32>,
857 pub sample_rate: u32,
859 pub channels: u8,
861 pub timestamp: chrono::DateTime<chrono::Utc>,
863}
864
865#[derive(Debug, Clone, Serialize, Deserialize)]
867pub struct BufferStats {
868 pub underruns: u32,
870 pub overruns: u32,
872 pub avg_buffer_level: f32,
874 pub peak_buffer_usage: f32,
876}
877
878#[derive(Debug, Clone, Serialize, Deserialize)]
880pub struct ArrayMetrics {
881 pub system_latency_ms: f32,
883 pub network_utilization: f32,
885 pub cpu_usage: f32,
887 pub memory_usage_mb: f32,
889 pub active_speakers: u32,
891 pub audio_quality_score: f32,
893 pub sync_accuracy_us: f32,
895}
896
897impl SpeakerArrayManager {
898 pub fn new() -> Self {
900 Self {
901 speakers: HashMap::new(),
902 arrays: HashMap::new(),
903 discovery: DiscoveryService::new(),
904 calibration: CalibrationEngine::new(),
905 router: AudioRouter::new(),
906 metrics: ArrayMetrics::default(),
907 }
908 }
909
910 pub async fn start_discovery(&mut self) -> Result<()> {
912 info!("Starting speaker discovery");
913 self.discovery.start().await?;
914 Ok(())
915 }
916
917 pub fn add_speaker(&mut self, speaker: SmartSpeaker) -> Result<()> {
919 info!("Adding speaker: {}", speaker.id);
920 self.speakers.insert(speaker.id.clone(), speaker);
921 Ok(())
922 }
923
924 pub fn remove_speaker(&mut self, speaker_id: &str) -> Result<()> {
926 if self.speakers.remove(speaker_id).is_some() {
927 info!("Removed speaker: {}", speaker_id);
928 Ok(())
929 } else {
930 Err(Error::processing("Speaker not found"))
931 }
932 }
933
934 pub fn create_array(&mut self, config: SpeakerArrayConfig) -> Result<()> {
936 info!("Creating speaker array: {}", config.name);
937
938 for speaker_id in self.get_required_speakers(&config)? {
940 if !self.speakers.contains_key(&speaker_id) {
941 return Err(Error::config(&format!("Speaker {speaker_id} not found")));
942 }
943 }
944
945 self.arrays.insert(config.name.clone(), config);
946 Ok(())
947 }
948
949 pub async fn calibrate_array(&mut self, array_name: &str) -> Result<CalibrationResults> {
951 let array = self
952 .arrays
953 .get(array_name)
954 .ok_or_else(|| Error::config("Array not found"))?;
955
956 info!("Starting calibration for array: {}", array_name);
957 self.calibration
958 .calibrate_array(array, &self.speakers)
959 .await
960 }
961
962 pub async fn start_routing(&mut self, routes: Vec<AudioRoute>) -> Result<()> {
964 for route in routes {
965 self.router.add_route(route).await?;
966 }
967 Ok(())
968 }
969
970 pub fn get_metrics(&self) -> &ArrayMetrics {
972 &self.metrics
973 }
974
975 pub fn update_metrics(&mut self) {
977 self.metrics = self.calculate_metrics();
978 }
979
980 pub fn get_speakers(&self) -> &HashMap<String, SmartSpeaker> {
982 &self.speakers
983 }
984
985 pub fn get_array(&self, name: &str) -> Option<&SpeakerArrayConfig> {
987 self.arrays.get(name)
988 }
989
990 fn get_required_speakers(&self, config: &SpeakerArrayConfig) -> Result<Vec<String>> {
991 match &config.topology {
993 ArrayTopology::Stereo { .. } => Ok(vec!["left".to_string(), "right".to_string()]),
994 ArrayTopology::Surround5_1 => Ok(vec![
995 "front_left".to_string(),
996 "front_right".to_string(),
997 "center".to_string(),
998 "lfe".to_string(),
999 "rear_left".to_string(),
1000 "rear_right".to_string(),
1001 ]),
1002 _ => Ok(self.speakers.keys().cloned().collect()),
1003 }
1004 }
1005
1006 fn calculate_metrics(&self) -> ArrayMetrics {
1007 ArrayMetrics {
1008 system_latency_ms: 50.0, network_utilization: 25.0,
1010 cpu_usage: 15.0,
1011 memory_usage_mb: 128.0,
1012 active_speakers: self.speakers.len() as u32,
1013 audio_quality_score: 85.0,
1014 sync_accuracy_us: 100.0,
1015 }
1016 }
1017}
1018
1019impl Default for SpeakerArrayManager {
1020 fn default() -> Self {
1021 Self::new()
1022 }
1023}
1024
1025impl DiscoveryService {
1026 fn new() -> Self {
1027 Self {
1028 protocols: vec![DiscoveryProtocol::UPnP, DiscoveryProtocol::Bonjour],
1029 discovery_interval: 30,
1030 auto_add: false,
1031 device_filters: Vec::new(),
1032 }
1033 }
1034
1035 async fn start(&self) -> Result<()> {
1036 info!(
1037 "Starting discovery service with {} protocols",
1038 self.protocols.len()
1039 );
1040
1041 for protocol in &self.protocols {
1042 match self.discover_with_protocol(protocol).await {
1043 Ok(devices) => {
1044 info!("Discovered {} devices with {:?}", devices.len(), protocol);
1045 }
1046 Err(e) => {
1047 warn!("Discovery failed for {:?}: {}", protocol, e);
1048 }
1049 }
1050 }
1051
1052 Ok(())
1053 }
1054
1055 async fn discover_with_protocol(
1056 &self,
1057 protocol: &DiscoveryProtocol,
1058 ) -> Result<Vec<DiscoveredDevice>> {
1059 match protocol {
1060 DiscoveryProtocol::UPnP => self.discover_upnp().await,
1061 DiscoveryProtocol::Bonjour => self.discover_bonjour().await,
1062 DiscoveryProtocol::Chromecast => self.discover_chromecast().await,
1063 DiscoveryProtocol::AirPlay => self.discover_airplay().await,
1064 DiscoveryProtocol::Sonos => self.discover_sonos().await,
1065 DiscoveryProtocol::IPScan { start_ip, end_ip } => {
1066 self.discover_ip_scan(start_ip, end_ip).await
1067 }
1068 }
1069 }
1070
1071 async fn discover_upnp(&self) -> Result<Vec<DiscoveredDevice>> {
1072 info!("Starting UPnP discovery");
1073
1074 let devices = vec![
1076 DiscoveredDevice {
1077 id: "upnp_speaker_1".to_string(),
1078 name: "Living Room Speaker".to_string(),
1079 manufacturer: "Generic UPnP".to_string(),
1080 model: "Smart Speaker".to_string(),
1081 ip_address: "192.168.1.101".to_string(),
1082 mac_address: "AA:BB:CC:DD:EE:01".to_string(),
1083 protocol: NetworkProtocol::WiFi,
1084 capabilities: self.create_default_capabilities(),
1085 services: vec!["MediaRenderer".to_string(), "AudioControl".to_string()],
1086 },
1087 DiscoveredDevice {
1088 id: "upnp_speaker_2".to_string(),
1089 name: "Kitchen Speaker".to_string(),
1090 manufacturer: "Generic UPnP".to_string(),
1091 model: "Smart Speaker Pro".to_string(),
1092 ip_address: "192.168.1.102".to_string(),
1093 mac_address: "AA:BB:CC:DD:EE:02".to_string(),
1094 protocol: NetworkProtocol::WiFi,
1095 capabilities: self.create_enhanced_capabilities(),
1096 services: vec![
1097 "MediaRenderer".to_string(),
1098 "AudioControl".to_string(),
1099 "RoomCorrection".to_string(),
1100 ],
1101 },
1102 ];
1103
1104 tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
1106
1107 Ok(devices)
1108 }
1109
1110 async fn discover_bonjour(&self) -> Result<Vec<DiscoveredDevice>> {
1111 info!("Starting Bonjour/mDNS discovery");
1112
1113 let devices = vec![DiscoveredDevice {
1115 id: "bonjour_speaker_1".to_string(),
1116 name: "Bedroom Speaker".to_string(),
1117 manufacturer: "Apple".to_string(),
1118 model: "HomePod mini".to_string(),
1119 ip_address: "192.168.1.103".to_string(),
1120 mac_address: "AA:BB:CC:DD:EE:03".to_string(),
1121 protocol: NetworkProtocol::AirPlay,
1122 capabilities: self.create_airplay_capabilities(),
1123 services: vec!["AirPlay".to_string(), "HomeKit".to_string()],
1124 }];
1125
1126 tokio::time::sleep(tokio::time::Duration::from_millis(150)).await;
1127
1128 Ok(devices)
1129 }
1130
1131 async fn discover_chromecast(&self) -> Result<Vec<DiscoveredDevice>> {
1132 info!("Starting Chromecast discovery");
1133
1134 let devices = vec![DiscoveredDevice {
1135 id: "chromecast_audio_1".to_string(),
1136 name: "Office Audio".to_string(),
1137 manufacturer: "Google".to_string(),
1138 model: "Chromecast Audio".to_string(),
1139 ip_address: "192.168.1.104".to_string(),
1140 mac_address: "AA:BB:CC:DD:EE:04".to_string(),
1141 protocol: NetworkProtocol::Chromecast,
1142 capabilities: self.create_chromecast_capabilities(),
1143 services: vec!["Cast".to_string(), "GoogleCast".to_string()],
1144 }];
1145
1146 tokio::time::sleep(tokio::time::Duration::from_millis(200)).await;
1147
1148 Ok(devices)
1149 }
1150
1151 async fn discover_airplay(&self) -> Result<Vec<DiscoveredDevice>> {
1152 info!("Starting AirPlay discovery");
1153
1154 let devices = vec![DiscoveredDevice {
1155 id: "airplay_speaker_1".to_string(),
1156 name: "Studio Monitor".to_string(),
1157 manufacturer: "Apple".to_string(),
1158 model: "HomePod".to_string(),
1159 ip_address: "192.168.1.105".to_string(),
1160 mac_address: "AA:BB:CC:DD:EE:05".to_string(),
1161 protocol: NetworkProtocol::AirPlay,
1162 capabilities: self.create_airplay_capabilities(),
1163 services: vec!["AirPlay2".to_string(), "Siri".to_string()],
1164 }];
1165
1166 tokio::time::sleep(tokio::time::Duration::from_millis(180)).await;
1167
1168 Ok(devices)
1169 }
1170
1171 async fn discover_sonos(&self) -> Result<Vec<DiscoveredDevice>> {
1172 info!("Starting Sonos discovery");
1173
1174 let devices = vec![DiscoveredDevice {
1175 id: "sonos_speaker_1".to_string(),
1176 name: "Sonos One".to_string(),
1177 manufacturer: "Sonos".to_string(),
1178 model: "One SL".to_string(),
1179 ip_address: "192.168.1.106".to_string(),
1180 mac_address: "AA:BB:CC:DD:EE:06".to_string(),
1181 protocol: NetworkProtocol::Sonos,
1182 capabilities: self.create_sonos_capabilities(),
1183 services: vec!["SonosZone".to_string(), "GroupManagement".to_string()],
1184 }];
1185
1186 tokio::time::sleep(tokio::time::Duration::from_millis(120)).await;
1187
1188 Ok(devices)
1189 }
1190
1191 async fn discover_ip_scan(
1192 &self,
1193 start_ip: &str,
1194 end_ip: &str,
1195 ) -> Result<Vec<DiscoveredDevice>> {
1196 info!("Starting IP scan from {} to {}", start_ip, end_ip);
1197
1198 let start_parts: Vec<&str> = start_ip.split('.').collect();
1200 let end_parts: Vec<&str> = end_ip.split('.').collect();
1201
1202 if start_parts.len() != 4 || end_parts.len() != 4 {
1203 return Err(Error::config("Invalid IP range format"));
1204 }
1205
1206 let start_last: u8 = start_parts[3]
1207 .parse()
1208 .map_err(|_| Error::config("Invalid start IP"))?;
1209 let end_last: u8 = end_parts[3]
1210 .parse()
1211 .map_err(|_| Error::config("Invalid end IP"))?;
1212 let base_ip = format!("{}.{}.{}", start_parts[0], start_parts[1], start_parts[2]);
1213
1214 let mut devices = Vec::new();
1215
1216 for ip_last in start_last..=end_last {
1217 let ip = format!("{base_ip}.{ip_last}");
1218
1219 if self.ping_and_scan(&ip).await? {
1221 devices.push(DiscoveredDevice {
1222 id: format!("ip_speaker_{ip_last}"),
1223 name: format!("Audio Device {ip_last}"),
1224 manufacturer: "Unknown".to_string(),
1225 model: "Generic Audio Device".to_string(),
1226 ip_address: ip,
1227 mac_address: format!("FF:FF:FF:FF:FF:{ip_last:02X}"),
1228 protocol: NetworkProtocol::Custom("TCP".to_string()),
1229 capabilities: self.create_default_capabilities(),
1230 services: vec!["Audio".to_string()],
1231 });
1232 }
1233
1234 tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
1236 }
1237
1238 Ok(devices)
1239 }
1240
1241 async fn ping_and_scan(&self, ip: &str) -> Result<bool> {
1242 let hash = ip.chars().map(|c| c as u32).sum::<u32>();
1245 let is_responsive = (hash % 7) == 0; tokio::time::sleep(tokio::time::Duration::from_millis(5)).await;
1248 Ok(is_responsive)
1249 }
1250
1251 fn create_default_capabilities(&self) -> SpeakerCapabilities {
1252 SpeakerCapabilities {
1253 frequency_range: (50.0, 18000.0),
1254 max_spl: 95.0,
1255 driver_count: 2,
1256 directivity: DirectivityPattern::Omnidirectional,
1257 dsp_features: vec![DspFeature::ParametricEQ],
1258 supported_formats: vec![
1259 AudioFormat::PCM {
1260 sample_rate: 48000,
1261 bit_depth: 16,
1262 },
1263 AudioFormat::AAC { bitrate_kbps: 256 },
1264 ],
1265 }
1266 }
1267
1268 fn create_enhanced_capabilities(&self) -> SpeakerCapabilities {
1269 SpeakerCapabilities {
1270 frequency_range: (40.0, 20000.0),
1271 max_spl: 105.0,
1272 driver_count: 3,
1273 directivity: DirectivityPattern::Cardioid,
1274 dsp_features: vec![
1275 DspFeature::RoomCorrection,
1276 DspFeature::ParametricEQ,
1277 DspFeature::Compression,
1278 DspFeature::TimeAlignment,
1279 ],
1280 supported_formats: vec![
1281 AudioFormat::PCM {
1282 sample_rate: 96000,
1283 bit_depth: 24,
1284 },
1285 AudioFormat::FLAC,
1286 AudioFormat::AAC { bitrate_kbps: 320 },
1287 ],
1288 }
1289 }
1290
1291 fn create_airplay_capabilities(&self) -> SpeakerCapabilities {
1292 SpeakerCapabilities {
1293 frequency_range: (45.0, 22000.0),
1294 max_spl: 100.0,
1295 driver_count: 4,
1296 directivity: DirectivityPattern::Custom(vec![
1297 (0.0, 0.0),
1298 (45.0, -1.0),
1299 (90.0, -3.0),
1300 (135.0, -6.0),
1301 (180.0, -10.0),
1302 (225.0, -6.0),
1303 (270.0, -3.0),
1304 (315.0, -1.0),
1305 ]),
1306 dsp_features: vec![
1307 DspFeature::RoomCorrection,
1308 DspFeature::BassManagement,
1309 DspFeature::Beamforming,
1310 ],
1311 supported_formats: vec![
1312 AudioFormat::PCM {
1313 sample_rate: 48000,
1314 bit_depth: 24,
1315 },
1316 AudioFormat::AAC { bitrate_kbps: 256 },
1317 ],
1318 }
1319 }
1320
1321 fn create_chromecast_capabilities(&self) -> SpeakerCapabilities {
1322 SpeakerCapabilities {
1323 frequency_range: (60.0, 16000.0),
1324 max_spl: 90.0,
1325 driver_count: 1,
1326 directivity: DirectivityPattern::Omnidirectional,
1327 dsp_features: vec![DspFeature::Compression],
1328 supported_formats: vec![
1329 AudioFormat::AAC { bitrate_kbps: 128 },
1330 AudioFormat::Opus { bitrate_kbps: 96 },
1331 ],
1332 }
1333 }
1334
1335 fn create_sonos_capabilities(&self) -> SpeakerCapabilities {
1336 SpeakerCapabilities {
1337 frequency_range: (50.0, 20000.0),
1338 max_spl: 98.0,
1339 driver_count: 2,
1340 directivity: DirectivityPattern::Bidirectional,
1341 dsp_features: vec![
1342 DspFeature::RoomCorrection,
1343 DspFeature::ParametricEQ,
1344 DspFeature::BassManagement,
1345 DspFeature::TimeAlignment,
1346 ],
1347 supported_formats: vec![
1348 AudioFormat::PCM {
1349 sample_rate: 48000,
1350 bit_depth: 16,
1351 },
1352 AudioFormat::FLAC,
1353 AudioFormat::AAC { bitrate_kbps: 320 },
1354 ],
1355 }
1356 }
1357}
1358
1359impl CalibrationEngine {
1360 fn new() -> Self {
1361 Self {
1362 methods: vec![
1363 CalibrationMethod::SweepTone {
1364 start_hz: 20.0,
1365 end_hz: 20000.0,
1366 duration_s: 10.0,
1367 },
1368 CalibrationMethod::PinkNoise { duration_s: 5.0 },
1369 ],
1370 signal_generator: TestSignalGenerator {
1371 sample_rate: 48000,
1372 bit_depth: 24,
1373 signal_level_db: -20.0,
1374 },
1375 analyzer: MeasurementAnalyzer {
1376 fft_size: 8192,
1377 window_function: WindowFunction::Hanning,
1378 smoothing_factor: 0.125,
1379 },
1380 optimizer: ArrayOptimizer {
1381 goals: vec![
1382 OptimizationGoal::FlatFrequencyResponse,
1383 OptimizationGoal::MaximizeSweetSpot,
1384 ],
1385 constraints: vec![
1386 OptimizationConstraint::MaxDelay(50.0),
1387 OptimizationConstraint::FrequencyResponseLimits {
1388 min_db: -6.0,
1389 max_db: 6.0,
1390 },
1391 ],
1392 algorithm: OptimizationAlgorithm::LeastSquares,
1393 },
1394 }
1395 }
1396
1397 async fn calibrate_array(
1398 &self,
1399 array: &SpeakerArrayConfig,
1400 speakers: &HashMap<String, SmartSpeaker>,
1401 ) -> Result<CalibrationResults> {
1402 info!("Calibrating array: {}", array.name);
1403
1404 Ok(CalibrationResults {
1411 array_name: array.name.clone(),
1412 calibration_quality: 0.95,
1413 speaker_delays: HashMap::new(),
1414 eq_settings: HashMap::new(),
1415 room_correction: None,
1416 calibrated_at: chrono::Utc::now(),
1417 })
1418 }
1419}
1420
1421impl AudioRouter {
1422 fn new() -> Self {
1423 Self {
1424 routes: HashMap::new(),
1425 matrix: RoutingMatrix::new(8, 8), stream_manager: StreamManager::new(),
1427 }
1428 }
1429
1430 async fn add_route(&mut self, route: AudioRoute) -> Result<()> {
1431 info!("Adding audio route: {}", route.id);
1432 self.routes.insert(route.id.clone(), route);
1433 Ok(())
1434 }
1435}
1436
1437impl RoutingMatrix {
1438 fn new(inputs: usize, outputs: usize) -> Self {
1439 Self {
1440 matrix: vec![vec![0.0; outputs]; inputs],
1441 input_count: inputs,
1442 output_count: outputs,
1443 }
1444 }
1445}
1446
1447impl StreamManager {
1448 fn new() -> Self {
1449 Self {
1450 streams: HashMap::new(),
1451 stats: StreamStats::default(),
1452 buffer_manager: BufferManager::new(),
1453 }
1454 }
1455}
1456
1457impl BufferManager {
1458 fn new() -> Self {
1459 Self {
1460 pools: HashMap::new(),
1461 stats: BufferStats::default(),
1462 }
1463 }
1464}
1465
1466impl Default for ArrayMetrics {
1467 fn default() -> Self {
1468 Self {
1469 system_latency_ms: 0.0,
1470 network_utilization: 0.0,
1471 cpu_usage: 0.0,
1472 memory_usage_mb: 0.0,
1473 active_speakers: 0,
1474 audio_quality_score: 100.0,
1475 sync_accuracy_us: 0.0,
1476 }
1477 }
1478}
1479
1480impl Default for StreamStats {
1481 fn default() -> Self {
1482 Self {
1483 total_streams: 0,
1484 active_streams: 0,
1485 total_bytes: 0,
1486 avg_bitrate_kbps: 0.0,
1487 }
1488 }
1489}
1490
1491impl Default for BufferStats {
1492 fn default() -> Self {
1493 Self {
1494 underruns: 0,
1495 overruns: 0,
1496 avg_buffer_level: 50.0,
1497 peak_buffer_usage: 0.0,
1498 }
1499 }
1500}
1501
1502#[derive(Debug, Clone, Serialize, Deserialize)]
1504pub struct CalibrationResults {
1505 pub array_name: String,
1507 pub calibration_quality: f32,
1509 pub speaker_delays: HashMap<String, f32>,
1511 pub eq_settings: HashMap<String, Vec<EQFilter>>,
1513 pub room_correction: Option<RoomCorrection>,
1515 pub calibrated_at: chrono::DateTime<chrono::Utc>,
1517}
1518
1519#[derive(Debug, Default)]
1521pub struct SpeakerArrayConfigBuilder {
1522 name: Option<String>,
1523 room_dimensions: Option<(f32, f32, f32)>,
1524 listening_position: Option<Position3D>,
1525 topology: Option<ArrayTopology>,
1526 sync_config: Option<SyncConfig>,
1527 processing_config: Option<ProcessingConfig>,
1528 network_config: Option<NetworkConfig>,
1529}
1530
1531impl SpeakerArrayConfigBuilder {
1532 pub fn new() -> Self {
1534 Self::default()
1535 }
1536
1537 pub fn name(mut self, name: impl Into<String>) -> Self {
1539 self.name = Some(name.into());
1540 self
1541 }
1542
1543 pub fn room_dimensions(mut self, width: f32, height: f32, depth: f32) -> Self {
1545 self.room_dimensions = Some((width, height, depth));
1546 self
1547 }
1548
1549 pub fn listening_position(mut self, position: Position3D) -> Self {
1551 self.listening_position = Some(position);
1552 self
1553 }
1554
1555 pub fn topology(mut self, topology: ArrayTopology) -> Self {
1557 self.topology = Some(topology);
1558 self
1559 }
1560
1561 pub fn sync_config(mut self, config: SyncConfig) -> Self {
1563 self.sync_config = Some(config);
1564 self
1565 }
1566
1567 pub fn processing_config(mut self, config: ProcessingConfig) -> Self {
1569 self.processing_config = Some(config);
1570 self
1571 }
1572
1573 pub fn network_config(mut self, config: NetworkConfig) -> Self {
1575 self.network_config = Some(config);
1576 self
1577 }
1578
1579 pub fn build(self) -> Result<SpeakerArrayConfig> {
1581 Ok(SpeakerArrayConfig {
1582 name: self
1583 .name
1584 .ok_or_else(|| Error::config("Array name required"))?,
1585 room_dimensions: self.room_dimensions.unwrap_or((5.0, 3.0, 4.0)),
1586 listening_position: self
1587 .listening_position
1588 .unwrap_or(Position3D::new(0.0, 0.0, 0.0)),
1589 topology: self
1590 .topology
1591 .unwrap_or(ArrayTopology::Stereo { separation_m: 2.0 }),
1592 sync_config: self.sync_config.unwrap_or(SyncConfig {
1593 clock_source: ClockSource::NTP,
1594 sync_tolerance_us: 100,
1595 sync_buffer_size: 512,
1596 jitter_compensation: true,
1597 auto_correction: true,
1598 }),
1599 processing_config: self.processing_config.unwrap_or_else(|| ProcessingConfig {
1600 crossover_frequencies: vec![80.0, 2500.0],
1601 time_alignment: HashMap::new(),
1602 speaker_eq: HashMap::new(),
1603 compression: CompressionConfig {
1604 enabled: false,
1605 threshold_db: -20.0,
1606 ratio: 3.0,
1607 attack_ms: 10.0,
1608 release_ms: 100.0,
1609 makeup_gain_db: 0.0,
1610 },
1611 limiting: LimitingConfig {
1612 enabled: true,
1613 ceiling_db: -0.5,
1614 release_ms: 50.0,
1615 lookahead_ms: 5.0,
1616 },
1617 room_correction_enabled: true,
1618 }),
1619 network_config: self.network_config.unwrap_or_else(|| NetworkConfig {
1620 multicast_group: "239.255.77.77".to_string(),
1621 base_port: 5004,
1622 qos_priority: 7,
1623 max_latency_ms: 50.0,
1624 packet_size: 1316,
1625 buffer_size: 8,
1626 }),
1627 })
1628 }
1629}
1630
1631#[cfg(test)]
1632mod tests {
1633 use super::*;
1634
1635 #[test]
1636 fn test_speaker_array_manager_creation() {
1637 let manager = SpeakerArrayManager::new();
1638 assert_eq!(manager.speakers.len(), 0);
1639 assert_eq!(manager.arrays.len(), 0);
1640 }
1641
1642 #[test]
1643 fn test_speaker_addition() {
1644 let mut manager = SpeakerArrayManager::new();
1645
1646 let speaker = SmartSpeaker {
1647 id: "test_speaker".to_string(),
1648 position: Position3D::new(1.0, 0.0, 0.0),
1649 capabilities: SpeakerCapabilities {
1650 frequency_range: (40.0, 20000.0),
1651 max_spl: 105.0,
1652 driver_count: 2,
1653 directivity: DirectivityPattern::Omnidirectional,
1654 dsp_features: vec![DspFeature::RoomCorrection],
1655 supported_formats: vec![AudioFormat::PCM {
1656 sample_rate: 48000,
1657 bit_depth: 24,
1658 }],
1659 },
1660 network_info: NetworkInfo {
1661 ip_address: "192.168.1.100".to_string(),
1662 mac_address: "00:11:22:33:44:55".to_string(),
1663 protocol: NetworkProtocol::WiFi,
1664 signal_strength: 85,
1665 latency_ms: 10.0,
1666 bandwidth_mbps: 100.0,
1667 },
1668 calibration: CalibrationStatus {
1669 is_calibrated: false,
1670 calibrated_at: None,
1671 room_correction: None,
1672 inter_speaker_distances: HashMap::new(),
1673 delay_compensation_ms: 0.0,
1674 },
1675 audio_specs: AudioSpecs {
1676 sample_rate: 48000,
1677 bit_depth: 24,
1678 channels: 2,
1679 buffer_size: 512,
1680 codec_latency_ms: 5.0,
1681 },
1682 };
1683
1684 manager
1685 .add_speaker(speaker)
1686 .expect("Should successfully add speaker to manager");
1687 assert_eq!(manager.speakers.len(), 1);
1688 }
1689
1690 #[test]
1691 fn test_array_config_builder() {
1692 let config = SpeakerArrayConfigBuilder::new()
1693 .name("test_array")
1694 .room_dimensions(5.0, 3.0, 4.0)
1695 .topology(ArrayTopology::Stereo { separation_m: 2.0 })
1696 .build()
1697 .expect("Should successfully build speaker array config");
1698
1699 assert_eq!(config.name, "test_array");
1700 assert_eq!(config.room_dimensions, (5.0, 3.0, 4.0));
1701 match config.topology {
1702 ArrayTopology::Stereo { separation_m } => assert_eq!(separation_m, 2.0),
1703 _ => panic!("Wrong topology"),
1704 }
1705 }
1706
1707 #[test]
1708 fn test_directivity_pattern_serialization() {
1709 let pattern = DirectivityPattern::Custom(vec![(0.0, 0.0), (90.0, -3.0), (180.0, -20.0)]);
1710 let serialized = serde_json::to_string(&pattern)
1711 .expect("Should successfully serialize directivity pattern");
1712 let deserialized: DirectivityPattern = serde_json::from_str(&serialized)
1713 .expect("Should successfully deserialize directivity pattern");
1714
1715 match deserialized {
1716 DirectivityPattern::Custom(angles) => {
1717 assert_eq!(angles.len(), 3);
1718 assert_eq!(angles[0], (0.0, 0.0));
1719 }
1720 _ => panic!("Wrong pattern type"),
1721 }
1722 }
1723
1724 #[test]
1725 fn test_eq_filter_creation() {
1726 let filter = EQFilter {
1727 filter_type: FilterType::Peaking,
1728 frequency: 1000.0,
1729 q_factor: 0.7,
1730 gain_db: 3.0,
1731 };
1732
1733 assert_eq!(filter.frequency, 1000.0);
1734 assert_eq!(filter.gain_db, 3.0);
1735 }
1736
1737 #[test]
1738 fn test_audio_format_variants() {
1739 let formats = vec![
1740 AudioFormat::PCM {
1741 sample_rate: 48000,
1742 bit_depth: 24,
1743 },
1744 AudioFormat::FLAC,
1745 AudioFormat::AAC { bitrate_kbps: 320 },
1746 AudioFormat::Opus { bitrate_kbps: 128 },
1747 ];
1748
1749 assert_eq!(formats.len(), 4);
1750
1751 match &formats[0] {
1752 AudioFormat::PCM {
1753 sample_rate,
1754 bit_depth,
1755 } => {
1756 assert_eq!(*sample_rate, 48000);
1757 assert_eq!(*bit_depth, 24);
1758 }
1759 _ => panic!("Wrong format type"),
1760 }
1761 }
1762
1763 #[test]
1764 fn test_calibration_results() {
1765 let results = CalibrationResults {
1766 array_name: "test_array".to_string(),
1767 calibration_quality: 0.95,
1768 speaker_delays: HashMap::new(),
1769 eq_settings: HashMap::new(),
1770 room_correction: None,
1771 calibrated_at: chrono::Utc::now(),
1772 };
1773
1774 assert_eq!(results.array_name, "test_array");
1775 assert_eq!(results.calibration_quality, 0.95);
1776 }
1777
1778 #[test]
1779 fn test_routing_matrix_creation() {
1780 let matrix = RoutingMatrix::new(4, 8);
1781 assert_eq!(matrix.input_count, 4);
1782 assert_eq!(matrix.output_count, 8);
1783 assert_eq!(matrix.matrix.len(), 4);
1784 assert_eq!(matrix.matrix[0].len(), 8);
1785 }
1786
1787 #[test]
1788 fn test_stream_metrics() {
1789 let metrics = StreamMetrics {
1790 bitrate_kbps: 1411.0,
1791 packet_loss_rate: 0.01,
1792 jitter_ms: 2.0,
1793 buffer_level: 75.0,
1794 dropouts: 0,
1795 };
1796
1797 assert_eq!(metrics.bitrate_kbps, 1411.0);
1798 assert_eq!(metrics.packet_loss_rate, 0.01);
1799 }
1800
1801 #[test]
1802 fn test_array_metrics_default() {
1803 let metrics = ArrayMetrics::default();
1804 assert_eq!(metrics.audio_quality_score, 100.0);
1805 assert_eq!(metrics.active_speakers, 0);
1806 }
1807
1808 #[test]
1809 fn test_discovery_protocols() {
1810 let protocols = vec![
1811 DiscoveryProtocol::UPnP,
1812 DiscoveryProtocol::Bonjour,
1813 DiscoveryProtocol::Chromecast,
1814 DiscoveryProtocol::AirPlay,
1815 ];
1816
1817 assert_eq!(protocols.len(), 4);
1818 }
1819
1820 #[test]
1821 fn test_optimization_goals() {
1822 let goals = vec![
1823 OptimizationGoal::FlatFrequencyResponse,
1824 OptimizationGoal::MaximizeSweetSpot,
1825 OptimizationGoal::MinimizeDelays,
1826 ];
1827
1828 assert_eq!(goals.len(), 3);
1829 }
1830}