audio_settings.rs

  1use std::{
  2    str::FromStr,
  3    sync::atomic::{AtomicBool, Ordering},
  4};
  5
  6use cpal::DeviceId;
  7use gpui::App;
  8use settings::{RegisterSetting, Settings, SettingsStore};
  9
 10#[derive(Clone, Debug, RegisterSetting)]
 11pub struct AudioSettings {
 12    /// Opt into the new audio system.
 13    ///
 14    /// You need to rejoin a call for this setting to apply
 15    pub rodio_audio: bool, // default is false
 16    /// Requires 'rodio_audio: true'
 17    ///
 18    /// Automatically increase or decrease you microphone's volume. This affects how
 19    /// loud you sound to others.
 20    ///
 21    /// Recommended: off (default)
 22    /// Microphones are too quite in zed, until everyone is on experimental
 23    /// audio and has auto speaker volume on this will make you very loud
 24    /// compared to other speakers.
 25    pub auto_microphone_volume: bool,
 26    /// Requires 'rodio_audio: true'
 27    ///
 28    /// Automatically increate or decrease the volume of other call members.
 29    /// This only affects how things sound for you.
 30    pub auto_speaker_volume: bool,
 31    /// Requires 'rodio_audio: true'
 32    ///
 33    /// Remove background noises. Works great for typing, cars, dogs, AC. Does
 34    /// not work well on music.
 35    pub denoise: bool,
 36    /// Requires 'rodio_audio: true'
 37    ///
 38    /// Use audio parameters compatible with the previous versions of
 39    /// experimental audio and non-experimental audio. When this is false you
 40    /// will sound strange to anyone not on the latest experimental audio. In
 41    /// the future we will migrate by setting this to false
 42    ///
 43    /// You need to rejoin a call for this setting to apply
 44    pub legacy_audio_compatible: bool,
 45    /// Requires 'rodio_audio: true'
 46    ///
 47    /// Select specific output audio device.
 48    pub output_audio_device: Option<DeviceId>,
 49    /// Requires 'rodio_audio: true'
 50    ///
 51    /// Select specific input audio device.
 52    pub input_audio_device: Option<DeviceId>,
 53}
 54
 55/// Configuration of audio in Zed
 56impl Settings for AudioSettings {
 57    fn from_settings(content: &settings::SettingsContent) -> Self {
 58        let audio = &content.audio.as_ref().unwrap();
 59        AudioSettings {
 60            rodio_audio: audio.rodio_audio.unwrap(),
 61            auto_microphone_volume: audio.auto_microphone_volume.unwrap(),
 62            auto_speaker_volume: audio.auto_speaker_volume.unwrap(),
 63            denoise: audio.denoise.unwrap(),
 64            legacy_audio_compatible: audio.legacy_audio_compatible.unwrap(),
 65            output_audio_device: audio
 66                .output_audio_device
 67                .as_ref()
 68                .and_then(|x| x.0.as_ref().and_then(|id| DeviceId::from_str(&id).ok())),
 69            input_audio_device: audio
 70                .input_audio_device
 71                .as_ref()
 72                .and_then(|x| x.0.as_ref().and_then(|id| DeviceId::from_str(&id).ok())),
 73        }
 74    }
 75}
 76
 77/// See docs on [LIVE_SETTINGS]
 78pub(crate) struct LiveSettings {
 79    pub(crate) auto_microphone_volume: AtomicBool,
 80    pub(crate) auto_speaker_volume: AtomicBool,
 81    pub(crate) denoise: AtomicBool,
 82}
 83
 84impl LiveSettings {
 85    pub(crate) fn initialize(&self, cx: &mut App) {
 86        cx.observe_global::<SettingsStore>(move |cx| {
 87            LIVE_SETTINGS.auto_microphone_volume.store(
 88                AudioSettings::get_global(cx).auto_microphone_volume,
 89                Ordering::Relaxed,
 90            );
 91            LIVE_SETTINGS.auto_speaker_volume.store(
 92                AudioSettings::get_global(cx).auto_speaker_volume,
 93                Ordering::Relaxed,
 94            );
 95
 96            let denoise_enabled = AudioSettings::get_global(cx).denoise;
 97            #[cfg(debug_assertions)]
 98            {
 99                static DENOISE_WARNING_SEND: AtomicBool = AtomicBool::new(false);
100                if denoise_enabled && !DENOISE_WARNING_SEND.load(Ordering::Relaxed) {
101                    DENOISE_WARNING_SEND.store(true, Ordering::Relaxed);
102                    log::warn!("Denoise does not work on debug builds, not enabling")
103                }
104            }
105            #[cfg(not(debug_assertions))]
106            LIVE_SETTINGS
107                .denoise
108                .store(denoise_enabled, Ordering::Relaxed);
109        })
110        .detach();
111
112        let init_settings = AudioSettings::get_global(cx);
113        LIVE_SETTINGS
114            .auto_microphone_volume
115            .store(init_settings.auto_microphone_volume, Ordering::Relaxed);
116        LIVE_SETTINGS
117            .auto_speaker_volume
118            .store(init_settings.auto_speaker_volume, Ordering::Relaxed);
119        let denoise_enabled = AudioSettings::get_global(cx).denoise;
120        #[cfg(debug_assertions)]
121        if denoise_enabled {
122            log::warn!("Denoise does not work on debug builds, not enabling")
123        }
124        #[cfg(not(debug_assertions))]
125        LIVE_SETTINGS
126            .denoise
127            .store(denoise_enabled, Ordering::Relaxed);
128    }
129}
130
131/// Allows access to settings from the audio thread. Updated by
132/// observer of SettingsStore. Needed because audio playback and recording are
133/// real time and must each run in a dedicated OS thread, therefore we can not
134/// use the background executor.
135pub(crate) static LIVE_SETTINGS: LiveSettings = LiveSettings {
136    auto_microphone_volume: AtomicBool::new(true),
137    auto_speaker_volume: AtomicBool::new(true),
138    denoise: AtomicBool::new(true),
139};