Pages Menu
TwitterRssFacebook

Posted by on May 29, 2015 in Learn Skype Web SDK

Learn Skype Web SDK Day 22 : Receiving an Incoming Audio Call

Learn Skype Web SDK Day 22 : Receiving an Incoming Audio Call

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

We’ve previously covered how to identify and respond to incoming Instant Message conversations. Doing the same thing for Audio calls is fairly similar – the only real difference is that instead of using chatService, instead it’s audioService.

When a new conversation request is received by the Skype for Web API, it is added to the list of conversations managed by the conversationsManager. By monitoring new conversations being added here you can then take actions when they appear.

You can register an event listener for new conversations being added with the event listener:

var client = new Skype.Web.Model.Application;
 //perform sign in
   client.conversationsManager.conversations.added(function (newConversation) {
//do something with newConversation
});

Obviously there is only one conversationsManager and if you’re starting your own conversations as well then conversations will be being added and removed from this fairly regularly. There are two important things you should check for to know whether this is a incoming conversation you need to act on. You should check that you are able to accept the conversation, and that the conversation is in the right state to be accepted.

The first thing you need to do is check to see whether this is an audio call which you are able to accept, by evaluating:

newConversation.audioService.accept.enabled()

Secondly, you should evaluate the state of the conversation. A conversation moves through various states during its lifetime and checking the current state will make sure you don’t try and accept or reject a conversation that isn’t ready for it. If the conversation state is Notified then it means that the conversation is waiting for an invitation decision to be made: i.e. it’s ready to be accepted or declined:

newConversation.audioService.state() == 'Notified'

Putting the two together gives you:

var client;
 //instantiate client object and perform sign in
   client.conversationsManager.conversations.added(function (newConversation) {
    if (newConversation.audioService.accept.enabled() && newConversation.audioService.state() == 'Notified')
      {
       //accept or reject invite
      }
});

Actually accepting or rejecting the conversation invitation is easy:

newConversation.audioService.accept();

or

newConversation.audioService.reject();

Because we’ve already done something pretty similar for Instant Messaging, I though this time it would be more fun to use toastr.js to actually display the incoming alert. This was actually pretty easy:

var msg = '<div>Incoming Call from ' + conversation.participants()[0].name() + '<br/><button id="btnAccept" class="btn btn-success">Accept</button><button id="btnReject" class="btn btn-danger">Reject</button>';
		var $toast = toastr["info"](msg, "Accept");
		
		 if ($toast.find('#btnAccept').length) {
                $toast.delegate('#btnAccept', 'click', function () {
                  AcceptConversation();
                    $toast.remove();
                });
            }
			
		 if ($toast.find('#btnReject').length) {
			$toast.delegate('#btnReject', 'click', function () {
				RejectConversation();
				$toast.remove();
			});
		}

First I build up the content of toast, containing the name of the caller, and two buttons to accept or reject the call. Then I call toastr and get a handle to the actual toast object. This causes the toast to be displayed. Finally, I add the functions for the button clicks to accept or reject the conversation. Have a look at the example for this post to see this, including the extra initialising stuff to set the style etc.

<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>
    <br/> Audio Status: <span id="lblAudioStatus"></span>
  </div>

  <hr/>

 
<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 = 'Receiving a New Audio Conversation';
  var blogPostLocation = "http://thoughtstuff.co.uk";
  var githubLocation = "http://github.com";
 
 
 var activeConversation;
 
  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!');
                     
          }, 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);
               $('#btnSendIM').prop('disabled', true);
             }, function (error) {
                //Something went wrong.
                alert(error);
              });
      });		
	  
	     
	  
	

client.conversationsManager.conversations.added(function (conversation) {
if (conversation.audioService.accept.enabled() &amp;amp;&amp;amp; conversation.audioService.state() == 'Notified') 
	{
		//incoming audio call
		activeConversation = conversation;
		
		//wire up audio state events
		conversation.selfParticipant.audio.state.changed(function (newState) {
			$('#lblAudioStatus').text(newState);
		});
		
		var msg = '<div>Incoming Call from ' + conversation.participants()[0].name() + '<br/><button id="btnAccept" class="btn btn-success">Accept</button><button id="btnReject" class="btn btn-danger">Reject</button>';
		var $toast = toastr["info"](msg, "Accept");
		
		 if ($toast.find('#btnAccept').length) {
                $toast.delegate('#btnAccept', 'click', function () {
                  AcceptConversation();
                    $toast.remove();
                });
            }
			
		 if ($toast.find('#btnReject').length) {
			$toast.delegate('#btnReject', 'click', function () {
				RejectConversation();
				$toast.remove();
			});
		}
		
	}
})



});

function InitialiseToastr()
{
toastr.options = {
  "closeButton": true,
  "debug": false,
  "newestOnTop": false,
  "progressBar": false,
  "positionClass": "toast-bottom-right",
  "preventDuplicates": false,
  "timeOut": "15000",
  "extendedTimeOut": "15000",
  "showEasing": "swing",
  "hideEasing": "linear",
  "showMethod": "fadeIn",
  "hideMethod": "fadeOut",

};


}

function AcceptConversation()
{
activeConversation.audioService.accept();
}

function RejectConversation()
{
activeConversation.audioService.reject();
}

</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.

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.