old-remnantchat/src/components/Room/useRoomScreenShare.ts
Jeremy Kahn 94a4b2fb2e
refactor(services): Standardize services and lib organization (#226)
* refactor(Notification): use instance methods
* refactor(Audio): move to lib layer
* refactor(EncryptionService): rename instance to encryption
* refactor(ConnectionTest): move to lib
* refactor(FileTransfer): move to lib
* refactor(PeerRoom): move to lib
* refactor(sleep): move to lib
* refactor(type-guards): move to lib
* refactor(SerializationService): use standard instance name
* refactor(SettingsService): use standard instance name
2024-01-28 20:46:59 -06:00

158 lines
4.1 KiB
TypeScript

import { useContext, useEffect, useCallback, useState } from 'react'
import { isRecord } from 'lib/type-guards'
import { RoomContext } from 'contexts/RoomContext'
import { ShellContext } from 'contexts/ShellContext'
import { PeerActions } from 'models/network'
import { ScreenShareState, Peer, VideoStreamType } from 'models/chat'
import { PeerRoom, PeerHookType, PeerStreamType } from 'lib/PeerRoom'
interface UseRoomScreenShareConfig {
peerRoom: PeerRoom
}
export function useRoomScreenShare({ peerRoom }: UseRoomScreenShareConfig) {
const shellContext = useContext(ShellContext)
const roomContext = useContext(RoomContext)
const [isSharingScreen, setIsSharingScreen] = useState(false)
const { peerList, setPeerList, setScreenState } = shellContext
const {
peerScreenStreams,
selfScreenStream,
setPeerScreenStreams,
setSelfScreenStream,
} = roomContext
const [sendScreenShare, receiveScreenShare] =
peerRoom.makeAction<ScreenShareState>(PeerActions.SCREEN_SHARE)
receiveScreenShare((screenState, peerId) => {
const newPeerList = peerList.map(peer => {
const newPeer: Peer = { ...peer }
if (peer.peerId === peerId) {
newPeer.screenShareState = screenState
if (screenState === ScreenShareState.NOT_SHARING) {
deletePeerScreen(peerId)
}
}
return newPeer
})
setPeerList(newPeerList)
})
peerRoom.onPeerStream(PeerStreamType.SCREEN, (stream, peerId, metadata) => {
const isScreenShareStream =
isRecord(metadata) &&
'type' in metadata &&
metadata.type === VideoStreamType.SCREEN_SHARE
if (!isScreenShareStream) return
setPeerScreenStreams({
...peerScreenStreams,
[peerId]: stream,
})
})
const cleanupScreenStream = useCallback(() => {
if (!selfScreenStream) return
for (const screenStreamTrack of selfScreenStream.getTracks()) {
screenStreamTrack.stop()
selfScreenStream.removeTrack(screenStreamTrack)
}
}, [selfScreenStream])
const handleScreenShareStart = async () => {
if (selfScreenStream) return
const displayMedia = await window.navigator.mediaDevices.getDisplayMedia({
audio: true,
video: true,
})
peerRoom.addStream(displayMedia, null, {
type: VideoStreamType.SCREEN_SHARE,
})
setSelfScreenStream(displayMedia)
sendScreenShare(ScreenShareState.SHARING)
setScreenState(ScreenShareState.SHARING)
setIsSharingScreen(true)
}
const handleScreenShareStop = () => {
if (!selfScreenStream) return
cleanupScreenStream()
peerRoom.removeStream(selfScreenStream, peerRoom.getPeers())
sendScreenShare(ScreenShareState.NOT_SHARING)
setScreenState(ScreenShareState.NOT_SHARING)
setSelfScreenStream(null)
setIsSharingScreen(false)
}
useEffect(() => {
return () => {
cleanupScreenStream()
}
}, [cleanupScreenStream])
useEffect(() => {
return () => {
if (selfScreenStream) {
setSelfScreenStream(null)
setScreenState(ScreenShareState.NOT_SHARING)
}
}
}, [selfScreenStream, setSelfScreenStream, setScreenState])
useEffect(() => {
return () => {
setPeerScreenStreams({})
}
}, [setPeerScreenStreams])
const deletePeerScreen = (peerId: string) => {
const newPeerScreens = { ...peerScreenStreams }
delete newPeerScreens[peerId]
setPeerScreenStreams(newPeerScreens)
}
const handleScreenForNewPeer = (peerId: string) => {
if (selfScreenStream) {
peerRoom.addStream(selfScreenStream, peerId, {
type: VideoStreamType.SCREEN_SHARE,
})
}
}
const handleScreenForLeavingPeer = (peerId: string) => {
if (selfScreenStream) {
peerRoom.removeStream(selfScreenStream, peerId)
}
deletePeerScreen(peerId)
}
peerRoom.onPeerJoin(PeerHookType.SCREEN, (peerId: string) => {
handleScreenForNewPeer(peerId)
})
peerRoom.onPeerLeave(PeerHookType.SCREEN, (peerId: string) => {
handleScreenForLeavingPeer(peerId)
})
return {
handleScreenShareStart,
handleScreenShareStop,
isSharingScreen,
setIsSharingScreen,
}
}