Skip to content

Commit

Permalink
#57 video-chat functionality first iteration
Browse files Browse the repository at this point in the history
  • Loading branch information
Nandu-D committed Jul 22, 2020
1 parent a45a940 commit c8b2b20
Show file tree
Hide file tree
Showing 8 changed files with 399 additions and 47 deletions.
5 changes: 5 additions & 0 deletions client/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
height: 603px !important;
}

video {
max-width: 200px !important;
max-height: 200px !important;
}

@keyframes App-logo-spin {
from {
transform: rotate(0deg);
Expand Down
73 changes: 73 additions & 0 deletions client/src/pages/CodeUI.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@ import "codemirror/lib/codemirror.css";
import "codemirror/theme/material.css";
import { theme } from "../themes/theme";
import socket from "../socket/socket";
import Video from 'twilio-video';
import ParticipantVideo from "../video-chat/ParticipantVideo";
require("codemirror/mode/xml/xml");
require("codemirror/mode/python/python");
require("codemirror/mode/clike/clike");
require("codemirror/mode/javascript/javascript");

const codeUIStyle = (theme) => ({
root: {
flexGrow: 1,
Expand Down Expand Up @@ -65,6 +68,14 @@ const codeUIStyle = (theme) => ({
fill: "black",
},
},
remoteParticipant: {
width: 200,
height: 200,
zIndex: 9,
position: 'absolute',
right: 0,
margin: "0 auto",
}
});
const qtitle = "Diagonal Difference";
const qdesc =
Expand All @@ -84,6 +95,9 @@ function CodeUI(props) {
const [runResult, setrunResult] = useState(null);
const [inRoom, setInRoom] = useState(false);
const history = useHistory();
const [videoRoom, setVideoRoom] = useState(null);
const [videoParticipants, setVideoParticipants] = useState([]);
const [token, setToken] = useState(null);

const [language, setLanguage] = useState("text/x-python");
useEffect(() => {
Expand Down Expand Up @@ -118,6 +132,60 @@ function CodeUI(props) {
});
}, []);

//For video chat room creation
useEffect(() => {
fetch(`/video/token/${props.match.params.id}`, {
method: 'POST',
body: JSON.stringify({}),
headers: { 'Content-Type': 'application/json' }
})
.then(res => res.json())
.then(data => setToken(data.token));
},[]);

//For video chat connection
useEffect(() => {
if (token) {
const participantConnected = participant => {
setVideoParticipants(prevParticipants => [...prevParticipants, participant]);
};

const participantDisconnected = participant => {
setVideoParticipants(prevParticipants =>
prevParticipants.filter(p => p !== participant)
);
};

Video.connect(token, {
name: props.match.params.id
}).then(videoRoom => {
setVideoRoom(videoRoom);
videoRoom.on('participantConnected', participantConnected);
videoRoom.on('participantDisconnected', participantDisconnected);
videoRoom.participants.forEach(participantConnected);
});

return () => {
setVideoRoom(currentRoom => {
if (currentRoom && currentRoom.localParticipant.state === 'connected') {
currentRoom.localParticipant.tracks.forEach(function(trackPublication) {
trackPublication.track.stop();
});
currentRoom.disconnect();
return null;
} else {
return currentRoom;
}
});
};
}
}, [props.match.params.id, token]);

//For video chat other participant video
const remoteParticipants = videoParticipants.map(participant => (
<ParticipantVideo key={participant.sid} participant={participant} />
));

const handleInRoom = () => {
inRoom ? setInRoom(false) : setInRoom(true);
};
Expand All @@ -142,6 +210,7 @@ function CodeUI(props) {
fetch(`/interviews/endInterview/${props.match.params.id}`)
.then((res) => socket.emit("endInterview", { id: props.match.params.id }))
.catch((err) => console.log(err));
setToken(null);//For video-chat logout
}

const changeLanguage = (lang) => {
Expand Down Expand Up @@ -203,6 +272,8 @@ function CodeUI(props) {
<MenuItem value={"text/x-csrc"}>C</MenuItem>
<MenuItem value={"text/x-c++src"}>C++</MenuItem>
</Select>
<div className={classes.remoteParticipant}>{remoteParticipants}</div>
{/* <div className={classes.remoteParticipant}>I want this above</div> */}
<CodeMirror
value={code}
options={{
Expand All @@ -215,7 +286,9 @@ function CodeUI(props) {
setCode(value);
}}
onChange={(editor, data, value) => {}}
style={{position: 'absolute'}}
/>
{/* <div className={classes.remoteParticipant}>{remoteParticipants}</div> */}
<Box bgcolor="#263238" height="200px">
<AppBar position="static" color="primary">
<Toolbar variant="dense">
Expand Down
83 changes: 83 additions & 0 deletions client/src/video-chat/ParticipantVideo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React, { useState, useEffect, useRef } from "react";
import { makeStyles } from "@material-ui/core/styles";

const useStyles = makeStyles((theme) => ({
screen: {
maxWidth: "200px",
maxHeight: "200px"
}
}));

const ParticipantVideo = ({ participant }) => {
const classes = useStyles();
const [videoTracks, setVideoTracks] = useState([]);
const [audioTracks, setAudioTracks] = useState([]);

const videoRef = useRef();
const audioRef = useRef();

const trackpubsToTracks = (trackMap) =>
Array.from(trackMap.values())
.map((publication) => publication.track)
.filter((track) => track !== null);

useEffect(() => {
setVideoTracks(trackpubsToTracks(participant.videoTracks));
setAudioTracks(trackpubsToTracks(participant.audioTracks));

const trackSubscribed = (track) => {
if (track.kind === "video") {
setVideoTracks((videoTracks) => [...videoTracks, track]);
} else if (track.kind === "audio") {
setAudioTracks((audioTracks) => [...audioTracks, track]);
}
};

const trackUnsubscribed = (track) => {
if (track.kind === "video") {
setVideoTracks((videoTracks) => videoTracks.filter((v) => v !== track));
} else if (track.kind === "audio") {
setAudioTracks((audioTracks) => audioTracks.filter((a) => a !== track));
}
};

participant.on("trackSubscribed", trackSubscribed);
participant.on("trackUnsubscribed", trackUnsubscribed);

return () => {
setVideoTracks([]);
setAudioTracks([]);
participant.removeAllListeners();
};
}, [participant]);

useEffect(() => {
const videoTrack = videoTracks[0];
if (videoTrack) {
videoTrack.attach(videoRef.current);
return () => {
videoTrack.detach();
};
}
}, [videoTracks]);

useEffect(() => {
const audioTrack = audioTracks[0];
if (audioTrack) {
audioTrack.attach(audioRef.current);
return () => {
audioTrack.detach();
};
}
}, [audioTracks]);

return (
<div className={classes.screen}>
<h4>{participant.identity}</h4>
<video ref={videoRef} autoPlay={true} />
<audio ref={audioRef} autoPlay={true} muted={true} />
</div>
);
};

export default ParticipantVideo;
2 changes: 2 additions & 0 deletions server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const interviewRouter = require("./interview/interview.controller");
const accountRouter = require("./users/users.controller");
const questionRouter = require("./question/question.controller");
const runCode = require("./helpers/runcode");
const videoRouter = require("./video-chat/videoChatApis");

const { json, urlencoded } = express;

Expand All @@ -23,6 +24,7 @@ app.use("/", accountRouter);
app.use("/users", require("./users/users.controller"));
app.use("/interviews", interviewRouter);
app.use("/questions", questionRouter);
app.use("/video", videoRouter);

// catch 404 and forward to error handler
app.use(function (req, res, next) {
Expand Down
Loading

0 comments on commit c8b2b20

Please sign in to comment.