Skip to content

Instantly share code, notes, and snippets.

@anderjs
Created July 20, 2020 19:58
Show Gist options
  • Select an option

  • Save anderjs/669e90a14618d86c5751b0cb66985453 to your computer and use it in GitHub Desktop.

Select an option

Save anderjs/669e90a14618d86c5751b0cb66985453 to your computer and use it in GitHub Desktop.
import React, { memo, useReducer, useEffect, useCallback } from 'react'
import { Row, Col } from 'react-bootstrap'
import Video from 'twilio-video'
import * as TWILIO_EVENT from './actions/twilio'
import classRoomReducer, { initialState } from './reducer/classroom'
import {
connectUserToRoom,
disconnectUserToRoom,
setRoomNetwork,
setScreenTrack
} from './actions'
import Participant from './Participant'
import useToggler from 'hooks/useToggler'
/**
* @typedef {Object} ClassRoomProps
* @property {string} token
* @property {string} name
*/
/**
* @type {React.FunctionComponent<ClassRoomProps>}
*/
const ClassRoom = ({ name, token }) => {
const [state, dispatch] = useReducer(classRoomReducer, initialState)
const [isSharingScreen, setSharingScreen] = useToggler(false)
const refConnection = useCallback(() => {
navigator.mediaDevices.getUserMedia({
audio: true,
video: true
})
/**
* @param {string} user
*/
const connect = user => {
console.log("connected", user)
dispatch(connectUserToRoom(user))
}
/**
* @param {string} user
*/
const disconnect = user => {
console.log("disconnect", user)
dispatch(disconnectUserToRoom(user))
}
Video.connect(token, {
name,
dominantSpeaker: true,
audio: true,
video: true
})
.then(room => {
console.log('room', room)
dispatch(setRoomNetwork(room))
room.on(TWILIO_EVENT.CONNECT_USER, connect)
room.on(TWILIO_EVENT.DISCONNECT_USER, disconnect)
room.on(TWILIO_EVENT.DOMINANT_SPEAKER_CHANGED, user => {
console.log(user)
})
room.participants.forEach(participant => {
console.log('participants', participant)
connect(participant)
participant.on(TWILIO_EVENT.TRACK_ADDED, track => {
track.attach()
})
participant.on(TWILIO_EVENT.TRACK_ADDED, track => {
track.attach()
})
})
})
.catch(err => {
console.warn(err)
})
/**
* @description
* Clean up.
*/
return () => {
/**
* @type {import ('twilio-video').Room}
*/
const context = state.room
if (context && context.localParticipant.state === 'connected') {
context.localParticipant.tracks.forEach(trackPublication => {
trackPublication.track.stop()
})
context.disconnect()
dispatch(setRoomNetwork(null))
} else {
dispatch(setRoomNetwork(context))
}
}
}, [name, state.room, token])
useEffect(refConnection, [name, token, state.tracks])
/**
* @see https://www.twilio.com/blog/screen-sharing-javascript-twilio-programmable-video
*/
const handleStopMediaScreen = useCallback(() => {
if (state.room) {
state.room.localParticipant.unpublishTrack(state.track)
state.track.stop()
dispatch(setScreenTrack(null))
}
}, [state.room, state.track])
/**
* @see https://www.twilio.com/docs/video/javascript-v1-screen-capture-chrome
*/
const handleMediaScreen = useCallback(async () => {
if (state.room) {
try {
const stream = await navigator.mediaDevices.getDisplayMedia()
const [videoTrack] = stream.getTracks()
const screenTrack = new Video.LocalVideoTrack(videoTrack)
await state.room.localParticipant.publishTrack(screenTrack)
dispatch(setScreenTrack(screenTrack))
screenTrack.mediaStreamTrack.onended = e => {
handleMediaScreen()
}
setSharingScreen()
} catch (err) {
console.error(err)
}
}
}, [state.room, setSharingScreen])
return (
<React.Fragment>
{state.room && (
<Row>
<Col md={6}>
<Participant
key={state.room.localParticipant.id}
participant={state.room.localParticipant}
onShareScreen={handleMediaScreen}
/>
<br />
</Col>
<Col md={6}>
{state.users.map(user => (
<Participant key={user.sid} participant={user.sid} />
))}
</Col>
</Row>
)}
</React.Fragment>
)
}
export default memo(ClassRoom)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment