loading...
Twilio

Build a Video App with JavaScript and the Twilio CLI in 9 Minutes

lizziepika profile image Lizzie Siegle ・5 min read

video header

With many of us now working remote, video chats are so in right now. Here’s how to get up-and-running with a video chat room in nine minutes using Twilio Programmable Video and the Twilio Serverless Toolkit in JavaScript.
example img

Setup

To build a Twilio Programmable Video application, we will need:

Save your API Keys somewhere you can access them soon and then install the Twilio Serverless Toolkit via the Twilio CLI if you haven't already by running

twilio plugins:install @twilio-labs/plugin-serverless

You can then see what commands the Serverless Toolkit offers by running

twilio serverless

Make a Serverless Project

Create a Serverless project with a blank template by running on the command line

twilio serverless:init --template blank {insert-project-name}

Replace {insert-project-name} with your project name--I called mine tfvideo. When the command completes, a directory with the project name will be created under your current directory.

The project directory contains some ready-made folders. In functions, add a file called video-token.js and in assets add two files: video.html and index.js. Set your environment variables in .env. You can leave the first two lines containing ACCOUNT_SID and AUTH_TOKEN alone. Below them, add your Account SID, API Key, and API Secret:
env

Generate an Access Token

In functions/video-token.js add the following code to generate an access token. Here we set your environment variables, a fixed room name, and the ACCESS_TOKEN_IDENTITY for each user. Each user is granted access to the room tf. This code was modified from this page which also contains more information on Access Tokens.

exports.handler = function(context, event, callback) {
    const TWILIO_ACCOUNT_SID = context.TWILIO_ACCOUNT_SID;
    const TWILIO_API_KEY = context.TWILIO_API_KEY;
    const TWILIO_API_SECRET = context.TWILIO_API_SECRET;
    const ACCESS_TOKEN_IDENTITY =
      Math.random()
        .toString(36)
        .substring(2, 15) +
      Math.random()
        .toString(36)
        .substring(2, 15);  // random client name 

    const ROOM_NAME = 'tf';  // fixed room name
    const AccessToken = Twilio.jwt.AccessToken;
    const VideoGrant = AccessToken.VideoGrant;
    // only tokens are available for participating rooms
    // Create a Video grant enabling client to use Video, only for this room 
    const videoGrant = new VideoGrant({
        room: ROOM_NAME
    });
    //Create an access token to sign and return to the client with the grant we just created
    const accessToken = new AccessToken(
        TWILIO_ACCOUNT_SID,
        TWILIO_API_KEY,
        TWILIO_API_SECRET
    );
    accessToken.addGrant(videoGrant); //Add the grant to the token
    accessToken.identity = ACCESS_TOKEN_IDENTITY;
    callback(null, {
        token: accessToken.toJwt() //Serialize the token to a JWT string
    });
};

Make our Video Site

Now open the blank assets/video.html file you made earlier. We're going to write some bare-bones HTML including buttons for joining and leaving the room, a video tag that will automatically display a preview of the user's camera, the index.js file we're about to write, and the Axios and Twilio Video.js libraries:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Twilio Video Serverless Demo</title>
</head>
  <body>
    <div id="room-controls">
      <video id="video" autoplay muted="true" width="320"
          height="240"></video>
      <button id="button-join">Join Room</button>
      <button id="button-leave" disabled>Leave Room</button>
    </div>

  <script src="//media.twiliocdn.com/sdk/js/video/releases/2.3.0/twilio-video.min.js"></script>
  <script src="https://unpkg.com/axios@0.19.0/dist/axios.min.js"></script>
  <script src="index.js"></script>
  </body>
</html>

Build the Video App

In assets/index.js add the following code. In a nutshell, this copy-and-pasteable script will:

  • set the serverless domain name (this will be the base URL) as whatever you called your project with the CLI template
  • set the name of your room name, and some variables
  • get the video element and display it in the preview screen
  • generate an access token using an axios call to the video-token file when a user joins the room
  • connect and disconnect users to the tf room when they click button-join or button-leave
  • display a remote participant's video by attaching an event listener to subscribe or unsubscribe their tracks to the tf room. If they are already in the room, we iterate over the existing participants and attach an event listener to trackSubscribed.

If you change the room name, you must also change the token that's generated.

(() => {
    'use strict';
    const TWILIO_DOMAIN = location.host; //unique to user, will be website to visit for video app
    const ROOM_NAME = 'tf';
    const Video = Twilio.Video;
    let videoRoom, localStream;
    const video = document.getElementById("video");

    // preview screen
    navigator.mediaDevices.getUserMedia({video: true, audio: true})
    .then(vid => {
        video.srcObject = vid;
        localStream = vid;
    })

    // buttons
    const joinRoomButton = document.getElementById("button-join");
    const leaveRoomButton = document.getElementById("button-leave");
    var site = `https://${TWILIO_DOMAIN}/video-token`;
    console.log(`site ${site}`);
    joinRoomButton.onclick = () => {
      // get access token
      axios.get(`https://${TWILIO_DOMAIN}/video-token`).then(async (body) => {
        const token = body.data.token;
        console.log(token);

        Video.connect(token, { name: ROOM_NAME }).then((room) => {
          console.log(`Connected to Room ${room.name}`);
          videoRoom = room;

          room.participants.forEach(participantConnected);
          room.on("participantConnected", participantConnected);

          room.on("participantDisconnected", participantDisconnected);
          room.once("disconnected", (error) =>
            room.participants.forEach(participantDisconnected)
          );
          joinRoomButton.disabled = true;
          leaveRoomButton.disabled = false;
        });
      });
    };
    leaveRoomButton.onclick = () => {
      videoRoom.disconnect();
      console.log(`Disconnected from Room ${videoRoom.name}`);
      joinRoomButton.disabled = false;
      leaveRoomButton.disabled = true;
    };
})();

const participantConnected = (participant) => {
    console.log(`Participant ${participant.identity} connected'`);

    const div = document.createElement('div');
    div.id = participant.sid;

    participant.on('trackSubscribed', track => trackSubscribed(div, track));
    participant.on('trackUnsubscribed', trackUnsubscribed);

    participant.tracks.forEach(publication => {
      if (publication.isSubscribed) {
        trackSubscribed(div, publication.track);
      }
    });
    document.body.appendChild(div);
}

const participantDisconnected = (participant) => {
    console.log(`Participant ${participant.identity} disconnected.`);
    document.getElementById(participant.sid).remove();
}

const trackSubscribed = (div, track) => {
    div.appendChild(track.attach());
}

const trackUnsubscribed = (track) => {
    track.detach().forEach(element => element.remove());
}

Yes, this has been Programmable Video demystified and simplified!

On the command line, run twilio serverless:deploy. The CLI will congratulate you with Serverless project successfully deployed and some other deployment details. You can delete or ignore functions/blank.js which was deployed with the auto-generated assets. Grab the video.html URL under Assets, share it with your friends, and tada! You have your own video room to use and share when you need a quick video call.
larger group call with Mica, Tilde

This app is pretty bare-bones but definitely decent given the lack of CSS written, eh? The complete code can be found here on GitHub.

What's Next

Twilio's Serverless Toolkit makes it easy to host apps and get them up-and-running quickly. Next you can write some more CSS to prettify the app, add a programmable chat feature or more Twilio Video features, get users' names and display them when they are in the chat, and more. Let me know online or in the comments what you're building.

Posted on by:

lizziepika profile

Lizzie Siegle

@lizziepika

twilio developer evangelist | swift && js hacker, chatbot + ml enthusiast | disney, pikachu, #gsw fan. newsletter: https://tinyletter.com/lizziepika

Twilio

We ❤️developers. Unlock the magic of communications to improve human experience. Twilio has democratized channels like voice, text, chat, and video through APIs.

Discussion

pic
Editor guide
 

I never knew it could be so simple.

 

I KNOW! Video used to (and still does to an extent, but less so) intimidate me, but learning how to make this really was encouraging for me personally because I didn't think it was this simple.

 

Twilio has made it exceptionally easy. WebRTC can be quite complicated.