From ac39e539cd4a5897bd53fbe132b64ed4d4d9316f Mon Sep 17 00:00:00 2001
From: harshithpabbati <pabbatiharshith@gmail.com>
Date: Tue, 11 Oct 2022 21:22:58 +0530
Subject: [PATCH 1/3] wip: play on device change so that it doesn't freeze

---
 src/components/VideoTile.vue | 57 ++++++++++++------------------------
 1 file changed, 18 insertions(+), 39 deletions(-)

diff --git a/src/components/VideoTile.vue b/src/components/VideoTile.vue
index b0b8048..95797cd 100644
--- a/src/components/VideoTile.vue
+++ b/src/components/VideoTile.vue
@@ -1,11 +1,11 @@
 <template>
   <div class="tile">
-    <audio autoPlay playsInline :srcObject="audioSource">
+    <audio autoPlay playsInline ref="audioRef">
       <track kind="captions" />
     </audio>
 
     <template v-if="participant.video">
-      <video autoPlay muted playsInline :srcObject="videoSource"></video>
+      <video autoPlay muted playsInline ref="videoRef"></video>
       <p class="participant-name">{{ username }}</p>
     </template>
 
@@ -46,8 +46,6 @@ export default {
   ],
   data() {
     return {
-      videoSource: null,
-      audioSource: null,
       username: "Guest",
     };
   },
@@ -55,6 +53,11 @@ export default {
     this.username = this.participant?.user_name;
     this.handleVideo(this.participant);
     this.handleAudio(this.participant);
+
+    navigator.mediaDevices.addEventListener("devicechange", this.playTracks);
+  },
+  unmounted() {
+    navigator.mediaDevices.removeEventListener("devicechange", this.playTracks);
   },
   updated() {
     this.username = this.participant?.user_name;
@@ -64,6 +67,11 @@ export default {
     this.handleAudio(this.participant);
   },
   methods: {
+    playTracks () {
+      this.$refs.videoRef.play();
+      this.$refs.audioRef.play();
+    },
+
     // Add srcObject to video element
     handleVideo() {
       const p = this.participant;
@@ -72,11 +80,9 @@ export default {
       // early out.
       if (!p?.video) return;
 
-      const track = p.tracks.video.persistentTrack;
-      const newStream = this.updateSource(this.videoSource, track);
-      if (newStream) {
-        this.videoSource = newStream;
-      }
+      const track = p?.tracks?.video?.persistentTrack;
+      this.$refs.videoRef.srcObject = new MediaStream([track]);
+      this.$refs.videoRef.play();
     },
 
     // Add srcObject to audio element
@@ -86,36 +92,9 @@ export default {
       // early out.
       if (!p || p.local || !p.audio) return;
 
-      const track = p.tracks.audio.persistentTrack;
-      const newStream = this.updateSource(this.audioSource, track);
-      if (newStream) {
-        this.audioSource = newStream;
-      }
-    },
-
-    // updateSource() updates the given stream with new tracks OR
-    // returns an entirely new stream to the caller.
-    updateSource(stream, newTrack) {
-      const existingTracks = stream?.getTracks();
-      // If the stream parameter contains no existing tracks,
-      // just return a new MediaStream to set. This should
-      // only happen the first time the tile is initialized.
-      if (!existingTracks || existingTracks.length === 0) {
-        return new MediaStream([newTrack]);
-      }
-      if (existingTracks.length > 1) {
-        console.warn(
-          `expected 1 track, found ${existingTracks.length}. Only using the first one.`
-        );
-      }
-      const existingTrack = existingTracks[0];
-      // If existing track is different from the new track,
-      // remove the existing track and add the new one.
-      if (newTrack.id !== existingTrack.id) {
-        stream.removeTrack(existingTrack);
-        stream.addTrack(newTrack);
-      }
-      return null;
+      const track = p?.tracks?.audio?.persistentTrack;
+      this.$refs.audioRef.srcObject = new MediaStream([track]);
+      this.$refs.audioRef.play();
     },
   },
 };

From 0e4f2e405227688e5fe0438ed40ee927c588bd0d Mon Sep 17 00:00:00 2001
From: harshithpabbati <pabbatiharshith@gmail.com>
Date: Wed, 12 Oct 2022 12:51:09 +0530
Subject: [PATCH 2/3] listen to canplay event

---
 src/components/VideoTile.vue | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/src/components/VideoTile.vue b/src/components/VideoTile.vue
index 95797cd..37d1533 100644
--- a/src/components/VideoTile.vue
+++ b/src/components/VideoTile.vue
@@ -54,9 +54,13 @@ export default {
     this.handleVideo(this.participant);
     this.handleAudio(this.participant);
 
+    this.$refs.videoRef?.addEventListener("canplay", this.handleVideoCanPlay);
+    this.$refs.audioRef?.addEventListener("canplay", this.handleAudioCanPlay);
     navigator.mediaDevices.addEventListener("devicechange", this.playTracks);
   },
   unmounted() {
+    this.$refs.videoRef?.removeEventListener("canplay", this.handleVideoCanPlay);
+    this.$refs.audioRef?.removeEventListener("canplay", this.handleAudioCanPlay);
     navigator.mediaDevices.removeEventListener("devicechange", this.playTracks);
   },
   updated() {
@@ -67,10 +71,18 @@ export default {
     this.handleAudio(this.participant);
   },
   methods: {
-    playTracks () {
+    handleVideoCanPlay () {
+      if (!this.$refs.videoRef.paused) return;
       this.$refs.videoRef.play();
+    },
+    handleAudioCanPlay () {
+      if (!this.$refs.audioRef.paused) return;
       this.$refs.audioRef.play();
     },
+    playTracks () {
+      this.handleVideoCanPlay();
+      this.handleAudioCanPlay();
+    },
 
     // Add srcObject to video element
     handleVideo() {
@@ -82,7 +94,7 @@ export default {
 
       const track = p?.tracks?.video?.persistentTrack;
       this.$refs.videoRef.srcObject = new MediaStream([track]);
-      this.$refs.videoRef.play();
+      this.$refs.videoRef.load();
     },
 
     // Add srcObject to audio element
@@ -94,7 +106,7 @@ export default {
 
       const track = p?.tracks?.audio?.persistentTrack;
       this.$refs.audioRef.srcObject = new MediaStream([track]);
-      this.$refs.audioRef.play();
+      this.$refs.audioRef.load();
     },
   },
 };

From 09982add50fd7cd807b398d3774b17f48fb657d5 Mon Sep 17 00:00:00 2001
From: harshithpabbati <pabbatiharshith@gmail.com>
Date: Wed, 12 Oct 2022 17:45:44 +0530
Subject: [PATCH 3/3] Log autoplay failure

---
 src/components/CallTile.vue  |  3 +++
 src/components/VideoTile.vue | 39 +++++++++++++++++++++++++++---------
 2 files changed, 32 insertions(+), 10 deletions(-)

diff --git a/src/components/CallTile.vue b/src/components/CallTile.vue
index 8a03c0b..7fb8c90 100644
--- a/src/components/CallTile.vue
+++ b/src/components/CallTile.vue
@@ -86,6 +86,9 @@ export default {
   mounted() {
     const option = {
       url: this.roomUrl,
+      dailyConfig: {
+        experimentalChromeVideoMuteLightOff: true,
+      }
     };
 
     // Create instance of Daily call object
diff --git a/src/components/VideoTile.vue b/src/components/VideoTile.vue
index 37d1533..837da61 100644
--- a/src/components/VideoTile.vue
+++ b/src/components/VideoTile.vue
@@ -1,11 +1,11 @@
 <template>
   <div class="tile">
-    <audio autoPlay playsInline ref="audioRef">
+    <audio autoplay playsInline ref="audioRef">
       <track kind="captions" />
     </audio>
 
     <template v-if="participant.video">
-      <video autoPlay muted playsInline ref="videoRef"></video>
+      <video autoplay muted playsInline ref="videoRef"></video>
       <p class="participant-name">{{ username }}</p>
     </template>
 
@@ -73,11 +73,19 @@ export default {
   methods: {
     handleVideoCanPlay () {
       if (!this.$refs.videoRef.paused) return;
-      this.$refs.videoRef.play();
+      this.$refs.videoRef.play().catch((e) => {
+        if (e instanceof DOMException && e.name === 'NotAllowedError') {
+          console.error("Autoplay failed", e);
+        } else console.error("Error playing video", e);
+      });
     },
     handleAudioCanPlay () {
       if (!this.$refs.audioRef.paused) return;
-      this.$refs.audioRef.play();
+      this.$refs.audioRef.play().catch((e) => {
+        if (e instanceof DOMException && e.name === 'NotAllowedError') {
+          console.error("Autoplay failed", e);
+        } else console.error("Error playing audio: ", e);
+      });
     },
     playTracks () {
       this.handleVideoCanPlay();
@@ -92,9 +100,13 @@ export default {
       // early out.
       if (!p?.video) return;
 
-      const track = p?.tracks?.video?.persistentTrack;
-      this.$refs.videoRef.srcObject = new MediaStream([track]);
-      this.$refs.videoRef.load();
+      try {
+        const track = p?.tracks?.video?.persistentTrack;
+        this.$refs.videoRef.srcObject = new MediaStream([track]);
+        this.$refs.videoRef.load();
+      } catch (e) {
+        console.error('show up a modal to get user gesture', e);
+      }
     },
 
     // Add srcObject to audio element
@@ -104,9 +116,12 @@ export default {
       // early out.
       if (!p || p.local || !p.audio) return;
 
-      const track = p?.tracks?.audio?.persistentTrack;
-      this.$refs.audioRef.srcObject = new MediaStream([track]);
-      this.$refs.audioRef.load();
+      try {
+        const track = p?.tracks?.audio?.persistentTrack;
+        this.$refs.audioRef.srcObject = new MediaStream([track]);
+      } catch (e) {
+        console.error('show up a modal to get user gesture', e);
+      }
     },
   },
 };
@@ -123,6 +138,10 @@ video {
   width: 100%;
   border-radius: 16px;
 }
+audio {
+  position: absolute;
+  visibility: hidden;
+}
 .participant-name {
   position: absolute;
   color: #fff;