git clone https://github.com/ahl389/video-chat-base.git cd video-chat-base
npm install twilio-cli -g twilio plugins:install @twilio-labs/plugin-serverless cd backend
mv .env.example .env
twilio serverless:start
npm install
joinRoom()
, you should see some code that looks like this:const response = await fetch(`{your-endpoint}?identity=${this.state.identity}`);
PORT 3000
, then your updated line will be:const response = await fetch(`http://localhost:3000/token?identity=${this.state.identity}`);
App
component controls what the user sees when they open your app. This component is also responsible for enabling the user to enter and leave the video call room. It has one child component: Room
.Room
component is the container for all the unique participants in the video room. It also listens for new remote participants coming or existing remote participants leaving. It can have one or more child Participant
components.Participant
component manages the given participant’s audio and video tracks. Each of these tracks are represented via the child Track
components.Track
component is responsible for attaching and rendering the track it receives as props.npm start
PORT 3000
, you’ll be prompted to run your React app on a different port. Press the y
key on your keyboard to confirm. When you’re done exploring the app you can stop your server by pressing CTRL + C
, but keep your backend server running.npm i --save @fortawesome/fontawesome-svg-core npm install --save @fortawesome/free-solid-svg-icons npm install --save @fortawesome/react-fontawesome
AVControl
. This component will manage the different icons that the local participant will interact with to turn their microphone and webcam on and off.import './App.scss'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faMicrophone, faMicrophoneSlash, faVideo, faVideoSlash } from '@fortawesome/free-solid-svg-icons';
FontAwesomeIcon
component from the FontAwesome React library, and then it imports the four icons you’ll be using:faMicrophone
: an SVG icon of a microphonefaMicrophoneSlash
: an SVG icon of the same microphone with a diagonal slash through itfaVideo
: an SVG icon of a video camerafaVideoSlash
: an SVG icon of the same video camera with a diagonal slash through itAVControl
:function AVControl(props) { } export default AVControl;
AVControl
receives props
as a parameter. Eventually you’ll render this component inside the Track
component where you’ll pass several pieces of data as props:toggleTrack()
method that will be called when the icon is clickedAVControl
component whether its parent track is currently on or offAVControl
component.AVControl()
function, add the following code:let icon; if (props.trackOff) { icon = props.type === 'audio' ? faMicrophoneSlash : faVideoSlash; } else { icon = props.type === 'audio' ? faMicrophone : faVideo; }
icon
. Then, the correct icon (of the four you imported) is chosen and assigned to this new variable based on whether the parent track is currently on or off, and whether it’s an audio or video track.AVControl
component will be the faMicrophone
. The icon will always represent the current on/off state of the corresponding track.AVControl
component, add the following return statement at the end of the AVControl()
function, before the closing curly brace:return ( <div className="avControl"> <FontAwesomeIcon icon={icon} onClick={() => props.toggleTrack()} /> </div> );
<div>
element with the class name avControl
. Inside this <div>
will be the correct FontAwesome icon, with a click event on it that calls the toggleTrack()
method that the component received as props.Track
component.AVControl
component you just created:import React, {Component} from 'react'; import './App.scss'; import AVControl from './AVControl';
Track
component’s constructor method, you’ll need to add the piece of state that keeps track of whether the track is enabled or disabled.constructor(props) { super(props); this.ref = React.createRef(); this.state = { trackOff: false } }
trackOff
state is false
, meaning that when this component renders, the track is on.toggleTrack()
method that gets passed to the AVControl
component.componentDidMount()
and render()
methods of the Track
component, add the following code:toggleTrack() { if (this.state.trackOff) { this.props.track.enable(); } else { this.props.track.disable() } this.setState({ trackOff: !this.state.trackOff }); }
Track
component state indicates that the track is currently off, then this code turns it back on with the enable()
method provided by Twilio Programmable Video. The enable()
method will restart a paused audio or video stream.disable()
method. The disable()
method will pause an existing audio or video stream.toggleTrack()
method, after enabling or disabling the track, the trackOff
state is also toggled to reflect the track’s new state.constructor()
method to bind the new toggleTrack()
method to the JavaScript keyword this
:constructor(props) { ... this.toggleTrack = this.toggleTrack.bind(this); }
render()
method to include the AVControl
component:render() { return ( <div className="track" ref={this.ref}> { this.props.local && this.props.track ? <AVControl toggleTrack={this.toggleTrack} trackOff={this.state.trackOff} type={this.props.track.kind}/> : '' } </div> ) }
AVControl
component is only rendered if the value of this.props.local
is truthy. This is because we only want to render the AVControl
component if the parent Participant
component is representing the local participant.Track
component doesn’t receive props called local
from its parent Participant
component. You’ll fix that now.Participant
component’s render()
method, update the line that renders the Track
component so it now passes the local
props:{ this.state.tracks.map(track => <Track key={track} track={track} local={this.props.localParticipant}/>) }
PORT 3000
.npm start
localhost:3001
, or whatever port your React server is running on. After entering your name, click the Join Room button.