Lazily initialize and destroy the audio handle state on call initiation and end

Mikayla created

Change summary

crates/audio/src/audio.rs | 40 +++++++++++++++++++++++++++-------------
crates/call/src/call.rs   |  2 ++
2 files changed, 29 insertions(+), 13 deletions(-)

Detailed changes

crates/audio/src/audio.rs 🔗

@@ -39,29 +39,43 @@ pub struct Audio {
 
 impl Audio {
     pub fn new() -> Self {
-        let (_output_stream, output_handle) = OutputStream::try_default().log_err().unzip();
-
         Self {
-            _output_stream,
-            output_handle,
+            _output_stream: None,
+            output_handle: None,
         }
     }
 
-    pub fn play_sound(sound: Sound, cx: &AppContext) {
+    fn ensure_output_exists(&mut self) -> Option<&OutputStreamHandle> {
+        if self.output_handle.is_none() {
+            let (_output_stream, output_handle) = OutputStream::try_default().log_err().unzip();
+            self.output_handle = output_handle;
+            self._output_stream = _output_stream;
+        }
+
+        self.output_handle.as_ref()
+    }
+
+    pub fn play_sound(sound: Sound, cx: &mut AppContext) {
         if !cx.has_global::<Self>() {
             return;
         }
 
-        let this = cx.global::<Self>();
+        cx.update_global::<Self, _, _>(|this, cx| {
+            let output_handle = this.ensure_output_exists()?;
+            let source = SoundRegistry::global(cx).get(sound.file()).log_err()?;
+            output_handle.play_raw(source).log_err()?;
+            Some(())
+        });
+    }
 
-        let Some(output_handle) = this.output_handle.as_ref() else {
+    pub fn end_call(cx: &mut AppContext) {
+        if !cx.has_global::<Self>() {
             return;
-        };
-
-        let Some(source) = SoundRegistry::global(cx).get(sound.file()).log_err() else {
-        return;
-    };
+        }
 
-        output_handle.play_raw(source).log_err();
+        cx.update_global::<Self, _, _>(|this, _| {
+            this._output_stream.take();
+            this.output_handle.take();
+        });
     }
 }

crates/call/src/call.rs 🔗

@@ -5,6 +5,7 @@ pub mod room;
 use std::sync::Arc;
 
 use anyhow::{anyhow, Result};
+use audio::Audio;
 use call_settings::CallSettings;
 use client::{
     proto, ChannelId, ClickhouseEvent, Client, TelemetrySettings, TypedEnvelope, User, UserStore,
@@ -309,6 +310,7 @@ impl ActiveCall {
     pub fn hang_up(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
         cx.notify();
         self.report_call_event("hang up", cx);
+        Audio::end_call(cx);
         if let Some((room, _)) = self.room.take() {
             room.update(cx, |room, cx| room.leave(cx))
         } else {