audio_settings.rs

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