From f6229317d8f59899d4bd0f292b3d39fb2f5a08d1 Mon Sep 17 00:00:00 2001 From: Jon Date: Thu, 17 Jun 2021 11:29:18 +0100 Subject: [PATCH] moved audio tracks component to shared library --- dailyjs/basic-call/components/Audio/Audio.js | 44 ----------- dailyjs/basic-call/components/Room/Room.js | 2 +- dailyjs/shared/components/Audio/Audio.js | 79 +++++++++++++++++++ .../components/Audio/index.js | 0 4 files changed, 80 insertions(+), 45 deletions(-) delete mode 100644 dailyjs/basic-call/components/Audio/Audio.js create mode 100644 dailyjs/shared/components/Audio/Audio.js rename dailyjs/{basic-call => shared}/components/Audio/index.js (100%) 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