audio.rs

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