Getting Started

Welcome to the Programmable Video Getting Started guide. This guide will give you a high-level overview of the features of the Video SDKs, as well as introduce you to the key objects and methods required to use them to add video to your web and mobile applications.

Running the quickstart applications

The best place to get started is to download and run our Video Quickstart applications on github. These simple apps will get you up and running quickly with a functioning application. Just follow the instructions in each quickstart's README to get going.

Once you've played with the Quickstart, come back to this guide for more detail on how to add video to your own app.

Downloading the SDKs

First, you'll need to download a Programmable Video SDK for your environment. Grab the right SDK by following the instructions here:

Create a Video Client
  • Java
  • JavaScript
  • Objective-C
  • Swift
VideoClient videoClient = new VideoClient(context, accessToken);
// If you are requiring twilio-video from CommonJS,
//
//     const Video = require('twilio-video');
//
//  If you are including twilio-video.js from a <script> tag,
//
//     const Video = Twilio.Video;
//

const client = new Video.Client(accessToken);
TVIVideoClient *videoClient = [TVIVideoClient clientWithToken:accessToken];
var videoClient = TVIVideoClient(token: accessToken)
Create a Video Client

Create a Video Client

To get started with the Video SDK, we first need to create a Video Client object.

A Video Client represents your user's "identity" in the context of a Twilio Video session, and allows your application to connect to a Room and share and receive Tracks with other Participants. You can think of a Room like a video conference room, and Tracks as the individual audio and video streams shared among its participants.

Construct a Video Client object with an Access Token. We'll cover Access Tokens in more detail toward the end of this guide, but for now, you can generate an Access Token in the Twilio Console here.

Setup LocalMedia
  • Java
  • JavaScript
  • Objective-C
  • Swift
// Create a local media object
LocalMedia localMedia = LocalMedia.create(context);

// Add an audio track
boolean enable = true;
LocalAudioTrack localAudioTrack = localMedia.addAudioTrack(enable);

// A video track requires an implementation of VideoCapturer
CameraCapturer cameraCapturer = new CameraCapturer(context,
        CameraCapturer.CameraSource.FRONT_CAMERA);

// Add a video track
LocalVideoTrack localVideoTrack = localMedia.addVideoTrack(enable, cameraCapturer);

// Rendering a local video track requires an implementation of VideoRenderer
// Let's assume we have added a VideoView in our view hierarchy
VideoView videoView = (VideoView) findViewById(R.id.video_view);

// Render a local video track to preview your camera
localVideoTrack.addRenderer(videoView);

// Remove audio track
localMedia.removeAudioTrack(localAudioTrack);

// Remove video track
localMedia.removeVideoTrack(localVideoTrack);

// You must call release to ensure you free native resources
localMedia.release();
// If you are requiring twilio-video from CommonJS,
//
//     const Video = require('twilio-video');
//
//  If you are including twilio-video.js from a <script> tag,
//
//     const Video = Twilio.Video;
//

const localMedia = new Video.LocalMedia();

// You can call getUserMedia and add the resulting MediaStream to localMedia.
Video.getUserMedia().then(mediaStream => {
  localMedia.addStream(mediaStream);
});

// Or you can add the microphone and camera independently.
localMedia.addMicrophone().then(() => {
  return localMedia.addCamera();
});

// Remove the microphone.
localMedia.removeMicrophone();

// Remove the camera.
localMedia.removeCamera();

// Remove any tracks on the localMedia.
localMedia.tracks.forEach(track => {
  localMedia.removeTrack(track);
});

// Stop localMedia and all Tracks on it.
localMedia.stop();
//Create a local media object
TVILocalMedia *localMedia = [[TVILocalMedia alloc] init];

// Add an audio track
BOOL enable = YES;
TVILocalAudioTrack *localAudioTrack = [localMedia addAudioTrack:enable];

// Create camera object
TVICameraCapturer *camera = = [[TVICameraCapturer alloc] init];

// Add a video track
TVILocalVideoTrack *localVideoTrack = [localMedia addVideoTrack:enable capturer:camera];

// Connect and share your local media
TVIRoom *room = [videoClient connectWithOptions:connectOptions delegate:self];

// Remove audio track
[localMedia removeAudioTrack:localAudioTrack];

// Remove video track
[localMedia removeVideoTrack:localVideoTrack];
// Create a local media object
var localMedia = TVILocalMedia()

// Add an audio track
var enable = true;
var localAudioTrack = localMedia.addAudioTrack(enable)

// Create camera object
var camera = TVICameraCapturer()

// Add a video track
var localVideoTrack = localMedia.addVideoTrack(enable, capturer: camera)

// Remove audio track
localMedia.removeAudioTrack(localAudioTrack?)

// Remove video track
localMedia.removeVideoTrack(localVideoTrack?)
Setup LocalMedia

Setup LocalMedia

A LocalMedia object collects the audio and video captured from the local device's microphone, camera, or screen-share.

LocalMedia keeps a collection for each type of media you're capturing: a collection of LocalAudioTracks and/or LocalVideoTracks. These Tracks represent the discrete audio and video sources available to your application.

Getting LocalMedia from the device's audio and video sources differs slightly in each platform:

  • In a JavaScript application, call the browser's getUserMedia() API to gain access to the user's microphone and camera. Note that some browsers, such as Google Chrome, will only let your application call this API when your site is served from localhost or over HTTPS.
  • In an iOS or Android application, begin capturing audio data by adding an AudioTrack to your LocalMedia object, and begin capturing video by adding a VideoTrack with an associated VideoCapturer. The mobile Video SDKs provides customizable video capturers for both camera and screen capture.
Connect to a Room
  • Java
  • JavaScript
  • Objective-C
  • Swift
// Specify the room you would like to join
String roomName = "my-room";
ConnectOptions connectOptions = new ConnectOptions.Builder()
    .roomName(roomName)
    .localMedia(localMedia)
    .build();

// Create a room listener
Room.Listener roomListener = new Room.Listener() {
    @Override
    public void onConnected(Room room) {
        // Notifies you that you are now connected to the Room
    }

    @Override
    public void onConnectFailure(Room room, TwilioException e) {
        // Notifies you that a failure occurred when attempting to the connect to the room
    }

    @Override
    public void onDisconnected(Room room, TwilioException e) {
        // Notifies you that you were disconnected from the Room
    }

    @Override
    public void onParticipantConnected(Room room, Participant participant) {
        // A participant joined the Room
    }

    @Override
    public void onParticipantDisconnected(Room room, Participant participant) {
        // A participant left the Room
    }
};

// Connect to the room
Room room = videoClient.connect(connectOptions, roomListener);
client.connect({
  to: 'my-room',
  localMedia: localMedia
}).then(room => {
  console.log('Connected to the Room "%s"', room.name);
}, error => {
  console.error('Failed to connect to the Room', error);
});
TVIConnectOptions *connectOptions = [TVIConnectOptions optionsWithBlock:^(TVIConnectOptionsBuilder * _Nonnull builder) {
    builder.name = @"my-room";
    builder.localMedia = self.localMedia;
}];

TVIRoom *room = [videoClient connectWithOptions:connectOptions delegate:self];

#pragma mark - TVIRoomDelegate

- (void)didConnectedToRoom:(nonnull TVIRoom *)room {
    // The Local Participant
    TVILocalParticipant *localParticipant = room.localParticipant;
    NSLog(@"Local Participant %@", localParticipant.identity);
    
    // Connected participants
    NSArray *participants = room.participants;
    NSLog(@"Number of connected participants %ld", [participants count]);
}

- (void)room:(nonnull TVIRoom *)room participantDidConnect:(nonnull TVIParticipant *)participant {
    NSLog(@"Participant %@ has joined Room %@", participant.identity, room.name);
}

- (void)room:(nonnull TVIRoom *)room participantDidDisconnect:(nonnull TVIParticipant *)participant {
    NSLog(@"Participant %@ has left Room %@", participant.identity, room.name);
}
let connectOptions = TVIConnectOptions { (builder) in
    builder.name = "my-room"
    builder.localMedia = self.localMedia
}
room = videoClient.connect(with: connectOptions, delegate: self)

// MARK: TVIRoomDelegate

func didConnect(to room: TVIRoom) {    
    // The Local Participant
    let localParticipant = room.localParticipant;
    print("Local identity \(localParticipant!.identity)")
    
    // Connected participants
    let participants = room.participants;
    print("Number of connected participants \(participants.count)")
}

func room(_ room: TVIRoom, participantDidConnect participant: TVIParticipant) {
    print ("Participant \(participant.identity) has joined Room \(room.name)")
}

func room(_ room: TVIRoom, participantDidDisconnect participant: TVIParticipant) {
    print ("Participant \(participant.identity) has left Room \(room.name)")
}
Connect to a Room

Connect to a Room

Once you have created a Video Client you can use it to connect to a Room. Connecting to a Room allows you to share your LocalMedia with other Participants in the Room, and receive remote Media from other Participants in the Room.

When you connect to a Room, you can specify options:

  • The name of the Room specifies which Room you wish to join. If a Room by that name does not exist, it will automatically be created for you. If a Room by that name is already active, you'll be connected to the Room and receive notifications from any other Participants also connected to the same Room. Room names must be unique within an account.
  • The LocalMedia option allows you to specify which media object you'd like to share upon connecting to the Room.

Once you've connected to a Room, any changes you make to the LocalMedia that you've shared will be reflected to other Participants in the same Room.

For example, if you add a Track to your LocalMedia, the other Participants will receive a “track added” event corresponding to your newly-added Track. Similarly, if you remove a Track from your LocalMedia, the other Participants will receive a “track removed” event and your Track will no longer be shared in the Room.

Handle Participants
  • Java
  • JavaScript
  • Objective-C
  • Swift
// Connect to room
Room room = videoClient.connect(connectOptions, new Room.Listener() {
    @Override
    public void onConnected(Room room) {}

    @Override
    public void onConnectFailure(Room room, TwilioException e) {}

    @Override
    public void onDisconnected(Room room, TwilioException e) {}

    @Override
    public void onParticipantConnected(Room room, Participant participant) {
        Log.i("Room.Listener", participant.getIdentity() + " has joined the room.");
    }

    @Override
    public void onParticipantDisconnected(Room room, Participant participant) {
        Log.i("Room.Listener", participant.getIdentity() + " has left the room.");
    }
);

// ... Assume we have received the connected callback

// After receiving the connected callback the LocalParticipant becomes available
LocalParticipant localParticipant = room.getLocalParticipant();
Log.i("LocalParticipant ", localParticipant.getIdentity());

// Get a participant from the room (let's assume we have a participant named Alice)
Participant participant = room.getParticipants().get("Alice");
Log.i("HandleParticipants", participant.getIdentity() + " is in the room.");
// Log your Client's LocalParticipant in the Room
const localParticipant = room.localParticipant;
console.log('Connected to the Room as LocalParticipant "%s"', localParticipant.identity);

// Log any Participants already connected to the Room
room.participants.forEach(participant => {
  console.log('Participant "%s" is connected to the Room', participant.identity);
});

// Log new Participants as they connect to the Room
room.once('participantConnected', participant => {
  console.log('Participant "%s" has connected to the Room', participant.identity);
});

// Log Participants as they disconnect from the Room
room.once('participantDisconnected', participant => {
  console.log('Participant "%s" has disconnected from Room', participant.identity);
});
TVIConnectOptions *connectOptions = [TVIConnectOptions optionsWithBlock:^(TVIConnectOptionsBuilder * _Nonnull builder) {
    builder.name = @"my-room";
    builder.localMedia = self.localMedia;
}];
TVIRoom *room = [videoClient connectWithOptions:connectOptions delegate:self];

#pragma mark - TVIRoomDelegate

- (void)didConnectedToRoom:(nonnull TVIRoom *)room {
    // The Local Participant
    TVILocalParticipant *localParticipant = room.localParticipant;
    NSLog(@"Local Participant %@", localParticipant.identity);
    
    // Connected participants
    NSArray *participants = room.participants;
    NSLog(@"Number of connected Participants %ld", [participants count]);
}

- (void)room:(nonnull TVIRoom *)room participantDidConnect:(nonnull TVIParticipant *)participant {
    NSLog(@"Participant %@ has joined Room %@", participant.identity, room.name);
}

- (void)room:(nonnull TVIRoom *)room participantDidDisconnect:(nonnull TVIParticipant *)participant {
    NSLog(@"Participant %@ has left Room %@", participant.identity, room.name);
}
let connectOptions = TVIConnectOptions { (builder) in
    builder.name = "my-room"
    builder.localMedia = self.localMedia
}
room = videoClient.connect(with: connectOptions, delegate: self)

// MARK: TVIRoomDelegate

func didConnect(to room: TVIRoom) {
    // The Local Participant
    let localParticipant = room.localParticipant;
    print("Local identity \(localParticipant.identity)")
    
    // Connected participants
    let participants = room.participants;
    print("Number of connected Participants \(participants.count)")
}

func room(_ room: TVIRoom, participantDidConnect participant: TVIParticipant) {
    print ("Participant \(participant.identity) has joined Room \(room.name)")
}

func room(_ room: TVIRoom, participantDidDisconnect participant: TVIParticipant) {
    print ("Participant \(participant.identity) has left Room \(room.name)")
}
Handle Participants

Handle Participants

A Participant represents a remote Client connected to the Room—typically other users on other devices, participating in this voice or video call. Your application’s Client is represented as a LocalParticipant in the Room.

Once your Client has connected to a Room, any already-connected Participants will be available as an array on the Room object, called participants.

Your application will be notified as additional Participants connect and disconnect from the Room through "connected" and "disconnected" events.

Just as with your Client object, every Participant and LocalParticipant has an identity property, which your application can use to identify the user associated with that application. As mentioned above, the identity property is specified in the Access Token you generate when you create a Client, and you can set it to whatever you like—a user ID you generate in your application, the user's email address, or some other identifier.

// Used to observe media events of a participant
Media.Listener mediaListener = new Media.Listener() {
    @Override
    public void onAudioTrackAdded(Media media, AudioTrack audioTrack) {
        // Notifies you that an audio track has been added
    }

    @Override
    public void onAudioTrackRemoved(Media media, AudioTrack audioTrack) {
        // Notifies you that an audio track has been removed
    }

    @Override
    public void onVideoTrackAdded(Media media, VideoTrack videoTrack) {
        // Notifies you that an video track has been added
    }

    @Override
    public void onVideoTrackRemoved(Media media, VideoTrack videoTrack) {
        // Notifies you that an video track has been removed
    }

    @Override
    public void onAudioTrackEnabled(Media media, AudioTrack audioTrack) {
        // Notifies you that an audio track has been enabled
    }

    @Override
    public void onAudioTrackDisabled(Media media, AudioTrack audioTrack) {
        // Notifies you that an audio track has been disabled
    }

    @Override
    public void onVideoTrackEnabled(Media media, VideoTrack videoTrack) {
        // Notifies you that an video track has been enabled
    }

    @Override
    public void onVideoTrackDisabled(Media media, VideoTrack videoTrack) {
        // Notifies you that an video track has been disabled
    }
};

// Grab the participant's media and register our listener
Media media = participant.getMedia();
media.setListener(mediaListener);

// Like a LocalVideoTrack, a VideoTrack can be rendered with a VideoRenderer 
VideoView videoView = (VideoView) findViewById(R.id.video_view);

// Render the first video track
VideoTrack videoTrack = media.getVideoTracks().get(0);
videoTrack.addRenderer(videoView);

// To stop rendering simply remove the renderer from the video track
videoTrack.removeRenderer(videoView);
Use Participant Media Android

Use Participant Media

Every Participant has a Media collection that represents the AudioTracks and VideoTracks they are sharing in the Room. Your application will be notified as Participants add and remove Tracks to and from their Media collections.

You can inspect the Media object for any connected Participant, and attach listeners to the object to receive notifications when each Participant adds, removes, or disables any of their audio or video Tracks.

Android

AudioTracks are automatically played on your specified audio output. Add a VideoRenderer to a VideoTrack to show it on the screen, or remove the VideoRenderer if you no longer need to see it.

On Android, the attached Media listener will raise events whenever Tracks are modified, added, or removed.

Use Participant Media iOS
  • Objective-C
  • Swift
// Set the Participant Delegate to receive participant's events
participant.delegate = self;

// UIView where you want to render remote participant's video
@property (nonatomic, weak) IBOutlet UIView *remoteView;

#pragma mark - TVIParticipantDelegate

- (void)participant:(nonnull TVIParticipant *)participant addedVideoTrack:(nonnull TVIVideoTrack *)videoTrack {
    // Attach remoteView on video track to render video
    [videoTrack attach:self.remoteView];
}

- (void)participant:(nonnull TVIParticipant *)participant removedVideoTrack:(nonnull TVIVideoTrack *)videoTrack {
    // To stop rendering simply call detach
    [videoTrack detach:self.remoteView];
}
- (void)participant:(nonnull TVIParticipant *)participant addedAudioTrack:(nonnull TVIAudioTrack *)audioTrack {
    // A Participant added an Audio Track
}

- (void)participant:(nonnull TVIParticipant *)participant removedAudioTrack:(nonnull TVIAudioTrack *)audioTrack {
    // A Participant removed an Audio Track
}

- (void)participant:(nonnull TVIParticipant *)participant enabledTrack:(nonnull TVITrack *)track {
    // A Participant enabled a Track
}

- (void)participant:(nonnull TVIParticipant *)participant disabledTrack:(nonnull TVITrack *)track {
    // A Participante disabled a Track
}
// Set the Participant Delegate to receive participant's events
participant.delegate = self;

// UIView where you want to render remote participant's video
@IBOutlet weak var remoteView: UIView!

// MARK: TVIParticipantDelegate

func participant(_ participant: TVIParticipant, addedVideoTrack videoTrack: TVIVideoTrack) {
    // Attach remoteView on video track to render video
    videoTrack.attach(remoteView);
}

func participant(_ participant: TVIParticipant, removedVideoTrack videoTrack: TVIVideoTrack) {
    // To stop rendering simply call detach
    videoTrack.detach(remoteView);
}

func participant(_ participant: TVIParticipant, addedAudioTrack audioTrack: TVIAudioTrack) {
    // A participant added an Audio Track
}

func participant(_ participant: TVIParticipant, removedAudioTrack audioTrack: TVIAudioTrack) {
    // A participant removed an Audio Track
}

func participant(_ participant: TVIParticipant, enabledTrack track: TVITrack) {
    // A participant enabled a Track
}

func participant(_ participant: TVIParticipant, disabledTrack track: TVITrack) {
    // A participant disabled a Track
}
Use Participant Media iOS

iOS

AudioTracks are automatically played on your specified audio output. Attach a view to a VideoTrack to show the track on the screen, or detach the view from a VideoTrack to displaying it. On iOS, the TVIParticipantDelegate will raise events whenever Tracks are modified, added, or removed.

participant.on('trackAdded', track => {
  if (track.kind === 'audio') {
    console.log('Added an AudioTrack %s', track.id);
  } else {
    console.log('Added a VideoTrack %s', track.id);
  }
});

participant.on('trackRemoved', track => {
  if (track.kind === 'audio') {
    console.log('Removed an AudioTrack %s', track.id);
  } else {
    console.log('Removed a VideoTrack %s', track.id);
  }
});

participant.on('trackEnabled', track => {
  if (track.kind === 'audio') {
    console.log('Enabled AudioTrack %s', track.id);
  } else {
    console.log('Enabled VideoTrack %s', track.id);
  }
});

participant.on('trackDisabled', track => {
  if (track.kind === 'audio') {
    console.log('Disabled AudioTrack %s', track.id);
  } else {
    console.log('Disabled VideoTrack %s', track.id);
  }
});

// You can attach a Participant's Media directly to a DOM element,
participant.media.attach(document.getElementById('#my-view'));

// You can pass the query selector directly,
participant.media.attach('#media-view');

// Or you can create a default element.
const element = participant.media.attach();
document.body.appendChild(element);

// In all three of these scenarios, as Tracks are added and removed, the
// attached element will be updated with the appropriate <audio> and <video>
// tags. If you would like to manage Track attachment yourself, you can always
// attach them manually. For example,
participant.media.tracks.forEach(track => {
  track.attach('#track-view');
});
Use Participant Media Javascript

Javascript

Participant Media and Track objects both provide an attach API for attaching them to the DOM. Use the Media-level attach method if you would like to automatically add and remove <audio> and <video> elements to and from a DOM element as Tracks are added and removed.

Use the Track-level attach method if you would like finer-grained control of when and how Tracks are attached to the DOM.

Finally, you may want to detach any attached Media or Tracks when a Participant disconnects to remove their video from the display.

Server Token Generation
  • C#
  • Java
  • Node.js
  • PHP
  • Python
  • Ruby
SDK Version:
  • 4.x
  • 5.x
SDK Version:
  • 6.x
  • 7.x
SDK Version:
  • 2.x
  • 3.x
SDK Version:
  • 4.x
  • 5.x
SDK Version:
  • 5.x
  • 6.x
SDK Version:
  • 4.x
  • 5.x
import static spark.Spark.get;
import static spark.Spark.staticFileLocation;

import java.util.HashMap;

import com.github.javafaker.Faker;
import com.google.gson.Gson;
import com.twilio.sdk.auth.AccessToken;
import com.twilio.sdk.auth.ConversationsGrant;

public class Webapp {

  public static void main(String[] args) {
    // Serve static files from src/main/resources/public
    staticFileLocation("/public");

    // Create a Faker instance to generate a random username for the connecting user
    Faker faker = new Faker();

    // Create an access token using our Twilio credentials
    get("/token", "application/json", (request, response) -> {
      // Generate a random username for the connecting client
      String identity = faker.firstName() + faker.lastName() + faker.zipCode();

      // Create Video grant
      VideoGrant grant = new VideoGrant();
      grant.configurationProfileSid = System.getenv("TWILIO_CONFIGURATION_SID");

      // Create access token
      AccessToken token = new AccessToken.Builder(
        System.getenv("TWILIO_ACCOUNT_SID"),
        System.getenv("TWILIO_API_KEY"),
        System.getenv("TWILIO_API_SECRET")
      ).identity(identity).grant(grant).build();

      // create JSON response payload
      HashMap<String, String> json = new HashMap<String, String>();
      json.put("identity", identity);
      json.put("token", token.toJWT());

      // Render JSON response
      Gson gson = new Gson();
      return gson.toJson(json);
    });
  }
}
import os
from flask import Flask, jsonify
from faker import Factory
from twilio.jwt.access_token import AccessToken, VideoGrant

app = Flask(__name__)
fake = Factory.create()


@app.route('/')
def index():
    return app.send_static_file('index.html')


@app.route('/token')
def token():
    # get credentials for environment variables
    account_sid = os.environ['TWILIO_ACCOUNT_SID']
    api_key = os.environ['TWILIO_API_KEY']
    api_secret = os.environ['TWILIO_API_SECRET']

    # Create an Access Token
    token = AccessToken(account_sid, api_key, api_secret)

    # Set the Identity of this token
    token.identity = fake.user_name()

    # Grant access to Video
    grant = VideoGrant()
    grant.configuration_profile_sid = os.environ['TWILIO_CONFIGURATION_SID']
    token.add_grant(grant)

    # Return token info as JSON
    return jsonify(identity=token.identity, token=token.to_jwt())

if __name__ == '__main__':
    app.run(debug=True)
using System.Configuration;
using System.Web.Mvc;
using Faker;
using Twilio.JWT;

namespace VideoQuickstart.Controllers
{
    public class TokenController : Controller
    {
        // GET: Token
        public ActionResult Index(string device)
        {
            // Load Twilio configuration from Web.config
            var accountSid = ConfigurationManager.AppSettings["TwilioAccountSid"];
            var apiKey = ConfigurationManager.AppSettings["TwilioApiKey"];
            var apiSecret = ConfigurationManager.AppSettings["TwilioApiSecret"];
            var videoConfigSid = ConfigurationManager.AppSettings["TwilioConfigurationSid"];

            // Create a random identity for the client
            var identity = Internet.UserName();

            // Create an Access Token generator
            var token = new AccessToken(accountSid, apiKey, apiSecret)
            {
                Identity = identity
            };

            // Grant access to Video
            var grant = new VideoGrant
            {
                ConfigurationProfileSid = videoConfigSid
            };
            token.AddGrant(grant);

            return Json(new
            {
                identity,
                token = token.ToJwt()
            }, JsonRequestBehavior.AllowGet);
        }
    }
}
<?php
// Get the PHP helper library from twilio.com/docs/php/install
require_once '/path/to/vendor/autoload.php'; // Loads the library
use Twilio\Jwt\AccessToken;
use Twilio\Jwt\Grants\ConversationsGrant;

// Required for all Twilio access tokens
$twilioAccountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$twilioApiKey = 'SKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$twilioApiSecret = 'your_api_secret';
$TwilioConfigurationSid = 'VSXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
// choose a random username for the connecting user
$identity = 'randomUsername';

// Create access token, which we will serialize and send to the client
$token = new AccessToken(
    $TWILIO_ACCOUNT_SID,
    $TWILIO_API_KEY,
    $TWILIO_API_SECRET,
    3600,
    $identity
);

// Grant access to Video
$grant = new VideoGrant();
$grant->setConfigurationProfileSid($TwilioConfigurationSid);
$token->addGrant($grant);

// return serialized token and the user's randomly generated ID
echo json_encode(
    array(
        'identity' => $identity,
        'token' => $token->toJWT(),
    )
);
import os
from flask import Flask, jsonify
from faker import Factory
from twilio.access_token import AccessToken, ConversationsGrant

app = Flask(__name__)
fake = Factory.create()


@app.route('/')
def index():
    return app.send_static_file('index.html')


@app.route('/token')
def token():
    # get credentials for environment variables
    account_sid = os.environ['TWILIO_ACCOUNT_SID']
    api_key = os.environ['TWILIO_API_KEY']
    api_secret = os.environ['TWILIO_API_SECRET']

    # Create an Access Token
    token = AccessToken(account_sid, api_key, api_secret)

    # Set the Identity of this token
    token.identity = fake.user_name()

    # Grant access to Video
    grant = VideoGrant()
    grant.configuration_profile_sid = os.environ['TWILIO_CONFIGURATION_SID']
    token.add_grant(grant)

    # Return token info as JSON
    return jsonify(identity=token.identity, token=token.to_jwt())

if __name__ == '__main__':
    app.run(debug=True)
require 'twilio-ruby'
require 'sinatra'
require 'sinatra/json'
require 'dotenv'
require 'faker'

# Load environment configuration
Dotenv.load

# Render home page
get '/' do
  File.read(File.join('public', 'index.html'))
end

# Generate a token for use in our Video application
get '/token' do
  # Create a random username for the client
  identity = Faker::Internet.user_name

  # Create an Access Token for Video usage
  token = Twilio::Util::AccessToken.new(
    ENV['TWILIO_ACCOUNT_SID'],
    ENV['TWILIO_API_KEY'],
    ENV['TWILIO_API_SECRET'],
    3600,
    identity
  )

  # Grant access to Video
  grant = Twilio::Util::AccessToken::VideoGrant.new
  grant.configuration_profile_sid = ENV['TWILIO_CONFIGURATION_SID']
  token.add_grant grant

  # Generate the token and send to client
  json identity: identity, token: token.to_jwt
end
require('dotenv').load();

const http = require('http');
const path = require('path');

const AccessToken = require('twilio').AccessToken;
const ConversationsGrant = AccessToken.ConversationsGrant;
const express = require('express');
const randomUsername = require('./randos');

// Create Express webapp
const app = express();
app.use(express.static(path.join(__dirname, 'public')));

app.get('/token', (request, response) => {
  const identity = randomUsername();

  // Create an access token which we will sign and return to the client,
  // containing the grant we just created
  const token = new AccessToken(
    process.env.TWILIO_ACCOUNT_SID,
    process.env.TWILIO_API_KEY,
    process.env.TWILIO_API_SECRET
  );

  // Assign the generated identity to the token.
  token.identity = identity;

  // Grant access to Video.
  const grant = new VideoGrant();
  grant.configurationProfileSid = process.env.TWILIO_CONFIGURATION_SID;
  token.addGrant(grant);

  // Serialize the token to a JWT string and include it in a JSON response
  response.send({
    identity: identity,
    token: token.toJwt(),
  });
});

// Create http server and run it
const server = http.createServer(app);
const port = process.env.PORT;

server.listen(port = 3000, function() {
  console.log('Express server running on *:' + port);
});
import static spark.Spark.get;
import static spark.Spark.staticFileLocation;

import java.util.HashMap;

import com.github.javafaker.Faker;
import com.google.gson.Gson;
import com.twilio.jwt.accesstoken.AccessToken;
import com.twilio.jwt.accesstoken.ConversationsGrant;


public class Webapp {
  public static void main(String[] args) {
    // Serve static files from src/main/resources/public
    staticFileLocation("/public");

    String ACCOUNT_SID = System.getenv("TWILIO_ACCOUNT_SID");
    String API_KEY = System.getenv("TWILIO_API_KEY");
    String API_SECRET = System.getenv("TWILIO_API_SECRET");

    String TWILIO_CONFIGURATION_SID = System.getenv("TWILIO_CONFIGURATION_SID");

    // Create a Faker instance to generate a random username for the connecting user
    Faker faker = new Faker();

    // Create an access token using our Twilio credentials
    get("/token", "application/json", (request, response) -> {
      // Generate a random username for the connecting client
      String identity =
          faker.name().firstName() + faker.name().lastName() + faker.address().zipCode();

      // Create Video grant
      VideoGrant grant =
          new VideoGrant().setConfigurationProfileSid(TWILIO_CONFIGURATION_SID);

      // Create access token
      AccessToken token = new AccessToken.Builder(ACCOUNT_SID, API_KEY, API_SECRET)
          .identity(identity)
          .grant(grant)
          .build();

      // create JSON response payload
      HashMap<String, String> json = new HashMap<String, String>();
      json.put("identity", identity);
      json.put("token", token.toJwt());

      // Render JSON response
      Gson gson = new Gson();
      return gson.toJson(json);
    });
  }
}
require('dotenv').load();
var http = require('http');
var path = require('path');
var AccessToken = require('twilio').AccessToken;
var ConversationsGrant = AccessToken.ConversationsGrant;
var express = require('express');
var randomUsername = require('./randos');

// Create Express webapp
var app = express();
app.use(express.static(path.join(__dirname, 'public')));

app.get('/token', function(request, response) {
    var identity = randomUsername();
    
    // Create an access token which we will sign and return to the client,
    // containing the grant we just created
    var token = new AccessToken(
        process.env.TWILIO_ACCOUNT_SID,
        process.env.TWILIO_API_KEY,
        process.env.TWILIO_API_SECRET
    );

    //assign the generated identity to the token
    token.identity = identity;
        
    //grant access to Video
    var grant = new VideoGrant();
    grant.configurationProfileSid = process.env.TWILIO_CONFIGURATION_SID;
    token.addGrant(grant);

    // Serialize the token to a JWT string and include it in a JSON response
    response.send({
        identity: identity,
        token: token.toJwt()
    });
});

// Create http server and run it
var server = http.createServer(app);
var port = process.env.PORT || 3000;
server.listen(port, function() {
    console.log('Express server running on *:' + port);
});
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Twilio;
using Twilio.Auth;
using JWT;
using Faker;

namespace VideoQuickstart.Controllers
{
    public class TokenController : Controller
    {
        // GET: /token
        public ActionResult Index(string Device)
        {
            // Load Twilio configuration from Web.config
            var accountSid = ConfigurationManager.AppSettings["TwilioAccountSid"];
            var apiKey = ConfigurationManager.AppSettings["TwilioApiKey"];
            var apiSecret = ConfigurationManager.AppSettings["TwilioApiSecret"];
            var videoConfigSid = ConfigurationManager.AppSettings["TwilioConfigurationSid"];

            // Create a random identity for the client
            var identity = Internet.UserName();

            // Create an Access Token generator
            var token = new AccessToken(accountSid, apiKey, apiSecret);
            token.Identity = identity;

            // Grant access to Video
            var grant = new VideoGrant();
            grant.ConfigurationProfileSid = videoConfigSid;
            token.AddGrant(grant);

            return Json(new
            {
                identity = identity,
                token = token.ToJWT()
            }, JsonRequestBehavior.AllowGet);
        }
    }
}
<?php
require_once('./twilio-php/Services/Twilio.php');
require_once('./randos.php');
require_once('./config.php');

// choose a random username for the connecting user
$identity = randomUsername();

// Create access token, which we will serialize and send to the client
$token = new Services_Twilio_AccessToken(
    $TWILIO_ACCOUNT_SID,
    $TWILIO_API_KEY,
    $TWILIO_API_SECRET,
    3600,
    $identity
);

// Grant access to Video
$grant = new Services_Twilio_Auth_VideoGrant();
$grant->setConfigurationProfileSid($TWILIO_CONFIGURATION_SID);
$token->addGrant($grant);

// return serialized token and the user's randomly generated ID
echo json_encode(array(
    'identity' => $identity,
    'token' => $token->toJWT(),
));
require 'twilio-ruby'
require 'sinatra'
require 'sinatra/json'
require 'dotenv'
require 'faker'

# Load environment configuration
Dotenv.load

# Render home page
get '/' do
  File.read(File.join('public', 'index.html'))
end

# Generate a token for use in our Video application
get '/token' do
  # Create a random username for the client
  identity = Faker::Internet.user_name

  # Create an Access Token for Video usage
  token = Twilio::Util::AccessToken.new ENV['TWILIO_ACCOUNT_SID'],
    ENV['TWILIO_API_KEY'], ENV['TWILIO_API_SECRET'], 3600, identity

  # Grant access to Video
  grant = Twilio::Util::AccessToken::VideoGrant.new
  grant.configuration_profile_sid = ENV['TWILIO_CONFIGURATION_SID']
  token.add_grant grant

  # Generate the token and send to client
  json :identity => identity, :token => token.to_jwt
end
Server Token Generation

Generate Access Tokens

We've covered the way a Video Client (an Android, iOS, or JavaScript app) can use Twilio Video's APIs to manage multi-party audio/video sessions.

But there's one more thing that every Twilio Video application must have: A server that vouches for the identity of your users by providing Access Tokens. When a user in their browser or on their mobile device wants to start a video call via your Twilio account, we need you to vouch that the user is authorized to do so by signing an Access Token, and using that token to create a Video Client for that user.

Twilio treats anyone possessing a signed, valid, non-revoked token as a trusted actor. Access Tokens are based on the JWT standard. You have control over the expiry time for the token, which allows you to provide granular control over when and how your users access Twilio-enabled video capabilities.

Let's look at how to an application server to vend Access Tokens, in a variety of back-end languages.

Specifying the user's identity

To figure out who the user is (their identity), you might use your existing authentication system (using session cookies, an API token, or whatever mechanism you use to secure your content today). You might not care who a user is at all, and assign them a temporary identity as in our quickstart apps.

Either way, once you decide how you'll specify the user's identity you need to encapsulate this in the Access Token by setting the token's identity property (you can also pass the identity in the AccessToken constructor).

Specifying the user's capabilities

Next, to grant the user access to Video service, you must add a VideoGrant with a valid Configuration Profile SID to their Access Token.

The VideoGrant enables the client initialized with this token to use Video services in your Twilio account. The Configuration Profile SID controls the account-level settings you've configured for the Video experience. You can create and manage your Configuration Profiles in the Twilio Console here.

Who the user is and how you determine their capabilities will vary from app to app. Here's how we generate those tokens in our quickstart apps.

These code samples use the server-side Twilio Helper Libraries.

Token Generation
  • Java
  • JavaScript
  • Objective-C
  • Swift
// Import necessary dependencies
import com.google.gson.JsonObject;
import com.koushikdutta.async.future.FutureCallback;
import com.koushikdutta.ion.Ion;

...

    private void retrieveAccessTokenfromServer() {
        Ion.with(this)
                // Make JSON request to server
                .load("http://localhost:8080/token.php")
                .asJsonObject()
                .setCallback(new FutureCallback<JsonObject>() {
                    @Override
                    // Handle response from server
                    public void onCompleted(Exception e, JsonObject result) {
                        if (e == null) {
                            // The identity can be used to receive calls
                            String identity = result.get("identity").getAsString();
                            String accessToken = result.get("token").getAsString();
                            Log.i(TAG, "Token found: " + accessToken);

                            videoClient = new VideoClient(VideoActivity.this, accessToken);
                        } else {
                            Log.i(TAG, "error fetching token from server");
                            Toast.makeText(VideoActivity.this,
                                    R.string.error_retrieving_access_token, Toast.LENGTH_SHORT)
                                    .show();
                        }
                    }
                });
    }

...
// We use jQuery to make an Ajax request to the server to retrieve our 
// Access Token
$.getJSON('/token', function(data) {
    // The data sent back from the server should contain a long string - this is
    // the JWT token you need to initialize the SDK. Read more about JWT 
    // (JSON Web Token) at http://jwt.io
    console.log(data.token);

    // Since the quickstart app doesn't implement authentication, the server
    // sends back a randomly generated username for the current client, which is
    // how they will be identified when sending and receiving Conversation
    // invites. If your app has an existing authentication system, you can use
    // the e-mail address or username that uniquely identifies a user instead.
    console.log(data.identity);
});
// Token server endpoint URL
NSString *urlString = @"http://localhost:8000/token.php"

// Make JSON request to server
NSData *jsonResponse = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]];
NSError *jsonError;
NSDictionary *tokenResponse = [NSJSONSerialization JSONObjectWithData:jsonResponse
                                                              options:kNilOptions
                                                                error:&jsonError];

// Handle response from server
if (!jsonError) {
  self.identity = tokenResponse[@"identity"];
  NSLog(@"Token found: %@", tokenResponse[@"token"])
} else {
  NSLog(@"error fetching token from server");
}
// Token server endpoint URL
let urlString = "http://localhost:8000/token.php"

// Get JSON from server
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config, delegate: nil, delegateQueue: nil)
let url = NSURL(string: urlString)
let request  = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "GET"

// Make HTTP request
session.dataTaskWithRequest(request, completionHandler: { data, response, error in
  if (data != nil) {
    // Parse result JSON
    let json = JSON(data: data!)
    let token = json["token"].stringValue
  }
}).resume()
Token Generation

Once your client receives an Access Token from your server, you can initialize the Video SDK by creating a Video Client.

In the example code here, the client requests an Access Token from the server via a simple HTTP request.

Wrapping up

With that, we've given you a whirlwind tour of the Twilio's Programmable Video APIs. To dive deeper, dig int our API documentation here:

Stuck on something? Can't find what you're looking for? Don't hesitate to reach out to us at help@twilio.com and we'll happily give you a hand.

1 / 1
Loading Code Samples...
VideoClient videoClient = new VideoClient(context, accessToken);
// If you are requiring twilio-video from CommonJS,
//
//     const Video = require('twilio-video');
//
//  If you are including twilio-video.js from a <script> tag,
//
//     const Video = Twilio.Video;
//

const client = new Video.Client(accessToken);
TVIVideoClient *videoClient = [TVIVideoClient clientWithToken:accessToken];
var videoClient = TVIVideoClient(token: accessToken)
// Create a local media object
LocalMedia localMedia = LocalMedia.create(context);

// Add an audio track
boolean enable = true;
LocalAudioTrack localAudioTrack = localMedia.addAudioTrack(enable);

// A video track requires an implementation of VideoCapturer
CameraCapturer cameraCapturer = new CameraCapturer(context,
        CameraCapturer.CameraSource.FRONT_CAMERA);

// Add a video track
LocalVideoTrack localVideoTrack = localMedia.addVideoTrack(enable, cameraCapturer);

// Rendering a local video track requires an implementation of VideoRenderer
// Let's assume we have added a VideoView in our view hierarchy
VideoView videoView = (VideoView) findViewById(R.id.video_view);

// Render a local video track to preview your camera
localVideoTrack.addRenderer(videoView);

// Remove audio track
localMedia.removeAudioTrack(localAudioTrack);

// Remove video track
localMedia.removeVideoTrack(localVideoTrack);

// You must call release to ensure you free native resources
localMedia.release();
// If you are requiring twilio-video from CommonJS,
//
//     const Video = require('twilio-video');
//
//  If you are including twilio-video.js from a <script> tag,
//
//     const Video = Twilio.Video;
//

const localMedia = new Video.LocalMedia();

// You can call getUserMedia and add the resulting MediaStream to localMedia.
Video.getUserMedia().then(mediaStream => {
  localMedia.addStream(mediaStream);
});

// Or you can add the microphone and camera independently.
localMedia.addMicrophone().then(() => {
  return localMedia.addCamera();
});

// Remove the microphone.
localMedia.removeMicrophone();

// Remove the camera.
localMedia.removeCamera();

// Remove any tracks on the localMedia.
localMedia.tracks.forEach(track => {
  localMedia.removeTrack(track);
});

// Stop localMedia and all Tracks on it.
localMedia.stop();
//Create a local media object
TVILocalMedia *localMedia = [[TVILocalMedia alloc] init];

// Add an audio track
BOOL enable = YES;
TVILocalAudioTrack *localAudioTrack = [localMedia addAudioTrack:enable];

// Create camera object
TVICameraCapturer *camera = = [[TVICameraCapturer alloc] init];

// Add a video track
TVILocalVideoTrack *localVideoTrack = [localMedia addVideoTrack:enable capturer:camera];

// Connect and share your local media
TVIRoom *room = [videoClient connectWithOptions:connectOptions delegate:self];

// Remove audio track
[localMedia removeAudioTrack:localAudioTrack];

// Remove video track
[localMedia removeVideoTrack:localVideoTrack];
// Create a local media object
var localMedia = TVILocalMedia()

// Add an audio track
var enable = true;
var localAudioTrack = localMedia.addAudioTrack(enable)

// Create camera object
var camera = TVICameraCapturer()

// Add a video track
var localVideoTrack = localMedia.addVideoTrack(enable, capturer: camera)

// Remove audio track
localMedia.removeAudioTrack(localAudioTrack?)

// Remove video track
localMedia.removeVideoTrack(localVideoTrack?)
// Specify the room you would like to join
String roomName = "my-room";
ConnectOptions connectOptions = new ConnectOptions.Builder()
    .roomName(roomName)
    .localMedia(localMedia)
    .build();

// Create a room listener
Room.Listener roomListener = new Room.Listener() {
    @Override
    public void onConnected(Room room) {
        // Notifies you that you are now connected to the Room
    }

    @Override
    public void onConnectFailure(Room room, TwilioException e) {
        // Notifies you that a failure occurred when attempting to the connect to the room
    }

    @Override
    public void onDisconnected(Room room, TwilioException e) {
        // Notifies you that you were disconnected from the Room
    }

    @Override
    public void onParticipantConnected(Room room, Participant participant) {
        // A participant joined the Room
    }

    @Override
    public void onParticipantDisconnected(Room room, Participant participant) {
        // A participant left the Room
    }
};

// Connect to the room
Room room = videoClient.connect(connectOptions, roomListener);
client.connect({
  to: 'my-room',
  localMedia: localMedia
}).then(room => {
  console.log('Connected to the Room "%s"', room.name);
}, error => {
  console.error('Failed to connect to the Room', error);
});
TVIConnectOptions *connectOptions = [TVIConnectOptions optionsWithBlock:^(TVIConnectOptionsBuilder * _Nonnull builder) {
    builder.name = @"my-room";
    builder.localMedia = self.localMedia;
}];

TVIRoom *room = [videoClient connectWithOptions:connectOptions delegate:self];

#pragma mark - TVIRoomDelegate

- (void)didConnectedToRoom:(nonnull TVIRoom *)room {
    // The Local Participant
    TVILocalParticipant *localParticipant = room.localParticipant;
    NSLog(@"Local Participant %@", localParticipant.identity);
    
    // Connected participants
    NSArray *participants = room.participants;
    NSLog(@"Number of connected participants %ld", [participants count]);
}

- (void)room:(nonnull TVIRoom *)room participantDidConnect:(nonnull TVIParticipant *)participant {
    NSLog(@"Participant %@ has joined Room %@", participant.identity, room.name);
}

- (void)room:(nonnull TVIRoom *)room participantDidDisconnect:(nonnull TVIParticipant *)participant {
    NSLog(@"Participant %@ has left Room %@", participant.identity, room.name);
}
let connectOptions = TVIConnectOptions { (builder) in
    builder.name = "my-room"
    builder.localMedia = self.localMedia
}
room = videoClient.connect(with: connectOptions, delegate: self)

// MARK: TVIRoomDelegate

func didConnect(to room: TVIRoom) {    
    // The Local Participant
    let localParticipant = room.localParticipant;
    print("Local identity \(localParticipant!.identity)")
    
    // Connected participants
    let participants = room.participants;
    print("Number of connected participants \(participants.count)")
}

func room(_ room: TVIRoom, participantDidConnect participant: TVIParticipant) {
    print ("Participant \(participant.identity) has joined Room \(room.name)")
}

func room(_ room: TVIRoom, participantDidDisconnect participant: TVIParticipant) {
    print ("Participant \(participant.identity) has left Room \(room.name)")
}
// Connect to room
Room room = videoClient.connect(connectOptions, new Room.Listener() {
    @Override
    public void onConnected(Room room) {}

    @Override
    public void onConnectFailure(Room room, TwilioException e) {}

    @Override
    public void onDisconnected(Room room, TwilioException e) {}

    @Override
    public void onParticipantConnected(Room room, Participant participant) {
        Log.i("Room.Listener", participant.getIdentity() + " has joined the room.");
    }

    @Override
    public void onParticipantDisconnected(Room room, Participant participant) {
        Log.i("Room.Listener", participant.getIdentity() + " has left the room.");
    }
);

// ... Assume we have received the connected callback

// After receiving the connected callback the LocalParticipant becomes available
LocalParticipant localParticipant = room.getLocalParticipant();
Log.i("LocalParticipant ", localParticipant.getIdentity());

// Get a participant from the room (let's assume we have a participant named Alice)
Participant participant = room.getParticipants().get("Alice");
Log.i("HandleParticipants", participant.getIdentity() + " is in the room.");
// Log your Client's LocalParticipant in the Room
const localParticipant = room.localParticipant;
console.log('Connected to the Room as LocalParticipant "%s"', localParticipant.identity);

// Log any Participants already connected to the Room
room.participants.forEach(participant => {
  console.log('Participant "%s" is connected to the Room', participant.identity);
});

// Log new Participants as they connect to the Room
room.once('participantConnected', participant => {
  console.log('Participant "%s" has connected to the Room', participant.identity);
});

// Log Participants as they disconnect from the Room
room.once('participantDisconnected', participant => {
  console.log('Participant "%s" has disconnected from Room', participant.identity);
});
TVIConnectOptions *connectOptions = [TVIConnectOptions optionsWithBlock:^(TVIConnectOptionsBuilder * _Nonnull builder) {
    builder.name = @"my-room";
    builder.localMedia = self.localMedia;
}];
TVIRoom *room = [videoClient connectWithOptions:connectOptions delegate:self];

#pragma mark - TVIRoomDelegate

- (void)didConnectedToRoom:(nonnull TVIRoom *)room {
    // The Local Participant
    TVILocalParticipant *localParticipant = room.localParticipant;
    NSLog(@"Local Participant %@", localParticipant.identity);
    
    // Connected participants
    NSArray *participants = room.participants;
    NSLog(@"Number of connected Participants %ld", [participants count]);
}

- (void)room:(nonnull TVIRoom *)room participantDidConnect:(nonnull TVIParticipant *)participant {
    NSLog(@"Participant %@ has joined Room %@", participant.identity, room.name);
}

- (void)room:(nonnull TVIRoom *)room participantDidDisconnect:(nonnull TVIParticipant *)participant {
    NSLog(@"Participant %@ has left Room %@", participant.identity, room.name);
}
let connectOptions = TVIConnectOptions { (builder) in
    builder.name = "my-room"
    builder.localMedia = self.localMedia
}
room = videoClient.connect(with: connectOptions, delegate: self)

// MARK: TVIRoomDelegate

func didConnect(to room: TVIRoom) {
    // The Local Participant
    let localParticipant = room.localParticipant;
    print("Local identity \(localParticipant.identity)")
    
    // Connected participants
    let participants = room.participants;
    print("Number of connected Participants \(participants.count)")
}

func room(_ room: TVIRoom, participantDidConnect participant: TVIParticipant) {
    print ("Participant \(participant.identity) has joined Room \(room.name)")
}

func room(_ room: TVIRoom, participantDidDisconnect participant: TVIParticipant) {
    print ("Participant \(participant.identity) has left Room \(room.name)")
}
// Used to observe media events of a participant
Media.Listener mediaListener = new Media.Listener() {
    @Override
    public void onAudioTrackAdded(Media media, AudioTrack audioTrack) {
        // Notifies you that an audio track has been added
    }

    @Override
    public void onAudioTrackRemoved(Media media, AudioTrack audioTrack) {
        // Notifies you that an audio track has been removed
    }

    @Override
    public void onVideoTrackAdded(Media media, VideoTrack videoTrack) {
        // Notifies you that an video track has been added
    }

    @Override
    public void onVideoTrackRemoved(Media media, VideoTrack videoTrack) {
        // Notifies you that an video track has been removed
    }

    @Override
    public void onAudioTrackEnabled(Media media, AudioTrack audioTrack) {
        // Notifies you that an audio track has been enabled
    }

    @Override
    public void onAudioTrackDisabled(Media media, AudioTrack audioTrack) {
        // Notifies you that an audio track has been disabled
    }

    @Override
    public void onVideoTrackEnabled(Media media, VideoTrack videoTrack) {
        // Notifies you that an video track has been enabled
    }

    @Override
    public void onVideoTrackDisabled(Media media, VideoTrack videoTrack) {
        // Notifies you that an video track has been disabled
    }
};

// Grab the participant's media and register our listener
Media media = participant.getMedia();
media.setListener(mediaListener);

// Like a LocalVideoTrack, a VideoTrack can be rendered with a VideoRenderer 
VideoView videoView = (VideoView) findViewById(R.id.video_view);

// Render the first video track
VideoTrack videoTrack = media.getVideoTracks().get(0);
videoTrack.addRenderer(videoView);

// To stop rendering simply remove the renderer from the video track
videoTrack.removeRenderer(videoView);
// Set the Participant Delegate to receive participant's events
participant.delegate = self;

// UIView where you want to render remote participant's video
@property (nonatomic, weak) IBOutlet UIView *remoteView;

#pragma mark - TVIParticipantDelegate

- (void)participant:(nonnull TVIParticipant *)participant addedVideoTrack:(nonnull TVIVideoTrack *)videoTrack {
    // Attach remoteView on video track to render video
    [videoTrack attach:self.remoteView];
}

- (void)participant:(nonnull TVIParticipant *)participant removedVideoTrack:(nonnull TVIVideoTrack *)videoTrack {
    // To stop rendering simply call detach
    [videoTrack detach:self.remoteView];
}
- (void)participant:(nonnull TVIParticipant *)participant addedAudioTrack:(nonnull TVIAudioTrack *)audioTrack {
    // A Participant added an Audio Track
}

- (void)participant:(nonnull TVIParticipant *)participant removedAudioTrack:(nonnull TVIAudioTrack *)audioTrack {
    // A Participant removed an Audio Track
}

- (void)participant:(nonnull TVIParticipant *)participant enabledTrack:(nonnull TVITrack *)track {
    // A Participant enabled a Track
}

- (void)participant:(nonnull TVIParticipant *)participant disabledTrack:(nonnull TVITrack *)track {
    // A Participante disabled a Track
}
// Set the Participant Delegate to receive participant's events
participant.delegate = self;

// UIView where you want to render remote participant's video
@IBOutlet weak var remoteView: UIView!

// MARK: TVIParticipantDelegate

func participant(_ participant: TVIParticipant, addedVideoTrack videoTrack: TVIVideoTrack) {
    // Attach remoteView on video track to render video
    videoTrack.attach(remoteView);
}

func participant(_ participant: TVIParticipant, removedVideoTrack videoTrack: TVIVideoTrack) {
    // To stop rendering simply call detach
    videoTrack.detach(remoteView);
}

func participant(_ participant: TVIParticipant, addedAudioTrack audioTrack: TVIAudioTrack) {
    // A participant added an Audio Track
}

func participant(_ participant: TVIParticipant, removedAudioTrack audioTrack: TVIAudioTrack) {
    // A participant removed an Audio Track
}

func participant(_ participant: TVIParticipant, enabledTrack track: TVITrack) {
    // A participant enabled a Track
}

func participant(_ participant: TVIParticipant, disabledTrack track: TVITrack) {
    // A participant disabled a Track
}
participant.on('trackAdded', track => {
  if (track.kind === 'audio') {
    console.log('Added an AudioTrack %s', track.id);
  } else {
    console.log('Added a VideoTrack %s', track.id);
  }
});

participant.on('trackRemoved', track => {
  if (track.kind === 'audio') {
    console.log('Removed an AudioTrack %s', track.id);
  } else {
    console.log('Removed a VideoTrack %s', track.id);
  }
});

participant.on('trackEnabled', track => {
  if (track.kind === 'audio') {
    console.log('Enabled AudioTrack %s', track.id);
  } else {
    console.log('Enabled VideoTrack %s', track.id);
  }
});

participant.on('trackDisabled', track => {
  if (track.kind === 'audio') {
    console.log('Disabled AudioTrack %s', track.id);
  } else {
    console.log('Disabled VideoTrack %s', track.id);
  }
});

// You can attach a Participant's Media directly to a DOM element,
participant.media.attach(document.getElementById('#my-view'));

// You can pass the query selector directly,
participant.media.attach('#media-view');

// Or you can create a default element.
const element = participant.media.attach();
document.body.appendChild(element);

// In all three of these scenarios, as Tracks are added and removed, the
// attached element will be updated with the appropriate <audio> and <video>
// tags. If you would like to manage Track attachment yourself, you can always
// attach them manually. For example,
participant.media.tracks.forEach(track => {
  track.attach('#track-view');
});
SDK Version:
  • 4.x
  • 5.x
SDK Version:
  • 6.x
  • 7.x
SDK Version:
  • 2.x
  • 3.x
SDK Version:
  • 4.x
  • 5.x
SDK Version:
  • 5.x
  • 6.x
SDK Version:
  • 4.x
  • 5.x
import static spark.Spark.get;
import static spark.Spark.staticFileLocation;

import java.util.HashMap;

import com.github.javafaker.Faker;
import com.google.gson.Gson;
import com.twilio.sdk.auth.AccessToken;
import com.twilio.sdk.auth.ConversationsGrant;

public class Webapp {

  public static void main(String[] args) {
    // Serve static files from src/main/resources/public
    staticFileLocation("/public");

    // Create a Faker instance to generate a random username for the connecting user
    Faker faker = new Faker();

    // Create an access token using our Twilio credentials
    get("/token", "application/json", (request, response) -> {
      // Generate a random username for the connecting client
      String identity = faker.firstName() + faker.lastName() + faker.zipCode();

      // Create Video grant
      VideoGrant grant = new VideoGrant();
      grant.configurationProfileSid = System.getenv("TWILIO_CONFIGURATION_SID");

      // Create access token
      AccessToken token = new AccessToken.Builder(
        System.getenv("TWILIO_ACCOUNT_SID"),
        System.getenv("TWILIO_API_KEY"),
        System.getenv("TWILIO_API_SECRET")
      ).identity(identity).grant(grant).build();

      // create JSON response payload
      HashMap<String, String> json = new HashMap<String, String>();
      json.put("identity", identity);
      json.put("token", token.toJWT());

      // Render JSON response
      Gson gson = new Gson();
      return gson.toJson(json);
    });
  }
}
import os
from flask import Flask, jsonify
from faker import Factory
from twilio.jwt.access_token import AccessToken, VideoGrant

app = Flask(__name__)
fake = Factory.create()


@app.route('/')
def index():
    return app.send_static_file('index.html')


@app.route('/token')
def token():
    # get credentials for environment variables
    account_sid = os.environ['TWILIO_ACCOUNT_SID']
    api_key = os.environ['TWILIO_API_KEY']
    api_secret = os.environ['TWILIO_API_SECRET']

    # Create an Access Token
    token = AccessToken(account_sid, api_key, api_secret)

    # Set the Identity of this token
    token.identity = fake.user_name()

    # Grant access to Video
    grant = VideoGrant()
    grant.configuration_profile_sid = os.environ['TWILIO_CONFIGURATION_SID']
    token.add_grant(grant)

    # Return token info as JSON
    return jsonify(identity=token.identity, token=token.to_jwt())

if __name__ == '__main__':
    app.run(debug=True)
using System.Configuration;
using System.Web.Mvc;
using Faker;
using Twilio.JWT;

namespace VideoQuickstart.Controllers
{
    public class TokenController : Controller
    {
        // GET: Token
        public ActionResult Index(string device)
        {
            // Load Twilio configuration from Web.config
            var accountSid = ConfigurationManager.AppSettings["TwilioAccountSid"];
            var apiKey = ConfigurationManager.AppSettings["TwilioApiKey"];
            var apiSecret = ConfigurationManager.AppSettings["TwilioApiSecret"];
            var videoConfigSid = ConfigurationManager.AppSettings["TwilioConfigurationSid"];

            // Create a random identity for the client
            var identity = Internet.UserName();

            // Create an Access Token generator
            var token = new AccessToken(accountSid, apiKey, apiSecret)
            {
                Identity = identity
            };

            // Grant access to Video
            var grant = new VideoGrant
            {
                ConfigurationProfileSid = videoConfigSid
            };
            token.AddGrant(grant);

            return Json(new
            {
                identity,
                token = token.ToJwt()
            }, JsonRequestBehavior.AllowGet);
        }
    }
}
<?php
// Get the PHP helper library from twilio.com/docs/php/install
require_once '/path/to/vendor/autoload.php'; // Loads the library
use Twilio\Jwt\AccessToken;
use Twilio\Jwt\Grants\ConversationsGrant;

// Required for all Twilio access tokens
$twilioAccountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$twilioApiKey = 'SKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$twilioApiSecret = 'your_api_secret';
$TwilioConfigurationSid = 'VSXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
// choose a random username for the connecting user
$identity = 'randomUsername';

// Create access token, which we will serialize and send to the client
$token = new AccessToken(
    $TWILIO_ACCOUNT_SID,
    $TWILIO_API_KEY,
    $TWILIO_API_SECRET,
    3600,
    $identity
);

// Grant access to Video
$grant = new VideoGrant();
$grant->setConfigurationProfileSid($TwilioConfigurationSid);
$token->addGrant($grant);

// return serialized token and the user's randomly generated ID
echo json_encode(
    array(
        'identity' => $identity,
        'token' => $token->toJWT(),
    )
);
import os
from flask import Flask, jsonify
from faker import Factory
from twilio.access_token import AccessToken, ConversationsGrant

app = Flask(__name__)
fake = Factory.create()


@app.route('/')
def index():
    return app.send_static_file('index.html')


@app.route('/token')
def token():
    # get credentials for environment variables
    account_sid = os.environ['TWILIO_ACCOUNT_SID']
    api_key = os.environ['TWILIO_API_KEY']
    api_secret = os.environ['TWILIO_API_SECRET']

    # Create an Access Token
    token = AccessToken(account_sid, api_key, api_secret)

    # Set the Identity of this token
    token.identity = fake.user_name()

    # Grant access to Video
    grant = VideoGrant()
    grant.configuration_profile_sid = os.environ['TWILIO_CONFIGURATION_SID']
    token.add_grant(grant)

    # Return token info as JSON
    return jsonify(identity=token.identity, token=token.to_jwt())

if __name__ == '__main__':
    app.run(debug=True)
require 'twilio-ruby'
require 'sinatra'
require 'sinatra/json'
require 'dotenv'
require 'faker'

# Load environment configuration
Dotenv.load

# Render home page
get '/' do
  File.read(File.join('public', 'index.html'))
end

# Generate a token for use in our Video application
get '/token' do
  # Create a random username for the client
  identity = Faker::Internet.user_name

  # Create an Access Token for Video usage
  token = Twilio::Util::AccessToken.new(
    ENV['TWILIO_ACCOUNT_SID'],
    ENV['TWILIO_API_KEY'],
    ENV['TWILIO_API_SECRET'],
    3600,
    identity
  )

  # Grant access to Video
  grant = Twilio::Util::AccessToken::VideoGrant.new
  grant.configuration_profile_sid = ENV['TWILIO_CONFIGURATION_SID']
  token.add_grant grant

  # Generate the token and send to client
  json identity: identity, token: token.to_jwt
end
require('dotenv').load();

const http = require('http');
const path = require('path');

const AccessToken = require('twilio').AccessToken;
const ConversationsGrant = AccessToken.ConversationsGrant;
const express = require('express');
const randomUsername = require('./randos');

// Create Express webapp
const app = express();
app.use(express.static(path.join(__dirname, 'public')));

app.get('/token', (request, response) => {
  const identity = randomUsername();

  // Create an access token which we will sign and return to the client,
  // containing the grant we just created
  const token = new AccessToken(
    process.env.TWILIO_ACCOUNT_SID,
    process.env.TWILIO_API_KEY,
    process.env.TWILIO_API_SECRET
  );

  // Assign the generated identity to the token.
  token.identity = identity;

  // Grant access to Video.
  const grant = new VideoGrant();
  grant.configurationProfileSid = process.env.TWILIO_CONFIGURATION_SID;
  token.addGrant(grant);

  // Serialize the token to a JWT string and include it in a JSON response
  response.send({
    identity: identity,
    token: token.toJwt(),
  });
});

// Create http server and run it
const server = http.createServer(app);
const port = process.env.PORT;

server.listen(port = 3000, function() {
  console.log('Express server running on *:' + port);
});
import static spark.Spark.get;
import static spark.Spark.staticFileLocation;

import java.util.HashMap;

import com.github.javafaker.Faker;
import com.google.gson.Gson;
import com.twilio.jwt.accesstoken.AccessToken;
import com.twilio.jwt.accesstoken.ConversationsGrant;


public class Webapp {
  public static void main(String[] args) {
    // Serve static files from src/main/resources/public
    staticFileLocation("/public");

    String ACCOUNT_SID = System.getenv("TWILIO_ACCOUNT_SID");
    String API_KEY = System.getenv("TWILIO_API_KEY");
    String API_SECRET = System.getenv("TWILIO_API_SECRET");

    String TWILIO_CONFIGURATION_SID = System.getenv("TWILIO_CONFIGURATION_SID");

    // Create a Faker instance to generate a random username for the connecting user
    Faker faker = new Faker();

    // Create an access token using our Twilio credentials
    get("/token", "application/json", (request, response) -> {
      // Generate a random username for the connecting client
      String identity =
          faker.name().firstName() + faker.name().lastName() + faker.address().zipCode();

      // Create Video grant
      VideoGrant grant =
          new VideoGrant().setConfigurationProfileSid(TWILIO_CONFIGURATION_SID);

      // Create access token
      AccessToken token = new AccessToken.Builder(ACCOUNT_SID, API_KEY, API_SECRET)
          .identity(identity)
          .grant(grant)
          .build();

      // create JSON response payload
      HashMap<String, String> json = new HashMap<String, String>();
      json.put("identity", identity);
      json.put("token", token.toJwt());

      // Render JSON response
      Gson gson = new Gson();
      return gson.toJson(json);
    });
  }
}
require('dotenv').load();
var http = require('http');
var path = require('path');
var AccessToken = require('twilio').AccessToken;
var ConversationsGrant = AccessToken.ConversationsGrant;
var express = require('express');
var randomUsername = require('./randos');

// Create Express webapp
var app = express();
app.use(express.static(path.join(__dirname, 'public')));

app.get('/token', function(request, response) {
    var identity = randomUsername();
    
    // Create an access token which we will sign and return to the client,
    // containing the grant we just created
    var token = new AccessToken(
        process.env.TWILIO_ACCOUNT_SID,
        process.env.TWILIO_API_KEY,
        process.env.TWILIO_API_SECRET
    );

    //assign the generated identity to the token
    token.identity = identity;
        
    //grant access to Video
    var grant = new VideoGrant();
    grant.configurationProfileSid = process.env.TWILIO_CONFIGURATION_SID;
    token.addGrant(grant);

    // Serialize the token to a JWT string and include it in a JSON response
    response.send({
        identity: identity,
        token: token.toJwt()
    });
});

// Create http server and run it
var server = http.createServer(app);
var port = process.env.PORT || 3000;
server.listen(port, function() {
    console.log('Express server running on *:' + port);
});
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Twilio;
using Twilio.Auth;
using JWT;
using Faker;

namespace VideoQuickstart.Controllers
{
    public class TokenController : Controller
    {
        // GET: /token
        public ActionResult Index(string Device)
        {
            // Load Twilio configuration from Web.config
            var accountSid = ConfigurationManager.AppSettings["TwilioAccountSid"];
            var apiKey = ConfigurationManager.AppSettings["TwilioApiKey"];
            var apiSecret = ConfigurationManager.AppSettings["TwilioApiSecret"];
            var videoConfigSid = ConfigurationManager.AppSettings["TwilioConfigurationSid"];

            // Create a random identity for the client
            var identity = Internet.UserName();

            // Create an Access Token generator
            var token = new AccessToken(accountSid, apiKey, apiSecret);
            token.Identity = identity;

            // Grant access to Video
            var grant = new VideoGrant();
            grant.ConfigurationProfileSid = videoConfigSid;
            token.AddGrant(grant);

            return Json(new
            {
                identity = identity,
                token = token.ToJWT()
            }, JsonRequestBehavior.AllowGet);
        }
    }
}
<?php
require_once('./twilio-php/Services/Twilio.php');
require_once('./randos.php');
require_once('./config.php');

// choose a random username for the connecting user
$identity = randomUsername();

// Create access token, which we will serialize and send to the client
$token = new Services_Twilio_AccessToken(
    $TWILIO_ACCOUNT_SID,
    $TWILIO_API_KEY,
    $TWILIO_API_SECRET,
    3600,
    $identity
);

// Grant access to Video
$grant = new Services_Twilio_Auth_VideoGrant();
$grant->setConfigurationProfileSid($TWILIO_CONFIGURATION_SID);
$token->addGrant($grant);

// return serialized token and the user's randomly generated ID
echo json_encode(array(
    'identity' => $identity,
    'token' => $token->toJWT(),
));
require 'twilio-ruby'
require 'sinatra'
require 'sinatra/json'
require 'dotenv'
require 'faker'

# Load environment configuration
Dotenv.load

# Render home page
get '/' do
  File.read(File.join('public', 'index.html'))
end

# Generate a token for use in our Video application
get '/token' do
  # Create a random username for the client
  identity = Faker::Internet.user_name

  # Create an Access Token for Video usage
  token = Twilio::Util::AccessToken.new ENV['TWILIO_ACCOUNT_SID'],
    ENV['TWILIO_API_KEY'], ENV['TWILIO_API_SECRET'], 3600, identity

  # Grant access to Video
  grant = Twilio::Util::AccessToken::VideoGrant.new
  grant.configuration_profile_sid = ENV['TWILIO_CONFIGURATION_SID']
  token.add_grant grant

  # Generate the token and send to client
  json :identity => identity, :token => token.to_jwt
end
// Import necessary dependencies
import com.google.gson.JsonObject;
import com.koushikdutta.async.future.FutureCallback;
import com.koushikdutta.ion.Ion;

...

    private void retrieveAccessTokenfromServer() {
        Ion.with(this)
                // Make JSON request to server
                .load("http://localhost:8080/token.php")
                .asJsonObject()
                .setCallback(new FutureCallback<JsonObject>() {
                    @Override
                    // Handle response from server
                    public void onCompleted(Exception e, JsonObject result) {
                        if (e == null) {
                            // The identity can be used to receive calls
                            String identity = result.get("identity").getAsString();
                            String accessToken = result.get("token").getAsString();
                            Log.i(TAG, "Token found: " + accessToken);

                            videoClient = new VideoClient(VideoActivity.this, accessToken);
                        } else {
                            Log.i(TAG, "error fetching token from server");
                            Toast.makeText(VideoActivity.this,
                                    R.string.error_retrieving_access_token, Toast.LENGTH_SHORT)
                                    .show();
                        }
                    }
                });
    }

...
// We use jQuery to make an Ajax request to the server to retrieve our 
// Access Token
$.getJSON('/token', function(data) {
    // The data sent back from the server should contain a long string - this is
    // the JWT token you need to initialize the SDK. Read more about JWT 
    // (JSON Web Token) at http://jwt.io
    console.log(data.token);

    // Since the quickstart app doesn't implement authentication, the server
    // sends back a randomly generated username for the current client, which is
    // how they will be identified when sending and receiving Conversation
    // invites. If your app has an existing authentication system, you can use
    // the e-mail address or username that uniquely identifies a user instead.
    console.log(data.identity);
});
// Token server endpoint URL
NSString *urlString = @"http://localhost:8000/token.php"

// Make JSON request to server
NSData *jsonResponse = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]];
NSError *jsonError;
NSDictionary *tokenResponse = [NSJSONSerialization JSONObjectWithData:jsonResponse
                                                              options:kNilOptions
                                                                error:&jsonError];

// Handle response from server
if (!jsonError) {
  self.identity = tokenResponse[@"identity"];
  NSLog(@"Token found: %@", tokenResponse[@"token"])
} else {
  NSLog(@"error fetching token from server");
}
// Token server endpoint URL
let urlString = "http://localhost:8000/token.php"

// Get JSON from server
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config, delegate: nil, delegateQueue: nil)
let url = NSURL(string: urlString)
let request  = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "GET"

// Make HTTP request
session.dataTaskWithRequest(request, completionHandler: { data, response, error in
  if (data != nil) {
    // Parse result JSON
    let json = JSON(data: data!)
    let token = json["token"].stringValue
  }
}).resume()