Skip to content

Commit

Permalink
Add recording state
Browse files Browse the repository at this point in the history
  • Loading branch information
havfo committed Mar 18, 2024
1 parent 7c0d8ab commit b9d713d
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 18 deletions.
2 changes: 2 additions & 0 deletions src/components/participantlist/ListPeer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import MicUnMutedIcon from '@mui/icons-material/MicNoneOutlined';
import WebcamIcon from '@mui/icons-material/VideocamOutlined';
import MoreButton from '../controlbuttons/MoreButton';
import { roomSessionsActions } from '../../store/slices/roomSessionsSlice';
import RecordIcon from '../recordicon/RecordIcon';

interface ListPeerProps {
peer: Peer;
Expand Down Expand Up @@ -75,6 +76,7 @@ const ListPeer = ({ peer, isModerator }: ListPeerProps): JSX.Element => {
else dispatch(roomSessionsActions.selectPeer({ sessionId: peer.sessionId, peerId: peer.id }));
}}>
<PeerAvatar src={peer.picture ?? '/images/buddy.svg'} />
{ peer.recording && <RecordIcon color='error' /> }
{ peer.raisedHand &&
<IconButton
disabled={!isModerator || peer.raisedHandInProgress}
Expand Down
13 changes: 13 additions & 0 deletions src/components/recordicon/RecordIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { styled } from '@mui/material';
import { memo } from 'react';
import FiberManualRecordIcon from '@mui/icons-material/FiberManualRecord';

export default memo(styled(FiberManualRecordIcon)({
'&': {
animation: 'blink 1.5s ease-in-out infinite'
},
'@keyframes blink': {
from: { opacity: 1 },
to: { opacity: 0 },
}
}));
5 changes: 4 additions & 1 deletion src/components/topbar/TopBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { AppBar, Chip, Toolbar, Typography } from '@mui/material';
import { styled } from '@mui/material/styles';
import { useEffect, useState } from 'react';
import { useAppSelector, usePermissionSelector } from '../../store/hooks';
import { lobbyPeersLengthSelector, roomSessionCreationTimestampSelector } from '../../store/selectors';
import { lobbyPeersLengthSelector, roomSessionCreationTimestampSelector, someoneIsRecordingSelector } from '../../store/selectors';
import edumeetConfig from '../../utils/edumeetConfig';
import { permissions } from '../../utils/roles';
import LobbyButton from '../controlbuttons/LobbyButton';
Expand All @@ -13,6 +13,7 @@ import SettingsButton from '../controlbuttons/SettingsButton';
import LeaveButton from '../textbuttons/LeaveButton';
import { formatDuration } from '../../utils/formatDuration';
import LogoutButton from '../controlbuttons/LogoutButton';
import RecordIcon from '../recordicon/RecordIcon';

interface TopBarProps {
fullscreenEnabled: boolean;
Expand Down Expand Up @@ -77,6 +78,7 @@ const TopBar = ({ fullscreenEnabled, fullscreen, onFullscreen }: TopBarProps): R
const roomCreationTimestamp = useAppSelector(roomSessionCreationTimestampSelector);
const [ meetingDuration, setMeetingDuration ] = useState<number>(0);
const loggedIn = useAppSelector((state) => state.permissions.loggedIn);
const someoneIsRecording = useAppSelector(someoneIsRecordingSelector);

useEffect(() => {
if (roomCreationTimestamp) {
Expand Down Expand Up @@ -111,6 +113,7 @@ const TopBar = ({ fullscreenEnabled, fullscreen, onFullscreen }: TopBarProps): R
</TopBarDiv>
<TopBarDiv grow={1} />
<TopBarDiv marginRight={1}>
{ someoneIsRecording && <RecordIcon color='error' /> }
{ fullscreenEnabled && <FullscreenButton type='iconbutton' fullscreen={fullscreen} onClick={onFullscreen} /> }
<SettingsButton type='iconbutton' />
{ canLock && <LockButton type='iconbutton' /> }
Expand Down
24 changes: 12 additions & 12 deletions src/store/actions/recordingActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ let mimeType: string;
export const startRecording = (): AppThunk<Promise<void>> => async (
dispatch,
getState,
{ mediaService }
{ mediaService, signalingService }
) => {
mimeType = getState().settings.preferredRecorderMimeType;

Expand Down Expand Up @@ -118,6 +118,8 @@ export const startRecording = (): AppThunk<Promise<void>> => async (
recorderStream = new MediaStream([ mixedAudioTrack, screenVideotrack ]);
recorder = new MediaRecorder(recorderStream, { mimeType });

signalingService.notify('recording', { recording: true });

recorder.addEventListener('error', (event) => {
logger.error('recording.error', event);

Expand All @@ -144,26 +146,24 @@ export const startRecording = (): AppThunk<Promise<void>> => async (
}
};

export const stopRecording = (): AppThunk<Promise<void>> => async (dispatch) => {
export const stopRecording = (): AppThunk<void> => (
dispatch,
_getState,
{ signalingService }
) => {
logger.debug('stopRecording()');

signalingService.notify('recording', { recording: false });

try {
recorder?.stop();
screenStream?.getTracks().forEach((track) => track.stop());
recorderStream?.getTracks().forEach((track) => track.stop());
audioContext?.close();
audioDestination?.disconnect();

// Give some time for last recording chunks to come through
setTimeout(async () => {
try {
await writableStream?.close();
} catch (error) {
logger.error('stopRecorder() [error:%o]', error);
}
}, RECORDING_SLICE_SIZE);
writableStream?.close();
} catch (error) {
logger.error('stopRecorder() [error:%o]', error);
logger.error('stopRecording() [error:%o]', error);
}

dispatch(roomActions.updateRoom({ recording: false }));
Expand Down
11 changes: 8 additions & 3 deletions src/store/middlewares/peerMiddleware.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ const createPeerMiddleware = ({
displayName,
picture,
raisedHand,
raisedHandTimestamp
raisedHandTimestamp,
recording,
} = notification.data;

dispatch(peersActions.addPeer({
Expand All @@ -46,6 +47,7 @@ const createPeerMiddleware = ({
picture,
raisedHand,
raisedHandTimestamp,
recording,
transcripts: [],
}));

Expand All @@ -70,13 +72,15 @@ const createPeerMiddleware = ({

case 'changeDisplayName':
case 'changePicture':
case 'recording':
case 'raisedHand': {
const {
peerId,
displayName,
picture,
raisedHand,
raisedHandTimestamp
raisedHandTimestamp,
recording,
} = notification.data;

dispatch(
Expand All @@ -85,7 +89,8 @@ const createPeerMiddleware = ({
displayName,
picture,
raisedHand,
raisedHandTimestamp
raisedHandTimestamp,
recording,
})
);

Expand Down
7 changes: 7 additions & 0 deletions src/store/selectors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const hideNonVideoSelector: Selector<boolean> = (state) => state.settings.hideNo
const hideSelfViewSelector: Selector<boolean> = (state) => state.settings.hideSelfView;
const devicesSelector: Selector<MediaDevice[]> = (state) => state.me.devices;
const headlessSelector: Selector<boolean | undefined> = (state) => state.room.headless;
const recordingSelector: Selector<boolean | undefined> = (state) => state.room.recording;

export const isMobileSelector: Selector<boolean> = (state) => state.me.browser.platform === 'mobile';

Expand Down Expand Up @@ -338,6 +339,12 @@ export const raisedHandsSelector = createSelector(
(peers) => peers.reduce((a, b) => (a + (b.raisedHand ? 1 : 0)), 0)
);

export const someoneIsRecordingSelector = createSelector(
sessionIdPeersSelector,
recordingSelector,
(peers, recording) => recording || peers.some((peer) => peer.recording)
);

/**
* Returns the one state consumer that is currently in fullscreen
* in the main window.
Expand Down
8 changes: 6 additions & 2 deletions src/store/slices/peersSlice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface Peer {
raisedHandInProgress?: boolean;
raisedHand?: boolean;
raisedHandTimestamp?: number;
recording?: boolean;
transcripts?: Transcript[];
}

Expand Down Expand Up @@ -61,7 +62,8 @@ const peersSlice = createSlice({
kickInProgress,
raisedHandInProgress,
raisedHand,
raisedHandTimestamp
raisedHandTimestamp,
recording,
} = action.payload;

if (displayName)
Expand All @@ -88,6 +90,8 @@ const peersSlice = createSlice({
peer.raisedHand = raisedHand;
if (raisedHandTimestamp !== undefined)
peer.raisedHandTimestamp = raisedHandTimestamp;
if (recording !== undefined)
peer.recording = recording;
}
}),
updateTranscript: ((state, action: PayloadAction<PeerTranscript>) => {
Expand Down Expand Up @@ -136,4 +140,4 @@ const peersSlice = createSlice({
});

export const peersActions = peersSlice.actions;
export default peersSlice;
export default peersSlice;

0 comments on commit b9d713d

Please sign in to comment.