feat: [#19] display which peers are speaking to the room

This commit is contained in:
Jeremy Kahn 2022-10-31 21:40:44 -05:00
parent 931ddf267f
commit ba21936c96
6 changed files with 72 additions and 12 deletions

View File

@ -7,10 +7,12 @@ import { ShellContext } from 'contexts/ShellContext'
import { SettingsContext } from 'contexts/SettingsContext'
import { PeerActions } from 'models/network'
import {
AudioState,
Message,
ReceivedMessage,
UnsentMessage,
isMessageReceived,
Peer,
} from 'models/chat'
import { funAnimalName } from 'fun-animal-names'
import { getPeerName } from 'components/PeerNameDisplay'
@ -97,6 +99,11 @@ export function useRoom(
const [sendPeerMessage, receivePeerMessage] =
usePeerRoomAction<UnsentMessage>(peerRoom, PeerActions.MESSAGE)
const [sendAudioChange, receiveAudioChange] = usePeerRoomAction<AudioState>(
peerRoom,
PeerActions.AUDIO_CHANGE
)
const sendMessage = async (message: string) => {
if (isMessageSending) return
@ -125,12 +132,12 @@ export function useRoom(
if (peerIndex === -1) {
shellContext.setPeerList([
...shellContext.peerList,
{ peerId: peerId, userId: userId },
{ peerId: peerId, userId: userId, audioState: AudioState.STOPPED },
])
} else {
const peerListClone = [...shellContext.peerList]
peerListClone[peerIndex].userId = userId
shellContext.setPeerList(peerListClone)
const newPeerList = [...shellContext.peerList]
newPeerList[peerIndex].userId = userId
shellContext.setPeerList(newPeerList)
}
})
@ -158,6 +165,20 @@ export function useRoom(
setMessageLog([...messageLog, { ...message, timeReceived: Date.now() }])
})
receiveAudioChange((audioState, peerId) => {
const newPeerList = shellContext.peerList.map(peer => {
const newPeer: Peer = { ...peer }
if (peer.peerId === peerId) {
newPeer.audioState = audioState
}
return newPeer
})
shellContext.setPeerList(newPeerList)
})
peerRoom.onPeerJoin((peerId: string) => {
shellContext.showAlert(`Someone has joined the room`, {
severity: 'success',
@ -239,6 +260,8 @@ export function useRoom(
})
peerRoom.addStream(newSelfStream)
sendAudioChange(AudioState.PLAYING)
shellContext.setAudioState(AudioState.PLAYING)
setAudioStream(newSelfStream)
}
} else {
@ -249,6 +272,8 @@ export function useRoom(
}
peerRoom.removeStream(audioStream, peerRoom.getPeers())
sendAudioChange(AudioState.STOPPED)
shellContext.setAudioState(AudioState.STOPPED)
setAudioStream(null)
}
}
@ -259,6 +284,8 @@ export function useRoom(
peerRoom,
audioStream,
selectedAudioDeviceId,
sendAudioChange,
shellContext,
])
const handleAudioDeviceSelect = async (audioDevice: MediaDeviceInfo) => {

View File

@ -1,24 +1,27 @@
import { PropsWithChildren } from 'react'
import MuiDrawer from '@mui/material/Drawer'
import List from '@mui/material/List'
import ListItemIcon from '@mui/material/ListItemIcon'
import ListItemText from '@mui/material/ListItemText'
import Divider from '@mui/material/Divider'
import IconButton from '@mui/material/IconButton'
import ChevronRightIcon from '@mui/icons-material/ChevronRight'
import VolumeUp from '@mui/icons-material/VolumeUp'
import ListItemButton from '@mui/material/ListItemButton'
import Typography from '@mui/material/Typography'
import { PeerListHeader } from 'components/Shell/PeerListHeader'
import { PeerNameDisplay } from 'components/PeerNameDisplay'
import { Peer } from 'models/chat'
import { AudioState, Peer } from 'models/chat'
export const peerListWidth = 240
export const peerListWidth = 300
export interface PeerListProps extends PropsWithChildren {
userId: string
isPeerListOpen: boolean
onPeerListClose: () => void
peerList: Peer[]
audioState: AudioState
}
export const PeerList = ({
@ -26,6 +29,7 @@ export const PeerList = ({
isPeerListOpen,
onPeerListClose,
peerList,
audioState,
}: PeerListProps) => {
return (
<MuiDrawer
@ -48,13 +52,25 @@ export const PeerList = ({
<Divider />
<List>
<ListItemButton disableRipple={true}>
<Typography>
{audioState === AudioState.PLAYING && (
<ListItemIcon>
<VolumeUp />
</ListItemIcon>
)}
<ListItemText>
<PeerNameDisplay>{userId}</PeerNameDisplay> (you)
</Typography>
</ListItemText>
</ListItemButton>
{peerList.map((peer: Peer) => (
<ListItemButton key={peer.peerId} disableRipple={true}>
{peer.audioState === AudioState.PLAYING && (
<ListItemIcon>
<VolumeUp />
</ListItemIcon>
)}
<ListItemText>
<PeerNameDisplay>{peer.userId}</PeerNameDisplay>
</ListItemText>
</ListItemButton>
))}
</List>

View File

@ -15,7 +15,7 @@ import { AlertColor } from '@mui/material/Alert'
import { ShellContext } from 'contexts/ShellContext'
import { SettingsContext } from 'contexts/SettingsContext'
import { AlertOptions } from 'models/shell'
import { Peer } from 'models/chat'
import { AudioState, Peer } from 'models/chat'
import { ErrorBoundary } from 'components/ErrorBoundary'
import { Drawer } from './Drawer'
@ -42,6 +42,7 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
const [isPeerListOpen, setIsPeerListOpen] = useState(false)
const [peerList, setPeerList] = useState<Peer[]>([]) // except you
const [tabHasFocus, setTabHasFocus] = useState(true)
const [audioState, setAudioState] = useState<AudioState>(AudioState.STOPPED)
const showAlert = useCallback<
(message: string, options?: AlertOptions) => void
@ -63,6 +64,8 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
setIsPeerListOpen,
peerList,
setPeerList,
audioState,
setAudioState,
}),
[
isPeerListOpen,
@ -73,6 +76,8 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
setNumberOfPeers,
setTitle,
showAlert,
audioState,
setAudioState,
]
)
@ -203,6 +208,7 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
isPeerListOpen={isPeerListOpen}
onPeerListClose={handlePeerListClick}
peerList={peerList}
audioState={audioState}
/>
</Box>
</ThemeProvider>

View File

@ -1,7 +1,7 @@
import { createContext, Dispatch, SetStateAction } from 'react'
import { AlertOptions } from 'models/shell'
import { Peer } from 'models/chat'
import { AudioState, Peer } from 'models/chat'
interface ShellContextProps {
numberOfPeers: number
@ -14,6 +14,8 @@ interface ShellContextProps {
setIsPeerListOpen: Dispatch<SetStateAction<boolean>>
peerList: Peer[]
setPeerList: Dispatch<SetStateAction<Peer[]>>
audioState: AudioState
setAudioState: Dispatch<SetStateAction<AudioState>>
}
export const ShellContext = createContext<ShellContextProps>({
@ -27,4 +29,6 @@ export const ShellContext = createContext<ShellContextProps>({
setIsPeerListOpen: () => {},
peerList: [],
setPeerList: () => {},
audioState: AudioState.STOPPED,
setAudioState: () => {},
})

View File

@ -5,9 +5,15 @@ export interface UnsentMessage {
authorId: string
}
export enum AudioState {
PLAYING = 'PLAYING',
STOPPED = 'STOPPED',
}
export interface Peer {
peerId: string
userId: string
audioState: AudioState
}
export interface ReceivedMessage extends UnsentMessage {

View File

@ -3,4 +3,5 @@ export enum PeerActions {
MESSAGE = 'MESSAGE',
MESSAGE_TRANSCRIPT = 'MSG_XSCRIPT',
PEER_NAME = 'PEER_NAME',
AUDIO_CHANGE = 'AUDIO_CHANGE',
}