Skip to content

Commit

Permalink
feat(webapp): add presentation
Browse files Browse the repository at this point in the history
  • Loading branch information
a-wing committed Dec 25, 2023
1 parent 8e45ec5 commit d65861a
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 25 deletions.
55 changes: 32 additions & 23 deletions webapp/components/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { useEffect, useState } from 'react'
import { useAtom } from 'jotai'
import Member from './member'
import Player from './player/player'
import WhipPlayer from './player/whip-player'
import WhepPlayer from './player/whep-player'
import DeviceBar from './device'
import { UserStatus, localStreamIdAtom, meetingJoinedAtom } from '../store/atom'
import {
UserStatus,
enabledPresentationAtom,
localStreamIdAtom,
meetingJoinedAtom,
presentationStreamAtom,
} from '../store/atom'
import copy from 'copy-to-clipboard'
import SvgDone from './svg/done'
import SvgEnd from './svg/end'
Expand All @@ -16,8 +23,10 @@ export default function Layout(props: { meetingId: string }) {
const [localStreamId] = useAtom(localStreamIdAtom)
const [remoteUserStatus, setRemoteUserStatus] = useState<{ [_: string]: UserStatus }>({})

const [speaker, setSpeaker] = useState<UserStatus | null>(null)
const [speakerId, setSpeakerId] = useState<string>("")
//const [speaker, setSpeaker] = useState<UserStatus | null>(null)
//const [speakerId, setSpeakerId] = useState<string>("")
const [enabledPresentation] = useAtom(enabledPresentationAtom)
const [presentationStream] = useAtom(presentationStreamAtom)

const refresh = async () => {
let res = await fetch(location.origin + `/room/${props.meetingId}`)
Expand All @@ -38,20 +47,18 @@ export default function Layout(props: { meetingId: string }) {
setMeetingJoined(false)
}

useEffect(() => {
let shareScreenId = ""
const setShareScreenId = (id: string) => shareScreenId = id
Object.keys(remoteUserStatus).map(i => remoteUserStatus[i].screen && setShareScreenId(i))

if (!shareScreenId) {
setSpeakerId("")
setSpeaker(null)
} else {
setSpeakerId(shareScreenId)
setSpeaker(remoteUserStatus[shareScreenId])
}

}, [remoteUserStatus])
//useEffect(() => {
// let shareScreenId = ""
// const setShareScreenId = (id: string) => shareScreenId = id
// Object.keys(remoteUserStatus).map(i => remoteUserStatus[i].screen && setShareScreenId(i))
// if (!shareScreenId) {
// setSpeakerId("")
// setSpeaker(null)
// } else {
// setSpeakerId(shareScreenId)
// setSpeaker(remoteUserStatus[shareScreenId])
// }
//}, [remoteUserStatus])

useEffect(() => {
const handle = setInterval(refresh, 3000)
Expand All @@ -62,14 +69,16 @@ export default function Layout(props: { meetingId: string }) {
<div className='flex flex-col justify-between' style={{ height: '100vh' }}>
<div></div>

{!speaker
? <div className='flex flex-row flex-wrap justify-evenly'>
<WhipPlayer streamId={localStreamId} width="320px" />
{Object.keys(remoteUserStatus).map(i => <WhepPlayer key={i} streamId={i} status={remoteUserStatus[i]} width="320px" />)}
</div>
: <WhepPlayer streamId={speakerId} status={speaker} width="auto" />
{ enabledPresentation
? <Player user={presentationStream} muted={true} width="auto" display="auto" />
: null
}

<div className='flex flex-row flex-wrap justify-evenly'>
<WhipPlayer streamId={localStreamId} width="320px" />
{Object.keys(remoteUserStatus).map(i => <WhepPlayer key={i} streamId={i} status={remoteUserStatus[i]} width="320px" />)}
</div>

<center>
<Member />
<div className='flex justify-evenly bg-gray-800/80'>
Expand Down
21 changes: 19 additions & 2 deletions webapp/components/player/whep-player.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { useEffect, useRef, useState } from 'react'
import Player from './player'
import { UserStream, UserStatus } from '../../store/atom'
import {
UserStream,
UserStatus,
presentationStreamAtom,
} from '../../store/atom'
import { WHEPClient } from '@binbat/whip-whep/whep'
import { useAtom } from 'jotai'

export default function WhepPlayer(props: { streamId: string, status: UserStatus, width: string }) {
const refEnabled = useRef(false)
Expand All @@ -11,6 +16,7 @@ export default function WhepPlayer(props: { streamId: string, status: UserStatus
stream: new MediaStream,
name: props.streamId,
})
const [presentationStream, setPresentationStream] = useAtom(presentationStreamAtom)

const newPeerConnection = () => {
const pc = new RTCPeerConnection()
Expand Down Expand Up @@ -57,7 +63,18 @@ export default function WhepPlayer(props: { streamId: string, status: UserStatus
if (props.status.state === "connected") {
restart(props.streamId)
}
}, [props.status.state, props.status.audio, props.status.video, props.status.screen])
}, [props.status.state, props.status.audio, props.status.video])

useEffect(() => {
if (props.status.screen) {
setPresentationStream(userStream)
} else {
setPresentationStream({
stream: new MediaStream,
name: presentationStream.name
})
}
}, [props.status.screen])

return (
<div className='flex flex-col'>
Expand Down
14 changes: 14 additions & 0 deletions webapp/components/player/whip-player.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ import { useEffect, useRef, useState } from 'react'
import { useAtom } from 'jotai'
import {
localStreamAtom,
presentationStreamAtom,

localUserStatusAtom,
currentDeviceAudioAtom,
currentDeviceVideoAtom,
} from '../../store/atom'
import Player from './player'
import { WHIPClient } from '@binbat/whip-whep/whip'
import { deviceScreen } from '../../lib/device'

export default function WhipPlayer(props: { streamId: string, width: string }) {
const refEnabled = useRef(false)
Expand All @@ -19,6 +22,8 @@ export default function WhipPlayer(props: { streamId: string, width: string }) {
const [currentDeviceAudio] = useAtom(currentDeviceAudioAtom)
const [currentDeviceVideo] = useAtom(currentDeviceVideoAtom)

const [presentationStream, setPresentationStream] = useAtom(presentationStreamAtom)

const newPeerConnection = () => {
const stream = localStream.stream
if (stream) {
Expand Down Expand Up @@ -108,6 +113,15 @@ export default function WhipPlayer(props: { streamId: string, width: string }) {
}, [currentDeviceAudio])

useEffect(() => {
if (currentDeviceVideo === deviceScreen.deviceId) {
setPresentationStream(localStream)
} else {
setPresentationStream({
stream: new MediaStream,
name: presentationStream.name
})
}

const mediaStream = localStream.stream
// If WebRTC is connected, switch track
// NOTE: array video index is: 1
Expand Down
12 changes: 12 additions & 0 deletions webapp/store/atom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ const localStreamAtom = atom<UserStream>({
})
localStreamAtom.debugLabel = 'localStream'

const presentationStreamAtom = atom<UserStream>({
stream: new MediaStream,
name: "Presentation",
})
presentationStreamAtom.debugLabel = 'presentationStream'

const enabledPresentationAtom = atom(get => get(presentationStreamAtom).stream.getVideoTracks().length !== 0)
enabledPresentationAtom.debugLabel = 'enabledPresentation'

const enabledAudioAtom = atom(get => get(localStreamAtom).stream.getAudioTracks().length !== 0)
enabledAudioAtom.debugLabel = 'enabledAudio'
const enabledVideoAtom = atom(get => get(localStreamAtom).stream.getVideoTracks().length !== 0)
Expand Down Expand Up @@ -73,11 +82,14 @@ export {
remoteUsersStatusAtom,

locationAtom,
presentationStreamAtom,

meetingIdAtom,
meetingJoinedAtom,
localStreamAtom,
enabledAudioAtom,
enabledVideoAtom,
enabledPresentationAtom,
currentDeviceAudioAtom,
currentDeviceVideoAtom,
}
Expand Down

0 comments on commit d65861a

Please sign in to comment.