diff --git a/custom/shared/components/Aside/NetworkAside.js b/custom/shared/components/Aside/NetworkAside.js
index 0f4d61c..0469039 100644
--- a/custom/shared/components/Aside/NetworkAside.js
+++ b/custom/shared/components/Aside/NetworkAside.js
@@ -22,9 +22,7 @@ export const NetworkAside = () => {
}, [callObject]);
useEffect(() => {
- if (!callObject) {
- return;
- }
+ if (!callObject) return;
updateStats();
@@ -38,7 +36,7 @@ export const NetworkAside = () => {
Math.round(
(networkStats?.stats?.latest?.videoRecvBitsPerSecond ?? 0) / 1000
),
- [networkStats]
+ [networkStats?.stats?.latest?.videoRecvBitsPerSecond]
);
const uploadKbs = useMemo(
@@ -46,7 +44,7 @@ export const NetworkAside = () => {
Math.round(
(networkStats?.stats?.latest?.videoSendBitsPerSecond ?? 0) / 1000
),
- [networkStats]
+ [networkStats?.stats?.latest?.videoSendBitsPerSecond]
);
if (!showAside || showAside !== NETWORK_ASIDE) {
diff --git a/custom/shared/components/Audio/Audio.js b/custom/shared/components/Audio/Audio.js
index a806340..a4d74dc 100644
--- a/custom/shared/components/Audio/Audio.js
+++ b/custom/shared/components/Audio/Audio.js
@@ -8,22 +8,30 @@
* into into a single audio node using the CombinedAudioTrack component
*/
import React, { useEffect, useMemo } from 'react';
+import { useCallState } from '@custom/shared/contexts/CallProvider';
import { useTracks } from '@custom/shared/contexts/TracksProvider';
+import { useUIState } from '@custom/shared/contexts/UIStateProvider';
+import { isScreenId } from '@custom/shared/contexts/participantsState';
import Bowser from 'bowser';
import { Portal } from 'react-portal';
import AudioTrack from './AudioTrack';
import CombinedAudioTrack from './CombinedAudioTrack';
+
export const Audio = () => {
+ const { disableAudio } = useCallState();
const { audioTracks } = useTracks();
+ const { setShowAutoplayFailedModal } = useUIState();
const renderedTracks = useMemo(
() =>
- Object.entries(audioTracks).reduce(
- (tracks, [id, track]) => ({ ...tracks, [id]: track }),
- {}
- ),
- [audioTracks]
+ Object.entries(audioTracks).reduce((tracks, [id, track]) => {
+ if (!disableAudio || isScreenId(id)) {
+ tracks[id] = track;
+ }
+ return tracks;
+ }, {}),
+ [audioTracks, disableAudio]
);
// On iOS safari, when headphones are disconnected, all audio elements are paused.
@@ -32,25 +40,31 @@ export const Audio = () => {
// To fix that, we call `play` on each audio track on all devicechange events.
useEffect(() => {
const playTracks = () => {
- document.querySelectorAll('.audioTracks audio').forEach(async (audio) => {
- try {
- if (audio.paused && audio.readyState === audio.HAVE_ENOUGH_DATA) {
- await audio?.play();
+ document
+ .querySelectorAll('.audioTracks audio')
+ .forEach(async (audio) => {
+ try {
+ if (audio.paused && audio.readyState === audio.HAVE_ENOUGH_DATA) {
+ await audio?.play();
+ }
+ } catch (e) {
+ setShowAutoplayFailedModal(true);
}
- } catch (e) {
- // Auto play failed
- }
- });
+ });
};
navigator.mediaDevices.addEventListener('devicechange', playTracks);
return () => {
navigator.mediaDevices.removeEventListener('devicechange', playTracks);
};
- }, []);
+ }, [setShowAutoplayFailedModal]);
const tracksComponent = useMemo(() => {
- const { browser } = Bowser.parse(navigator.userAgent);
- if (browser.name === 'Chrome' && parseInt(browser.version, 10) >= 92) {
+ const { browser, platform, os } = Bowser.parse(navigator.userAgent);
+ if (
+ browser.name === 'Chrome' &&
+ parseInt(browser.version, 10) >= 92 &&
+ (platform.type === 'desktop' || os.name === 'Android')
+ ) {
return ;
}
return Object.entries(renderedTracks).map(([id, track]) => (
diff --git a/custom/shared/components/Audio/AudioTrack.js b/custom/shared/components/Audio/AudioTrack.js
index 82b22db..5da059d 100644
--- a/custom/shared/components/Audio/AudioTrack.js
+++ b/custom/shared/components/Audio/AudioTrack.js
@@ -1,38 +1,35 @@
import React, { useRef, useEffect } from 'react';
+import { useUIState } from '@custom/shared/contexts/UIStateProvider';
import PropTypes from 'prop-types';
-const AudioTrack = ({ track }) => {
+export const AudioTrack = ({ track }) => {
const audioRef = useRef(null);
+ const { setShowAutoplayFailedModal } = useUIState();
useEffect(() => {
- if (!audioRef.current) return false;
+ const audioTag = audioRef.current;
+ if (!audioTag) return false;
let playTimeout;
const handleCanPlay = () => {
playTimeout = setTimeout(() => {
- console.log('Unable to autoplay audio element');
+ setShowAutoplayFailedModal(true);
}, 1500);
};
const handlePlay = () => {
clearTimeout(playTimeout);
};
- audioRef.current.addEventListener('canplay', handleCanPlay);
- audioRef.current.addEventListener('play', handlePlay);
- audioRef.current.srcObject = new MediaStream([track]);
-
- const audioEl = audioRef.current;
+ audioTag.addEventListener('canplay', handleCanPlay);
+ audioTag.addEventListener('play', handlePlay);
+ audioTag.srcObject = new MediaStream([track]);
return () => {
- audioEl?.removeEventListener('canplay', handleCanPlay);
- audioEl?.removeEventListener('play', handlePlay);
+ audioTag?.removeEventListener('canplay', handleCanPlay);
+ audioTag?.removeEventListener('play', handlePlay);
};
- }, [track]);
+ }, [setShowAutoplayFailedModal, track]);
- return track ? (
-
- ) : null;
+ return track ? : null;
};
AudioTrack.propTypes = {
diff --git a/custom/shared/components/Audio/CombinedAudioTrack.js b/custom/shared/components/Audio/CombinedAudioTrack.js
index 0e81f23..0082860 100644
--- a/custom/shared/components/Audio/CombinedAudioTrack.js
+++ b/custom/shared/components/Audio/CombinedAudioTrack.js
@@ -2,7 +2,7 @@ import React, { useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import { useDeepCompareEffect, useDeepCompareMemo } from 'use-deep-compare';
-const CombinedAudioTrack = ({ tracks }) => {
+export const CombinedAudioTrack = ({ tracks }) => {
const audioEl = useRef(null);
useEffect(() => {
@@ -25,12 +25,21 @@ const CombinedAudioTrack = ({ tracks }) => {
allTracks.forEach((track) => {
const persistentTrack = track?.persistentTrack;
if (persistentTrack) {
- persistentTrack.addEventListener(
- 'ended',
- (ev) => stream.removeTrack(ev.target),
- { once: true }
- );
- stream.addTrack(persistentTrack);
+ switch (persistentTrack.readyState) {
+ case 'ended':
+ stream.removeTrack(persistentTrack);
+ break;
+ case 'live':
+ persistentTrack.addEventListener(
+ 'ended',
+ (ev) => {
+ stream.removeTrack(ev.target);
+ },
+ { once: true }
+ );
+ stream.addTrack(persistentTrack);
+ break;
+ }
}
});
@@ -53,11 +62,7 @@ const CombinedAudioTrack = ({ tracks }) => {
playAudio();
}, [tracks, trackIds]);
- return (
-
- );
+ return ;
};
CombinedAudioTrack.propTypes = {
diff --git a/custom/shared/components/Capsule/Capsule.js b/custom/shared/components/Capsule/Capsule.js
index 09362b0..1849715 100644
--- a/custom/shared/components/Capsule/Capsule.js
+++ b/custom/shared/components/Capsule/Capsule.js
@@ -6,18 +6,19 @@ export const Capsule = ({ children, variant }) => (
{children}
+ >
+ );
}),
(p, n) => shallowEqualObjects(p, n)
);
diff --git a/custom/shared/contexts/UIStateProvider.js b/custom/shared/contexts/UIStateProvider.js
index d2e02d1..0a376fb 100644
--- a/custom/shared/contexts/UIStateProvider.js
+++ b/custom/shared/contexts/UIStateProvider.js
@@ -20,6 +20,7 @@ export const UIStateProvider = ({
customTrayComponent,
children,
}) => {
+ const [isMobile, setIsMobile] = useState(false);
const [pinnedId, setPinnedId] = useState(null);
const [preferredViewMode, setPreferredViewMode] = useState(VIEW_MODE_SPEAKER);
const [viewMode, setViewMode] = useState(preferredViewMode);
@@ -28,6 +29,7 @@ export const UIStateProvider = ({
const [showAside, setShowAside] = useState();
const [activeModals, setActiveModals] = useState({});
const [customCapsule, setCustomCapsule] = useState();
+ const [showAutoplayFailedModal, setShowAutoplayFailedModal] = useState(false);
const openModal = useCallback((modalName) => {
setActiveModals((prevState) => ({
@@ -87,6 +89,10 @@ export const UIStateProvider = ({
setShowParticipantsBar,
customCapsule,
setCustomCapsule,
+ showAutoplayFailedModal,
+ setShowAutoplayFailedModal,
+ isMobile,
+ setIsMobile,
}}
>
{children}