audio.rs

 1use assets::SoundRegistry;
 2use derive_more::{Deref, DerefMut};
 3use gpui::{AppContext, AssetSource, BorrowAppContext, Global};
 4use rodio::{OutputStream, OutputStreamHandle};
 5use util::ResultExt;
 6
 7mod assets;
 8
 9pub fn init(source: impl AssetSource, cx: &mut AppContext) {
10    SoundRegistry::set_global(source, cx);
11    cx.set_global(GlobalAudio(Audio::new()));
12}
13
14pub enum Sound {
15    Joined,
16    Leave,
17    Mute,
18    Unmute,
19    StartScreenshare,
20    StopScreenshare,
21}
22
23impl Sound {
24    fn file(&self) -> &'static str {
25        match self {
26            Self::Joined => "joined_call",
27            Self::Leave => "leave_call",
28            Self::Mute => "mute",
29            Self::Unmute => "unmute",
30            Self::StartScreenshare => "start_screenshare",
31            Self::StopScreenshare => "stop_screenshare",
32        }
33    }
34}
35
36pub struct Audio {
37    _output_stream: Option<OutputStream>,
38    output_handle: Option<OutputStreamHandle>,
39}
40
41#[derive(Deref, DerefMut)]
42struct GlobalAudio(Audio);
43
44impl Global for GlobalAudio {}
45
46impl Audio {
47    pub fn new() -> Self {
48        Self {
49            _output_stream: None,
50            output_handle: None,
51        }
52    }
53
54    fn ensure_output_exists(&mut self) -> Option<&OutputStreamHandle> {
55        if self.output_handle.is_none() {
56            let (_output_stream, output_handle) = OutputStream::try_default().log_err().unzip();
57            self.output_handle = output_handle;
58            self._output_stream = _output_stream;
59        }
60
61        self.output_handle.as_ref()
62    }
63
64    pub fn play_sound(sound: Sound, cx: &mut AppContext) {
65        if !cx.has_global::<GlobalAudio>() {
66            return;
67        }
68
69        cx.update_global::<GlobalAudio, _>(|this, cx| {
70            let output_handle = this.ensure_output_exists()?;
71            let source = SoundRegistry::global(cx).get(sound.file()).log_err()?;
72            output_handle.play_raw(source).log_err()?;
73            Some(())
74        });
75    }
76
77    pub fn end_call(cx: &mut AppContext) {
78        if !cx.has_global::<GlobalAudio>() {
79            return;
80        }
81
82        cx.update_global::<GlobalAudio, _>(|this, _| {
83            this._output_stream.take();
84            this.output_handle.take();
85        });
86    }
87}