Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: audio level #1884

Merged
merged 22 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7bd25a1
feat: try new audio level
raviteja83 Sep 8, 2023
21c3a4e
fix: link audio level to animation
raviteja83 Sep 8, 2023
eebb2c7
fix: optimise audio level
raviteja83 Sep 8, 2023
162a4f3
Merge remote-tracking branch 'origin/main' into fix/WEB-2137-audio-level
raviteja83 Sep 11, 2023
c8c71cb
fix: audio level image
raviteja83 Sep 11, 2023
7702269
fix: overlay chat repostion on tapping
amar-1995 Sep 12, 2023
ca7550d
fix: show end session if endRoom permission exists
KaustubhKumar05 Sep 12, 2023
382d9ca
Merge remote-tracking branch 'origin/main' into fix/WEB-2137-audio-level
raviteja83 Sep 12, 2023
2c229ad
fix: audio level
raviteja83 Sep 13, 2023
0fe49d7
Merge branch 'dev' into fix/WEB-2137-audio-level
raviteja83 Sep 14, 2023
cc61ed0
fix: lint error
raviteja83 Sep 14, 2023
af6883b
fix: lint error
raviteja83 Sep 14, 2023
5e1886c
fix: audio level
raviteja83 Sep 14, 2023
5c686fd
Merge branch 'dev' into fix/WEB-2137-audio-level
raviteja83 Sep 19, 2023
875b7ba
Merge remote-tracking branch 'origin/dev' into fix/WEB-2137-audio-level
raviteja83 Sep 19, 2023
c69b87f
refactor: move audio level out of prebuilt
raviteja83 Sep 19, 2023
b54e099
fix: remove redundant css prop
raviteja83 Sep 19, 2023
7f1d05b
fix: use non-prefix for firefox
raviteja83 Sep 19, 2023
44e2892
Merge branch 'dev' into fix/WEB-2137-audio-level
raviteja83 Sep 19, 2023
843b226
Merge branch 'dev' into fix/WEB-2137-audio-level
raviteja83 Sep 19, 2023
a488dc6
refactor: remove unnecessary util
raviteja83 Sep 19, 2023
2d3a9ac
fix: audio level on smaller tiles
raviteja83 Sep 19, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 79 additions & 30 deletions packages/roomkit-react/src/AudioLevel/AudioLevel.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,83 @@
import { useCallback, useRef } from 'react';
import { HMSTrackID } from '@100mslive/hms-video-store';
import { useAudioLevelStyles } from '@100mslive/react-sdk';
import { useTheme } from '../Theme';
import React, { useEffect, useRef } from 'react';
import { selectTrackAudioByID, useHMSVanillaStore } from '@100mslive/react-sdk';
import { Box, Flex } from '../Layout';
import { keyframes } from '../Theme';
//@ts-ignore
import bg from './audio-level.png';

/**
* pass in a track id and get a ref. That ref can be attached to an element which will have border
* as per audio level post that.
*/
export function useBorderAudioLevel(audioTrackId?: HMSTrackID) {
const { theme } = useTheme();
const color = theme.colors.primary_default.value;
const getStyle = useCallback(
(level: number) => {
const style: Record<string, string> = {
transition: 'outline 0.4s ease-in-out',
};
style['outline'] = level ? `${sigmoid(level) * 4}px solid ${color}` : '0px solid transparent';
return style;
},
[color],
// keep the calculated values before hand to avoid recalcuation everytime
const positionValues = new Array(101).fill(0).reduce((acc, _, index) => {
acc[index] = Math.round((index / 100) * 4) / 4; // convert to 0.25 multiples
return acc;
}, {});

const barAnimation = keyframes({
from: {
maskSize: '4em .8em',
'-webkit-mask-position-y': '.1em',
maskPosition: 'initial .1em',
},

'50%': {
maskSize: '4em 1em',
'-webkit-mask-position-y': 0,
maskPosition: 'initial 0',
},

to: {
maskSize: '4em .8em',
'-webkit-mask-position-y': '.1em',
maskPosition: 'initial 0',
},
});

const AudioBar = () => {
return (
<Box
css={{
width: '.25em',
height: '1em',
maskImage: `url(${bg})`,
'-webkit-mask-repeat': 'no-repeat',
backgroundColor: '$on_primary_high',
maskSize: '4em 1em',
}}
/>
);
const ref = useRef(null);
useAudioLevelStyles({
trackId: audioTrackId,
getStyle,
ref,
});
return ref;
}
};

export const AudioLevel = ({ trackId, size }: { trackId?: string; size?: 'small' | 'medium' }) => {
const ref = useRef<HTMLDivElement | null>(null);
const vanillaStore = useHMSVanillaStore();

export const sigmoid = (z: number) => {
return 1 / (1 + Math.exp(-z));
useEffect(() => {
const unsubscribe = vanillaStore.subscribe(audioLevel => {
if (ref.current) {
let index = 0;
//@ts-ignore
for (const child of ref.current.children) {
const positionX = `-${positionValues[audioLevel] * (index === 1 ? 2.5 : 1.25)}em`;
child.style['-webkit-mask-position-x'] = positionX;
child.style['mask-position'] = `${positionX} 0`;
child.style['animation'] =
positionValues[audioLevel] > 0 ? `${barAnimation} 0.6s steps(3,jump-none) 0s infinite` : 'none';
index++;
}
}
}, selectTrackAudioByID(trackId));
return unsubscribe;
}, [vanillaStore, trackId]);
return (
<Flex
ref={ref}
css={{
fontSize: size === 'small' ? '0.75rem' : '1rem',
gap: size === 'small' ? '$1' : '$2',
}}
>
<AudioBar />
<AudioBar />
<AudioBar />
</Flex>
);
};
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion packages/roomkit-react/src/AudioLevel/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { useBorderAudioLevel } from './AudioLevel';
export { useBorderAudioLevel } from './useBorderAudioLevel';
export { AudioLevel } from './AudioLevel';
34 changes: 34 additions & 0 deletions packages/roomkit-react/src/AudioLevel/useBorderAudioLevel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useCallback, useRef } from 'react';
import { HMSTrackID } from '@100mslive/hms-video-store';
import { useAudioLevelStyles } from '@100mslive/react-sdk';
import { useTheme } from '../Theme';

/**
* pass in a track id and get a ref. That ref can be attached to an element which will have border
* as per audio level post that.
*/
export function useBorderAudioLevel(audioTrackId?: HMSTrackID) {
const { theme } = useTheme();
const color = theme.colors.primary_default.value;
const getStyle = useCallback(
(level: number) => {
const style: Record<string, string> = {
transition: 'outline 0.4s ease-in-out',
};
style['outline'] = level ? `${sigmoid(level) * 4}px solid ${color}` : '0px solid transparent';
return style;
},
[color],
);
const ref = useRef(null);
useAudioLevelStyles({
trackId: audioTrackId,
getStyle,
ref,
});
return ref;
}

export const sigmoid = (z: number) => {
return 1 / (1 + Math.exp(-z));
};
7 changes: 0 additions & 7 deletions packages/roomkit-react/src/Prebuilt/common/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,3 @@ export const formatTime = timeInSeconds => {
const hour = hours !== 0 ? `${hours < 10 ? '0' : ''}${hours}:` : '';
return `${hour}${minutes < 10 ? '0' : ''}${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
};

export const getAttributeBoxSize = (width, height) => {
if (!width || !height) {
return '';
}
return width < 180 || height < 180 ? 'small' : 'medium';
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
} from '@100mslive/react-sdk';
import { MicOffIcon, SettingsIcon } from '@100mslive/react-icons';
import { Avatar, Box, config as cssConfig, Flex, flexCenter, styled, StyledVideoTile, Text, Video } from '../../..';
import { AudioLevel } from '../../../AudioLevel';
import { useHMSPrebuiltContext } from '../../AppContext';
// @ts-ignore: No implicit Any
import IconButton from '../../IconButton';
Expand All @@ -31,8 +32,6 @@ import { Logo } from '../Header/HeaderComponents';
// @ts-ignore: No implicit Any
import SettingsModal from '../Settings/SettingsModal';
// @ts-ignore: No implicit Any
import { AudioLevel } from '../VideoTile';
// @ts-ignore: No implicit Any
import PreviewForm from './PreviewForm';
// @ts-ignore: No implicit Any
import { useAuthToken, useUISettings } from '../AppData/useUISettings';
Expand Down Expand Up @@ -246,7 +245,9 @@ export const PreviewTile = ({ name, error }: { name: string; error?: boolean })
<MicOffIcon />
</StyledVideoTile.AudioIndicator>
) : (
<AudioLevel trackId={localPeer?.audioTrack} />
<StyledVideoTile.AudioIndicator size="medium">
<AudioLevel trackId={localPeer?.audioTrack} />
</StyledVideoTile.AudioIndicator>
)}
</StyledVideoTile.Container>
);
Expand Down
91 changes: 22 additions & 69 deletions packages/roomkit-react/src/Prebuilt/components/VideoTile.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import React, { Fragment, useCallback, useMemo, useRef, useState } from 'react';
import { useMedia } from 'react-use';
import {
selectAudioTrackByPeerID,
Expand All @@ -8,24 +8,21 @@ import {
selectPeerMetadata,
selectPeerNameByID,
selectSessionStore,
selectTrackAudioByID,
selectVideoTrackByID,
selectVideoTrackByPeerID,
useHMSStore,
useHMSVanillaStore,
} from '@100mslive/react-sdk';
import { BrbTileIcon, HandIcon, MicOffIcon } from '@100mslive/react-icons';
import TileConnection from './Connection/TileConnection';
import TileMenu, { isSameTile } from './TileMenu/TileMenu';
import { AudioLevel } from '../../AudioLevel';
import { Avatar } from '../../Avatar';
import { Box, Flex } from '../../Layout';
import { VideoTileStats } from '../../Stats';
import { config as cssConfig, keyframes } from '../../Theme';
import { config as cssConfig } from '../../Theme';
import { Video } from '../../Video';
import { StyledVideoTile } from '../../VideoTile';
import { getVideoTileLabel } from './peerTileUtils';
import { useSetAppDataByKey, useUISettings } from './AppData/useUISettings';
import { getAttributeBoxSize } from '../common/utils';
import { APP_DATA, SESSION_STORE_KEY, UI_SETTINGS } from '../common/constants';

const Tile = ({
Expand Down Expand Up @@ -80,16 +77,22 @@ const Tile = ({

const isTileBigEnoughToShowStats = calculatedHeight >= 180 && calculatedWidth >= 180;

const avatarSize = useMemo(() => {
const [avatarSize, attribBoxSize] = useMemo(() => {
if (!calculatedWidth || !calculatedHeight) {
return undefined;
return [undefined, undefined];
}
let avatarSize = 'large';
if (calculatedWidth <= 150 || calculatedHeight <= 150) {
return 'small';
avatarSize = 'small';
} else if (calculatedWidth <= 300 || calculatedHeight <= 300) {
return 'medium';
avatarSize = 'medium';
}
return 'large';
let attribBoxSize = 'medium';
if (calculatedWidth <= 180 || calculatedHeight <= 180) {
attribBoxSize = 'small';
}

return [avatarSize, attribBoxSize];
}, [calculatedWidth, calculatedHeight]);

return (
Expand Down Expand Up @@ -139,14 +142,13 @@ const Tile = ({

{!hideAudioMuteOnTile ? (
isAudioMuted ? (
<StyledVideoTile.AudioIndicator
data-testid="participant_audio_mute_icon"
size={getAttributeBoxSize(calculatedWidth, calculatedHeight)}
>
<StyledVideoTile.AudioIndicator data-testid="participant_audio_mute_icon" size={attribBoxSize}>
<MicOffIcon />
</StyledVideoTile.AudioIndicator>
) : (
<AudioLevel trackId={audioTrack?.id} />
<StyledVideoTile.AudioIndicator size={attribBoxSize}>
<AudioLevel trackId={audioTrack?.id} size={attribBoxSize} />
</StyledVideoTile.AudioIndicator>
)
) : null}
{isMouseHovered || (isDragabble && isMobile) ? (
Expand All @@ -158,7 +160,7 @@ const Tile = ({
enableSpotlightingPeer={enableSpotlightingPeer}
/>
) : null}
{!hideMetadataOnTile && <PeerMetadata peerId={peerId} height={calculatedHeight} width={calculatedWidth} />}
{!hideMetadataOnTile && <PeerMetadata peerId={peerId} size={attribBoxSize} />}

<TileConnection
hideLabel={hideParticipantNameOnTile}
Expand All @@ -175,69 +177,20 @@ const Tile = ({
);
};

const heightAnimation = value =>
keyframes({
'50%': {
transform: `scale3d(1,${value},1)`,
},
'100%': {
transform: `scale3d(1,1,1)`,
},
});

const AudioLevelIndicator = ({ trackId, value, delay }) => {
const vanillaStore = useHMSVanillaStore();
const ref = useRef();

useEffect(() => {
const unsubscribe = vanillaStore.subscribe(audioLevel => {
if (ref.current) {
ref.current.style['animation'] = `${heightAnimation(
audioLevel ? value : 1,
)} 0.3s cubic-bezier(0.61, 1, 0.88, 1) infinite ${delay}s`;
}
}, selectTrackAudioByID(trackId));
return unsubscribe;
}, [vanillaStore, trackId, value, delay]);
return (
<Box
ref={ref}
css={{
w: 4,
height: 6,
r: 2,
bg: '$on_primary_high',
}}
/>
);
};

export const AudioLevel = ({ trackId }) => {
return (
<StyledVideoTile.AudioIndicator>
<Flex align="center" justify="center" css={{ gap: '$2' }}>
{[3, 2, 3].map((v, i) => (
<AudioLevelIndicator trackId={trackId} value={v} delay={i * 0.15} key={i} />
))}
</Flex>
</StyledVideoTile.AudioIndicator>
);
};

const PeerMetadata = ({ peerId, height, width }) => {
const PeerMetadata = ({ peerId, size }) => {
const metaData = useHMSStore(selectPeerMetadata(peerId));
const isBRB = metaData?.isBRBOn || false;
const isHandRaised = useHMSStore(selectHasPeerHandRaised(peerId));

return (
<Fragment>
{isHandRaised ? (
<StyledVideoTile.AttributeBox size={getAttributeBoxSize(width, height)} data-testid="raiseHand_icon_onTile">
<StyledVideoTile.AttributeBox size={size} data-testid="raiseHand_icon_onTile">
<HandIcon width={24} height={24} />
</StyledVideoTile.AttributeBox>
) : null}
{isBRB ? (
<StyledVideoTile.AttributeBox size={getAttributeBoxSize(width, height)} data-testid="brb_icon_onTile">
<StyledVideoTile.AttributeBox size={size} data-testid="brb_icon_onTile">
<BrbTileIcon width={22} height={22} />
</StyledVideoTile.AttributeBox>
) : null}
Expand Down
Loading