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};