audio_settings.rs

  1use std::sync::atomic::{AtomicBool, Ordering};
  2
  3use anyhow::Result;
  4use gpui::App;
  5use schemars::JsonSchema;
  6use serde::{Deserialize, Serialize};
  7use settings::{Settings, SettingsKey, SettingsSources, SettingsStore, SettingsUi};
  8
  9#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, SettingsUi)]
 10pub struct AudioSettings {
 11    /// Opt into the new audio system.
 12    ///
 13    /// You need to rejoin a call for this setting to apply
 14    #[serde(rename = "experimental.rodio_audio", default)]
 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    #[serde(
 26        rename = "experimental.auto_microphone_volume",
 27        default = "default_false"
 28    )]
 29    pub auto_microphone_volume: bool,
 30    /// Requires 'rodio_audio: true'
 31    ///
 32    /// Automatically increate or decrease the volume of other call members.
 33    /// This only affects how things sound for you.
 34    #[serde(rename = "experimental.auto_speaker_volume", default = "default_true")]
 35    pub auto_speaker_volume: bool,
 36    /// Requires 'rodio_audio: true'
 37    ///
 38    /// Remove background noises. Works great for typing, cars, dogs, AC. Does
 39    /// not work well on music.
 40    #[serde(rename = "experimental.denoise", default = "default_false")]
 41    pub denoise: bool,
 42    /// Requires 'rodio_audio: true'
 43    ///
 44    /// Use audio parameters compatible with the previous versions of
 45    /// experimental audio and non-experimental audio. When this is false you
 46    /// will sound strange to anyone not on the latest experimental audio. In
 47    /// the future we will migrate by setting this to false
 48    ///
 49    /// You need to rejoin a call for this setting to apply
 50    #[serde(
 51        rename = "experimental.legacy_audio_compatible",
 52        default = "default_true"
 53    )]
 54    pub legacy_audio_compatible: bool,
 55}
 56/// Configuration of audio in Zed.
 57#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, SettingsUi, SettingsKey)]
 58#[serde(default)]
 59#[settings_key(key = "audio")]
 60pub struct AudioSettingsContent {
 61    /// Opt into the new audio system.
 62    ///
 63    /// You need to rejoin a call for this setting to apply
 64    #[serde(rename = "experimental.rodio_audio", default)]
 65    pub rodio_audio: bool, // default is false
 66    /// Requires 'rodio_audio: true'
 67    ///
 68    /// Automatically increase or decrease you microphone's volume. This affects how
 69    /// loud you sound to others.
 70    ///
 71    /// Recommended: off (default)
 72    /// Microphones are too quite in zed, until everyone is on experimental
 73    /// audio and has auto speaker volume on this will make you very loud
 74    /// compared to other speakers.
 75    #[serde(
 76        rename = "experimental.auto_microphone_volume",
 77        default = "default_false"
 78    )]
 79    pub auto_microphone_volume: bool,
 80    /// Requires 'rodio_audio: true'
 81    ///
 82    /// Automatically increate or decrease the volume of other call members.
 83    /// This only affects how things sound for you.
 84    #[serde(rename = "experimental.auto_speaker_volume", default = "default_true")]
 85    pub auto_speaker_volume: bool,
 86    /// Requires 'rodio_audio: true'
 87    ///
 88    /// Remove background noises. Works great for typing, cars, dogs, AC. Does
 89    /// not work well on music.
 90    #[serde(rename = "experimental.denoise", default = "default_false")]
 91    pub denoise: bool,
 92    /// Requires 'rodio_audio: true'
 93    ///
 94    /// Use audio parameters compatible with the previous versions of
 95    /// experimental audio and non-experimental audio. When this is false you
 96    /// will sound strange to anyone not on the latest experimental audio. In
 97    /// the future we will migrate by setting this to false
 98    ///
 99    /// You need to rejoin a call for this setting to apply
100    #[serde(
101        rename = "experimental.legacy_audio_compatible",
102        default = "default_true"
103    )]
104    pub legacy_audio_compatible: bool,
105}
106
107fn default_true() -> bool {
108    true
109}
110
111fn default_false() -> bool {
112    false
113}
114
115impl Settings for AudioSettings {
116    type FileContent = AudioSettingsContent;
117
118    fn load(sources: SettingsSources<Self::FileContent>, _cx: &mut App) -> Result<Self> {
119        sources.json_merge()
120    }
121
122    fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {}
123}
124
125/// See docs on [LIVE_SETTINGS]
126pub(crate) struct LiveSettings {
127    pub(crate) auto_microphone_volume: AtomicBool,
128    pub(crate) auto_speaker_volume: AtomicBool,
129    pub(crate) denoise: AtomicBool,
130}
131
132impl LiveSettings {
133    pub(crate) fn initialize(&self, cx: &mut App) {
134        cx.observe_global::<SettingsStore>(move |cx| {
135            LIVE_SETTINGS.auto_microphone_volume.store(
136                AudioSettings::get_global(cx).auto_microphone_volume,
137                Ordering::Relaxed,
138            );
139            LIVE_SETTINGS.auto_speaker_volume.store(
140                AudioSettings::get_global(cx).auto_speaker_volume,
141                Ordering::Relaxed,
142            );
143
144            let denoise_enabled = AudioSettings::get_global(cx).denoise;
145            #[cfg(debug_assertions)]
146            {
147                static DENOISE_WARNING_SEND: AtomicBool = AtomicBool::new(false);
148                if denoise_enabled && !DENOISE_WARNING_SEND.load(Ordering::Relaxed) {
149                    DENOISE_WARNING_SEND.store(true, Ordering::Relaxed);
150                    log::warn!("Denoise does not work on debug builds, not enabling")
151                }
152            }
153            #[cfg(not(debug_assertions))]
154            LIVE_SETTINGS
155                .denoise
156                .store(denoise_enabled, Ordering::Relaxed);
157        })
158        .detach();
159
160        let init_settings = AudioSettings::get_global(cx);
161        LIVE_SETTINGS
162            .auto_microphone_volume
163            .store(init_settings.auto_microphone_volume, Ordering::Relaxed);
164        LIVE_SETTINGS
165            .auto_speaker_volume
166            .store(init_settings.auto_speaker_volume, Ordering::Relaxed);
167        let denoise_enabled = AudioSettings::get_global(cx).denoise;
168        #[cfg(debug_assertions)]
169        if denoise_enabled {
170            log::warn!("Denoise does not work on debug builds, not enabling")
171        }
172        #[cfg(not(debug_assertions))]
173        LIVE_SETTINGS
174            .denoise
175            .store(denoise_enabled, Ordering::Relaxed);
176    }
177}
178
179/// Allows access to settings from the audio thread. Updated by
180/// observer of SettingsStore. Needed because audio playback and recording are
181/// real time and must each run in a dedicated OS thread, therefore we can not
182/// use the background executor.
183pub(crate) static LIVE_SETTINGS: LiveSettings = LiveSettings {
184    auto_microphone_volume: AtomicBool::new(true),
185    auto_speaker_volume: AtomicBool::new(true),
186    denoise: AtomicBool::new(true),
187};