Introduction

Vidyo.io™ is a platform as a service (PaaS) that enables developers to provide high-quality, real-time video communication capabilities. The service includes the VidyoClient SDK, which provides the APIs for integrating such communication capabilities into a variety of applications and workflows.

Some of the features of Vidyo.io include:

  • Multi-party audio and video conferencing
  • Group chat
  • Application sharing

The VidyoClient SDK offers the same APIs on all supported platforms, providing a fast learning curve and enabling rapid development on all device types.

Connecting to the Vidyo.io cloud is done by passing a token from your application through the VidyoClient SDK to the Vidyio.io cloud. The token identifies both your application and the user.

To learn more about how to get the most out of Vidyo.io, we invite you to review the Key Concepts of our platform.


Supported Platforms

The VidyoClient SDK, along with the VidyoConnector reference app, run on the following platforms:

Web Browser Windows macOS iOS Android
Version See Quick Start Guide 7+ 10.11+ 9+ 4.4+
Language JavaScript C Objective-C Objective-C Java
IDE JavaScript editor Microsoft Visual Studio 2013 Apple Xcode Apple Xcode Google Android Studio
SDK Download Link Link Link Link Link
Quick Start Guide Link Link Link Link Link

Getting Started

To start enjoying Vidyo.io, your main objective is to write your client application and integrate it with your business flow.

Here’s the easiest way to understand Vidyo.io and get started with using it:

  1. Launch the demo app, and tinker with it.
  2. Pick your platform of choice and follow the Quick Start Guide in the Supported Platforms section above.

To dig deeper into Vidyo.io, we suggest you check out its Key Concepts.


Need Help?

We are here to make sure you get the best video experience your customers can ever wish for. Just email us at support@vidyo.io.


Key Concepts

Vidyo.io comprises a high-quality video cloud service coupled with a VidyoClient SDK. The VidyoClient SDK offers the same APIs on all supported platforms, offering a fast learning curve and enabling rapid development on all device types.

When developing your application, you integrate the VidyoClient SDK with your application on any of the platforms necessary. Connecting to the Vidyo.io cloud is done by passing a token from your application through the VidyoClient SDK to the Vidyio.io cloud, identifying both your application and the user.

The illustration above details the components you will be interacting with when using Vidyo.io:

  1. Vidyo.io Cloud Service - This is the backend service that the VidyoClient SDK and ultimately your own application interacts with. It enables support for multiparty conferences, smart routing of video, resource allocation and management, and many other functions.
  2. VideoClient SDK - This is the client-side SDK that your application calls when it needs to add video support. The VidyoClient SDK shares the same APIs across the multiple platforms.
  3. Your Application - This is the application that you are developing. It has a lot to do with your own service and a bit to do with video communications, which is where it interacts with the VidyoClient SDK. To make it simpler, we’ve created a reference application that you can use as a starting point for your own app.

The rest of this document will cover some important concepts that you need to understand in order to make the best use of the Vidyo.io platform.


The VidyoClient

There are two important concepts in Vidyo.io that you need to know about:

  1. Tokens
  2. Resources

To make things simple, tokens identify a device to the Vidyo.io service and resources are meeting points for your users. You need to generate these access tokens when you connect a new device via the VidyoClient SDK to the Vidyo.io cloud. And you create a resource simply by calling it by name - resources don’t need to be provisioned ahead of time and can be created ad hoc as you go along.

Check out more about tokens and resources.

Initializing

When using the client library, the first step is to initialize the VidyoConnector

/* JavaScript Example: */
/* Load the VidyoClient.js script and pass the onVidyoClientLoaded callback as an onload parameter */

<script src="https://static.vidyo.io/4.1.15.7/javascript/VidyoClient/VidyoClient.js?onload=onVidyoClientLoaded"></script>

/* When the library loads the callback will be invoked */
<script type="text/javascript">
  function onVidyoClientLoaded(status) {
    switch (status.state) {
      case "READY":    // The library is operating normally
        // After the VidyoClient/VidyoConnector is successfully initialized,
        // a global VC object will become available.
        //
        // Load the rest of the application here
        // ...
        break;
      case "RETRYING":     // The library operating is temporarily paused
        break;
      case "FAILED":       // The library operating has stopped
        break;
      case "FAILEDVERSION":// The version of the Javascript library does not match the plugin
        status.plugInVersion; // The Version of the plugin currently installed
        status.jsVersion;     // The Version of the Javascript library loaded
        break;
      case "NOTAVAILABLE": // The library is not available
        break;
    }
    status.downloadType;                // Available download types with possible values of "MOBILE" "PLUGIN" "APP"
    status.downloadPathApp;             // Path to the application installer for the app which could be invoked with a protocol handler
    status.downloadPathPlugIn;          // Path to the Plugin that can be installed
    status.downloadPathWebRTCExtension; // Path to the optional extension required for Screen Sharing in WebRTC

    return true; // Return true to reload the plugins if not available
  }
</script>
/* C Example: */
#include <Lmi/VidyoClient/VidyoConnector.h>

/* Initialize VidyoConnector */
VidyoConnectorInitialize();
/* Objective-C Example: */
#import <Lmi/VidyoClient/VidyoConnector_Objc.h>

/* Initialize VidyoConnector */
[VidyoClientConnector Initialize];
/* Java Example: */
import com.vidyo.VidyoClient.Connector.VidyoConnector;
import com.vidyo.VidyoClient.Connector.Connector;

/* Initialize VidyoConnector */
Connector.SetApplicationUIContext(this);
Connector.Initialize();

Connecting to Vidyo.io

VidyoConnector is a very simple API that only requires two steps:

  1. Construct and pass the window where the preview and participants should be rendered.
  2. Connect to the live conference. A developer can choose the userId that represents the user in their application (used in token generation) and the resourceId where they want all the live participants to connect.
/* JavaScript Example: */
/* Assume that the DOM has a div with id="renderer" where the preview and the live conference should be rendered */
/* After the VidyoClient is successfully initialized a global VC object will become available  */

VC.CreateVidyoConnector({
  viewId: "renderer",                            // Div ID where the composited video will be rendered, see VidyoConnector.html
  viewStyle: "VIDYO_CONNECTORVIEWSTYLE_Default", // Visual style of the composited renderer
  remoteParticipants: 16,                        // Maximum number of participants
  logFileFilter: "warning all@VidyoConnector info@VidyoClient",
  logFileName:"",
  userData:""
}).then(function(vidyoConnector) {
   vidyoConnector.Connect({
     host: "prod.vidyo.io",
     token: generatedToken,
     displayName: "John Smith",
     resourceId: "JohnSmithRoom",

     // Define handlers for connection events.
     onSuccess: function()            {/* Connected */},
     onFailure: function(reason)      {/* Failed */},
     onDisconnected: function(reason) {/* Disconnected */}
    }).then(function(status) {
        if (status) {
            console.log("ConnectCall Success");
        } else {
            console.error("ConnectCall Failed");
        }
    }).catch(function() {
        console.error("ConnectCall Failed");
    });
}).catch(function() {
  console.error("CreateVidyoConnector Failed");
});

/* C Example: */

/* Pass in the view, dimensions and the position within the view where the conference should be rendered */
void ConnectToResource(LmiViewId* viewId, LmiInt x, LmiInt y, LmiUint width, LmiUint height,
                       const char* host, const char* token, const char* displayName, const char *resourceId)
{
  VidyoConnector c;
  LmiUint remoteParticipants = 16; /* Maximum number of remote participants to show */

  VidyoConnectorConstruct(&c, viewId, VIDYO_CONNECTORVIEWSTYLE_Default, remoteParticipants,
      "warning all@VidyoConnector info@VidyoClient", NULL, NULL);
  VidyoConnectorShowViewAt(&c, viewId, x, y, width, height);
  VidyoConnectorConnect(&c, host, token, displayName, resourceId,
      OnSuccess, OnFailure, OnDisconnected);
}

void OnSuccess(VidyoConnector* c)                                             { /* Connected */    }
void OnFailure(VidyoConnector* c, VidyoConnectorFailReason reason)            { /* Failed */       }  
void OnDisconnected(VidyoConnector* c, VidyoConnectorDisconnectReason reason) { /* Disconnected */ }
/* Objective-C Example: */

/* Pass in the view, dimensions and the position within the view where the conference should be rendered */
-(void)ConnectToResource:(void*)viewId X:(int)x Y:(int)y Width:(unsigned int)width Height:(unsigned int)height
                       Host:(const char*)host Token:(const char*)token
                       DisplayName:(const char*)displayName ResourceId:(const char*)resourceId
{
  Connector *c;
  unsigned int remoteParticipants = 16; /* Maximum number of remote participants to show */

  c = [[Connector alloc] init:(void*)&videoView
                          ViewStyle:CONNECTORVIEWSTYLE_Default
                          RemoteParticipants:remoteParticipants
                          LogFileFilter:"info@VidyoClient info@VidyoConnector warning"
                          LogFileName:""
                          UserData:0];
  [c ShowViewAt:NULL X:x Y:y Width:width Height:height];
  [c Connect:host
     Token:token
     DisplayName:displayName
     ResourceId:resourceId
     Connect:self];
}

/* Implementation of the IConnect interface, which are callbacks */
/* that notify the status of the Connect call.                   */
-(void) OnSuccess                                        { /* Connected */ }
-(void) OnFailure:(ConnectorFailReason)reason            { /* Failed */ }
-(void) OnDisconnected:(ConnectorDisconnectReason)reason { /* Disconnected */}
/* Java Example: */

public class MainActivity extends Activity implements VidyoConnector.IConnect
{
    private VidyoConnector mVidyoConnector = null;
    private int remoteParticipants = 16;

    private void ConnectToResource(FrameLayout viewId, String host, String token, String displayName, String resourceId) {
        mVidyoConnector = new VidyoConnector(viewId, VidyoConnector.VidyoConnectorViewStyle.VIDYO_CONNECTORVIEWSTYLE_Default, remoteParticipants, "warning all@VidyoConnector info@VidyoClient", "", 0);
        mVidyoConnector.ShowViewAt(viewId, 0, 0, viewId.getWidth(), viewId.getHeight());
        mVidyoConnector.Connect(host, token, displayName, resourceId, this);
    }

    /*
     *  Connector Events
     */

    // Connected
    public void OnSuccess() {}

    // Failed
    public void OnFailure(VidyoConnector.VidyoConnectorFailReason reason) {}

    // Disconnected
    public void OnDisconnected(VidyoConnector.VidyoConnectorDisconnectReason reason) {}
}

Tokens

To connect to Vidyo.io, the VidyoClient SDK needs to pass a token. A token is a short-lived authentication credential that grants access to the Vidyo.io service on behalf of the developer to a specific user. When an endpoint requests access to the service, your application backend should generate a token and pass it on to the client application.

Important: Never generate a token in the client application itself - this exposes your DeveloperKey which can then be used by other developers.

How to Generate a Token

For each application, you must create a DeveloperKey and ApplicationID in the API Key section of the Vidyo.io site and securely store it in your application backend. Then, each time you need to grant access to the Vidyo.io service, you must generate a Token from the DeveloperKey and ApplicationID as described below and pass it to their endpoint application or the VidyoConnector application.

Tokens can be rather long (typically 200 characters or more), so plan accordingly.

DeveloperKey and ApplicationID are “static” in your application. You will also need to provide a user name and an expiration time whenever you need to generate a token for a user.

Developer Key

A DeveloperKey is a shared secret between the Vidyo.io service and the developer’s backend application. It is used to generate access tokens on the customer backend and should never be sent to the endpoint itself. Access to the DeveloperKey should be restricted since every token that is signed by it will be used for access and billing.

Application ID

The ApplicationID identifies your application when connecting to the Vidyo.io platform. You can automatically provision any user (for example, user1@ApplicationID) when generating a token.

User Name

A token is associated to a specific user in Vidyo.io. To that end, when a token is generated, a user name needs to be provided. The user name is an open-ended alphanumeric string of your choosing which will be provisioned on the fly.

Vidyo.io will refer to users in Participant and Chat related APIs as user@applicationId.

Expiration

Each token has a lifetime. Its lifetime is determined when the token is generated by specifying the number of seconds until it expires.

Expiration ensures that access to the system is secure and isn’t open to abuse.

Samples

Python sample generator: https://static.vidyo.io/4.1.15.7/utils/generateToken.py

python3 generateToken.py --key=rUlaMASgt1Byi4Kp3sKYDeQzo --appID=ApplicationID --userName=user1 --expiresInSecs=10000

Java sample generator: https://static.vidyo.io/4.1.15.7/utils/generateToken.jar

java -jar generateToken.jar --key=rUlaMASgt1Byi4Kp3sKYDeQzo --appID=ApplicationID --userName=user1 --expiresInSecs=10000

Node.js sample generator: https://static.vidyo.io/4.1.15.7/utils/generateToken.js

node generateToken.js --key=rUlaMASgt1Byi4Kp3sKYDeQzo --appID=ApplicationID --userName=user1 --expiresInSecs=10000

C# sample generator: https://github.com/Vidyo/generateToken-c-sharp

GenerateToken.exe --key=rUlaMASgt1Byi4Kp3sKYDeQzo --appID=ApplicationID --userName=user1 --expiresInSecs=10000

Resources

Resources are strings of text denoting meeting points in your application. They are in an ad-hoc fashion simply by directing a user to a resource. If the resource doesn’t exist, then it is created. If the resource already exists, the user will join the other participants who are already “connected” to the resource.

Naming Resources

The following examples show how you can use the resourceId. Think about the requirements of your application, and then decide how to name the resources needed to connect your video sessions.

  • You can think of resources as meeting rooms. You can connect participants to a meeting room with a resourceId of “Blue” or “Red”, for example.
  • You can decide that resources are private meeting rooms of users, and name your resourceIds accordingly, such as “John room” or "john@example.com".
  • You can create random rooms by designating random resourceIds, such as “3e24d54ff8”.
  • You can even generate 1:1 calls with them, such as “Alice-Bob” if Alice calls Bob.

A resource operates in Vidyo.io as a collection of users joining in a video session together. These users are referred to as participants. You can get notified on participant updates or send and receive messages with participants connected to the same resourceId.

Participants

VidyoParticipant represents all other users connected to the same resourceId (that is, connected to the same video conference/session). Once you are connected, RegisterParticipantEventListener can be triggered to receive notifications upon participant updates.

/* JavaScript Example: */

vidyoConnector.RegisterParticipantEventListener(
{
  onJoined: function(participant) { /* Participant Joined */ },
  onLeft: function(participant)   { /* Participant Left */ },
  onDynamicChanged: function(participants, cameras) { /* Ordered array of participants according to rank */ },
  onLoudestChanged: function(participant, audioOnly) { /* Current loudest speaker */ }
}).then(function() {
  console.log("RegisterParticipantEventListener Success");
}).catch(function() {
  console.err("RegisterParticipantEventListener Failed");
});
/* C Example: */

/* Register for Participant callbacks */
VidyoConnectorRegisterParticipantEventListener(&c, OnParticipantJoined,
   OnParticipantLeft, OnDynamicParticipantChanged, OnLoudestParticipantChanged);

void OnParticipantJoined(VidyoConnector* c, VidyoParticipant* participant)
{ /* Participant Joined */ }

void OnParticipantLeft(VidyoConnector* c, VidyoParticipant* participant)
{ /* Participant Left */ }

void OnDynamicParticipantChanged(VidyoConnector* c, LmiVector(VidyoParticipant)* participants, LmiVector(VidyoRemoteCamera)* remoteCameras)
{ /* Ordered array of participants according to rank */ }

void OnLoudestParticipantChanged(VidyoConnector* c, const VidyoParticipant* participant, LmiBool audioOnly)
{ /* Current loudest speaker */ }
/* Objective-C Example: */

/* Register for Participant callbacks */
[c RegisterParticipantEventListener:self];

/* Implementation of the IRegisterParticipantEventListener interface */

-(void) OnParticipantJoined:(Participant*)participant
{ /* Participant Joined */ }

-(void) OnParticipantLeft:(Participant*)participant
{ /* Participant Left */ }

-(void) OnDynamicParticipantChanged:(NSMutableArray*)participants Cameras:(NSMutableArray*)cameras
{ /* Ordered array of participants according to rank */ }

-(void) OnLoudestParticipantChanged:(Participant*)participant AudioOnly:(BOOL)audioOnly
{ /* Current loudest speaker */ }
/* Java Example: */

public class MainActivity extends Activity implements VidyoConnector.IRegisterParticipantEventListener
{
    // Participant Joined
    public void OnParticipantJoined(VidyoParticipant participant) {}

    // Participant Left
    public void void OnParticipantLeft(VidyoParticipant participant) {}

    // Ordered array of participants according to rank
    public void OnDynamicParticipantChanged(ArrayList participants, ArrayList cameras) {}

    // Current loudest speaker
    public void OnLoudestParticipantChanged(VidyoParticipant participant, boolean audioOnly) {}
}

Group Chat

The Vidyo.io service supports message sending to all participants that are connected to the same resourceId.

/* JavaScript Example: */

/* Register to receive chat messages */
vidyoConnector.RegisterMessageEventListener({
  onChatMessageReceived: function(participant, chatMessage) { /* Message received from other participant */ }
}).then(function() {
  console.log("RegisterMessageEventListener Success");
}).catch(function() {
  console.err("RegisterMessageEventListener Failed");
});

/* Send chat message */
vidyoConnector.SendChatMessage("Hello");
/* C Example: */

/* Register to receive chat messages */
VidyoConnectorRegisterMessageEventListener(&c, OnChatMessageReceived);

/* Chat message received */
void OnChatMessageReceived(VidyoConnector* c, VidyoParticipant* participant, VidyoChatMessage* chatMessage)
{ /* Message received from other participants */ }

/* Send chat message */
VidyoConnectorSendChatMessage(&c, "Hello");
/* Objective-C Example: */

/* Register to receive chat messages */
[c RegisterMessageEventListener:self];

/* Implementation of the IRegisterMessageEventListener interface */
/* Chat message received */
-(void) OnChatMessageReceived:(Participant*)participant ChatMessage:(ChatMessage*)chatMessage;
{ /* Message received from other participants */ }

/* Send chat message */
[c SendChatMessage:"Hello"];
/* Java Example: */

public class MainActivity extends Activity implements VidyoConnector.IRegisterMessageEventListener
{    
    private void SendChatMessage(String message) {
        mVidyoConnector.SendChatMessage(message);
    }

    // Message received from other participants
    public void OnChatMessageReceived(VidyoParticipant participant, VidyoChatMessage chatMessage) {}
}

Device Management

The VidyoConnector will pick the default camera, microphone, and speaker. However, you can override this using one of two ways of manipulating devices: cycling and selecting.

Cycling

With cycling, the VidyoClient SDK creates a button that the user can press to cycle the camera/microphone/speaker until the right one is found. This is similar to how you switch between front and back cameras in your smartphone’s built-in camera app. This provides an easy-to-use UI where the user can attempt the various combinations until reaching the one desired.

/* JavaScript Example: */

vidyoConnector.CycleCamera();
vidyoConnector.CycleMicrophone();
vidyoConnector.CycleSpeaker();
/* C Example: */

VidyoConnectorCycleCamera();
VidyoConnectorCycleMicrophone();
VidyoConnectorCycleSpeaker();
/* Objective-C Example: */

[c CycleCamera];
[c CycleMicrophone];
[c CycleSpeaker];
/* Java Example: */

mVidyoConnector.CycleCamera();
mVidyoConnector.CycleMicrophone();
mVidyoConnector.CycleSpeaker();

Selecting

With selecting, a drop-down menu is created with the named camera, microphone, and speaker devices, and the user can choose the desired devices from the menu. To get notified which devices are available and select a device by name, you can use the RegisterLocalCameraEventListener / RegisterLocalMicrophoneEventListener / RegisterLocalSpeakerEventListener and SelectCamera / SelectMicrophone / SelectSpeaker APIs.

/* JavaScript Example: */

/* Camera event listener */
vidyoConnector.RegisterLocalCameraEventListener({
  onAdded: function(localCamera) { /* New camera is available */
    if (/* This is the camera that is desired */) {
        vidyoConnector.SelectLocalCamera(localCamera);
    }
  },
  onRemoved:  function(localCamera) { /* Existing camera became unavailable */ },
  onSelected: function(localCamera) { /* Camera was selected by user or automatically */ },
  onStateUpdated: function(localCamera, state) { /* Camera state was updated */ }
}).then(function() {
  console.log("RegisterLocalCameraEventListener Success");
}).catch(function() {
  console.error("RegisterLocalCameraEventListener Failed");
});

/* Microphone event listener */
vidyoConnector.RegisterLocalMicrophoneEventListener({
  onAdded: function(localMicrophone) { /* New microphone is available */
    if (/* This is the microphone that is desired */) {
      vidyoConnector.SelectLocalMicrophone(localMicrophone);
    }
  },
  onRemoved:  function(localMicrophone) { /* Existing microphone became unavailable */ },
  onSelected: function(localMicrophone) { /* Microphone was selected by user or automatically */ },
  onStateUpdated: function(localMicrophone, state) { /* Microphone state was updated */ }
}).then(function() {
  console.log("RegisterLocalMicrophoneEventListener Success");
}).catch(function() {
  console.error("RegisterLocalMicrophoneEventListener Failed");
});

/* Speaker event listener */
vidyoConnector.RegisterLocalSpeakerEventListener({
  onAdded: function(localSpeaker) { /* New speaker is available */
    if (/* This is the speaker that is desired */) {
      vidyoConnector.SelectLocalSpeaker(localSpeaker);
    }
  },
  onRemoved:  function(localSpeaker) { /* Existing speaker became unavailable */ },
  onSelected: function(localSpeaker) { /* Speaker was selected by user or automatically */ },
  onStateUpdated: function(localSpeaker, state) { /* Speaker state was updated */ }
}).then(function() {
  console.log("RegisterLocalSpeakerEventListener Success");
}).catch(function() {
  console.error("RegisterLocalSpeakerEventListener Failed");
});

/* C Example: */

/* Register for camera events */
VidyoConnectorRegisterLocalCameraEventListener(&c, OnLocalCameraAdded, OnLocalCameraRemoved,
    OnLocalCameraSelected, OnLocalCameraStateUpdated);

/* Camera event listeners */
void OnLocalCameraAdded(VidyoConnector* c, VidyoLocalCamera* localCamera)
{ /* New camera is available */
    if (/* This is the camera that is desired */) {
        VidyoConnectorSelectLocalCamera(c, localCamera);
    }
}

void OnLocalCameraRemoved(VidyoConnector* c, VidyoLocalCamera* localCamera)
{ /* Existing camera became unavailable */ }

void OnLocalCameraSelected(VidyoConnector* c, VidyoLocalCamera* localCamera)
{ /* Camera was selected by user or automatically */ }

void OnLocalCameraStateUpdated(VidyoConnector* c, VidyoLocalCamera* localCamera, VidyoDeviceState state)
{ /* Camera state was updated */ }

/******************************************************************************/

/* Register for microphone events */
VidyoConnectorRegisterLocalMicrophoneEventListener(&vc, OnLocalMicrophoneAdded,
    OnLocalMicrophoneRemoved, OnLocalMicrophoneSelected, OnLocalMicrophoneStateUpdated);

/* Microphone event listeners */
void OnLocalMicrophoneAdded(VidyoConnector* c, VidyoLocalMicrophone* localMicrophone)
{ /* New microphone is available */
    if (/* This is the microphone that is desired */) {
        VidyoConnectorSelectLocalMicrophone(c, localMicrophone);
    }
}

void OnLocalMicrophoneRemoved(VidyoConnector* c, VidyoLocalMicrophone* localMicrophone)
{ /* Existing microphone became unavailable */ }

void OnLocalMicrophoneSelected(VidyoConnector* c, VidyoLocalMicrophone* localMicrophone)
{ /* Microphone was selected by user or automatically */ }

void OnLocalMicrophoneStateUpdated(VidyoConnector* c, VidyoLocalMicrophone* localMicrophone, VidyoDeviceState state)
{ /* Microphone state was updated */ }

/******************************************************************************/

/* Register for speaker events */
VidyoConnectorRegisterLocalSpeakerEventListener(&vc, OnLocalSpeakerAdded,
    OnLocalSpeakerRemoved, OnLocalSpeakerSelected, OnLocalSpeakerStateUpdated);

/* Speaker event listeners */
void OnLocalSpeakerAdded(VidyoConnector* c, VidyoLocalSpeaker* localSpeaker)
{ /* New speaker is available */
    if (/* This is the speaker that is desired */) {
        VidyoConnectorSelectLocalSpeaker(c, localSpeaker);
    }
}

void OnLocalSpeakerRemoved(VidyoConnector* c, VidyoLocalSpeaker* localSpeaker)
{ /* Existing speaker became unavailable */ }

void OnLocalSpeakerSelected(VidyoConnector* c, VidyoLocalSpeaker* localSpeaker)
{ /* Speaker was selected by user or automatically */ }

void OnLocalSpeakerStateUpdated(VidyoConnector* c, VidyoLocalSpeaker* localSpeaker, VidyoDeviceState state)
{ /* Speaker state was updated */ }
/* Objective-C Example: */

/* Register for camera events */
[c RegisterLocalCameraEventListener:self];

/* Implementation of the IRegisterLocalCameraEventListener interface (camera event listeners) */

-(void) OnLocalCameraAdded:(LocalCamera*)localCamera {
  /* New camera is available */
  if (/* This is the camera that is desired */) {
      [c SelectLocalCamera:localCamera];
  }
}

-(void) OnLocalCameraRemoved:(LocalCamera*)localCamera
{ /* Existing camera became unavailable */ }

-(void) OnLocalCameraSelected:(LocalCamera*)localCamera
{ /* Camera was selected by user or automatically */ }

-(void) OnLocalCameraStateUpdated:(LocalCamera*)localCamera State:(DeviceState)state;
{ /* Camera state was updated */ }

/******************************************************************************/

/* Register for microphone events */
[c RegisterLocalMicrophoneEventListener:self];

/* Implementation of the IRegisterLocalMicrophoneEventListener interface (microphone event listeners) */

-(void) OnLocalMicrophoneAdded:(LocalMicrophone*)localMicrophone {
  /* New microphone is available */
  if (/* This is the microphone that is desired */) {
      [c SelectLocalMicrophone:localMicrophone];
  }
}

-(void) OnLocalMicrophoneRemoved:(LocalMicrophone*)localMicrophone
{ /* Existing microphone became unavailable */ }

-(void) OnLocalMicrophoneSelected:(LocalMicrophone*)localMicrophone
{ /* Microphone was selected by user or automatically */ }

-(void) OnLocalMicrophoneStateUpdated:(LocalMicrophone*)localMicrophone State:(DeviceState)state;
{ /* Microphone state was updated */ }

/******************************************************************************/

/* Register for speaker events */
[c RegisterLocalSpeakerEventListener:self];

/* Implementation of the IRegisterLocalSpeakerEventListener interface (speaker event listeners) */

-(void) OnLocalSpeakerAdded:(LocalSpeaker*)localSpeaker {
  /* New speaker is available */
  if (/* This is the speaker that is desired */) {
      [c SelectLocalSpeaker:localSpeaker];
  }
}

-(void) OnLocalSpeakerRemoved:(LocalSpeaker*)localSpeaker
{ /* Existing speaker became unavailable */ }

-(void) OnLocalSpeakerSelected:(LocalSpeaker*)localSpeaker
{ /* Speaker was selected by user or automatically */ }

-(void) OnLocalSpeakerStateUpdated:(LocalSpeaker*)localSpeaker State:(DeviceState)state;
{ /* Speaker state was updated */ }

/* Java Example: */

import com.vidyo.VidyoClient.Connector.VidyoConnector;
import com.vidyo.VidyoClient.Connector.Connector;

public class MainActivity extends Activity implements VidyoConnector.IRegisterLocalCameraEventListener, VidyoConnector.IRegisterLocalMicrophoneEventListener, VidyoConnector.IRegisterLocalSpeakerEventListener
{
    /* Camera event listener */
    public void OnLocalCameraAdded(VidyoLocalCamera localCamera)    { /* New camera is available */
        if (/* This is the camera that is desired */) {
            mVidyoConnector.SelectLocalCamera(localCamera);
        }
    }
    public void OnLocalCameraRemoved(VidyoLocalCamera localCamera)  { /* Existing camera became unavailable */          }
    public void OnLocalCameraSelected(VidyoLocalCamera localCamera) { /* Camera was selected by user or automatically */ }
    public void OnLocalCameraStateUpdated(VidyoLocalCamera localCamera, VidyoDeviceState state) { /* Camera state was updated */ }

    /* Microphone event listener */
    public void OnLocalMicrophoneAdded(VidyoLocalMicrophone localMicrophone)    { /* New microphone is available */
        if (/* This is the microphone that is desired */) {
            mVidyoConnector.SelectLocalMicrophone(localMicrophone);
        }
    }
    public void OnLocalMicrophoneRemoved(VidyoLocalMicrophone localMicrophone)  { /* Existing microphone became unavailable */          }
    public void OnLocalMicrophoneSelected(VidyoLocalMicrophone localMicrophone) { /* Microphone was selected by user or automatically */ }
    public void OnLocalMicrophoneStateUpdated(VidyoLocalMicrophone localMicrophone, VidyoDeviceState state) { /* Microphone state was updated */ }

    /* Speaker event listener */
    public void OnLocalSpeakerAdded(VidyoLocalSpeaker localSpeaker)    { /* New speaker is available */
        if (/* This is the speaker that is desired */) {
            mVidyoConnector.SelectLocalSpeaker(localSpeaker);
        }
    }
    public void OnLocalSpeakerRemoved(VidyoLocalSpeaker localSpeaker)  { /* Existing speaker became unavailable */          }
    public void OnLocalSpeakerSelected(VidyoLocalSpeaker localSpeaker) { /* Speaker was selected by user or automatically */ }
    public void OnLocalSpeakerStateUpdated(VidyoLocalSpeaker localSpeaker, VidyoDeviceState state) { /* Speaker state was updated */ }
}

Resetting to Default

To reset devices back to their defaults, you can use the SelectDefaultCamera / SelectDefaultMicrophone / SelectDefaultSpeaker APIs.

/* JavaScript Example: */

vidyoConnector.SelectDefaultCamera();
vidyoConnector.SelectDefaultMicrophone();
vidyoConnector.SelectDefaultSpeaker();
/* C Example: */

VidyoConnectorSelectDefaultCamera();
VidyoConnectorSelectDefaultMicrophone();
VidyoConnectorSelectDefaultSpeaker();
/* Objective-C Example: */

[c SelectDefaultCamera];
[c SelectDefaultMicrophone];
[c SelectDefaultSpeaker];
/* Java Example: */

mVidyoConnector.SelectDefaultCamera();
mVidyoConnector.SelectDefaultMicrophone();
mVidyoConnector.SelectDefaultSpeaker();

Screen Sharing

Windows and monitors can be shared in a session taking place on a resourceId. Passing null ("{}" in JavaScript) into SelectWindow / SelectMonitor will stop the sharing.

The RegisterLocalWindowShareEventListener should only be called when the application is ready to share and it should be unregistered after the share was selected.

In the case of WebRTC, an extension is required to enable window sharing. It can be downloaded from the link provided in status.downloadPathWebRTCExtension; inside the VidyoClient.js?onload= event. See Initializing section. The browser will pop up it’s own share selection dialog once RegisterLocalWindowShareEventListener is called and the result of the user selection will be the available in the onAdded event.

Screen sharing does not currently work in the mobile SDKs (iOS and Android).

/* JavaScript Example: */

/* WindowShare event listener */
vidyoConnector.RegisterLocalWindowShareEventListener({
  onAdded: function(localWindowShare) { /* New window is available for sharing */
    if (/* This is the window the user wants to share */) {
      vidyoConnector.SelectLocalWindowShare(localWindowShare);
    }
  },
  onRemoved:  function(localWindowShare) { /* Existing window is no longer available for sharing */ },
  onSelected: function(localWindowShare) {
    /* Window was selected */
    if (localWindowShare) {
        localWindowShare.GetPreviewFrameDataUriAsync({
            maxWidth: 300,
            maxHeight: 300,
            onComplete: function(response) {
                // Assign an image source in the UI with the preview frame
            }
        });
    } else {
        // Unassign the image source in the UI from the preview frame
    }
  }
  onStateUpdated: function(localWindowShare, state) { /* window share state has been updated */ }
}).then(function() {
  console.log("RegisterLocalWindowShareEventListener Success");
}).catch(function() {
  console.error("RegisterLocalWindowShareEventListener Failed");
});

/* Monitor event listener */
vidyoConnector.RegisterLocalMonitorEventListener({
  onAdded: function(localMonitor) { /* New monitor is available for sharing */
    if (/* This is the monitor that should be shared */) {
      vidyoConnector.SelectLocalMonitor(localMonitor)
    }
  },
  onRemoved:  function(localMonitor) { /* Existing monitor is no longer available for sharing */ },
  onSelected: function(localMonitor) {
    /* Monitor was selected */
    if (localMonitor) {
        localMonitor.GetPreviewFrameDataUriAsync({
            maxWidth: 300,
            maxHeight: 300,
            onComplete: function(response) {
                // Assign an image source in the UI with the preview frame
            }
        });
    } else {
        // Unassign the image source in the UI from the preview frame
    }
  }
  onStateUpdated: function(localMonitor, state) { /* Monitor state has been updated */ }
}).then(function() {
  console.log("RegisterLocalMonitorEventListener Success");
}).catch(function() {
  console.error("RegisterLocalMonitorEventListener Failed");
});
/* C Example: */

/* Register for LocalWindowShare callbacks */
VidyoConnectorRegisterLocalWindowShareEventListener(&c, OnLocalWindowShareAdded,
   OnLocalWindowShareRemoved, OnLocalWindowShareSelected, OnLocalWindowShareStateUpdated);

/* WindowShare event listener */
void OnLocalWindowShareAdded(VidyoConnector* c, VidyoLocalWindowShare* localWindowShare)
{ /* New window is available */
   if (/* This is the window that should be shared */) {
      VidyoConnectorSelectLocalWindowShare(c, localWindowShare);
   }
}

void OnLocalWindowShareRemoved(VidyoConnector* c, VidyoLocalWindowShare* localWindowShare)
{ /* Existing window became unavailable */ }

void OnLocalWindowShareSelected(VidyoConnector* c, VidyoLocalWindowShare* localWindowShare)
{ /* window was selected by user or automatically */ }

void OnLocalWindowShareStateUpdated(VidyoConnector* c, VidyoLocalWindowShare* localWindowShare, VidyoDeviceState state)
{ /* window share state has been updated */ }

/******************************************************************************/

/* Register for LocalMonitor callbacks */
VidyoConnectorRegisterLocalMonitorEventListener(&vc, OnLocalMonitorAdded,
   OnLocalMonitorRemoved, OnLocalMonitorSelected, OnLocalMonitorStateUpdated);

/* Monitor event listener */
void OnLocalMonitorAdded(VidyoConnector* c, VidyoLocalMonitor* localMonitor)
{ /* New monitor is available */
   if (/* This is the monitor that should be shared */) {
      VidyoConnectorSelectLocalMonitor(c, localMonitor);
   }
}

void OnLocalMonitorRemoved(VidyoConnector* c, VidyoLocalMonitor* localMonitor)
{ /* Existing monitor became unavailable */ }

void OnLocalMonitorSelected(VidyoConnector* c, VidyoLocalMonitor* localMonitor)
{ /* monitor was selected by user or automatically */ }

void OnLocalMonitorStateUpdated(VidyoConnector* c, VidyoLocalMonitor* localMonitor, VidyoDeviceState state)
{ /* monitor state has been updated */ }
/* Objective-C Example: */

/* Register for LocalWindowShare callbacks */
[c RegisterLocalWindowShareEventListener:self];

/* Implementation of the IRegisterLocalWindowShareEventListener interface */

-(void) OnLocalWindowShareAdded:(LocalWindowShare*)localWindowShare
{ /* New window is available */
   if (/* This is the window that should be shared */) {
      [c SelectLocalWindowShare:localWindowShare];
   }
}

-(void) OnLocalWindowShareRemoved:(LocalWindowShare*)localWindowShare
{ /* Existing window became unavailable */ }

-(void) OnLocalWindowShareSelected:(LocalWindowShare*)localWindowShare
{ /* window was selected by user or automatically */ }

-(void) OnLocalWindowShareStateUpdated:(LocalWindowShare*)localWindowShare State:(DeviceState)state
{ /* window share state has been updated */ }

/******************************************************************************/

/* Register for LocalMonitor callbacks */
[c RegisterLocalMonitorEventListener:self];

/* Implementation of the IRegisterLocalMonitorEventListener interface */

-(void) OnLocalMonitorAdded:(LocalMonitor*)localMonitor
{ /* New monitor is available */
   if (/* This is the monitor that should be shared */) {
      [c SelectLocalMonitor:localMonitor];
   }
}

-(void) OnLocalMonitorRemoved:(LocalMonitor*)localMonitor
{ /* Existing monitor became unavailable */ }

-(void) OnLocalMonitorSelected:(LocalMonitor*)localMonitor
{ /* monitor was selected by user or automatically */ }

-(void) OnLocalMonitorStateUpdated:(LocalMonitor*)localMonitor State:(DeviceState)state
{ /* monitor state has been updated */ }
/* Java Example: */

public class MainActivity extends Activity implements VidyoConnector.IRegisterLocalWindowShareEventListener,
      VidyoConnector.IRegisterLocalMonitorEventListener
{
  /* WindowShare Event Listener */
  public void OnLocalWindowShareAdded(VidyoLocalWindowShare localWindowShare) { /* New window is available for sharing */
    if (/* This is the window that should be shared */) {
      mVidyoConnector.SelectLocalWindowShare(localWindowShare)
    }
  }
  public void OnLocalWindowShareRemoved(VidyoLocalWindowShare localWindowShare)  { /* Existing window is no longer available for sharing */ }
  public void OnLocalWindowShareSelected(VidyoLocalWindowShare localWindowShare) { /* Window was selected */ }
  public void OnLocalWindowShareStateUpdated(VidyoLocalWindowShare localWindowShare, VidyoDeviceState state) {  /* window share state has been updated */ }

  /* Monitor Event Listener */
  public void OnLocalMonitorAdded(VidyoLocalMonitor localMonitor)    { /* New monitor is available for sharing*/
    if (/* This is the monitor that should be shared */) {
      mVidyoConnector.SelectLocalMonitor(localMonitor)
    }
  }
  public void OnLocalMonitorRemoved(VidyoLocalMonitor localMonitor)  { /* Existing monitor is no longer available for sharing */ }
  public void OnLocalMonitorSelected(VidyoLocalMonitor localMonitor) { /* Monitor was selected */ }
  public void OnLocalMonitorStateUpdated(VidyoLocalMonitor localMonitor, VidyoDeviceState state) {  /* monitor state has been updated */ }
}

Video Layout

While VidyoConnector provides a default layout, you can also customize it if you want. The default compositing renderer is used when you call ConnectorConstruct with the viewId of your choice. If you’d rather create your own layout, you can instead pass Null to ConnectorConstruct as the viewId and show/hide sources into particular views using the following APIs:

  • AssignViewToLocalCamera, AssignViewToRemoteCamera, AssignViewToRemoteWindowShare: assigns a view to a local camera, remote camera, or remote window share
  • ShowViewAt: display the view in the UI that is assigned in AssignViewTo*
    - It is not necessary to call ShowViewAt when using JavaScript API
  • HideView: hide a local camera, remote camera, or remote window share from a view

Other considerations when using a custom layout:

  • AssignViewTo*, ShowViewAt, and HideView should be called on the main/UI thread of application.
  • When replacing one camera or window share with another, it is not necessary to call HideView on the view being replaced. Only call AssignViewTo* followed by ShowViewAt.

Compositing and custom layouts are mutually exclusive.

/* JavaScript Example: */

/* custom local preview */
vidyoConnector.RegisterLocalCameraEventListener({
  onAdded: function(localCamera) {
      /* New camera is available. */
  },
  onRemoved: function(localCamera) {
      /* Existing camera became unavailable. */
      if ( /* the removed camera is the selected camera */ ) {
          vidyoConnector.HideView({ viewId: "Div where camera was rendered" });
      }
  },
  onSelected: function(localCamera) {
    /* Camera was selected by user or automatically */
    vidyoConnector.AssignViewToLocalCamera({
      viewId: "Div where camera should be rendered",
      localCamera: localCamera,
      displayCropped: true,
      allowZoom: false
    });
  },
  onStateUpdated: function(localCamera, state) { /* Camera state was updated */ }
}).then(function() {
  console.log("RegisterLocalCameraEventListener Success");
}).catch(function() {
  console.error("RegisterLocalCameraEventListener Failed");
});

/* Local camera change initiated by user. Note: this is an arbitrary function name. */
function handleCameraChange() {
  /* Hide view of previously selected camera. */
  vidyoConnector.HideView({
    viewId: "Div where camera is rendered"
  });
  /* Select new camera */
  vidyoConnector.SelectLocalCamera({
    localCamera: camera
  });
}

/******************************************************************************/

/* custom remote participant's source view */
vidyoConnector.RegisterRemoteCameraEventListener({
  onAdded: function(remoteCamera, participant) {
    /* New camera is available. */
    if (/* This camera is desired to be viewed */) {       
      vidyoConnector.AssignViewToRemoteCamera({
        viewId: "Div where camera should be rendered",
        remoteCamera: remoteCamera,
        displayCropped: true,
        allowZoom: false
      });
    }
  },
  onRemoved: function(remoteCamera, participant) {
    /* Existing camera became unavailable. */
    if (/* This camera was being viewed */) {
      vidyoConnector.HideView({
        viewId: "Div where camera is rendered"
      });
    }
  },
  onStateUpdated: function(remoteCamera, participant, state) { /* Camera state was updated */ }
}).then(function() {
  console.log("RegisterRemoteCameraEventListener Success");
}).catch(function() {
  console.error("RegisterRemoteCameraEventListener Failed");
});

/******************************************************************************/

/* custom remote participant's window share view */
vidyoConnector.RegisterRemoteWindowShareEventListener({
  onAdded: function(remoteWindowShare, participant) {
    /* New window is available for sharing. */
    if (/* This is the window that is desired to view */) {       
      vidyoConnector.AssignViewToRemoteWindowShare({
        viewId: "Div where window should be rendered",
        remoteWindowShare: remoteWindowShare,
        displayCropped: true,
        allowZoom: false
      });
    }
  },
  onRemoved: function(remoteWindowShare, participant) {
    /* Existing window is no longer available for sharing */
    if (/* This is the window that was being viewed */) {   
      vidyoConnector.HideView({
        viewId: "Div where remoteWindowShare is rendered"
      });
    }
  }
}).then(function() {
  console.log("RegisterRemoteWindowShareEventListener Success");
}).catch(function() {
  console.error("RegisterRemoteWindowShareEventListener Failed");
});

/* C Example: */

/* Custom local preview */

/* Register for local camera events */
VidyoConnectorRegisterLocalCameraEventListener(&c, OnLocalCameraAdded,
    OnLocalCameraRemoved, OnLocalCameraSelected, OnLocalCameraStateUpdated);

void OnLocalCameraAdded(VidyoConnector* c, VidyoLocalCamera* localCamera)
{       /* New camera is available. */ }

void OnLocalCameraRemoved(VidyoConnector* c, VidyoLocalCamera* localCamera)
{
        /* Existing camera became unavailable. */
        if ( /* the removed camera is the selected camera */ ) {
                VidyoConnectorHideView(c, viewId);
        }
}

void OnLocalCameraSelected(VidyoConnector* c, VidyoLocalCamera* localCamera)
{       /* Camera was selected by user or automatically */
        VidyoConnectorAssignViewToLocalCamera(c, viewId, localCamera, displayCropped, allowZoom);
        VidyoConnectorShowViewAt(c, viewId, x, y, width, height);
}

void OnLocalCameraStateUpdated(VidyoConnector* c, VidyoLocalCamera* localCamera, VidyoDeviceState state)
{       /* Camera state is updated */ }

/* Local camera change initiated by user. Note: this is an arbitrary function name. */
void HandleCameraChange()
{
        /* Hide view of previously selected camera. */
        VidyoConnectorHideView(c, viewId);
        /* Select new local camera */
        VidyoConnectorSelectLocalCamera(c, camera);
}

/******************************************************************************/

/* Custom remote participant's source view */

/* Register for Remote camera events */
VidyoConnectorRegisterRemoteCameraEventListener(&c, OnRemoteCameraAdded, OnRemoteCameraRemoved);

void OnRemoteCameraAdded(VidyoConnector* c, VidyoRemoteCamera* remoteCamera, const VidyoParticipant* participant)
{   /* New camera is available. */

    if (/* This is the camera that is desired */) {
        VidyoConnectorAssignViewToRemoteCamera(c, viewId, remoteCamera, displayCropped, allowZoom);
        VidyoConnectorShowViewAt(c, viewId, x, y, width, height);
    }
}

void OnRemoteCameraRemoved(VidyoConnector* c, VidyoRemoteCamera* remoteCamera, const VidyoParticipant* participant)
{   /* Existing camera became unavailable. */
    if (/* This camera was being viewed */) {
        VidyoConnectorHideView(c, viewId);
    }
}

/******************************************************************************/

/* Custom participant's window share view */

/* Register for RemoteWindowShare callbacks */
VidyoConnectorRegisterRemoteWindowShareEventListener(&c, OnRemoteWindowShareAdded, OnRemoteWindowShareRemoved);

void OnRemoteWindowShareAdded(VidyoConnector* c, VidyoRemoteWindowShare* remoteWindowShare, const VidyoParticipant* participant)
{   /* New remoteWindowShare is available for sharing */

    if (/* This is the remoteWindowShare that is desired to view */) {
        AssignViewToRemoteWindowShare(c, viewId, remoteWindowShare, displayCropped, allowZoom);
        VidyoConnectorShowViewAt(c, viewId, x, y, width, height);
    }
}

void OnRemoteWindowShareRemoved(VidyoConnector* c, VidyoRemoteWindowShare* remoteWindowShare, const VidyoParticipant* participant)
{   /* Existing remoteWindowShare became unavailable */
    if (/* This is the window that was being viewed */) {
        VidyoConnectorHideView(c, viewId);
    }
}
/* Objective-C Example: */

/* Custom local preview */

/* Register for local camera events */
[c RegisterLocalCameraEventListener:self];

/* Implementation of the IRegisterLocalCameraEventListener interface (local camera event listeners) */
-(void) OnLocalCameraAdded:(LocalCamera*)localCamera
{ /* New camera is available */ }

-(void) OnLocalCameraRemoved:(LocalCamera*)localCamera
{ /* Existing camera became unavailable */
    if ( /* the removed camera is the selected camera */ ) {
        [c HideView:viewId];
    }
}

-(void) OnLocalCameraSelected:(LocalCamera*)localCamera
{ /* Camera was selected by user or automatically */
  [c AssignViewToLocalCamera:viewId Camera:localCamera DisplayCropped:displayCropped AllowZoom:allowZoom];
  [c ShowViewAt:viewId X:x Y:y Width:width Height:height];
}

-(void) OnLocalCameraStateUpdated:(LocalCamera*)localCamera State:(DeviceState)state
{ /* Camera state was updated */ }

/* Local camera change initiated by user. Note: this is an arbitrary function name. */
-(void) HandleCameraChange
{
  /* Hide view of previously selected camera. */
  [c HideView:viewId];
  /* Select new local camera */
  [c SelectLocalCamera:camera];
}

/******************************************************************************/

/* Custom participant's source view */

/* Register for Remote camera events */
[c RegisterRemoteCameraEventListener:self];

/* Implementation of the IRegisterRemoteCameraEventListener interface (remote camera event listeners) */

-(void) OnRemoteCameraAdded:(RemoteCamera*)remoteCamera Participant:(Participant*)participant {
  /* New camera is available */
  if (/* This camera is desired to be viewed */) {
      [c AssignViewToRemoteCamera:viewId Camera:remoteCamera DisplayCropped:displayCropped AllowZoom:allowZoom];  
      [c ShowViewAt:viewId X:x Y:y Width:width Height:height];
  }
}

-(void) OnRemoteCameraRemoved:(RemoteCamera*)remoteCamera Participant:(Participant*)participant {
  /* Existing camera became unavailable */
  if (/* This camera that was being viewed */) {   
      [c HideView:viewId];
  }
}

/******************************************************************************/

/* Custom participant's window share view */

/* Register for RemoteWindowShare callbacks */
[c RegisterRemoteWindowShareEventListener:self];

/* Implementation of the IRegisterRemoteWindowShareEventListener interface */

-(void) OnRemoteWindowShareAdded:(RemoteWindowShare*)remoteWindowShare Participant:(Participant*)participant
{   /* New remoteWindowShare is available */
    if (/* This is the remoteWindowShare that is desired */) {
        [c AssignViewToRemoteWindowShare:viewId RemoteWindowShare:remoteWindowShare DisplayCropped:displayCropped AllowZoom:allowZoom];
        [c ShowViewAt:viewId X:x Y:y Width:width Height:height];
    }
}

-(void) OnRemoteWindowShareRemoved:(RemoteWindowShare*)remoteWindowShare Participant:(Participant*)participant
{   /* Existing remoteWindowShare became unavailable */
    if (/* This is the window that was being viewed */) {
        [c HideView:viewId];
    }
}
/* Java Example: */

public class MainActivity extends Activity implements VidyoConnector.IRegisterLocalCameraEventListener,
    VidyoConnector.IRegisterRemoteCameraEventListener, VidyoConnector.IRegisterRemoteWindowShareEventListener
{
  /* custom local preview */
  public void OnLocalCameraAdded(VidyoLocalCamera localCamera)    { /* New camera is available */ }

  public void OnLocalCameraRemoved(VidyoLocalCamera localCamera)  { /* Existing camera became unavailable */
    if ( /* the removed camera is the selected camera */ ) {
        mVidyoConnector.HideView(viewId);
    }
  }

  public void OnLocalCameraSelected(VidyoLocalCamera localCamera) { /* Camera was selected by user or automatically */
    mVidyoConnector.AssignViewToLocalCamera(viewId, localCamera, displayCropped, allowZoom);
    mVidyoConnector.ShowViewAt(viewId, 0, 0, viewId.getWidth(), viewId.getHeight());
  }

  public void OnLocalCameraStateUpdated(VidyoLocalCamera localCamera, VidyoDeviceState state) { /* Camera state is updated */ }

  /* Local camera change initiated by user. Note: this is an arbitrary function name. */
  public void HandleCameraChange() {
    /* Hide view of previously selected camera. */
    mVidyoConnector.HideView(viewId);
    /* Select new local camera */
    mVidyoConnector.SelectLocalCamera(camera);
  }

  /******************************************************************************/

  /* custom participant's source view */
  public void OnRemoteCameraAdded(VidyoRemoteCamera remoteCamera, VidyoRemoteParticipant participant) {
    /* New camera is available */
    if (/* This camera is desired to be viewed */) {
        mVidyoConnector.AssignViewToLocalCamera(viewId, localCamera, displayCropped, allowZoom);
        mVidyoConnector.ShowViewAt(viewId, 0, 0, viewId.getWidth(), viewId.getHeight());
    }
  }

  public void OnRemoteCameraRemoved(VidyoRemoteCamera remoteCamera, VidyoRemoteParticipant participant) {
    /* Existing camera became unavailable */
    if (/* This is the camera that was being viewed */) {   
      mVidyoConnector.HideView(viewId));
    }
  }

  /******************************************************************************/

  /* custom participant's window share view */
  public void OnRemoteWindowShareAdded(VidyoRemoteWindowShare remoteWindowShare, VidyoRemoteParticipant participant) {
    /* New window is available for sharing*/
    if (/* This is the window that is desired to view */) {
      mVidyoConnector.ShowRemoteWindowShareInView(viewId, remoteWindowShare, displayCropped, allowZoom);
      mVidyoConnector.ShowViewAt(viewId, 0, 0, viewId.getWidth(), viewId.getHeight());
    }
  }

  public void OnRemoteWindowShareRemoved(VidyoRemoteWindowShare remoteWindowShare, VidyoRemoteParticipant participant) {
    /* Existing window is no longer available for sharing */
    if (/* This is the window that was being viewed */) {
      mVidyoConnector.HideView(viewId));
    }
  }
}

Accessing Raw Frames

While using the custom layout above, you can register to access raw frames from both local and remote sources.

Register a listener for raw VdyoVideoFrame or VidyoAudioFrame events using the following API:

  • RegisterLocalCameraFrameListener(), LocalWindowShareFrameListener(), LocalMonitorFrameListener(), RegisterLocalMicrophoneFrameListener(), RegisterRemoteCameraFrameListener(), RegisterRemoteWindowShareFrameListener(), RegisterRemoteMicrophoneFrameListener()

The callback per frame will contain the necessary information to copy the raw frame into your own buffer.

  • VidyoVideoFrame in YCbCr.
  • VidyoAudioFrame in PCM format using a 32bit floating point.

These API’s are only available in C and ObjC.

/* C Example: */

/* Custom Raw frame access for localCamera */

/* Register for local camera events */
VidyoConnectorRegisterLocalCameraEventListener(&c, OnLocalCameraAdded,
    OnLocalCameraRemoved, OnLocalCameraSelected, OnLocalCameraStateUpdated);

void OnLocalCameraAdded(VidyoConnector* c, VidyoLocalCamera* localCamera)
{	/* New Camera is available. */ }

void OnLocalCameraRemoved(VidyoConnector* c, VidyoLocalCamera* localCamera)
{	/* Existing Camera became unavailable. */ }

void OnLocalCameraSelected(VidyoConnector* c, VidyoLocalCamera* localCamera)
{ 
	/* Camera was selected by user or automatically */
	/* Register for the event listener with any requested width and height */ 
	if (!VidyoConnectorRegisterLocalCameraFrameListener(&vc, OnLocalCameraFrame, localCamera, requestedWidth, requestedHeight, 0)) {
		Logger::Instance().Log("VidyoConnectorRegisterLocalCameraFrameListener registration failed");
	}
}

void OnLocalCameraStateUpdated(VidyoConnector* c, VidyoLocalCamera* localCamera, VidyoDeviceState state)
{	/* Camera state is updated */ }

void OnLocalCameraFrame(VidyoConnector* c, VidyoLocalCamera* localCamera, const VidyoVideoFrame *videoFrame)
{
	std::stringstream filePathSS;
	std::string filePath;
	std::ofstream *fileStream;

	/* Create file path. Each resolution will have it's own file since the raw YCbCr does not have header describing the width/heigh and the stream size might change due to bandwidth/CPU */
	filePathSS << "C:\\tmp\\" << LmiStringCStr(VidyoLocalCameraGetName(localCamera)) << "-" << VidyoVideoFrameGetWidth(videoFrame) << "x" << VidyoVideoFrameGetHeight(videoFrame) << ".yuv";
	filePath = filePathSS.str();

	if (fileMap.find(filePath) == fileMap.end()) {
		/* Open new file or append to existing file */
		fileMap[filePath] = new std::ofstream(filePath, std::ofstream::binary | std::ofstream::out | std::ofstream::app);
	}

	fileStream = fileMap[filePath];
    /* Data pointer to video frame payload */
    char* data = (char *)VidyoVideoFrameGetData(videoFrame);
    /* Data pointer to Chroma plane of the YCbCr frame */
    char* dataY = data + VidyoVideoFrameGetOffsetY(videoFrame);
    /* width in bytes of the plane*/
    LmiSizeT widthY = VidyoVideoFrameGetWidthY(videoFrame);
    /* Iterate over the entire plane and save the data to a file without padding */
    for (int i = 0; i < VidyoVideoFrameGetHeightY(videoFrame);i++) {
        /* offset by pitch to move to the next line */
		fileStream->write(dataY, widthY);
        dataY += VidyoVideoFrameGetPitchY(videoFrame);
	}
	/* Data pointer to Chroma plane of the YCbCr frame */
	char* dataCb = data + VidyoVideoFrameGetSizeY(videoFrame) + VidyoVideoFrameGetOffsetCb(videoFrame);
	/* width in bytes of the plane*/
	LmiSizeT widthCb = VidyoVideoFrameGetWidthCb(videoFrame);
	/* Iterate over the entire plane and save the data to a file without padding */
	for (int i = 0; i < VidyoVideoFrameGetHeightCb(videoFrame); i++) {
		/* offset by pitch to move to the next line */
		fileStream->write(dataCb, widthCb);
        dataCb += VidyoVideoFrameGetPitchCb(videoFrame);
	}
	/* Data pointer to Chroma plane of the YCbCr frame */
	char* dataCr = data + VidyoVideoFrameGetSizeY(videoFrame) + VidyoVideoFrameGetSizeCb(videoFrame) + VidyoVideoFrameGetOffsetCr(videoFrame);
	/* width in bytes of the plane*/
	LmiSizeT widthCr = VidyoVideoFrameGetWidthCr(videoFrame);
	/* Iterate over the entire plane and save the data to a file without padding */
	for (int i = 0; i < VidyoVideoFrameGetHeightCr(videoFrame); i++) {
		/* offset by pitch to move to the next line */
		fileStream->write(dataCr, widthCr);
        dataCr += VidyoVideoFrameGetPitchCr(videoFrame);
    }
}

VidyoConnectorRegisterLocalMicrophoneameraEventListener(&c, OnLocalMicrophoneAdded,
    OnLocalMicrophoneRemoved, OnLocalMicrophoneSelected, OnLocalMicrophoneStateUpdated);

void OnLocalMicrophoneAdded(VidyoConnector* c, VidyoLocalMicrophone* localMicrophone)
{	/* New Microphone is available. */ }

void OnLocalMicrophoneRemoved(VidyoConnector* c, VidyoLocalMicrophone* localMicrophone)
{	/* Existing Microphone became unavailable. */ }

void OnLocalMicrophoneSelected(VidyoConnector* c, VidyoLocalMicrophone* localMicrophone)
{ 
	/* Microphone was selected by user or automatically */
	if (!VidyoConnectorRegisterLocalMicrophoneFrameListener(&vc, OnLocalMicrophoneFrame, localMicrophone, 100, 100, 0)) {
		Logger::Instance().Log("VidyoConnectorRegisterLocalMicrophoneFrameListener registration failed");
	}
}

void OnLocalMicrophoneStateUpdated(VidyoConnector* c, VidyoLocalMicrophone* localMicrophone, VidyoDeviceState state)
{	/* Microphone state is updated */ }

void OnLocalMicrophoneFrame(VidyoConnector* c, VidyoLocalMicrophone* localMicrophone, const VidyoAudioFrame *audioFrame) {
	std::stringstream filePathSS;
	std::string filePath;
	std::ofstream *fileStream;

	/* Create file path */
	filePathSS << "C:\\tmp\\" << LmiStringCStr(VidyoLocalMicrophoneGetName(localMicrophone)) << ".pcm";
	filePath = filePathSS.str();

	if (fileMap.find(filePath) == fileMap.end()) {
		/* Open new file or append to existing file */
		fileMap[filePath] = new std::ofstream(filePath, std::ofstream::binary | std::ofstream::out | std::ofstream::app);
	}
	fileStream = fileMap[filePath];

	/* Data pointer to audio frame payload */
	char* data = (char *)VidyoAudioFrameGetData(audioFrame);

	/* size in bytes of the frame */
	LmiSizeT dataSize = VidyoAudioFrameGetSize(audioFrame);
	LmiSizeT numOfSamples = VidyoAudioFrameGetNumberOfSamples(audioFrame);
	
	fileMap[filePath]->write(data, numOfSamples * 4);
}

/* Objective-C Example: */

/* Add Vidyo base types */
#import "Lmi/Utils/SysDep/LmiBaseTypes.h"

/* Create a fileHandle map to keep all the raw data */
fileHandeMap   = [[NSMapTable alloc] initWithKeyOptions:NSMapTableStrongMemory valueOptions:NSMapTableStrongMemory capacity:1];

/* Custom Raw frame access for localCamera */

/* Register for local camera events */
[c RegisterLocalCameraEventListener:self];

/* Implementation of the IRegisterLocalCameraEventListener interface (local camera event listeners) */
-(void) OnLocalCameraAdded:(LocalCamera*)localCamera
{ /* New camera is available */ }

-(void) OnLocalCameraRemoved:(LocalCamera*)localCamera
{ /* Existing camera became unavailable */ }

-(void) OnLocalCameraSelected:(LocalCamera*)localCamera
{ /* Camera was selected by user or automatically */
	/* Register for local camera Frame callbacks */
	/* Register for the event listener with any requested width and height */ 
	if ( ![vc RegisterLocalCameraFrameListener:self LocalCamera:localCamera Width:requestedWidth Height:requestedHeight FrameInterval:0] ) {
		[logger Log:@"RegisterLocalCameraFrameListener registration failed."];
	}
	/* Set file handle for raw recording */
	NSString *filePath = [NSString stringWithFormat:@"/tmp/%@.video", [localCamera GetName]];
	NSFileManager *fileManager = [NSFileManager defaultManager];
	if ([fileManager fileExistsAtPath: filePath ] == NO) {
		[fileManager createFileAtPath: filePath contents: nil attributes: nil];
	}
	NSFileHandle *myHandle = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
	[fileHandeMap setObject:myHandle forKey:filePath];
}

-(void) OnLocalCameraStateUpdated:(LocalCamera*)localCamera State:(DeviceState)state
{ /* Camera state was updated */ }

/* Implementation of the IRegisterLocalCameraFrameListener interface (local camera frame listeners) */
- (void)OnLocalCameraFrame:(LocalCamera *)localCamera VideoFrame:(VideoFrame *)videoFrame
{
	NSString *filePath = [NSString stringWithFormat:@"/tmp/%@.video", [localCamera GetName]];
	NSFileHandle *myHandle = [fileHandeMap objectForKey:filePath];

    /* Data pointer to video frame payload */
    char* data = (char *)VidyoVideoFrameGetData(videoFrame);
    /* Data pointer to Chroma plane of the YCbCr frame */
    char* dataY = data + VidyoVideoFrameGetOffsetY(videoFrame);
    /* width in bytes of the plane*/
    LmiSizeT widthY = VidyoVideoFrameGetWidthY(videoFrame);
    /* Iterate over the entire plane and save the data to a file without padding */
    for (int i = 0; i < VidyoVideoFrameGetHeightY(videoFrame);i++) {
        /* offset by pitch to move to the next line */
		NSData *myData = [[NSData alloc] initWithBytes:dataY length:widthY];
		[myHandle writeData:myData];
        dataY += VidyoVideoFrameGetPitchY(videoFrame);
	}
	/* Data pointer to Chroma plane of the YCbCr frame */
	char* dataCb = data + VidyoVideoFrameGetSizeY(videoFrame) + VidyoVideoFrameGetOffsetCb(videoFrame);
	/* width in bytes of the plane*/
	LmiSizeT widthCb = VidyoVideoFrameGetWidthCb(videoFrame);
	/* Iterate over the entire plane and save the data to a file without padding */
	for (int i = 0; i < VidyoVideoFrameGetHeightCb(videoFrame); i++) {
		/* offset by pitch to move to the next line */
		NSData *myData = [[NSData alloc] initWithBytes:dataCb length:widthCb];
		[myHandle writeData:myData];
        dataCb += VidyoVideoFrameGetPitchCb(videoFrame);
	}
	/* Data pointer to Chroma plane of the YCbCr frame */
	char* dataCr = data + VidyoVideoFrameGetSizeY(videoFrame) + VidyoVideoFrameGetSizeCb(videoFrame) + VidyoVideoFrameGetOffsetCr(videoFrame);
	/* width in bytes of the plane*/
	LmiSizeT widthCr = VidyoVideoFrameGetWidthCr(videoFrame);
	/* Iterate over the entire plane and save the data to a file without padding */
	for (int i = 0; i < VidyoVideoFrameGetHeightCr(videoFrame); i++) {
		/* offset by pitch to move to the next line */
		NSData *myData = [[NSData alloc] initWithBytes:dataCr length:widthCr];
		[myHandle writeData:myData];
        dataCr += VidyoVideoFrameGetPitchCr(videoFrame);
    }
}

/* Register for local Microphone events */
[c RegisterLocalMicrophoneEventListener:self];

/* Implementation of the IRegisterLocalMicrophoneEventListener interface (local Microphone event listeners) */
-(void) OnLocalMicrophoneAdded:(LocalMicrophone*)localMicrophone
{ /* New Microphone is available */ }

-(void) OnLocalMicrophoneRemoved:(LocalMicrophone*)localMicrophone
{ /* Existing Microphone became unavailable */ }

-(void) OnLocalMicrophoneSelected:(LocalMicrophone*)localMicrophone
{ /* Microphone was selected by user or automatically */
	/* Register for local Microphone Frame callbacks */
	
	if ( ![vc RegisterLocalMicrophoneFrameListener:self LocalMicrophone:localMicrophone] ) {
		[logger Log:@"RegisterLocalMicrophoneFrameListener registration failed."];
	}
	/* Set file handle for raw recording */
	
	NSString *filePath = [NSString stringWithFormat:@"/tmp/%@.audio", [localMicrophone GetName]];
	NSFileManager *fileManager = [NSFileManager defaultManager];
	if ([fileManager fileExistsAtPath: filePath ] == NO) {
		[fileManager createFileAtPath: filePath contents: nil attributes: nil];
	}
	NSFileHandle *myHandle = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
	[fileHandeMap setObject:myHandle forKey:filePath];
}

-(void) OnLocalMicrophoneStateUpdated:(LocalMicrophone*)localMicrophone State:(DeviceState)state
{ /* Microphone state was updated */ }

/* Implementation of the IRegisterLocalMicrophoneFrameListener interface (local Microphone frame listeners) */
- (void)OnLocalMicrophoneFrame:(LocalMicrophone *)localMicrophone AudioFrame:(AudioFrame *)audioFrame
{
	NSString *filePath = [NSString stringWithFormat:@"/tmp/%@.audio", [localMicrophone GetName]];
	NSFileHandle *myHandle = [fileHandeMap objectForKey:filePath];

	if ( myHandle != nil ) {
		NSData *myData = [[NSData alloc] initWithBytes:audioFrame->data length:audioFrame->size];
		[myHandle writeData:myData];
	}
}

Network Interface Management

The VidyoConnector will pick the best available interface by default. However, you can override this by selecting a specific network interface for signaling or media.

Selecting

To get notified which network interfaces are available and select an interface by name, you can use the RegisterNetworkInterfaceEventListener and SelectNetworkInterfaceForSignaling / SelectNetworkInterfaceForMedia APIs.

/* JavaScript Example: */

/* NetworkInterface event listener */
vidyoConnector.RegisterNetworkInterfaceEventListener({
  onAdded: function(networkInterface) { /* New network interface is available */
    if (/* This is the network interface that is desired */) {
        vidyoConnector.SelectNetworkInterfaceForSignaling(networkInterface);
        vidyoConnector.SelectNetworkInterfaceForMedia(networkInterface);
    }
  },
  onRemoved:  function(networkInterface) { /* Existing network interface became unavailable */ },
  onSelected: function(networkInterface, transportType) { /* Network interface was selected for a specific transport type */ },
  onStateUpdated: function(networkInterface, state) { /* Network interface state was updated */ }
}).then(function() {
  console.log("RegisterNetworkInterfaceEventListener Success");
}).catch(function() {
  console.error("RegisterNetworkInterfaceEventListener Failed");
});

/* C Example: */

/* Register for network interface events */
VidyoConnectorRegisterNetworkInterfaceEventListener(&c, OnNetworkInterfaceAdded, OnNetworkInterfaceRemoved,
    OnNetworkInterfaceSelected, OnNetworkInterfaceStateUpdated);

/* Network interface event listeners */
void OnNetworkInterfaceAdded(VidyoConnector* c, VidyoNetworkInterface* networkInterface)
{ /* New network interface is available */
    if (/* This is the NetworkInterface that is desired */) {
        VidyoConnectorSelectNetworkInterfaceForSignaling(c, networkInterface);
        VidyoConnectorSelectNetworkInterfaceForMedia(c, networkInterface);
    }
}

void OnNetworkInterfaceRemoved(VidyoConnector* c, VidyoNetworkInterface* networkInterface)
{ /* Existing network interface became unavailable */ }

void OnNetworkInterfaceSelected(VidyoConnector* c, VidyoNetworkInterface* networkInterface, VidyoNetworkInterfaceTransportType transportType)
{ /* Network interface was selected for a specific transport type */ }

void OnNetworkInterfaceStateUpdated(VidyoConnector* c, VidyoNetworkInterface* networkInterface, VidyoNetworkInterfaceState state)
{ /* Network interface state was updated */ }

/* Objective-C Example: */

/* Register for network interface events */
[c RegisterNetworkInterfaceEventListener:self];

/* Implementation of the IRegisterNetworkInterfaceEventListener interface (network interface event listeners) */

-(void) OnNetworkInterfaceAdded:(NetworkInterface*)networkInterface {
  /* New network interface is available */
  if (/* This is the network interface that is desired */) {
      [c SelectNetworkInterfaceForSignaling:networkInterface];
      [c SelectNetworkInterfaceForMedia:networkInterface];
  }
}

-(void) OnNetworkInterfaceRemoved:(NetworkInterface*)networkInterface
{ /* Existing network interface became unavailable */ }

-(void) OnNetworkInterfaceSelected:(NetworkInterface*)networkInterface TransportType:(NetworkInterfaceTransportType)transportType
{ /* Network interface was selected by user or automatically */ }

-(void) OnNetworkInterfaceStateUpdated:(NetworkInterface*)networkInterface State:(NetworkInterfaceState)state;
{ /* Network interface state was updated */ }

/* Java Example: */

import com.vidyo.VidyoClient.Connector.VidyoConnector;
import com.vidyo.VidyoClient.Connector.Connector;

public class MainActivity extends Activity implements VidyoConnector.IRegisterNetworkInterfaceEventListener, VidyoConnector.IRegisterLocalMicrophoneEventListener, VidyoConnector.IRegisterLocalSpeakerEventListener
{
    /* Network interface event listener */
    public void OnNetworkInterfaceAdded(VidyoNetworkInterface networkInterface)    { /* New network interface is available */
        if (/* This is the network interface that is desired */) {
            mVidyoConnector.SelectNetworkInterfaceForSignaling(networkInterface);
            mVidyoConnector.SelectNetworkInterfaceForMedia(networkInterface);
        }
    }
    public void OnNetworkInterfaceRemoved(VidyoNetworkInterface networkInterface)  { /* Existing network interface became unavailable */          }
    public void OnNetworkInterfaceSelected(VidyoNetworkInterface networkInterface) { /* Network interface was selected by user or automatically */ }
    public void OnNetworkInterfaceStateUpdated(VidyoNetworkInterface networkInterface, VidyoDeviceState state) { /* Network interface state was updated */ }
}

Resetting to Default

To reset network interfaces back to their defaults, which will use any availabe interface, you can use the SelectDefaultNetworkInterfaceForSignaling / SelectDefaultNetworkInterfaceForMedia APIs.

/* JavaScript Example: */

vidyoConnector.SelectDefaultNetworkInterfaceForSignaling();
vidyoConnector.SelectDefaultNetworkInterfaceForMedia();
/* C Example: */

VidyoConnectorSelectDefaultNetworkInterfaceForSignaling();
VidyoConnectorSelectDefaultNetworkInterfaceForMedia();
/* Objective-C Example: */

[c SelectDefaultNetworkInterfaceForSignaling];
[c SelectDefaultNetworkInterfaceForMedia];
/* Java Example: */

mVidyoConnector.SelectDefaultNetworkInterfaceForSignaling();
mVidyoConnector.SelectDefaultNetworkInterfaceForMedia();

Certificate Authority Management

The VidyoConnector will use a default Certificate Authority list embedded in the library. However, you can override this by providing a custom Certificate Authority list that will be used to authenticate the TLS connections to Vidyo.io. Passing in an empty string will reset the use to the default list.

Setting the list

To set the list of Certificate Authority’s certificates, you can use the SetCertificateAuthorityList APIs and provide a list as a string in PEM format.

/* JavaScript Example: */

vidyoConnector.SetCertificateAuthorityList("List as a string in PEM format");
/* C Example: */

VidyoConnectorSetCertificateAuthorityList("List as a string in PEM format");
/* Objective-C Example: */

[c SetCertificateAuthorityList:@"List as a string in PEM format"];
/* Java Example: */

mVidyoConnector.SetCertificateAuthorityList("List as a string in PEM format");

Getting Started

Live Demo

You can use the VidyoConnector helper application to easily set up a live demo. The Demo section can launch the VidyoConnector sample as well as generate a temporary token.

A separate demo link must be generated for each participant.

Follow these instructions to launch the live demo:

  1. Sign up.
  2. Navigate to the Demo section.
  3. To launch the VidyoConnector Web app with an auto-generated token, click LAUNCH.
    • You can generate a temporary link and email/send it to other demo participants by clicking GENERATE LINK.
  4. The VidyoConnector app will launch in one of the following ways:
    • In WebRTC mode on Chrome and Firefox.
    • In Plugin mode with provided instructions to download an installer on Firefox, Safari, and IE.
    • As a protocol handler link with provided instructions to download and install the VidyoConnector helper application in every other desktop case.
    • As a protocol handler link on iOS and Android. After the VidyoConnector is built and installed, follow the iOS Quick Start or Android Quick Start instructions to build the necessary clients.

Click here to find the sample token generator script.


VidyoConnector Reference Application

VidyoConnector is a reference application built using the Vidyo Client SDK. Its source code and project files are provided as part of the SDK package, and you can use it as a baseline for creating your own custom application.

The SDK package also contains a VidyoConnector installer that registers a protocol handler for easy invocation from a URL. This is especially useful for workflows where embedding a client library is difficult.

To start the application, the following parameters may be passed, several of which are required to connect to a video conference:

Argument Default Value Required Description
host prod.vidyo.io Yes Entry point into Vidyo.io service. Production environment should always be set to prod.vidyo.io.
token Yes An access token required to authenticate the session. A new token should be created for every endpoint.
displayName Yes The name displayed to other participants in a video conference. For example, “John Smith”.
resourceId Yes The ID of the video conference. All the endpoints must share the same ID to join the same video conference. For example, “SalesMeeting”.
hideConfig 0 No 0 = when in preview mode (not connected to a resource), the video conference connection settings (host, token, displayName, resourceId) are displayed and may be configured.
1 = the video conference connection settings are never displayed and thus must have been passed to the app via command line or URL
Note: On Android, use “false” and “true”, rather than “0” and “1”.
autoJoin 0 No 0 = upon starting the application, do not automatically connect to the resource.
1 = upon starting the application, automatically attempt to connect to the resource.
Note: On Android, use “false” and “true”, rather than “0” and “1”.
allowReconnect 1 No 0 = after the user disconnects from a successful connection, the toolbar will display “Call ended” and no other connection may be established.
1 = there are no limits on the number of successful connections the user may make.
Note: On Android, use “false” and “true”, rather than “0” and “1”.
enableDebug 0 No 0 = disable debug logging and statistics.
1 = enable debug logging and statistics.
Note: On Android, use “false” and “true”, rather than “0” and “1”.
returnURL No The VidyoConnector app uses this field to return to the application which opened it.
iOS and Android only.
Include a call state as a return parameter indicating to the application whether the VidyoConnector app completed a successful call.
Example iOS usage:
// Provide a callstate of either 0 or 1, depending on whether the call was successful.
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?callstate=%d", returnURL, callState]]];
Example Android usage:
// Provide a callstate of either 0 or 1, depending on whether the call was successful.
Intent returnApp = getPackageManager().getLaunchIntentForPackage( mReturnURL );
returnApp.putExtra( "callstate", callState );
startActivity( returnApp );

Invoking VidyoConnector without any parameters will bring up the dialog box. However, in order to integrate it into the workflow, all the parameters may be passed in.

Web App

The VidyoConnector web app is built using the Javascript version of the client library which can be used inside a web browser and loaded by opening VidyoConnector.html.

For WebRTC-supported browsers, the VidyoClient.js library will load automatically. For others, it will present download or protocol handler launch options.

For proper WebRTC function, VidyoConnector.html must be hosted on a secure server and accessed via https.

The Plugin installer is available for:

Invocation

https://static.vidyo.io/4.1.15.7/connector/VidyoConnector.html?host=prod.vidyo.io&token=SomeToken&resourceId=SomeRoom

Desktop App

For convenience, the VidyoConnector application is pre-built and signed for each supported platform.

The Application installer is provided for:

Mac Invocation

open VidyoConnector.app --args -host prod.vidyo.io -token SomeToken -resourceId SomeRoom -fullScreen 1 -autoJoin 1 -allowReconnect 0

Windows Invocation

VidyoConnector.exe -host prod.vidyo.io -token SomeToken -resourceId SomeRoom -fullScreen 0

Protocol Handler Invocation Example

vidyoconnector://?host=prod.vidyo.io&token=SomeToken&resourceId=SomeRoom

Mobile App

Mobile pre-built versions of VidyoConnector are not available in the SDK package due to code signing issues, but it is easy to build and install the application on a mobile device using the provided project files.

Note: Currently the mobile applications are unable to run in the emulator and must be installed on a physical device.

iOS Invocation

Example for invoking VidyoConnector from another mobile app:

[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"VidyoConnector://?token=someToken&resourceId=SomeRoom&fullScreen=0&returnURL=URLSchemeOfLaunchingApp://"]];

The value of the returnURL parameter (URLSchemeOfLaunchingApp://) is defined in the launching app’s URL Scheme, as defined in the URL types key of the app’s Info.plist file.

Android Invocation

Here is an example of invoking VidyoConnector from another mobile app:

Intent vidyoConnectorApp = getPackageManager().getLaunchIntentForPackage( "com.vidyo.vidyoconnector" );
vidyoConnectorApp.putExtra( "host", "prod.vidyo.io" );
vidyoConnectorApp.putExtra( "token", "SomeToken" );
vidyoConnectorApp.putExtra( "resourceId", "SomeResource" );
vidyoConnectorApp.putExtra( "autoJoin", true );
vidyoConnectorApp.putExtra( "fullScreen", false );
vidyoConnectorApp.putExtra( "allowReconnect", true );
vidyoConnectorApp.putExtra( "enableDebug", true );
vidyoConnectorApp.putExtra( "returnURL", "com.sample.vidyo.myAppName" );
startActivity( vidyoConnectorApp );

Building Your Own

Please refer to the platform section in the Overview for links to download the VidyoClient SDK and a quick-start instructions for building the VidyoConnector sample.


Quick Starts

Quicks starts are available for a variety of platoforms and will help you build your own sample app.

JavaScript

This guide will help you to quickly download and run the JavaScript plugin or WebRTC-based VidyoConnector app.

The VidyoClient.js JavaScript library seamlessly switches between Plugin mode and WebRTC mode, with Plugin mode being preferred. While the plugin offers a superior experience, the following table shows which modes are supported across the different web browsers:

Mode Chrome 11+ Firefox 3.6+ Safari 5+ IE 10+ EDGE
Plugin no yes yes yes no
WebRTC yes yes no no no

The VideoClient.js receives the following arguments:

Argument Default Value Required Description
onload Yes Registered callback that provides library status changes.
plugin true No Setting to false prevents NPAPI or ActiveX plugin from loading.
webrtc true No Setting to false prevents WebRTC from loading.
<script src="https://static.vidyo.io/4.1.15.7/javascript/VidyoClient/VidyoClient.js?onload=onVidyoClientLoaded"></script>

SDK Package

This section explains how to download and run the VidyoConnector.html from the SDK Package and make alterations to it. A default version of the app is hosted on Vidyo.io:

https://static.vidyo.io/4.1.15.7/connector/VidyoConnector.html

Prerequisites

  • Supported web browser installed on the system.
  • Optional secure https server for WebRTC.

Download and Run

  1. Download the Web Browser SDK package.
  2. Extract the downloaded .zip file to a folder.
  3. Within this folder, locate the samples/VidyoConnector/js/VidyoConnector.html file.
  4. Open VidyoConnector.html in a supported browser.
  5. If the browser supports WebRTC, the VidyoConnector initializes; otherwise, you are prompted to download and run an installer for the VidyoClient plugin.

If WebRTC has issues initializing on the endpoint, it might need to be hosted on a secure https server, locally or remotely.

  1. If prompted, authorize the browser to run the plugin or WebRTC and access the devices on the computer.
  2. The browser displays the Vidyo.io app with a login form on the left and a preview image from the video camera on the right.
  3. Review the Vidyo.io app login form. See VidyoConnector parameters for more details.

The VidyoConnector App Login Form

  • Cameras: list of the cameras that are available
  • Microphones: list of the microphones that are available
  • Speakers: list of the speakers that are available
  1. To start a video conference, click the green Connect button.

Green connect button

Code Walkthrough

  • The VidyoConnector app is located in the Samples/VidyoConnector/js/ folder. It relies primarily on VidyoConnector.html, VidyoClient.js, and VidyoConnector.js.
  • VidyoConnector.html loads VidyoClient.js from a cloud server.
  • Together, VidyoConnector.css and VidyoConnector.html control the styling and presentation of the app.
  • The Images folder contains icons used by the app.

App Customization

To customize the JavaScript application, you should modify VidyoConnector.html, VidyoConnector.css, and VidyoConnector.js.


Windows

Building a VidyoConnector Sample from Source

This guide shows how to quickly download, build, and run the VidyoConnector application on a Windows system from the SDK Package and make alterations to it.

Prerequisites

  • Visual Studio or Visual Studio Express 2013 IDEs (later versions are not supported)

Download and Run the App

  1. Download the Windows SDK package.
  2. Extract the downloaded .zip file to a folder.
  3. Use the IDE to open the VidyoConnector12.sln, which is located in the extracted folder.
  4. In the IDE, click the Start button. The IDE will build, load, and run the app on the Windows system.
  5. In the app that appears, enter the required VidyoConnector parameters.
  6. Click the Connect icon.

Code Walkthrough

In the IDE, select the Project navigator view and select VidyoConnector > win > VidyoConnector > VidyoViewController.cpp.

This file contains the primary logic of the VidyoConnector application. To create a custom app, you should modify and extend this file.

The VidyoViewController.cpp file contains the following logic:

  • Initialize and manage session communications
  • Manage UI and hardware events

macOS

This guide shows how to quickly download, build, and run the VidyoConnector Application on a macOS system from the SDK Package and make alterations to it.

SDK Package

This section explains how to download and run the macOS VidyoConnector application.

Prerequisites

  • On the Mac system, get the latest version of Xcode from the App Store and install it.
  • To distribute the app, you must use your Apple ID to enroll in the Apple Developer program.
  • Add your Apple ID to the Xcode account preferences.

For more information, see the Xcode help topic “Adding an Apple ID to Your Accounts.”

Download and Run the App

  1. Download the macOS SDK package.
  2. Extract the downloaded .zip file to a folder.
  3. Use Xcode to open VidyoConnector.xcodeproj, which is located in the extracted folder.
  4. In Xcode, run the app. Xcode will build, load, and run the app on the Mac.
  5. In the app that appears, enter the required VidyoConnector parameters.
  6. Click the Connect icon.

Code Walkthrough

In Xcode, select the Project navigator view and look at VidyoConnector > macos > VidyoConnector > VidyoViewController.m.

This file contains the primary logic of the VidyoConnector application. To create a custom app, you should modify and extend this file.

VidyoViewController.m contains the following logic:

  • Initialize and manage session communications
  • Manage UI and hardware events

iOS

This guide shows how to quickly download, build, and run the VidyoConnector application on an iOS device from the SDK Package and make alterations to it.

SDK Package

This section explains how to download and run the iOS VidyoConnector application.

Prerequisites

  • On a Mac computer, go to the App Store to get the latest version of Xcode and install it.
  • Connect an iOS device to the Mac computer.
  • Become a member of the Apple developer program, and obtain a valid developer ID.
  • Provision the iOS device for development use for the above-mentioned developer program.
  • Configure Xcode to run the app on the iOS device.

For more information, see the Xcode help topic “Running on a Device.”

Download and Run the App

  1. Download the iOS SDK package.
  2. Extract the downloaded .zip file to a folder.
  3. Use Xcode to open VidyoConnector-iOS.xcodeproj, which is located in the extracted folder.
  4. In Xcode, run the app. Xcode will build, load, and run the app on the iOS device.
  5. In the app that appears, enter the required VidyoConnector parameters.
  6. Click the Connect icon.

Code Walkthrough

In Xcode select the Project navigator view and look at VidyoConnector > ios > VidyoConnector > VidyoViewController.m.

This file contains the primary logic of the VidyoConnector application. To create a custom app, you should modify and extend this file.

VidyoViewController.m contains the following logic:

  • Initialize and manage session communications
  • Manage UI and device events

Android

This guide shows how to quickly download, build, and run the VidyoConnector application on an Android device from the SDK Package and make alterations to it.

Run VidyoConnector from the SDK Package

This section explains how to download and run the Android VidyoConnector application.

Prerequisites

If Android Studio prompts you to download and install various tools during the following procedure, follow the prompts and then resume the procedure.

On Windows, Android Studio has a known issue with long pathnames that might cause builds to fail for any project, including the VidyoConnector app. Even if the project itself has a short pathname, such as C:\MyApp, files with long pathnames might be generated in its subdirectories.

Download and run the app

  1. Download the Android SDK package.
  2. Extract the downloaded .zip file to a folder.
  3. In Android Studio, use Import project to open and import the Android project for the app, which is located in the extracted folder (select the samples/VidyoConnector/android folder to import).
  4. In Android Studio, run the app. Android Studio will build, load, and run the app on an Android device.
  5. In the app that appears, enter the required VidyoConnector parameters.
  6. Click the Connect icon.

Code Walkthrough

In Android Studio, open app/src/main/java/com/vidyo/vidyoconnector/MainActivity.java.

This file contains the primary logic of the VidyoConnector application. To create a custom app, you should modify and extend this file.

MainActivity.java contains the following logic:

  • Initialize and manage session communications
  • Manage UI and device events

Media Bridge

As you develop applications that leverage Vidyo.io, you may want to include a feature for recording and distributing recordings for private or public viewing. You may also want to include SIP-enabled participants in your calls. By integrating the Media Bridge Docker image with your Vidyo application, you can record and distribute your Vidyo conferences and include incorporate SIP-enabled video conferencing systems.

What’s Docker?

Docker is a robust software container platform you install on a dedicated server and use to run the Media Bridge image. The Media Bridge image provides record/playback functionality you might want to integrate with your Vidyo.io-based application. Docker provides the thorough resources and documentation you need to integrate basic or extensive Media Bridge features. See the Docker Overview here.


What’s Media Bridge?

Media Bridge is a downloadable Docker image that provides the following:

  • Recorder for the archiving of Vidyo.io-based video conferences
  • Streamer for the distribution of Vidyo.io-based video conferences
  • Gateway for SIP-enabled systems

From Docker, you pull the Media Bridge image, create a config file, create a container, drop in your config file, then start recording.


Before You Begin

Before you begin, ensure that your Linux server is configured with a running Docker Engine.

What you will need

Server platforms other than Ubuntu Linux 14.04+ have not been tested; they might not run smoothly or predictably in your deployment.


Set-up

To set up your server with Media Bridge for managing video conference recordings, follow these steps:

  1. Install the Media Bridge docker image:

    docker pull vidyo/mediabridge
    
  2. Create a recording configuration file (see Recording Configuration File).

  3. Create a container from the Media Bridge image:

    docker run -d --name my_mediabridge vidyo/mediabridge
    
  4. Copy your config file to the container:

    docker cp config my_mediabridge:/opt/vidyo
    

Start a Recording

To start the container, enter:

docker exec -d my_mediabridge /opt/vidyo/connect

Monitor a Recording

To monitor the recording, enter:

docker exec my_mediabridge pgrep -x call

If a recording is active, the command returns the process ID; otherwise, it returns nothing.


Stop a Recording

The recording stops automatically when the last participant leaves the room.

To force the recording to stop with a SIGINT call, enter:

docker exec my_mediabridge pkill -x --signal INT call

Retrieve a Recording

By default, the recording is saved to a file named recording.flv at this path:

/opt/vidyo folder

To retrieve the recording, enter:

docker cp my_mediabridge:/opt/vidyo/recording.flv $HOME

To override this, use the destination option described in the Recording Configuration File Options table below.


<a class=“headerAnchor” name=“SIPGatewayCalls”">

Include SIP-enabled systems

To make a SIP outbound call, set the destination key in the config file to the full SIP URI:

destination=sip:mary@5.6.7.8

To receive an incoming SIP call, leave the destination key empty:

destination=     

To start the Docker container for SIP calls, use the -p parameter to map host ports to the container for both media and signaling. For example, if the mediaPorts key in the config file is set to 50000-50100, the Docker command is:

docker run -d --name sipCall -p 50000-50100:50000-50100/udp -p 5060:5060/udp vidyo/mediabridge

You must map SIP signaling UDP port 5060 from the host to the container.


Troubleshooting

If you encounter a problem, retrieve the log file gw.log from the container at this path and use it to troubleshoot:

/var/log

To enable full logging, add log=full|debug|info,|warn|error|none. The default is debug.


Resource Requirements

To ensure Media Bridge has sufficient resources for smooth HD streaming and playback, use the following CPU and memory reservation guidelines.

Resolution (fps) CPU [GHz] RAM [GB]
HD @ 720p (30) 2.2 2
HD @ 1080p (30) 4.0 4

Recording Configuration File

The recording configuration file is a plain text file with key-value pairs. Name this file config and place it at this path:

/opt/vidyo

Each key-value pair must be on a separate line.

The key is separated from the value with an equal (=) sign only; do not use spaces in key-value pairs.

Use a # before comments; text appearing on a line after a # is ignored at runtime.

The following table describes the options available for the recording configuration file.

Option Description
width The width of the video stream.
height The height of the video stream.
fps The frame rate of the video stream in frames per second.
kbps The bandwidth of the recording in kilo-bits per second.
layout Set to 1 for a basic layout, set to 2 for a presenter layout, where the current speaker occupies a larger tile than the rest, set to 3 for a film strip layout, where the current speaker occupies most of the screen and other participants appear in a film strip at the bottom.
maxParticipants The maximum number of participants to be rendered in the video stream. Minimum is 1, maximum is 8.
overlay When set to 1, Media Bridge displays each participant’s name as an overlay in the video stream.
presentationAllowed When set to 0, Media Bridge ignores presentations during the conference. When set to 1, Media Bridge records presentations instead of the main video streams.
presWidth The maximum width of the presentation stream.
presHeight The maximum height of the presentation stream.
presFps The frame rate of the presentation stream in frames per second.
presKbps The bandwidth used for the presentation stream in kilo-bits per second.
destination This can be a file name, a folder name (preceded by flv:) or an RTMP URI (preceded by rtmp:). When you set this field to a folder name, Media Bridge randomly generates the file name. This directs the recording to a central storage location you mount inside the docker container (use the -v option). When you set this field to an RTMP URI, Media Bridge streams the recording to that destination. No permanent record is stored.
resourceId The vidyo.io resource to connect to and record.
token The access token to the vidyo.io system.
host The vidyo.io host name to connect to. Make sure that this host name can be resolved inside your container. This can be done using the --add-host parameter when creating the container.
mediaPorts The ports used to send and receive media from the SIP endpoint (e.g. mediaPorts=50000-50100). When you start the Docker container, map these ports to the same port numbers on the host via the -p parameter.
publicIp The IP address of the host. It must be reachable by the SIP endpoint participating in the call (e.g. publicIp=1.2.3.4).

Sample Configuration File

#main video settings
width=1280
height=720
fps=30
kbps=2000
layout=1
maxParticipants=8
overlay=1

#Presentation settings
presentationAllowed=1 #0 - ignore presentations 1 - replace main video with presentation
presWidth=1280
presHeight=720
presFps=5
presKbps=300
destination="flv:/opt/vidyo/recording.flv"

#vidyo.io connection info
resourceId="my_room"
token="GENERATED_TOKEN"
host="prod.vidyo.io"

#SIP gateway info
mediaPorts="min_port_number-max_port_number"
publicIp="host_ip_address"