diff --git a/dailyjs/basic-call/components/Audio/Audio.js b/dailyjs/basic-call/components/Audio/Audio.js
deleted file mode 100644
index 3e5b7f1..0000000
--- a/dailyjs/basic-call/components/Audio/Audio.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import React, { useRef, useEffect } from 'react';
-import { useParticipants } from '@dailyjs/shared/contexts/ParticipantsProvider';
-import useAudioTrack from '@dailyjs/shared/hooks/useAudioTrack';
-import PropTypes from 'prop-types';
-
-const AudioItem = React.memo(({ participant }) => {
- const audioRef = useRef(null);
- const audioTrack = useAudioTrack(participant);
-
- useEffect(() => {
- if (!audioTrack || !audioRef.current) return;
-
- // quick sanity to check to make sure this is an audio track...
- if (audioTrack.kind !== 'audio') return;
-
- audioRef.current.srcObject = new MediaStream([audioTrack]);
- }, [audioTrack]);
-
- return (
- <>
-
- >
- );
-});
-
-AudioItem.propTypes = {
- participant: PropTypes.object,
-};
-
-export const Audio = React.memo(() => {
- const { allParticipants } = useParticipants();
-
- return (
- <>
- {allParticipants.map(
- (p) => !p.isLocal &&
- )}
- >
- );
-});
-
-export default Audio;
diff --git a/dailyjs/basic-call/components/Room/Room.js b/dailyjs/basic-call/components/Room/Room.js
index b78228b..2402bbf 100644
--- a/dailyjs/basic-call/components/Room/Room.js
+++ b/dailyjs/basic-call/components/Room/Room.js
@@ -1,4 +1,5 @@
import React from 'react';
+import { Audio } from '@dailyjs/shared/components/Audio';
import {
WaitingRoomModal,
WaitingRoomNotification,
@@ -16,7 +17,6 @@ import { ReactComponent as IconMicOn } from '@dailyjs/shared/icons/mic-on-md.svg
import { ReactComponent as IconSettings } from '@dailyjs/shared/icons/settings-md.svg';
import PropTypes from 'prop-types';
-import { Audio } from '../Audio';
import { VideoGrid } from '../VideoGrid';
import { Header } from './Header';
import { Tray, TrayButton } from './Tray';
diff --git a/dailyjs/shared/components/Audio/Audio.js b/dailyjs/shared/components/Audio/Audio.js
new file mode 100644
index 0000000..a0e1497
--- /dev/null
+++ b/dailyjs/shared/components/Audio/Audio.js
@@ -0,0 +1,79 @@
+/**
+ * Audio
+ * ---
+ * Renders audio tags for each audible participant / screen share in the call
+ * Note: it's very important to minimise DOM mutates for audio components
+ * as iOS / Safari do a lot of browser 'magic' that may result in muted
+ * tracks. We heavily memoize this component to avoid unnecassary re-renders.
+ */
+import React, { useRef, useEffect } from 'react';
+import { useParticipants } from '@dailyjs/shared/contexts/ParticipantsProvider';
+import useAudioTrack from '@dailyjs/shared/hooks/useAudioTrack';
+import PropTypes from 'prop-types';
+
+const AudioItem = React.memo(
+ ({ participant }) => {
+ const audioRef = useRef(null);
+ const audioTrack = useAudioTrack(participant);
+
+ useEffect(() => {
+ if (!audioTrack || !audioRef.current) return;
+
+ // quick sanity to check to make sure this is an audio track...
+ if (audioTrack.kind !== 'audio') return;
+
+ audioRef.current.srcObject = new MediaStream([audioTrack]);
+ }, [audioTrack]);
+
+ useEffect(() => {
+ // On iOS safari, when headphones are disconnected, all audio elements are paused.
+ // This means that when a user disconnects their headphones, that user will not
+ // be able to hear any other users until they mute/unmute their mics.
+ // To fix that, we call `play` on each audio track on all devicechange events.
+ if (audioRef.currenet) {
+ return false;
+ }
+ const startPlayingTrack = () => {
+ audioRef.current?.play();
+ };
+
+ navigator.mediaDevices.addEventListener(
+ 'devicechange',
+ startPlayingTrack
+ );
+
+ return () =>
+ navigator.mediaDevices.removeEventListener(
+ 'devicechange',
+ startPlayingTrack
+ );
+ }, [audioRef]);
+
+ return (
+ <>
+
+ >
+ );
+ },
+ () => true
+);
+
+AudioItem.propTypes = {
+ participant: PropTypes.object,
+};
+
+export const Audio = React.memo(() => {
+ const { allParticipants } = useParticipants();
+
+ return (
+ <>
+ {allParticipants.map(
+ (p) => !p.isLocal &&
+ )}
+ >
+ );
+});
+
+export default Audio;
diff --git a/dailyjs/basic-call/components/Audio/index.js b/dailyjs/shared/components/Audio/index.js
similarity index 100%
rename from dailyjs/basic-call/components/Audio/index.js
rename to dailyjs/shared/components/Audio/index.js