Skip to main content

voirs_spatial/
mobile.rs

1//! Mobile Platform Optimizations for VoiRS Spatial Audio
2//!
3//! This module provides platform-specific optimizations for iOS and Android devices,
4//! including power management, performance tuning, and mobile-specific audio processing.
5
6use crate::config::SpatialConfig;
7use crate::core::SpatialProcessor;
8use crate::types::Position3D;
9use crate::{Error, Result};
10use serde::{Deserialize, Serialize};
11use std::time::{Duration, Instant};
12
13/// Mobile platform types
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
15pub enum MobilePlatform {
16    /// iOS (iPhone, iPad)
17    Ios,
18    /// Android devices
19    Android,
20    /// Generic mobile platform
21    Generic,
22}
23
24/// Mobile optimization configuration
25#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct MobileConfig {
27    /// Target platform
28    pub platform: MobilePlatform,
29    /// Battery optimization level (0.0 = performance, 1.0 = maximum battery life)
30    pub battery_optimization: f32,
31    /// Thermal throttling threshold (°C)
32    pub thermal_threshold: f32,
33    /// Maximum CPU usage percentage
34    pub max_cpu_usage: f32,
35    /// Adaptive quality enabled
36    pub adaptive_quality: bool,
37    /// Background processing enabled
38    pub background_processing: bool,
39    /// Maximum concurrent sources in low power mode
40    pub low_power_max_sources: usize,
41    /// Reduced sample rate for battery saving
42    pub battery_sample_rate: f32,
43    /// Use device-specific optimizations
44    pub device_optimizations: bool,
45    /// Enable spatial audio in calls/media
46    pub media_integration: bool,
47}
48
49impl Default for MobileConfig {
50    fn default() -> Self {
51        Self {
52            platform: MobilePlatform::Generic,
53            battery_optimization: 0.3,
54            thermal_threshold: 40.0,
55            max_cpu_usage: 25.0,
56            adaptive_quality: true,
57            background_processing: false,
58            low_power_max_sources: 8,
59            battery_sample_rate: 24000.0,
60            device_optimizations: true,
61            media_integration: true,
62        }
63    }
64}
65
66/// Mobile device capabilities and characteristics
67#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct MobileDevice {
69    /// Device model/name
70    pub model: String,
71    /// Available CPU cores
72    pub cpu_cores: usize,
73    /// RAM in MB
74    pub ram_mb: u32,
75    /// Battery capacity in mAh
76    pub battery_capacity: u32,
77    /// Supports hardware audio acceleration
78    pub has_audio_hardware: bool,
79    /// Supports metal/vulkan GPU acceleration
80    pub has_gpu_acceleration: bool,
81    /// Maximum supported sample rate
82    pub max_sample_rate: f32,
83    /// Built-in spatial audio support
84    pub native_spatial_support: bool,
85}
86
87impl Default for MobileDevice {
88    fn default() -> Self {
89        Self {
90            model: "Unknown".to_string(),
91            cpu_cores: 4,
92            ram_mb: 4096,
93            battery_capacity: 3000,
94            has_audio_hardware: true,
95            has_gpu_acceleration: false,
96            max_sample_rate: 48000.0,
97            native_spatial_support: false,
98        }
99    }
100}
101
102/// Power management states
103#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
104pub enum PowerState {
105    /// Full performance mode
106    Performance,
107    /// Balanced mode
108    Balanced,
109    /// Power saving mode
110    PowerSaver,
111    /// Ultra low power mode
112    UltraLowPower,
113    /// Thermal throttling active
114    Throttled,
115}
116
117/// Mobile audio quality preset
118#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
119pub enum QualityPreset {
120    /// Maximum quality (high battery usage)
121    Ultra,
122    /// High quality
123    High,
124    /// Balanced quality/performance
125    Medium,
126    /// Low quality (battery optimized)
127    Low,
128    /// Minimal quality (emergency battery mode)
129    Minimal,
130}
131
132impl QualityPreset {
133    /// Get quality level as float
134    pub fn as_float(&self) -> f32 {
135        match self {
136            QualityPreset::Ultra => 1.0,
137            QualityPreset::High => 0.8,
138            QualityPreset::Medium => 0.6,
139            QualityPreset::Low => 0.4,
140            QualityPreset::Minimal => 0.2,
141        }
142    }
143
144    /// Get maximum sources for this quality preset
145    pub fn max_sources(&self) -> usize {
146        match self {
147            QualityPreset::Ultra => 32,
148            QualityPreset::High => 16,
149            QualityPreset::Medium => 12,
150            QualityPreset::Low => 8,
151            QualityPreset::Minimal => 4,
152        }
153    }
154
155    /// Get preferred sample rate for this preset
156    pub fn sample_rate(&self) -> f32 {
157        match self {
158            QualityPreset::Ultra => 48000.0,
159            QualityPreset::High => 44100.0,
160            QualityPreset::Medium => 32000.0,
161            QualityPreset::Low => 24000.0,
162            QualityPreset::Minimal => 16000.0,
163        }
164    }
165}
166
167/// Mobile optimizer for spatial audio
168pub struct MobileOptimizer {
169    config: MobileConfig,
170    device: MobileDevice,
171    current_power_state: PowerState,
172    current_quality: QualityPreset,
173    battery_level: f32,
174    thermal_state: f32,
175    cpu_usage_history: Vec<f32>,
176    performance_metrics: MobileMetrics,
177    last_optimization: Instant,
178}
179
180/// Mobile performance metrics
181#[derive(Debug, Clone, Default)]
182pub struct MobileMetrics {
183    /// Average CPU usage percentage
184    pub cpu_usage: f32,
185    /// Current thermal state (0.0 = cool, 1.0 = hot)
186    pub thermal_state: f32,
187    /// Battery drain rate (mA/hour)
188    pub battery_drain_rate: f32,
189    /// Processing latency (ms)
190    pub processing_latency: f32,
191    /// Quality level achieved
192    pub quality_level: f32,
193    /// Number of sources processed
194    pub sources_processed: u32,
195    /// Frame drops per second
196    pub frame_drops: f32,
197    /// Memory usage (MB)
198    pub memory_usage: f32,
199}
200
201impl MobileOptimizer {
202    /// Create a new mobile optimizer
203    pub fn new(config: MobileConfig, device: MobileDevice) -> Self {
204        let initial_quality = if config.battery_optimization > 0.7 {
205            QualityPreset::Low
206        } else if config.battery_optimization > 0.5 {
207            QualityPreset::Medium
208        } else {
209            QualityPreset::High
210        };
211
212        Self {
213            config,
214            device,
215            current_power_state: PowerState::Balanced,
216            current_quality: initial_quality,
217            battery_level: 1.0,
218            thermal_state: 0.0,
219            cpu_usage_history: Vec::with_capacity(60), // 1 minute of history
220            performance_metrics: MobileMetrics::default(),
221            last_optimization: Instant::now(),
222        }
223    }
224
225    /// Update system state and optimize accordingly
226    pub fn update_state(&mut self, battery_level: f32, thermal_temp: f32, cpu_usage: f32) {
227        self.battery_level = battery_level.clamp(0.0, 1.0);
228        self.thermal_state = (thermal_temp - 20.0) / (self.config.thermal_threshold - 20.0);
229        self.thermal_state = self.thermal_state.clamp(0.0, 1.0);
230
231        // Update CPU usage history
232        self.cpu_usage_history.push(cpu_usage);
233        if self.cpu_usage_history.len() > 60 {
234            self.cpu_usage_history.remove(0);
235        }
236
237        // Update metrics
238        self.performance_metrics.cpu_usage = cpu_usage;
239        self.performance_metrics.thermal_state = self.thermal_state;
240
241        // Determine power state
242        self.current_power_state = self.determine_power_state();
243
244        // Adjust quality based on state
245        if self.config.adaptive_quality {
246            self.current_quality = self.determine_optimal_quality();
247        }
248    }
249
250    /// Determine optimal power state based on current conditions
251    fn determine_power_state(&self) -> PowerState {
252        // Thermal throttling takes priority
253        if self.thermal_state > 0.9 {
254            return PowerState::Throttled;
255        }
256
257        // Ultra low power if battery is critically low
258        if self.battery_level < 0.1 {
259            return PowerState::UltraLowPower;
260        }
261
262        // Power saver if battery is low or high optimization requested
263        if self.battery_level < 0.2 || self.config.battery_optimization > 0.7 {
264            return PowerState::PowerSaver;
265        }
266
267        // Performance mode if battery is high and optimization is low
268        if self.battery_level > 0.8 && self.config.battery_optimization < 0.3 {
269            return PowerState::Performance;
270        }
271
272        // Default to balanced
273        PowerState::Balanced
274    }
275
276    /// Determine optimal quality preset
277    fn determine_optimal_quality(&self) -> QualityPreset {
278        let avg_cpu = if self.cpu_usage_history.is_empty() {
279            0.0
280        } else {
281            self.cpu_usage_history.iter().sum::<f32>() / self.cpu_usage_history.len() as f32
282        };
283
284        match self.current_power_state {
285            PowerState::Performance => {
286                if avg_cpu < 20.0 {
287                    QualityPreset::Ultra
288                } else {
289                    QualityPreset::High
290                }
291            }
292            PowerState::Balanced => {
293                if avg_cpu < 15.0 {
294                    QualityPreset::High
295                } else {
296                    QualityPreset::Medium
297                }
298            }
299            PowerState::PowerSaver => {
300                if avg_cpu < 10.0 {
301                    QualityPreset::Medium
302                } else {
303                    QualityPreset::Low
304                }
305            }
306            PowerState::UltraLowPower | PowerState::Throttled => QualityPreset::Minimal,
307        }
308    }
309
310    /// Get optimized spatial configuration for current state
311    pub fn get_optimized_config(&self) -> SpatialConfig {
312        let mut config = SpatialConfig::default();
313
314        // Adjust based on quality preset
315        config.quality_level = self.current_quality.as_float();
316        config.max_sources = self.current_quality.max_sources();
317        config.sample_rate = self.current_quality.sample_rate() as u32;
318
319        // Platform-specific optimizations
320        match self.config.platform {
321            MobilePlatform::Ios => {
322                // iOS-specific optimizations
323                config.use_gpu = self.device.has_gpu_acceleration
324                    && matches!(
325                        self.current_power_state,
326                        PowerState::Performance | PowerState::Balanced
327                    );
328                config.buffer_size = if self.current_power_state == PowerState::UltraLowPower {
329                    2048
330                } else {
331                    1024
332                };
333            }
334            MobilePlatform::Android => {
335                // Android-specific optimizations
336                config.use_gpu = self.device.has_gpu_acceleration
337                    && !matches!(
338                        self.current_power_state,
339                        PowerState::PowerSaver | PowerState::UltraLowPower
340                    );
341                config.buffer_size = if self.current_power_state == PowerState::UltraLowPower {
342                    4096
343                } else {
344                    1024
345                };
346            }
347            MobilePlatform::Generic => {
348                // Conservative settings for unknown platforms
349                config.use_gpu = false;
350                config.buffer_size = 2048;
351            }
352        }
353
354        // Thermal throttling adjustments
355        if self.current_power_state == PowerState::Throttled {
356            config.quality_level *= 0.5;
357            config.max_sources = (config.max_sources / 2).max(2);
358            config.use_gpu = false;
359        }
360
361        config
362    }
363
364    /// Process audio with mobile-optimized settings
365    pub fn process_mobile_audio(
366        &mut self,
367        processor: &mut SpatialProcessor,
368        audio_data: &[f32],
369        listener_pos: Position3D,
370        sources: &[(Position3D, &[f32])],
371    ) -> Result<Vec<f32>> {
372        let start_time = Instant::now();
373
374        // Limit sources based on current power state
375        let max_sources = self.current_quality.max_sources();
376        let limited_sources = if sources.len() > max_sources {
377            &sources[..max_sources]
378        } else {
379            sources
380        };
381
382        // Process with current settings
383        // This would integrate with the actual spatial processor
384        let output = vec![0.0f32; audio_data.len()];
385
386        // Update metrics
387        let processing_time = start_time.elapsed();
388        self.performance_metrics.processing_latency = processing_time.as_secs_f32() * 1000.0;
389        self.performance_metrics.sources_processed = limited_sources.len() as u32;
390        self.performance_metrics.quality_level = self.current_quality.as_float();
391
392        // Check if we need to drop frames due to performance
393        if processing_time > Duration::from_millis(20) {
394            // Assuming 50fps target
395            self.performance_metrics.frame_drops += 1.0;
396        }
397
398        Ok(output)
399    }
400
401    /// Get current performance metrics
402    pub fn get_metrics(&self) -> MobileMetrics {
403        self.performance_metrics.clone()
404    }
405
406    /// Get current power state
407    pub fn get_power_state(&self) -> PowerState {
408        self.current_power_state
409    }
410
411    /// Get current quality preset
412    pub fn get_quality_preset(&self) -> QualityPreset {
413        self.current_quality
414    }
415
416    /// Force a specific quality preset
417    pub fn set_quality_preset(&mut self, preset: QualityPreset) {
418        self.current_quality = preset;
419    }
420
421    /// Enable/disable background processing
422    pub fn set_background_processing(&mut self, enabled: bool) {
423        self.config.background_processing = enabled;
424    }
425
426    /// Check if background processing is enabled
427    pub fn is_background_processing_enabled(&self) -> bool {
428        self.config.background_processing
429    }
430}
431
432/// iOS-specific optimizations
433pub mod ios {
434    use super::*;
435
436    /// iOS device detection
437    pub fn detect_device() -> MobileDevice {
438        MobileDevice {
439            model: "iOS Device".to_string(),
440            cpu_cores: 6, // Typical for modern iPhones
441            ram_mb: 6144, // Common iPhone configuration
442            battery_capacity: 3200,
443            has_audio_hardware: true, // iOS devices have good audio hardware
444            has_gpu_acceleration: true, // Metal support
445            max_sample_rate: 48000.0,
446            native_spatial_support: true, // iOS has spatial audio support
447        }
448    }
449
450    /// iOS-specific audio session configuration
451    pub fn configure_audio_session() -> Result<()> {
452        // Would configure AVAudioSession for spatial audio
453        // This would be implemented with iOS-specific APIs
454        Ok(())
455    }
456
457    /// Enable iOS spatial audio features
458    pub fn enable_spatial_audio() -> Result<()> {
459        // Would enable spatial audio through AVAudioSession
460        Ok(())
461    }
462}
463
464/// Android-specific optimizations
465pub mod android {
466    use super::*;
467
468    /// Android device detection
469    pub fn detect_device() -> MobileDevice {
470        MobileDevice {
471            model: "Android Device".to_string(),
472            cpu_cores: 8, // Typical for modern Android phones
473            ram_mb: 8192, // Common Android configuration
474            battery_capacity: 4000,
475            has_audio_hardware: true,
476            has_gpu_acceleration: true, // Vulkan/OpenGL ES support
477            max_sample_rate: 48000.0,
478            native_spatial_support: false, // Most Android devices don't have native support
479        }
480    }
481
482    /// Android-specific audio configuration
483    pub fn configure_audio_track() -> Result<()> {
484        // Would configure AudioTrack for low-latency audio
485        Ok(())
486    }
487
488    /// Enable Android spatial audio features (if available)
489    pub fn enable_spatial_audio() -> Result<()> {
490        // Would enable spatial audio through Android APIs
491        Ok(())
492    }
493}
494
495/// Platform-specific optimizations for iOS devices
496#[cfg(target_os = "ios")]
497pub mod ios_optimizations {
498    use super::*;
499
500    /// iOS-specific audio configuration using AVAudioEngine integration
501    #[derive(Debug, Clone, Serialize, Deserialize)]
502    pub struct IosAudioConfig {
503        /// Use AVAudioEngine for hardware acceleration
504        pub use_av_audio_engine: bool,
505        /// Enable spatial audio in iOS native framework
506        pub native_spatial_audio: bool,
507        /// Use iOS audio interruption handling
508        pub handle_audio_interruptions: bool,
509        /// Enable AirPods Pro head tracking integration
510        pub airpods_head_tracking: bool,
511        /// Use iOS Core Audio for low-latency processing
512        pub use_core_audio: bool,
513        /// Buffer size optimized for iOS (256, 512, 1024 samples)
514        pub ios_buffer_size: usize,
515    }
516
517    impl Default for IosAudioConfig {
518        fn default() -> Self {
519            Self {
520                use_av_audio_engine: true,
521                native_spatial_audio: true,
522                handle_audio_interruptions: true,
523                airpods_head_tracking: true,
524                use_core_audio: true,
525                ios_buffer_size: 512,
526            }
527        }
528    }
529
530    /// iOS device capabilities detection
531    pub struct IosDeviceDetector;
532
533    impl IosDeviceDetector {
534        /// Detect iOS device capabilities
535        pub fn detect_device() -> MobileDevice {
536            // Platform-specific device detection would be implemented here
537            // using iOS system APIs
538            MobileDevice {
539                model: "iOS Device".to_string(),
540                cpu_cores: Self::detect_cpu_cores(),
541                ram_mb: Self::detect_ram(),
542                battery_capacity: 3000, // Estimated
543                has_audio_hardware: true,
544                has_gpu_acceleration: Self::has_metal_support(),
545                max_sample_rate: 48000.0,
546                native_spatial_support: Self::has_spatial_audio_support(),
547            }
548        }
549
550        fn detect_cpu_cores() -> usize {
551            // Would use iOS system APIs to detect actual core count
552            std::thread::available_parallelism()
553                .map(|n| n.get())
554                .unwrap_or(4)
555        }
556
557        fn detect_ram() -> u32 {
558            // Would use iOS APIs to detect actual RAM
559            4096 // Default estimate
560        }
561
562        fn has_metal_support() -> bool {
563            // Would check for Metal GPU acceleration support
564            true // Most modern iOS devices support Metal
565        }
566
567        fn has_spatial_audio_support() -> bool {
568            // Would check iOS version and device capability
569            true // iOS 14+ devices typically support spatial audio
570        }
571    }
572
573    /// iOS-specific power management
574    pub struct IosPowerManager {
575        config: IosAudioConfig,
576        current_state: PowerState,
577    }
578
579    impl IosPowerManager {
580        pub fn new(config: IosAudioConfig) -> Self {
581            Self {
582                config,
583                current_state: PowerState::Balanced,
584            }
585        }
586
587        /// Handle iOS app lifecycle changes
588        pub fn handle_app_state_change(&mut self, entering_background: bool) {
589            if entering_background {
590                self.current_state = PowerState::PowerSaver;
591            } else {
592                self.current_state = PowerState::Balanced;
593            }
594        }
595
596        /// Handle iOS audio interruptions (calls, notifications)
597        pub fn handle_audio_interruption(&mut self, interrupted: bool) -> Result<()> {
598            if self.config.handle_audio_interruptions {
599                if interrupted {
600                    self.current_state = PowerState::UltraLowPower;
601                } else {
602                    self.current_state = PowerState::Balanced;
603                }
604            }
605            Ok(())
606        }
607
608        /// Get recommended iOS buffer size based on power state
609        pub fn get_buffer_size(&self) -> usize {
610            match self.current_state {
611                PowerState::Performance => 256,
612                PowerState::Balanced => 512,
613                PowerState::PowerSaver => 1024,
614                PowerState::UltraLowPower => 2048,
615                PowerState::Throttled => 4096,
616            }
617        }
618    }
619}
620
621/// Platform-specific optimizations for Android devices
622#[cfg(target_os = "android")]
623pub mod android_optimizations {
624    use super::*;
625
626    /// Android-specific audio configuration
627    #[derive(Debug, Clone, Serialize, Deserialize)]
628    pub struct AndroidAudioConfig {
629        /// Use AAudio for low-latency processing
630        pub use_aaudio: bool,
631        /// Enable OpenSL ES for hardware acceleration
632        pub use_opensl_es: bool,
633        /// Use Android AudioTrack for output
634        pub use_audio_track: bool,
635        /// Enable Pro Audio features if available
636        pub enable_pro_audio: bool,
637        /// Use MMAP for low-latency audio
638        pub use_mmap: bool,
639        /// Performance class optimization
640        pub performance_class: AndroidPerformanceClass,
641        /// Target audio latency in milliseconds
642        pub target_latency_ms: f32,
643    }
644
645    /// Android performance class categories
646    #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
647    pub enum AndroidPerformanceClass {
648        /// High-end devices (R Performance Class or newer)
649        Premium,
650        /// Mid-range devices with good performance
651        Standard,
652        /// Basic devices with limited capabilities
653        Basic,
654        /// Unknown or very old devices
655        Legacy,
656    }
657
658    impl Default for AndroidAudioConfig {
659        fn default() -> Self {
660            Self {
661                use_aaudio: true,
662                use_opensl_es: true,
663                use_audio_track: true,
664                enable_pro_audio: true,
665                use_mmap: true,
666                performance_class: AndroidPerformanceClass::Standard,
667                target_latency_ms: 20.0,
668            }
669        }
670    }
671
672    /// Android device capabilities detection
673    pub struct AndroidDeviceDetector;
674
675    impl AndroidDeviceDetector {
676        /// Detect Android device capabilities
677        pub fn detect_device() -> MobileDevice {
678            MobileDevice {
679                model: "Android Device".to_string(),
680                cpu_cores: Self::detect_cpu_cores(),
681                ram_mb: Self::detect_ram(),
682                battery_capacity: Self::detect_battery_capacity(),
683                has_audio_hardware: Self::has_audio_hardware(),
684                has_gpu_acceleration: Self::has_vulkan_support(),
685                max_sample_rate: Self::detect_max_sample_rate(),
686                native_spatial_support: Self::has_spatial_audio_support(),
687            }
688        }
689
690        fn detect_cpu_cores() -> usize {
691            std::thread::available_parallelism()
692                .map(|n| n.get())
693                .unwrap_or(4)
694        }
695
696        fn detect_ram() -> u32 {
697            // Would use Android APIs to detect actual RAM
698            4096 // Default estimate
699        }
700
701        fn detect_battery_capacity() -> u32 {
702            // Would read from Android battery manager
703            3500 // Common Android battery capacity
704        }
705
706        fn has_audio_hardware() -> bool {
707            // Would check for dedicated audio hardware
708            true
709        }
710
711        fn has_vulkan_support() -> bool {
712            // Would check for Vulkan API support
713            false // Conservative default
714        }
715
716        fn detect_max_sample_rate() -> f32 {
717            // Would query Android AudioManager
718            48000.0
719        }
720
721        fn has_spatial_audio_support() -> bool {
722            // Would check Android version and OEM spatial audio support
723            false // Many Android devices don't have native spatial audio
724        }
725
726        /// Detect Android performance class
727        pub fn detect_performance_class() -> AndroidPerformanceClass {
728            // Would use Android APIs to detect performance class
729            // Based on Android R Performance Class requirements
730            AndroidPerformanceClass::Standard
731        }
732    }
733
734    /// Android-specific audio optimization
735    pub struct AndroidAudioOptimizer {
736        config: AndroidAudioConfig,
737        performance_class: AndroidPerformanceClass,
738    }
739
740    impl AndroidAudioOptimizer {
741        pub fn new(config: AndroidAudioConfig) -> Self {
742            let performance_class = AndroidDeviceDetector::detect_performance_class();
743            Self {
744                config,
745                performance_class,
746            }
747        }
748
749        /// Get optimal buffer size for Android device
750        pub fn get_optimal_buffer_size(&self) -> usize {
751            match self.performance_class {
752                AndroidPerformanceClass::Premium => {
753                    if self.config.use_mmap {
754                        128
755                    } else {
756                        256
757                    }
758                }
759                AndroidPerformanceClass::Standard => {
760                    if self.config.use_aaudio {
761                        256
762                    } else {
763                        512
764                    }
765                }
766                AndroidPerformanceClass::Basic => 1024,
767                AndroidPerformanceClass::Legacy => 2048,
768            }
769        }
770
771        /// Check if low-latency audio is available
772        pub fn has_low_latency_audio(&self) -> bool {
773            match self.performance_class {
774                AndroidPerformanceClass::Premium | AndroidPerformanceClass::Standard => {
775                    self.config.use_aaudio || self.config.enable_pro_audio
776                }
777                _ => false,
778            }
779        }
780
781        /// Get recommended sample rate
782        pub fn get_optimal_sample_rate(&self) -> f32 {
783            match self.performance_class {
784                AndroidPerformanceClass::Premium => 48000.0,
785                AndroidPerformanceClass::Standard => 44100.0,
786                AndroidPerformanceClass::Basic => 44100.0,
787                AndroidPerformanceClass::Legacy => 22050.0,
788            }
789        }
790
791        /// Handle Android audio focus changes
792        pub fn handle_audio_focus_change(&mut self, has_focus: bool) -> Result<()> {
793            // Would integrate with Android AudioFocus system
794            if !has_focus {
795                // Reduce processing when losing audio focus
796            }
797            Ok(())
798        }
799    }
800}
801
802/// Cross-platform mobile optimizations
803pub struct MobilePlatformOptimizer {
804    #[cfg(target_os = "ios")]
805    ios_config: ios_optimizations::IosAudioConfig,
806    #[cfg(target_os = "android")]
807    android_config: android_optimizations::AndroidAudioConfig,
808    mobile_config: MobileConfig,
809}
810
811impl MobilePlatformOptimizer {
812    /// Create new cross-platform mobile optimizer
813    pub fn new(mobile_config: MobileConfig) -> Self {
814        Self {
815            #[cfg(target_os = "ios")]
816            ios_config: ios_optimizations::IosAudioConfig::default(),
817            #[cfg(target_os = "android")]
818            android_config: android_optimizations::AndroidAudioConfig::default(),
819            mobile_config,
820        }
821    }
822
823    /// Get platform-specific optimal buffer size
824    pub fn get_platform_buffer_size(&self) -> usize {
825        #[cfg(target_os = "ios")]
826        {
827            let power_manager = ios_optimizations::IosPowerManager::new(self.ios_config.clone());
828            power_manager.get_buffer_size()
829        }
830        #[cfg(target_os = "android")]
831        {
832            let optimizer =
833                android_optimizations::AndroidAudioOptimizer::new(self.android_config.clone());
834            optimizer.get_optimal_buffer_size()
835        }
836        #[cfg(not(any(target_os = "ios", target_os = "android")))]
837        {
838            1024 // Generic mobile default
839        }
840    }
841
842    /// Get platform-specific optimal sample rate
843    pub fn get_platform_sample_rate(&self) -> f32 {
844        #[cfg(target_os = "ios")]
845        {
846            48000.0 // iOS typically supports high sample rates well
847        }
848        #[cfg(target_os = "android")]
849        {
850            let optimizer =
851                android_optimizations::AndroidAudioOptimizer::new(self.android_config.clone());
852            optimizer.get_optimal_sample_rate()
853        }
854        #[cfg(not(any(target_os = "ios", target_os = "android")))]
855        {
856            44100.0 // Generic mobile default
857        }
858    }
859
860    /// Check if platform has low-latency audio support
861    pub fn has_low_latency_support(&self) -> bool {
862        #[cfg(target_os = "ios")]
863        {
864            self.ios_config.use_core_audio || self.ios_config.use_av_audio_engine
865        }
866        #[cfg(target_os = "android")]
867        {
868            let optimizer =
869                android_optimizations::AndroidAudioOptimizer::new(self.android_config.clone());
870            optimizer.has_low_latency_audio()
871        }
872        #[cfg(not(any(target_os = "ios", target_os = "android")))]
873        {
874            false
875        }
876    }
877}
878#[cfg(test)]
879mod tests {
880    use super::*;
881
882    #[test]
883    fn test_mobile_config_creation() {
884        let config = MobileConfig::default();
885        assert_eq!(config.platform, MobilePlatform::Generic);
886        assert!(config.adaptive_quality);
887    }
888
889    #[test]
890    fn test_quality_preset_values() {
891        assert_eq!(QualityPreset::Ultra.as_float(), 1.0);
892        assert_eq!(QualityPreset::Low.as_float(), 0.4);
893        assert_eq!(QualityPreset::Ultra.max_sources(), 32);
894        assert_eq!(QualityPreset::Minimal.max_sources(), 4);
895    }
896
897    #[test]
898    fn test_mobile_optimizer_creation() {
899        let config = MobileConfig::default();
900        let device = MobileDevice::default();
901        let optimizer = MobileOptimizer::new(config, device);
902
903        assert_eq!(optimizer.current_power_state, PowerState::Balanced);
904        assert_eq!(optimizer.battery_level, 1.0);
905    }
906
907    #[test]
908    fn test_power_state_determination() {
909        let config = MobileConfig::default();
910        let device = MobileDevice::default();
911        let mut optimizer = MobileOptimizer::new(config, device);
912
913        // Test low battery
914        optimizer.update_state(0.05, 25.0, 10.0);
915        assert_eq!(optimizer.get_power_state(), PowerState::UltraLowPower);
916
917        // Test thermal throttling
918        optimizer.update_state(0.8, 45.0, 10.0);
919        assert_eq!(optimizer.get_power_state(), PowerState::Throttled);
920
921        // Test normal conditions
922        optimizer.update_state(0.6, 30.0, 15.0);
923        assert_eq!(optimizer.get_power_state(), PowerState::Balanced);
924    }
925
926    #[test]
927    fn test_quality_adaptation() {
928        let config = MobileConfig {
929            adaptive_quality: true,
930            ..Default::default()
931        };
932        let device = MobileDevice::default();
933        let mut optimizer = MobileOptimizer::new(config, device);
934
935        // High CPU usage should reduce quality
936        optimizer.update_state(0.5, 30.0, 35.0);
937        let quality = optimizer.get_quality_preset();
938        assert!(matches!(
939            quality,
940            QualityPreset::Low | QualityPreset::Medium
941        ));
942    }
943
944    #[test]
945    fn test_optimized_config_generation() {
946        let config = MobileConfig::default();
947        let device = MobileDevice::default();
948        let optimizer = MobileOptimizer::new(config, device);
949
950        let spatial_config = optimizer.get_optimized_config();
951        assert!(spatial_config.quality_level > 0.0);
952        assert!(spatial_config.max_sources > 0);
953    }
954
955    #[test]
956    fn test_ios_device_detection() {
957        let device = ios::detect_device();
958        assert_eq!(device.model, "iOS Device");
959        assert!(device.has_audio_hardware);
960        assert!(device.native_spatial_support);
961    }
962
963    #[test]
964    fn test_android_device_detection() {
965        let device = android::detect_device();
966        assert_eq!(device.model, "Android Device");
967        assert!(device.has_audio_hardware);
968        assert!(!device.native_spatial_support);
969    }
970
971    #[tokio::test]
972    async fn test_mobile_audio_processing() {
973        let config = MobileConfig::default();
974        let device = MobileDevice::default();
975        let mut optimizer = MobileOptimizer::new(config, device);
976
977        // Mock spatial processor (would be real in actual implementation)
978        let spatial_config = SpatialConfig::default();
979        let mut processor = SpatialProcessor::new(spatial_config).await.unwrap();
980
981        let audio_data = vec![0.5; 1024];
982        let listener_pos = Position3D::new(0.0, 0.0, 0.0);
983        let sources = vec![
984            (Position3D::new(1.0, 0.0, 0.0), audio_data.as_slice()),
985            (Position3D::new(-1.0, 0.0, 0.0), audio_data.as_slice()),
986        ];
987
988        let result =
989            optimizer.process_mobile_audio(&mut processor, &audio_data, listener_pos, &sources);
990        assert!(result.is_ok());
991
992        let output = result.unwrap();
993        assert_eq!(output.len(), audio_data.len());
994    }
995
996    #[test]
997    fn test_metrics_collection() {
998        let config = MobileConfig::default();
999        let device = MobileDevice::default();
1000        let optimizer = MobileOptimizer::new(config, device);
1001
1002        let metrics = optimizer.get_metrics();
1003        assert!(metrics.cpu_usage >= 0.0);
1004        assert!(metrics.quality_level >= 0.0 && metrics.quality_level <= 1.0);
1005    }
1006}