2016-05-05



alvinashcraft
shared this story
from Twilio Cloud Communications Blog.

AngularJS is a popular JavaScript framework for building client side applications. Using it steers you towards creating well-factored apps with clear Separation of Concerns (SoC).  To demonstrate how Angular does this let’s convert the existing JavaScript Quickstart for Video into an Angular application.

If you want to skip ahead and grab the source for this post, it’s all on Github.  Otherwise let’s get started.

Setting It All Up

Before we jump into the code we’ll need to do some setup.  First, if you don’t already have a Twilio account hop on over to twilio.com and create a new one.  It’s easy and free for development.

Once you have an account we need to set up a new Api Key and Secret which we’ll use in a bit to authenticate with the Twilio API.  Create a new Api Key by heading into the developer console and select the Create an Api Key option.

Make sure you put the Api Secret some place safe because you won’t be able to see it again once you leave the Key page.

Next, create a new Configuration Profile for our application.  The Configuration profile is a collection of configuration values specific to the Twilio Video service.  For our app we just need to create a new one and grab the Configuration Profile SID.



With the Api Key and Configuration Profile created we can starting writing some code.  As the base for our application we’ll use a Twilio Video for JavaScript Quickstart application.  These applications are intended to get you to a working video application in just a few minutes and are available with server sides in a variety of programming languages.

Download the starter app that matches the backend language you are most interested in and follow the setup instructions for setting up your Account SID, Api Key and Secret and Configuration Profile SID in the app.

When you’re ready, give the app a spin and wave to yourself in the camera!

Approaching Angular

With the Video Quickstart running, it’s time to start converting the client side to Angular.

Start by adding the Angular library to the application view.  For most of the quickstarts this means locating and opening the index.html file included in the project.  For .NET developers you are looking for Index.cshtml.

Once you’ve opened the file add a <script> tag whose src attribute points to the Angular library.  You can download the library from https://angularjs.org/ and include it directly in your project or you can leverage a CDN host like cdnjs.com.  Whichever you choose, you’ll want to use the latest released version of AngularJS 1.x (version 1.5.5 at the time of writing).

Next add a new folder named app wherever you want to serve the application specific JavaScript files from.  Where you create this folder in the Quickstart project again depends on which language you chose.  For Python you’ll create it in the static folder.  In Ruby, it will be under the public folder.  For C#, you’ll place it under the Scripts folder.

In that folder create a new app.module.js file and define our main Angular module in it:

Create another file named videochat.controller.js.  This file will contain the Angular controller that we’ll use to drive our video chat UI.

Open the file and define a new Angular module, its dependencies and the controller:

Head back to the application’s main view and add a <script> element after the Angular script that points to our new module JavaScript file.

In the same view add a new <div> element that surrounds the existing markup.  Use the ng-app attribute to designate the root <div> element as the root of our Angular application.  Then attach the videochat controller to the same <div> using the ng-controller attribute:

Run the application and verify that controller attached and check that there are no errors in the browser’s JavaScript console.

Revving up some Video

With the Angular controller connected, let’s separate the existing UI elements from their logic, starting with the button that previews the local video.

In the controller create a property named previewMedia that will hold an instance of the LocalMedia object.

Next, define a new function named previewCamera.  Inside this function, create an instance of LocalMedia and call its getLocalMedia function.  Use the addStream function to add the returned media to the LocalMedia instance.

Notice that addStream is called inside of Angular’s $apply function.  Later in the post we’ll hook a watch up to the previewMedia object but because getUserMedias promise callback happens outside of the scope of Angular’s digest loop we have to explicitly tell Angular that we want to apply a change.  You will use the pattern in multiple places as you move through the code in this post.

Finally, add a click event to the button-preview button using Angulars ng-click attribute:

Run the application and press the preview button.  You should get prompted for microphone and camera access. However, nothing else happens because we have not attached the media streams to any UI element.  Let’s handle attaching media streams to UI elements next.

Directing Directives

LocalMedia has an attach method that creates new <video> HTML elements and automatically attaches their media streams for us, but to use it I have to pass attach a DOM reference which breaks my seperation of concerns.  To keep my controller clean I don’t want it to have any DOM references.  Angular Directives are great ways of building intermediaries between a controller and view.

Create a new file in the app directory named video.directive.js and define the new directive in it:

Restrict the directive to match only an element name, define the directive scope with a single media property and create the template our directive will output.

Finally, add a $watch to the directives media property.  This will let us check to see if there is a new media stream to attach to the div in our template.

Back in the view add another <script> element below the existing scripts to reference the new directive JavaScript file.  Replace the local-media div with our new Angular directive and bind the media attribute to the controllers previewMedia property.

Run the project and press the button.  You should now see yourself!

You’ve created one half of a conversation, but talking to ourselves gets boring fast.  Let’s create a conversation with someone else.

Tackling Tokens

To create a conversation we need an access token. An access token allows our application to authenticate with Twilio.

The quickstart already has a server side route that returns an access token.  We could call that route directly from our controller but that would violate the SoC principle. Instead, keep the request for a token isolated by using an Angular Service that we inject into the controller.

Create a new file named token.service.js and define the token service in it:

Using Angular’s built-in $http service add a GET request to the Token endpoint and return the resulting data:

Add one more <script> element to the view to include the token service Javascript file.

To use the token service we’ll use Angular’s Dependency Injection capabilities to inject an instance of the token service into the video chat controller:

Once the service is injected we can use the Twilio Video Javascript SDK to create new Conversation Client and have that client begin listening for and automatically accept any incoming conversation invitations.

Creating Conversations

Create a new Conversation by defining a few new variables in the VideoChatController:

As well as two new properties:

Next, create a function named getToken that calls the injected Token Service and populates the token and identity properties:

Define and call a function named activate that will acquire the token and use it to create a Conversation Client:

Use the client to listen for and automatically accept incoming conversation invitations:

When the client receives an invitation we want to put the audio and video of the invited conversation participants into the appropriate locations in the UI.

To do that define a new function named conversationStarted that accepts a single conversation parameter.

Change the instance of the client so that when it receives an invite it calls the conversationStarted function:

In the conversationStarted function set the conversation as the activeConversation:

Check to see if we are already showing the local participants audio and video in the UI and if not, do that.

When a conversation participant connects, add their media streams to the remoteParticipants dictionary which is keyed using their participant SID.

When a participant disconnects, remove their media from the remoteParticipants dictionary using the participant SID.

Finally, if the entire conversation ends, stop the local media, disconnect from the conversation and set the activeConversation to null.

Run the app and head over to Twilio Console to use the Testing Tools to invite your client into a video conversation.

Through the testing tools you’ll be able to see the “remote” participants’ video, but the app won’t display video coming from the testing tool.  Why?  Because although the quickstart application is accepting the invitation from the testing tool, we’ve not done anything to attach the media streams coming from the testing tool to any elements in the quickstart UI.  Let’s fix that so our application correctly attaches media streams to our UI.

Patch in Participants

To attach “remote” conversation participant media streams to our UI we’ll use the twilio-video directive we created earlier.  If we only replace the existing remote-media div with the twilio-video directive we’ll quickly see that we can only attach media from one remote participant.  How do we attach media from any number of remote participants?  For that we’ll leverage Angular’s ng-repeat directive and create as many twilio-video elements as there are remote participants.

Replace the existing remote-media div with this markup:

Run the app again. Head back to the testing tools and give it another try. This time you’ll see both the local and remote media in our app.  All that’s left to complete the transformation of the quickstart to an Angular app is to allow the quickstart to invite other participants.

Initiate Invites

Using the test tools we’ve seen that we now have an app that works great as long as someone else invites.  But waiting for that invite to come we could get lonely fast.  The quickstart UI already includes a way for us to send conversation invites.  Let’s modify that UI to trigger those invites via Angular.

Start by adding another property to the controller:

Use the ng-model attribute to bind the inviteTo property to the invite-to input element in our view:

Define a new function named sendInvite in the controller:

In the sendInvite function check to see if we are already in a conversation and want to add a new participant, or if we are starting a new conversation from scratch.

Finally, bind the sendInvite function to an ng-click attribute on the button-invite button element:

Run the application and open it in two browser windows.  From the first browser window, invite the user in the second to join a conversation.  Now open up a third browser and from the first invite the third user into the existing conversation.

Bam!  Multiple participants in a single Angular powered video chat!

Wrapup

Clean separation between views and our controllers is just one of the reasons I really like AngularJS.  Isolating DOM and controller interactions in directives lets me keep my code well factored and clean.

There is so much more we could do with this app.  The UI for remote participants could be enhanced, we could add more controls like mute or pause camera buttons, or even add an audio meter to the UI.

Building apps with Twilio Video is so much fun and combining it with AngularJS makes it even better.  Grab the code from Github and start video conferencing today.

Show me what you’re making with Twilio Video or AngularJS.  Send me an email at devin@twilio.com or hit me up on Twitter @devinrader.

Build Video Chat using AngularJS 1.x

Show more