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