Pages Menu
TwitterRssFacebook

Posted by on Jun 2, 2015 in Learn Skype Web SDK

Learn Skype Web SDK Day 24 : Starting a New Video Conversation

Learn Skype Web SDK Day 24 : Starting a New Video Conversation

This is one post in a series of more than 30, devoted to helping you get up to speed quickly with the new Skype Web SDK. Each lesson comes with source code (in GitHub) and a working demo page so you can see what it does. Check out the full list of posts on the Skype Web SDK page.


View Demo

One step on from Instant Message and Audio calls is Video calling. This allows you to make a real connection with your end user for offering advice, assistance or just collaborating on a project.

Although at first glance using the videoService seems very similar to the audioService used to place audio calls, there is one important thing to be aware of. With an audio call, once it’s accepted you know that both sides of the conversation have enabled audio, and so you can plan accordingly. However, with video it’s possible for one side to start their video, but the other side to choose not to, and remain as an audio-only caller. Therefore, you cannot blindly assume that just because you started a video call that the remote participant will have their video enabled. Instead, you can start your video, and instead listen for an event for when the remote caller’s video is connected – and then you can connect to their video stream.

Once you have their video stream you can easily render it on the screen by specifying the div in which it should appear. The video will resize to fit the div.

In order to make video calls, you need to make sure the Plugin is installed.

Step 1 – Create the conversation. Like the rest of Skype for Web API – new objects are not ever instantiated in isolation – they always come from a parent. In this case we use the parent conversationManager to create a new conversation:

var application;
//instantiate application object and do sign-in process
var conversation = application.conversationsManager.createConversation();

Step 2 – Add the participants. You don’t need to add yourself, but you need to add anyone else in the conversation. Assuming you already have the person object:

var conversationParticipant = conversation.createParticipant(person);
conversation.participants.add(conversationParticipant);

Step 3 – Register the conversation. Before you start the conversation you need to tell the conversationsManager about it by adding it into its list of conversation:

application.conversationsManager.conversations.add(conversation);

Step 4 – Start the conversation! You’re now ready to begin the Video Service. Doing this will start your video automtically, which means that once the call has started you can connect to your video stream and display it in a div of your choosing:

conversation.videoService.start().then(function () {
 //at this point, we know our video is working, so show it in the div
 conversation.selfParticipant.video.channels(0).stream.source.sink.container(document.getElementById("divSelfVideoWindow")); 
 });

Step 5 – You want to listen for an event which tells you that the remote participant has also started their video. You can do this by listening to the stateChanged event on the participant’s video.state:

 //watch the state of the remote participants video. When it's connected, show it in the div
 convParticipant.video.state.changed(function(state) {
   if (state == 'Connected')  
	convParticipant.video.channels(0).stream.source.sink.container(document.getElementById("divRemoteVideoWindow"));
 });

As you can see, once the video state is ‘Connected’, you can then connect to the remote video stream and display it in another div.

 <div class="form-horizontal">
    <div class="form-group">
      <label for="username" class="col-sm-2 control-label">Username</label>
      <div class="col-sm-10">
        <input type="email" class="form-control" id="username" placeholder="Email">
      </div>
    </div>
    <div class="form-group">
      <label for="password" class="col-sm-2 control-label">Password</label>
      <div class="col-sm-10">
        <input type="password" class="form-control" id="password" placeholder="Password">
      </div>
    </div>

    <div class="form-group">
      <div class="col-sm-offset-2 col-sm-10">
        <button class="btn btn-default" id="btnLogIn">Log in</button>
      </div>
    </div>

    <div class="form-group">
      <div class="col-sm-offset-2 col-sm-10">
        <button class="btn btn-default" id="btnLogOut">Log out</button>
      </div>
    </div>
  </div>

  <div>
    <span id="loginStatus"></span>
  </div>

  <hr/>

  <div class="form-horizontal">
    <div class="form-group">
      <label for="contact" class="col-sm-2 control-label">Start Video Call with:</label>
      <div class="col-sm-10">
        <input type="email" class="form-control" id="contact" placeholder="Contact SIP Address">
      </div>
    </div>  

    <div class="form-group">
      <div class="col-sm-offset-2 col-sm-10">
        <button class="btn btn-default" id="btnStartConversation" disabled="disabled">Start</button>
      </div>
    </div>
  </div>
  
  <div>
    <span id="videoStatus"></span>
	<h3>My Video</h3>
	<div id="divSelfVideoWindow"></div>
	<h3>Remote Video</h3>
	<div id="divRemoteVideoWindow"></div>
  </div>
<div id="footer"></div>
  
  <!-- This is not needed for the samples to run, but adds standard headers and footers to the samples, to display title, instructions, about etc.
       If you're taking this code and using it yourself, you can remove this.-->
   <script type="text/javascript" src="../../assets/layoutcodesample-min.js"></script>
  
  <script type="text/javascript">

  <!-- These variables are only needed for laying out the code sample, they are not part of the sample code. -->
  var pageTitle = 'Starting an Video Conversation';
  var blogPostLocation = "http://thoughtstuff.co.uk";
  var githubLocation = "http://github.com";
 
  var client;
  $(function () {
    'use strict';

	Skype.initialize({
            apiKey: 'SWX-BUILD-SDK',
        }, function (api) {
            client = new api.application();           
			
		// whenever client.state changes, display its value
		client.signInManager.state.changed(function (state) {
		$('#loginStatus').text("Login State: " + state);
		});
	
        }, function (err) {
            alert('Error loading Skype Web SDK: ' + err);
        }); 

    $('#btnLogIn').click(function () {

        // start signing in
        client.signInManager.signIn({
          username: $('#username').val(),
          password: $('#password').val()
        }).then(function () {
            //log in worked!
            alert('Logged in!');
            $('#btnStartConversation').prop('disabled', false);
            
          }, function (error) {
            //Something went wrong.
            alert(error);
          });
      });

    $('#btnLogOut').click(function () {
        // start signing out
        client.signInManager.signOut()
        .then(function () {
               //log out worked!
               alert('Logged out!');
               $('#btnStartConversation').prop('disabled', true);
             }, function (error) {
                //Something went wrong.
                alert(error);
              });
      });

    $('#btnStartConversation').click(function () {
      StartConversation($('#contact').val());
    });

  function StartConversation (contactSIP) {
  //first, get the person to start a conversation with. Assume one person.
  var person;
  GetContactFromName(contactSIP).then(function (results) {
    results.forEach(function (result) {
    person = result.result;          
  });

 //create the conversation object
 var conversation = client.conversationsManager.createConversation();

 //add the person to the conversation by creating a conversation participant object
 var convParticipant = conversation.createParticipant(person);
 conversation.participants.add(convParticipant);

 //add the newly created conversation to the ConversationManager list
 client.conversationsManager.conversations.add(conversation);

 
 conversation.videoService.start().then(function () {
 //at this point, we know our video is working, so show it in the div
 conversation.selfParticipant.video.channels(0).stream.source.sink.container(document.getElementById("divSelfVideoWindow")); 
 });
 
 //watch the state of the remote participants video. When it's connected, show it in the div
 convParticipant.video.state.changed(function(state) {
   if (state == 'Connected')
		convParticipant.video.channels(0).stream.source.sink.container(document.getElementById("divRemoteVideoWindow"));
 });
 
 
 
});

}

function GetContactFromName(contactSIP)
{
 var query = client.personsAndGroupsManager.createPersonSearchQuery();
 query.text(contactSIP);
 query.limit(1);
 return query.getMore();          
}

});

</script>

Demo Online

You can try this code out against your own Skype for Business environment by going to the demo page. From here you can also download the code from GitHub if you want to host it locally, or take it and use it in your next project.

Disclaimer: This is sample code, intended to inform and educate. It is not production-ready and is lacking key components such as error handling. You use it entirely at your own risk. You should fully understand the effects, limitations and risks of the code before executing, and understand the implications of any set-up steps. By using these code examples you are using the Skype Web SDK, so you should read the Skype Software License Terms to which you are agreeing.

Good to Know

Written by Tom Morgan

Tom is a Microsoft Teams Platform developer and Microsoft MVP who has been blogging for over a decade. Find out more.
Buy the book: Building and Developing Apps & Bots for Microsoft Teams. Now available to purchase online with free updates.

1 Comment

  1. Hi!

    I have two issues when the conference is complete

    1. I cant mute self audio. This the code
    conversation.selfParticipant.audio.isMuted.set(conversation.selfParticipant.audio.isMuted());

    2. When a participant disable your video, I cant hide the div that contains the video.
    conversation.participants.added(function (p) {
    p.video.state.changed(function (newState, reason, oldState) {
    var selfChannel;
    if (newState == ‘Notified’ && !timerId) {
    //timerId = setTimeout(onAudioVideoNotified, 0);

    } else if (newState == ‘Connected’) {
    selfChannel = conversation.selfParticipant.video.channels(0);
    selfChannel.stream.source.sink.container.set(document.getElementById(“call-self”));
    }
    else if (newState == ‘Diconnected’) {
    document.getElementById(“call-self”).appendChild(elem);
    elem.src = ‘images/video-no-disponible.gif’;
    }

    Help me please!!

Post a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.