Created
July 20, 2020 19:58
-
-
Save anderjs/669e90a14618d86c5751b0cb66985453 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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