Oracle® Communications WebRTC Session Controller

Application Developer's Guide

Release 7.1

E55126-03

July 2015

Oracle Communications WebRTC Session Controller Application Developer's Guide, Release 7.1

E55126-03

Copyright © 2013, 2015, Oracle and/or its affiliates. All rights reserved.

This software and related documentation are provided under a license agreement containing restrictions on use and disclosure and are protected by intellectual property laws. Except as expressly permitted in your license agreement or allowed by law, you may not use, copy, reproduce, translate, broadcast, modify, license, transmit, distribute, exhibit, perform, publish, or display any part, in any form, or by any means. Reverse engineering, disassembly, or decompilation of this software, unless required by law for interoperability, is prohibited.

The information contained herein is subject to change without notice and is not warranted to be error-free. If you find any errors, please report them to us in writing.

If this is software or related documentation that is delivered to the U.S. Government or anyone licensing it on behalf of the U.S. Government, then the following notice is applicable:

U.S. GOVERNMENT END USERS: Oracle programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, delivered to U.S. Government end users are "commercial computer software" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations. As such, use, duplication, disclosure, modification, and adaptation of the programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, shall be subject to license terms and license restrictions applicable to the programs. No other rights are granted to the U.S. Government.

This software or hardware is developed for general use in a variety of information management applications. It is not developed or intended for use in any inherently dangerous applications, including applications that may create a risk of personal injury. If you use this software or hardware in dangerous applications, then you shall be responsible to take all appropriate fail-safe, backup, redundancy, and other measures to ensure its safe use. Oracle Corporation and its affiliates disclaim any liability for any damages caused by use of this software or hardware in dangerous applications.

Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.

Intel and Intel Xeon are trademarks or registered trademarks of Intel Corporation. All SPARC trademarks are used under license and are trademarks or registered trademarks of SPARC International, Inc. AMD, Opteron, the AMD logo, and the AMD Opteron logo are trademarks or registered trademarks of Advanced Micro Devices. UNIX is a registered trademark of The Open Group.

This software or hardware and documentation may provide access to or information about content, products, and services from third parties. Oracle Corporation and its affiliates are not responsible for and expressly disclaim all warranties of any kind with respect to third-party content, products, and services unless otherwise set forth in an applicable agreement between you and Oracle. Oracle Corporation and its affiliates will not be responsible for any loss, costs, or damages incurred due to your access to or use of third-party content, products, or services, except as set forth in an applicable agreement between you and Oracle.

Contents

Preface

- Audience

- Related Documents

- Documentation Accessibility

1 Creating HTML5 Applications for WebRTC-Enabled Browsers

- About Applications for WebRTC-Enabled Browsers

- About Your Application Development Environment

- About WebRTC Session Controller Signaling Engine

- About the WebRTC Session Controller and Your Applications

- About Supported WebRTC-Enabled Browsers

- About JavaScript

- About the Browser Protocols and Your Applications

- About the Conventions Used in This Guide

2 About Using the WebRTC Session Controller JavaScript API

- About the wsc Namespace

- About Using the WebRTC Session Controller JavaScript API Library

- About the API Used for General Tasks

- About the API Used for Call-Related Tasks

- About the API Used for Message-Related Tasks

- About Extending WebRTC Session Controller JavaScript API

- Managing Sessions with wsc.Session

- Authenticating Users with wsc.AuthHandler

- Handling Session State Changes

- Debugging Your Application with wsc.LOGLEVEL

- Managing Calls with wsc.CallPackage

- Managing a Call with wsc.Call

- Specifying the Configuration for Calls with wsc.CallConfig

- Handling Changes in Call States

- Handling Changes in Media Stream States

- Transferring Data With wsc.DataTransfer

- Sending Data Using wsc.DataSender

- Receiving Data Using wsc.DataReceiver

- About the Code Segments Displayed in This Guide

- About the Application HTML File

- About Web Applications Using WebRTC Session Controller JavaScript API

- General Call Logic of Your Applications

- General Notifications Logic of Your Applications

- WebRTC Session Controller Support Libraries

- Verifying Browser Capabilities

- About Monitoring Your Application WebSocket Connection

- About Handling Events in the Application Environment

- Managing the Sessions in Your Application

- How Your Application Saves Session Information

- Recreating the Session Using the Session ID

- How WebRTC Session Controller JavaScript API Library Restores Application Data

- Restoring Your Application Package Data After Your Application Pages Reload

- Restoring CallPackage Data After Pages Reload

- Restoring Extended MessageAlertPackage Data After Pages Reload

- Restoring a Call Session

- Restoring a Subscription Session

- Resuming Your Application Operation

3 Setting Up Security

- Handling Login to WebRTC Session Controller

- Login Using Basic Authentication

- Redirecting After a Successful Login

- Login Using OAuth Authentication

- Login Using Form-Based Authentication

- Login Using REST Authentication

- Handling Logout from WebRTC Session Controller

4 Setting Up Audio Calls in Your Applications

- About Implementing the Audio Call Feature in Your Applications

- About the WebRTC Session Controller JavaScript API Used in Implementing Audio Calls

- Setting Up Audio Calls in Your Applications

- About the Sample Audio Call Application

- Overview of Setting Up the Audio Call Feature in Your Application

- Setting Up the General Elements for the Audio Call Feature

- Setting Up the Main Objects and Values

- Current Stage in the Development of the Audio Call Feature

- Enabling Users to Make Audio Calls From Your Application

- Setting Up the Configuration for Calls Supported by the Application

- Setting Up the Session Object

- Setting Up the Call Package for the Session

- Handling Session State Changes

- Obtaining the Callee Information

- Current Stage in the Development of the Audio Call Feature in Your Application

- Initial Actions of the Sample Audio Call Application

- Implementing the Logic to Set Up the Call Session

- Starting a Call From Your Application

- Retrieving the Appropriate Authentication Headers

- About Digest Access Authentication

- Creating the authHeader Object for the Response

- Setting Up the Event Handler for Call State Changes

- Setting Up the Event Handler for the Media Streams

- Current Stage in the Development of the Audio Call Feature in Your Application

- How the Sample Audio Call Application Starts a Call

- Enabling Your Application Users to Receive Calls

- Responding to Your User's Actions on an Incoming Call

- Current Stage in the Development of the Audio Call Feature in Your Application

- How the Sample Audio Call Application Handles Incoming Calls

- How a Call is Established in the Sample Audio Call Application

- Monitoring the Call

- How the Sample Audio Call Application Monitors a Call

- Ending the Call

- Current Stage in the Development of the Audio Call Feature in Your Application

- Closing the Session When the User Logs Out

- Other Actions on Calls

- Gathering Information on the Current Call

- Supporting Multiple Calls Using CallPackage

- Managing Interactive Connectivity Establishment Interval

- About the Use of ICE and ICE Candidate Trickling

- About WebRTC Session Controller Signaling Engine and the ICE Interval

- Retrieving the Current ICE Interval for the Call

- Setting Up the ICE Interval for the Call

- Enabling Trickle ICE to Improve Application Performance

- Updating a Call

- Reconnecting Dropped Calls

5 Setting Up Video Calls in Your Applications

- About Implementing the Video Call Feature in Your Applications

- About the WebRTC Session Controller JavaScript API Used in Implementing Video Calls

- Setting Up Video Calls in Your Applications

- Setting Up the Video Display

- Specifying the Video Direction in the Call Configuration

- Managing the Video Display on Your Application Page

- Managing the Video Streams in the Media Stream Event Handler

6 Setting Up Data Transfers in Your Applications

- About Data Transfers and Signaling Engine

- About Setting Up Data Transfers in Your Applications

- About the API Used to Manage the Transfer of Data

- Managing Data Channels Using wsc.DataTransfer

- Sending Data Using wse.DataSender

- Handling Incoming Data Using wsc.DataReceiver

- Setting up Data Transfers in Your Application

- Setting Up the General Elements for the Data Transfer Feature

- Declaring Variables Specific to the Chat Sessions

- Setting Up the Configuration for Data Transfers in Chat Sessions

- Assigning the Data Transfer Event Handler to the Call Package

- Obtaining the Callee Information

- Starting the Call with the Data Transfer Feature in the Call

- Responding to Your User's Actions on an Incoming Call

- Setting Up the Chat Session User Interface

- Setting Up the Data Transfer State Event Handler for the Chat Session

- Managing the Flow of Data

- Handling the Open State of the Data Channel

- Handling the Received Text

- Sending the Text

- Handling the Closed State of the Data Channel

- Monitoring the Chat Session

7 Setting Up Message Alert Notifications

- About Message Alert Notifications and Signaling Engine

- Handling Message Notifications in Your Web Applications

- About the API Used to Manage Message Alert Notifications

- Managing Message Alert Notifications with wsc.MessageAlertPackage

- Handling Notifications with wsc.Notification

- Subscribing to Notifications with wsc.Subscription

- Getting Message Summary Information

- Retrieving Message Counts from Message-Summary Notifications

- Managing Subscriptions

- Enabling the User to Subscribe to Notifications

- Setting Up a Subscription

- Creating a Subscription

- Verifying that a Subscription is Active

- Handling the Ending of a Subscription

- Restoring a Subscription

- Managing Notifications

- Handling Message Notifications

8 Developing Rich Communication Services Applications

- About Rich Communication Services

- About WebRTC Session Controller RCS Support

- Prerequisites

- About the Examples in This Chapter

- Capabilities Exchange

- Sample Capability Exchange HTML File

- Initiate a Capability Exchange Query

- Handle a Capability Query Response

- Handle an Incoming Capability Query

- Handle Capability Exchange Errors

- Initiate a Capability Exchange Request in a Call

- Sending a Standalone Message

- Messaging Sample HTML File

- Send a Message

- Handle an Incoming Message

- Handle Messaging Success Events

- Handle Messaging Error Events

- Creating an RCS Chat Application

- Chat Sample HTML File

- Implementing Chat

- Initiate the Chat Session

- Send a Chat Message

- Handle Incoming Chat Requests

- Handle Chat Signaling State Changes

- Handle Chat Connection State Changes

- Handle Incoming Chat Messages

- Handle Message Transmission Success and Failure Events

- Handle Participant Typing Notifications

- Implementing File Transfer

- File Exchange Example HTML File

- Setup a File Transfer Session

- Control and Return Information on the File Transfer

- Terminate the File Transfer Session

- Send a File from Your Application

- Handle Incoming File Transfer Requests

- Handle File Transfer Signaling State Changes

- Handle File Transfer Connection State Changes

- Handle Message Transmission Success and Failure Events

- Handle File Data Transmission

- Handle File Transfer Progress Updates

9 Creating WebRTC Session Controller Applications Compatible with Internet Explorer

- About WebRTC Session Controller Internet Explorer Support

- System Requirements

- Supported Flash Plug-ins

- Supported Browsers

- Supported Video and Audio Codecs

- About the WebRTC Session Controller Flash Interface

- Installing the Flash Extension Patch

- Downloading the Flash Extension Patch

- Installing the Flash Extension on Signalling Engine

- Grant a WebRTC Session Controller Application Access to the Flash extension

- Configuring Flash Extension Support for Media Engine

- About ME Flash Extension Configuration

- Configuring RTMP

- Configuring RTMPS

- Configuring RTMPT

- Adding Flash Support to a Session Config

- Adding Flash Support to Your WebRTC Web Application

- WebRTC Session Controller JavaScript Flash Support Overview

- Downloading the Google SWFObject JavaScript Support Library

- Referencing the WebRTC Session Controller Flash JavaScript Extension Libraries

- Initializing the Flash JavaScript Extension

- Determining Flash Browser Support

- Passing Flash/WebRTC Support Information to a WebRTC Session Controller Session

- Initiating a Call Using the Flash Extension

- Terminating a Flash Extension Call

- Processing an Incoming Audio/Video Call

- Determining Whether a Particular Call is Flash-based

10 Extending Your Applications Using WebRTC Session Controller JavaScript API

- About the Default Messaging Mechanism Used by Your Applications

- About Extending the WSC Namespace

- Extending Objects Using the wsc.extend Method

- Extending Sessions with wsc.ExtensibleSession Class

- Extending and Overriding WebRTC Session Controller JavaScript API Object Methods

- Handling Extended Call Sessions with CallPackage.onMessage

- Preparing Custom Calls with CallPackage.prepareCall

- Inserting Calls into a Session with CallPackage.putCall

- Processing Custom Messages for a Call with Call.onMessage

- Extending Headers in Call Messages

- Handling Custom Message Notifications

- Handling Extensions to Notifications with MessageAlertPackage.onMessage

- Handling Additional Headers in Messages

- About Additional Headers in Messages

- Handling Additional Headers

- Managing Calls with Additional Headers

- Working with wsc.ExtensibleSession

- Creating an Extensible Session in Your Application

- Creating Custom Packages Using the ExtensibleSession Object

- Saving Your Custom Session

- Sending And Receiving Custom Messages

- About the API Classes Used to Create Custom Message

- wsc.Message

- wsc.Message#control

- wsc.Message#header

- wsc.Message#payload

- Managing Custom Message Data Flows

- Sending a Custom Message to Signaling Engine

- Processing an Incoming Custom Message

- Customizing Your Applications by Extending the Package Objects

- Working with Extended CallPackage Objects

- Creating an Extended Call Package

- Registering the Extended Package with the Session

- Extending the Methods and Event Handlers in the Extended Call Package

- Working with Extended Calls

- Working with Extended MessageAlertPackage Objects

- Extending the Methods and Event Handlers

- Extending the MessageAlertPackage to Support Other Message Events

11 WebRTC Session Controller JavaScript API Error Codes and Errors

- About wsc.ERRORCODE

- About the Error Codes

- Using wsc.ErrorInfo

- About the Error Handlers

- Handling Errors Related to Sessions

- Handling Errors Related to Calls

- Handling Errors Related to Data Transfers

- Handling Errors Related to Subscriptions

12 Sample Audio Call Application

- About the Sample Audio Call Application

- The Sample Audio Call Application Code

13 Developing WebRTC-enabled Android Applications

- About the Android SDK

- About the Android SDK WebRTC Call Workflow

- Prerequisites

- Android SDK System Requirements

- About the Examples in This Chapter

- General Android SDK Best Practices

- Installing the Android SDK

- WebRTC Session Controller SDK Required Permissions

- Configuring Logging

- Authenticating with WebRTC Session Controller

- Initialize the CookieManager

- Initialize a URL Connection

- Configure Authorization Headers if Required

- Configure the SSL Context if Required

- Build the HTTP Context

- Connect to the URL

- Configuring Interactive Connectivity Establishment (ICE)

- Creating a WebRTC Session Controller Session

- Implement the ConnectionCallback Interface

- Create a Session Observer Object

- Build the Session Object

- Configure Session Properties

- Adding WebRTC Voice Support to your Android Application

- Initialize the CallPackage Object

- Place a WebRTC Voice Call from Your Android Application

- Initialize the Call Object

- Configure Trickle ICE

- Create a Call Observer Object

- Register the CallObserver with the Call Object

- Create a CallConfig Object

- Configure the Local MediaStream for Audio

- Start the Audio Call

- Terminating the Audio Call

- Receiving a WebRTC Voice Call in Your Android Application

- Create a CallPackage Observer

- Bind the CallPackage Observer to the CallPackage

- Adding WebRTC Video Support to your Android Application

- Find and Return the Video Capture Device

- Create a GLSurfaceView in Your User Interface Layout

- Initialize the GLSurfaceView Control

- Placing a WebRTC Video Call from Your Android Application

- Create a CallConfig Object

- Configure the Local MediaStream for Audio and Video

- Start the Video Call

- Terminate the Video Call

- Receiving a WebRTC Video Call in Your Android Application

- Upgrading and Downgrading Calls

- Handle Upgrade and Downgrade Requests from Your Application

- Handle Incoming Upgrade Requests

14 Developing WebRTC-enabled iOS Applications

- About the iOS SDK

- Supported Architectures

- About the iOS SDK WebRTC Call Workflow

- Prerequisites

- iOS SDK System Requirements

- About the Examples in This Chapter

- Installing the iOS SDK

- Authenticating with WebRTC Session Controller

- Initialize a URL Object

- Configure Authorization Headers if Required

- Connect to the URL

- Configure the SSL Context if Required

- Retrieve the Response Headers from the Request

- Build the HTTP Context

- Configure Interactive Connectivity Establishment (ICE)

- Creating a WebRTC Session Controller Session

- Implement the WSCSessionConnectionDelegate Protocol

- Implement the WSCSession Connection Observer Protocol

- Build the Session Object and Open the Session Connection

- Configure Additional WSCSession Properties

- Adding WebRTC Voice Support to your iOS Application

- Initialize the CallPackage Object

- Place a WebRTC Voice Call from Your iOS Application

- Add the Audio Capture Device to Your Session

- Initialize the Call Object

- Configure Trickle ICE

- Create a CallObserverDelegate Protocol

- Register the CallObserverDelegate Protocol with the Call Object

- Create a WSCCallConfig Object

- Configure the Local MediaStream for Audio

- Start the Audio Call

- Terminating the Audio Call

- Receiving a WebRTC Voice Call in Your iOS Application

- Create a CallPackageObserverDelegate

- Bind the CallPackage Observer to the CallPackage

- Adding WebRTC Video Support to your iOS Application

- Add the Audio and Video Capture Devices to Your Session

- Configure a View Controller and a View Display Incoming Video

- Placing a WebRTC Video Call from Your iOS Application

- Create a WSCCallConfig Object

- Configure the Local WSCMediaStream for Audio and Video

- Bind the Video Track to the View Controller

- Start the Video Call

- Terminate the Video Call

- Receiving a WebRTC Video Call in Your iOS Application

- Upgrading and Downgrading Calls

- Handle Upgrade and Downgrade Requests from Your Application

- Handle Incoming Upgrade Requests

Preface

This document provides an overview of the Oracle Communications WebRTC Session Controller application programming interfaces (API) for JavaScript, Android, and iOS, that support multimedia and data stream communications in multiple platforms running under multiple protocols.

Audience

This document is intended for developers who use WebRTC Session Controller JavaScript, Android, or iOS APIs to create WebRTC enabled applications.

Related Documents

For more information, see the following documents:

- Oracle Communications WebRTC Session Controller Concepts

- Oracle Communications WebRTC Session Controller Extension Developer's Guide

- Oracle Communications WebRTC Session Controller JavaScript API Reference

- Oracle Communications WebRTC Session Controller Android API Reference

- Oracle Communications WebRTC Session Controller iOS API Reference

- Oracle Communications WebRTC Session Controller System Administrator's Guide

- Oracle Communications WebRTC Session Controller Security Guide

Documentation Accessibility

For information about Oracle's commitment to accessibility, visit the Oracle Accessibility Program website at http://www.oracle.com/pls/topic/lookup?ctx=acc&id=docacc.

Access to Oracle Support

Oracle customers that have purchased support have access to electronic support through My Oracle Support. For information, visit http://www.oracle.com/pls/topic/lookup?ctx=acc&id=info or visit http://www.oracle.com/pls/topic/lookup?ctx=acc&id=trs if you are hearing impaired.

1 Creating HTML5 Applications for WebRTC-Enabled Browsers

This chapter presents an overview of how you can use the Oracle Communications WebRTC Session Controller JavaScript application programming interface (API) library to create multimedia applications that run in WebRTC-enabled browsers.

About Applications for WebRTC-Enabled Browsers

WebRTC-enabled browsers are web browsers that support real-time communications (RTC) capabilities. The WebRTC standardization effort employs standardized browser capabilities, JavaScript API, and HTML5 to support real-time multimedia communication in applications without the use of any browser plugins. For more information, see the WebRTC website at http://www.webrtc.org.

The WebRTC Session Controller JavaScript API enables your web applications to communicate with WebRTC Session Controller so that applications can allow the user to make calls, configure callbacks to handle incoming calls, notifications, media state in the call, session state changes, and so on.

Web applications developed for WebRTC-enabled browsers can establish real-time communication with each other and, when used in conjunction with WebRTC Session Controller, with legacy network services. To access such applications, a subscriber needs to be connected to the Internet and use a device (such as a mobile phone, a laptop, a tablet or a desktop computer) equipped with a WebRTC-enabled browser.

Such applications enable end users to perform a multitude of tasks. Suppose that you create an application for the web pages of a real-estate company. When an interested party, such as a buyer's agent, accesses the company's web page, your application starts to respond to the agent's actions while the agent is on that web page. The content of the session managed by your application could include:

- A call session when the buyer's agent uses the calling feature in your application to contact and communicate with the seller's agent

- An online video chat between the two agents, where your application manages the audio and video synchronization

- Sending and/or receiving text or data files, such as a data sheet about the property with a photo of the house

- Sending and/or receiving video data, such as an online tour of the house

- Signing of some initial terms using electronic signatures

About Your Application Development Environment

WebRTC Session Controller supports the following building blocks required for your web application development:

- WebRTC Session Controller Signaling Engine. See "About WebRTC Session Controller Signaling Engine".

- WebRTC Session Controller. See "About the WebRTC Session Controller and Your Applications".

- WebRTC-enabled browsers. See "About Supported WebRTC-Enabled Browsers".

- JavaScript. See "About JavaScript".

- JavaScript Object Notation. See "About the Browser Protocols and Your Applications".

About WebRTC Session Controller Signaling Engine

WebRTC Session Controller Signaling Engine manages the connectivity between the browser and network services endpoints. Sitting between the browser and the telecommunication network, it does the following:

- Acts as an intermediary between the web browser and the telecommunication network services, thereby making the browser a client of the network services.

- Provides security to the interactions between your applications and the telecommunication network services.

- Provides the JavaScript API enabling you to develop applications targeted for WebRTC-enabled browsers.

For more information on Signaling Engine, see Oracle Communications WebRTC Session Controller Concepts.

About the WebRTC Session Controller and Your Applications

The WebSocket uniform resource identifier (URI) your application uses to connect to the WebRTC Session Controller identifies your application, its configuration, and extensions to that default configuration (when present). All interactions between the WebRTC Session Controller and your application take place within that default or extended configuration.

For more information on WebRTC Session Controller, see Oracle Communications WebRTC Session Controller Extension Developer's Guide.

About Supported WebRTC-Enabled Browsers

WebRTC Session Controller works with any WebRTC-enabled browser. For a listing of browser versions that have been tested with WebRTC Session Controller, see http://www.oracle.com/technetwork/developer-tools/webrtc/documentation/index.html.

In addition, you can create WebRTC applications that work with Microsoft Internet Explorer versions 8 through 11. For more information, see Chapter 9, "Creating WebRTC Session Controller Applications Compatible with Internet Explorer."

About JavaScript

The business logic of a web application is implemented in JavaScript along with HTML and CSS for the presentation layer. Applications written in JavaScript can interact with the user, control the browser, communicate asynchronously, and alter the content displayed on the browser page.

About the Browser Protocols and Your Applications

WebRTC-enabled browsers are equipped with the WebRTC API. For more information, see http://www.webrtc.org/reference/native-apis.

The WebRTC Session Controller JavaScript API library communicates with WebRTC Session Controller using the JSONRTC protocol for communication-related functions such as call control, file transfer, and message notification. The JSONRTC protocol is a sub protocol of the MessageBroker WebSocket protocol. For more information on JSONRTC, see Appendix A of the Oracle Communications WebRTC Session Controller Extension Developer's Guide.

Your applications can use the WebRTC Session Controller JavaScript API to set up and manage communication-related functions associated with calls and subscriptions. See "About Using the WebRTC Session Controller JavaScript API" for a description of the components of the WebRTC Session Controller JavaScript API.

About the Conventions Used in This Guide

This guide uses the following conventions:

- Whenever the term "application" is used, it refers to a WebRTC-enabled Web application.

- The WebRTC Session Controller JavaScript API class objects, their events, and methods are shown in bold font. For example:
Session, CallConfig, onIncomingCall, and getValue

- Italicized words are placeholders. For example:
wscSession, callObj, callConfig, and so on.

2 About Using the WebRTC Session Controller JavaScript API

This chapter presents a general overview of the Oracle Communications WebRTC Session Controller JavaScript application programming interface (API) library for the use of web application developers.

Note:
This document assumes that you have experience with developing applications using HTML5 features designed for WebRTC-enabled browsers. Its focus is restricted to how you can use the WebRTC Session Controller JavaScript API library to manage real-time communication featuring media stream and data transfers.

This chapter covers the following topics:

- About the wsc Namespace

- About the Application HTML File

- About Monitoring Your Application WebSocket Connection

- About Handling Events in the Application Environment

- Managing the Sessions in Your Application

For information on error codes used by this API library, see "WebRTC Session Controller JavaScript API Error Codes and Errors".

For information on the Service Provider Interface (SPI) functions supported by this API library, see "Extending Your Applications Using WebRTC Session Controller JavaScript API".

Note:
Creating and implementing the design of the application's page, the appearance of its user interface and display elements are beyond the scope of this document.

See WebRTC Session Controller JavaScript API Reference for more information on the individual WebRTC Session Controller JavaScript API classes.

About the wsc Namespace

The wsc namespace exposes the WebRTC Session Controller JavaScript API library so that you can access specific objects and methods in your applications.

About Using the WebRTC Session Controller JavaScript API Library

The WebRTC Session Controller JavaScript API library enables you to set up and manage real-time communication-related functionality associated with a call session, for example, audio and video call management, file transfers, message notifications, and so on.

About the API Used for General Tasks

The following WebRTC Session Controller JavaScript API classes are used to perform general tasks in your application:

- wsc.Session to manage the application session. See "Managing Sessions with wsc.Session".

- wsc.AuthHandler to authenticate users. See "Authenticating Users with wsc.AuthHandler".

- wsc.SESSIONSTATE to manage changes in the state of the application session. See "Handling Session State Changes".

- wsc.LOGLEVEL to set the logging level. See "Debugging Your Application with wsc.LOGLEVEL".

- wsc.ERRORCODE to respond to errors. See "WebRTC Session Controller JavaScript API Error Codes and Errors".

In addition, your application needs to verify the media streaming capabilities of the browser. See "Verifying Browser Capabilities".

About the API Used for Call-Related Tasks

The following WebRTC Session Controller JavaScript API classes are used to perform call-related tasks in your application:

- wsc.CallPackage to manage call applications. See "Managing Calls with wsc.CallPackage".

- wsc.Call to manage a call. See "Managing a Call with wsc.Call".

- wsc.CallConfig to set up the capabilities of the call. See "Specifying the Configuration for Calls with wsc.CallConfig".

- wsc.CALLSTATE to manage the changes in the call state. See "Handling Changes in Call States".

- wsc.MEDIASTREAMEVENT to manage the changes in the media stream. See "Handling Changes in Media Stream States".

- wsc.DataTransfer to manage a data channel between two peers. See "Transferring Data With wsc.DataTransfer".

- wsc.DataSender to send raw data over the data channel. See "Sending Data Using wsc.DataSender".

- wsc.DataReceiver to receive raw data over the data channel. See "Receiving Data Using wsc.DataReceiver".

About the API Used for Message-Related Tasks

The WebRTC Session Controller JavaScript API classes used to perform message and notification-related tasks in your application are described in "Setting Up Message Alert Notifications".

About Extending WebRTC Session Controller JavaScript API

The ways in which you can extend your applications by extending WebRTC Session Controller JavaScript API classes are described in "Extending Your Applications Using WebRTC Session Controller JavaScript API".

Managing Sessions with wsc.Session

You manage the WebSocket connection between your application and WebRTC Session Controller using the wsc.Session class. It represents a persistent association between your application and WebRTC Session Controller Signaling Engine. All the media streams, data transfers, and message alert notifications in your application take place within the scope of wsc.Session.

When your application page loads and the user logs in to your application, you first create an instance of the Session class before you use any of the other WebRTC Session Controller JavaScript API objects associated with calls, data transfers, or message notifications.

You provide the following information when you create a session object:

- The user's name

- The WebSocket URI

- The callback function in your application that should be invoked when the session is created

- The callback function in your application that should be invoked when there is an error in creating the session

See "Setting Up the Session Object" for more information.

Your application's session object is associated with a unique session identifier. If you are creating the session object for the first time, WebRTC Session Controller Signaling Engine assigns the session identifier. You can use this identifier to refresh the session, for example, when the application page reloads. When the session has been successfully created, provide the settings to manage the connection. See "About Monitoring Your Application WebSocket Connection".

Your application's session may have many changes in its state. See "Handling Session State Changes" for information on session states and how your application can manage session state changes.

Authenticating Users with wsc.AuthHandler

You authenticate your application users with the wsc.AuthHandler class. This class enables your application to ensure that the user credentials are appropriate and will not disrupt message flow during the life of the session.

For example, based on your user's action, your application may send a request to a target Uniform Resource Locator (URL). WebRTC Session Controller Signaling Engine forwards the request to the target URL. The Session Initialization Protocol (SIP) proxy or registrar server may not allow that request to go further in the target environment if it does not have enough user credential information to do so. When that happens, the server sends back a challenge to WebRTC Session Controller Signaling Engine asking for more credential information.

On receiving the challenge from the SIP server, Traversal Using Relays around Network Address Translation (TURN) server, or proxy or registrar server, WebRTC Session Controller Signaling Engine forwards the challenge to the WebRTC Session Controller JavaScript API library. The WebRTC Session Controller JavaScript API library invokes the refresh event in your application's authentication handler. Your application can respond to such a challenge by retrieving the user credentials and returning that information as a JSON object. On receiving this information, WebRTC Session Controller Signaling Engine can then send your application's response to the SIP proxy/registrar server.

When you create an instance of the wsc.AuthHandler class in your application, set up a callback function to handle the AuthHandler.refresh event. In the following example, an application creates an authentication handler called authHandler and assigns a callback function called refreshAuth to its refresh event:

// Create the session.
// Here, userName is null. WebRTC Session Controller can determine it
// by the cookie of the request.
wscSession = new wsc.Session(null, webSocketUri, sessionSuccessHandler, sessionErrorHandler);
// Register a wsc.AuthHandler with the session,
// which provides customized authentication info, such as username/password.
var authHandler = new wsc.AuthHandler(wscSession);
authHandler.refresh = refreshAuth;

The callback function has two parameters, authType and authHeaders. The authType entry indicates the authentication type and is one of the following entries:

- wsc.AUTHTYPE.TURN: The type of authentication that allows for the client to authenticate with a TURN server. TURN servers facilitate communication between clients residing behind network address translator (NAT) routers or firewalls.

- wsc.AUTHTYPE.SERVICE: The type of authentication used when a back-end SIP application, such as the proxy/registrar, requires user authentication.

Use the value in authType to obtain the authentication information from the authHeaders and return it as a JSON object, as shown in Example 4-8, "Template for the refreshAuth Function()".

Handling Session State Changes

Session state values are constants, such as CLOSED or CONNECTED. Session states are defined in the wsc.SESSIONSTATE enumerator.

If wscSession is your application's session object, you can set up a callback function and assign that function to your application's Session.onSessionStateChange event handler. Whenever the state of your application's session changes, the WebRTC Session Controller JavaScript API library invokes your application's Session.onSessionStateChange event handler and provides the new state.

In the callback function, you can check the new session state against the defined constants and set up appropriate actions to respond to the new state. For example, a change in the value of wsc.SESSIONSTATE from RECONNECTING to CONNECTED indicates that the attempt to reconnect succeeded and that the application can proceed. Or if the state changes from RECONNECTING to FAILED, the attempt to reconnect failed. In each case, your application may need to take appropriate action with respect to the user.

For a more information on the wsc.SESSIONSTATE enumerator, see Oracle Communications Web Session Controller JavaScript API Reference.

Debugging Your Application with wsc.LOGLEVEL

You use the wsc.LOGLEVEL enumerator object to set up the type of records your application must log. The supported log levels are indicated by the data constants:

- DEBUG (0)

- INFO (1)

- WARN (2)

- ERROR (3)

- OFF (4)

To set up the log level for debugging, pass the desired constant to the setLogLevel method at the start of your JavaScript application:

wsc.setLogLevel(wsc.LOGLEVEL.DEBUG);

Alternatively, you can directly input the associated numeric value, in this case, 0, corresponding to the DEBUG log level:

wsc.setLogLevel(0);

See "Sample Setup of Global Variables and WebSocket URI".

Managing Calls with wsc.CallPackage

You use the wsc.CallPackage class to manage audio or video communication and/or data transfers in calls made from or received by your application. When you create an instance of wsc.CallPackage class, the WebRTC Session Controller JavaScript API library handles the messaging and call flow for all calls created through that object for that application session.

In the following example code, an application creates an instance of wsc.CallPackage named callPackage. Here, wscSession is the application's session with WebRTC Session Controller Signaling Engine.

var callPackage;
...
callPackage = new wsc.CallPackage(wscSession);

After creating an instance of the CallPackage class in your application, you assign a callback function to handle each of the following events:

- An incoming call, using the onIncomingCall event handler.
In this callback function, you implement the logic to process the incoming call, such as filtering to reject calls from blacklisted numbers or responding when the user accepts or declines the call. For information on how the default CallPackage class can be used in your applications, see "Setting Up Audio Calls in Your Applications".

- A reconnected call, using the onResurrect event handler.
In this callback function, you implement the logic to handle the call that was dropped momentarily. See "Reconnecting Dropped Calls" for more information.

You use your application's CallPackage object to create outgoing calls. See "Managing a Call with wsc.Call".

See "Extending and Overriding WebRTC Session Controller JavaScript API Object Methods" for more information on extending the Call and CallPackage API classes.

Managing a Call with wsc.Call

You manage all audio, video streams, or data transfers that are associated with a single call session, by using the wsc.Call class. The wsc.Call object represents a single call and is used within a call package.

You can set up your application's Call object in the following ways:

- When your application user initiates a call, create the call object using the CallPackage.createCall method and provide your application's call configuration.

- When your application accepts an incoming call, use the incoming call object and the remote call configuration for the resulting call session. The WebRTC Session Controller JavaScript API library invokes the CallPackage.onIncomingCall event handler and provides the incoming call object and the caller's call configuration, as shown in Example 4-13, "Sample onIncomingCall Function".

You manage changes in the state of the call and its associated audio, media or data channel with the event handlers of the wsc.Call class, by implementing the logic in the callback function you assign for each event. For:

- Call state changes, use the onCallStateChange event handler. See "Handling Changes in Call States".

- Media state changes, use the onMediaStreamEvent event handler. See "Handling Changes in Media Stream States".

- Data transfer object creation, use the onDataTransfer event handler. See "Transferring Data With wsc.DataTransfer".

Specifying the Configuration for Calls with wsc.CallConfig

Specify the audio, video, and data channel capability for calls made from your application, with the wsc.CallConfig class.

When you create an instance of the wsc.CallConfig class in your application, you set up the direction of the audio and video elements in the local media stream. Use the wsc.MEDIADIRECTION enumerator to specify the direction of the local media stream as one of the following:

- wsc.MEDIADIRECTION.SENDRECV which indicates that the local media stream can send and receive the media stream.

- wsc.MEDIADIRECTION.SENDONLY which indicates that the local media stream can send the media stream.

- wsc.MEDIADIRECTION.RECVONLY which indicates that the local media stream can receive the media stream.

- wsc.MEDIADIRECTION.NONE which indicates that media is not supported.

Set up the configuration for the data transfers in the dataChannelConfig parameter with key-value pairs in JSON format. Input the settings for the media stream and data transfers when you create the call configuration object in your application.

In the following example, an application sets up the local media stream to send and receive audio calls only:

var audioMediaDirection = wsc.MEDIADIRECTION.SENDRECV;
var videoMediaDirection = wsc.MEDIADIRECTION.NONE;

The application sets up the configuration for data transfers in dtConfigs with:

var dtConfigs = new Array();
dtConfigs[0] = {"label":"DataLabel", "reliable" : false };

Finally, the application uses those parameters to create a call configuration object called callConfig:

var callConfig = new wsc.CallConfig(audioMediaDirection,videoMediaDirection, dtConfigs);

See "Verifying Browser Capabilities" for information on how to verify the browser support for media streams.

Handling Changes in Call States

Your application needs to respond to the changes in the state of a call. The fields of the wsc.CALLSTATE enumerator object hold the various states of a call, such as STARTED, RESPONSED, and ENDED. For more information on the wsc.CALLSTATE enumerator, see Web Session Controller JavaScript API Reference.

The WebRTC Session Controller JavaScript API library also provides the wsc.CallState class which represents the state of the call. To process changes to the current call within the callback function you assign to your application's Call.onCallStateChange event handler, use the wsc.Callstate#status class and determine the call state status, the code for the current state, and the reason for the current state.

See "Setting Up the Event Handler for Call State Changes".

Handling Changes in Media Stream States

The media stream associated with your application is made up of two media components, local (in your application's browser) and remote (the other party's browser).

Your application needs to respond to changes in the media stream states of the call, whether it is voice or video. The WebRTC Session Controller JavaScript API library provides the wsc.MEDIASTREAMEVENT enumerator which defines the following three states each for the local and remote streams.

- Added (LOCAL_STREAM_ADDED or REMOTE_STREAM_ADDED)

- Removed (LOCAL_STREAM_REMOVED or REMOTE_STREAM_REMOVED)

- In error (LOCAL_STREAM_ERROR or REMOTE_STREAM_ERROR)

See "Setting Up the Event Handler for the Media Streams" for information on how to use the wsc.MEDIASTREAMEVENT enumerator.

For a more information on the wsc.MEDIASTREAMEVENT enumerator, see Oracle Communications WebRTC Session Controller JavaScript API Reference.

Transferring Data With wsc.DataTransfer

If your application supports features such text messaging, chat sessions, and file transfers, you can set up data transfer objects to manage the corresponding data channels in your application. Additionally, you can use the data channels with or without the audio or video streams.

The wsc.DataTransfer class manages a data channel between two peers. Each data transfer has a label. See "Specifying the Configuration for Calls with wsc.CallConfig" for information on dataChannelConfig, the data channel configuration parameter in your application's CallConfig object.

You can retrieve the following from your application's DataTransfer object:

- The sender of the data transfer as an instance of wsc.DataSender class, by using the getSender method.

- The receiver of the data transfer as an instance of wsc.DataReceiver class, by using the getReceiver method.

- The state of the data transfer, by using the getState method.

To manage the open, closed, and error states of a data transfer, use the onOpen, onClose, and onError event handlers associated with your application's DataTransfer object.

See "Setting Up Data Transfers in Your Applications" for more information on how you can create applications that support data transfers.

Sending Data Using wsc.DataSender

The wsc.DataSender API works in connection with wsc.DataTransfer and wsc.DataReceiver API class objects.

If your application supports the sending of raw data, it can send a raw data object in the data channel of a data transfer as a string or a binary large object (BLOB) in your application's DataTransfer object. You can retrieve the identity of the sender by using the getSender() method of your application's DataSender object. Set up the data object that is to be sent and send it using the send method of the DataSender object in your application. See "Sample Send Function" for more information.

Receiving Data Using wsc.DataReceiver

The wsc.DataReceiver class works in connection with wsc.DataTransfer and wsc.DataSender classes.

If your application supports receiving raw data, and receiver is the instance of wsc.DataReceiver in your application, set up a callback function for the application's receiver.onMessage event handler. In that callback function, retrieve and handle the retrieved data as required by your application. For example:

receiver.onMessage = function(evt) {
var rcvdDataElm = document.getElementById("rcvData");
rcvdDataElm.value = evt.data;
...
}

Here, evt is the raw data in its entirety such as a text string, a BLOB, or array data.

About the Code Segments Displayed in This Guide

The example code segments shown in this guide focus on the features of the WebRTC Session Controller JavaScript API library and use minimal HTML5 elements for display aspects such as messages and control buttons. Any description of the display aspects of your applications and their CSS elements are beyond the scope of this guide.

The sample applications described in this guide show the use of the console.log method for displaying debug messages. When you create your applications, use the JavaScript Console API methods supported in your application's web browser to assist you in your application development process.

About the Application HTML File

This section describes the following aspects of your application's HTML file:

- About Web Applications Using WebRTC Session Controller JavaScript API

- WebRTC Session Controller Support Libraries

- Verifying Browser Capabilities

- WebRTC Session Controller JavaScript API Error Codes and Errors

About Web Applications Using WebRTC Session Controller JavaScript API

Every web application that uses audio, media stream, or data transfer (such as chat sessions) does so because of a call or a subscription associated with the application user. For web applications using the WebRTC Session Controller JavaScript API library, the Call object or the Subscription object is the critical element for providing communication functionality.

General Call Logic of Your Applications

The general logic associated with calls in web applications comprises the following:

- Enabling a user who is logged in to your application to place a call.
To do so, your application:

- Sets up the logic necessary to obtain information on the recipient of the call (the callee's identifier).

- On receiving the number to call from the user, performs the actions necessary to establish the call session between the caller and callee.

- Enabling a user to accept or decline an audio or video call invitation.
To do so, your application:

- Sets up the necessary elements to respond to the incoming call request and perhaps filters the incoming call.

- If necessary, provides the controls for the callee to accept or decline the audio or video call invitation from the caller.

- If the callee accepts the call, completes the steps to establish the call session.

- If the callee declines the call, takes appropriate steps.

- If the caller cancels the call before it is established, takes appropriate steps.

- Monitoring the established call session until one of the parties ends the call.
To do so, your application:

- Provides the logic necessary to end the call.

- Takes appropriate action based on whether the call was ended or a party logged out (thus ending the session).

General Notifications Logic of Your Applications

The general logic associated with message alert notifications in web applications comprises the following:

- Enabling a user who is logged in to subscribe to receiving notifications.
To do so, your application:

- Sets up the elements necessary for the user to subscribe for notifications.

- On receiving the subscription target from the subscriber, sets up the subscriptions.

- Enabling the user to access and process the received notifications.
To do so, your application:

- Sets up the elements necessary to receive the incoming notification and displays it for the user.

- Sets up the logic to respond to the user's actions on his subscriptions.

WebRTC Session Controller Support Libraries

WebRTC Session Controller provides a set of libraries that you include in your application to support various WebRTC functions. Table 2-1 lists the provided JavaScript files and details the functions each supports.

Table 2-1 WebRTC Session Controller JavaScript Files

File name

Description

wsc-call.js

Call Package API implementation. Include this file in your application to support audio and video calls. For more information see "Setting Up Audio Calls in Your Applications."

wsc-capability.js

Capability exchange API implementation. Include this file in your application to support capability exchange. For more information see "Capabilities Exchange."

wsc-chat.js

Message Session Relay Protocol (MSRP) chat API implementation. Include this file in your application to support one to one and one to many chat functionality. For more information see "Creating an RCS Chat Application."

wsc-common.js

Common utilities and functionality required by other files. This file is always required unless you are including wsc.js.

wsc-filetransfer.js

File transfer API implementation. Include this file to support file transfers in your application. For more information see "Implementing File Transfer."

wsc-flash.js

Module that provides support for implementing WebRTC applications using the Adobe Flash browser plug-in. Used in concert with wsc-ie-adapter.js. For more information, see Chapter 9, "Creating WebRTC Session Controller Applications Compatible with Internet Explorer."

wsc-ie-adapter.js

Module that provides Microsoft Internet Explorer (IE) specific support. Used in concert with wsc-flash.js.

wsc-messaging.js

Stand alone messaging API implementation. Include this file to support basic messaging. For more information see "Sending a Standalone Message."

wsc-msgalert.js

Message notification API implementation. Include this file to support message alerts. For more information see "Setting Up Message Alert Notifications."

wsc.js

A combined file including all of the WebRTC Session Controller APIs.

You insert references to the appropriate libraries in the head element of your application's HTML file.

Example 2-1 Referencing WebRTC Session Controller JavaScript Libraries

<head>
...
<script type="text/JavaScript" src="wsc_context_root/api/wsc-common.js"></script>
<script type="text/JavaScript" src="wsc_context_root/api/wsc-call.js"></script>
...
</head>

In Example 2-1, wsc_context_root represents the HTTP location where the WebRTC Session Controller is provisioned. The libraries wsc-common.js and wsc-call.js are included to support audio and video calling. You can include other libraries from Table 2-1 depending on the requirements of your application.

Note:
The utilities file, wsc-common.js, is required for all applications, unless you are using the composite wsc.js file which includes all of the APIs as well as the utility functions.

Note:
If you need access the entire WebRTC Session Controller JavaScript API, you can include the composite wsc.js file. Generally though, to improve application performance, only include the files supporting the specific functionality you require.

Verifying Browser Capabilities

At the start of your application logic, check your browser's capabilities to access local media including audio and/or video media. If your browser does not appear to support the streaming needs of your application, enable your application to perform a graceful exit. If your browser can access the local media and your application obtains the media stream, your application can attach the media stream to the video/audio HTML5 media element, as appropriate.

In the following example, an application checks its browser to see if it can access the local media. If it cannot, the application calls a local function to perform a graceful exit.

if (!navigator.mozGetUserMedia && !navigator.webkitGetUserMedia) {
// Cannot access media. Call function to exit gracefully.
reportBrowserIssue();
};

Below, the same application employs a utility function named attachMediaStream to attach a media stream to a video/audio element, when necessary:

var attachMediaStream = null;
attachMediaStream = function(element, stream) {
element.src = URL.createObjectURL(stream);
}

About Monitoring Your Application WebSocket Connection

The state of the application session depends on the state of the WebSocket connection between your application and WebRTC Session Controller Signaling Engine. The WebRTC Session Controller JavaScript API library monitors this connection.

When you instantiate your session object, you configure how the functionality in WebRTC Session Controller JavaScript API library checks your application's WebSocket connection. Monitor the state of the connection, by setting the following values in your application's Session object:

- How often the WebRTC Session Controller JavaScript API library must ping the WebRTC Session Controller Signaling Engine:

- Session.busyPingInterval, when there are subsessions inside the session. The default is 3,000 milliseconds (ms).

- Session.idlePingInterval, when there are no subsessions inside the session. The default is 10,000 ms.

- Session.reconnectInterval, which specifies the interval between attempts to reconnect to the WebRTC Session Controller Signaling Engine. The default is 2000 ms.

- Session.retryCount which specifies the number of retry attempts to check the ping-pong time out after which the WebRTC Session Controller JavaScript API library reconnects to the WebRTC Session Controller Signaling Engine.

- Session.reconnectTime, which specifies the maximum time for the interval during which the WebRTC Session Controller JavaScript API library should attempt to reconnect to the server. If the specified time is reached and the connection still fails, no further attempt is made to reconnect to the WebRTC Session Controller Signaling Engine. Instead, the session failureCallback event handler is invoked in your application. The default value is 60,000 ms.

Note:
Verify that the Session.reconnectTime value does not exceed the value configured for "WebSocket Disconnect Time Limit" in WebRTC Session Controller.

When your application is active, these values are used to check the state of the web socket connection.

About Handling Events in the Application Environment

Your application may be affected by the following events in your deployment environment, if the application is in operation when the events occur:

- Client rehydration
At times, the local application page state may be reinitialized if your application user reloaded the page or because the application reloaded itself. See "Managing the Sessions in Your Application".

- Network switch over
A network switch over takes place when the end-user's IP address changes for example, when the end-user's device switches from a WIFI network to 4G network. Issues may arise when there is a switch over in the network environment. When a network switch over takes place, the WebRTC Session Controller JavaScript API library reconnects your application's session with WebRTC Session Controller Signaling Engine and tries to resurrect all the subsessions inside your application's Session object, such as the call and the subscription.

For information on handling a call after a network switch over, see "Restoring a Call Session". For information on handling a subscription after a network switch over, see "Restoring a Subscription Session".

- Clustered server shut down
If the WebRTC Session Controller runs in a cluster environment, the server to which your application browser web browser is connected may shut down. In this scenario, the WebRTC Session Controller JavaScript API library tries to reconnect your application's session to the corresponding fail-over server. If the connection is reestablished, the WebRTC Session Controller JavaScript API library attempts to resurrect all the subsessions inside your application's Session object.

For information on handling a call after a server fail over, see "Restoring a Call Session". For information on handling a subscription after a server fail over, see "Restoring a Subscription Session".

Managing the Sessions in Your Application

When you use the WebRTC Session Controller JavaScript API library in your application, your application can create an instance of the Session object and its subsessions, such as a call session or a subscription session. This section describes how the WebRTC Session Controller JavaScript API library manages the session and subsession information.

Note:
Any discussion on the management of arbitrary session or subsession data is beyond the scope of this document.

How Your Application Saves Session Information

By default, when your application uses the WebRTC Session Controller JavaScript API library and your application's session changes, the WebRTC Session Controller JavaScript API library saves all of the session information associated with the following objects in your application's session:

- CallPackage

- Call

- MessageAlertPackage

- Subscription

The WebRTC Session Controller JavaScript API library stores this application data in JSON format in the browser's sessionStorage object.

Note:
If you extend any WebRTC Session Controller JavaScript API class object, save the session identifier (sessionId) for use when you attempt to create the current session after your application page reloads.

Recreating the Session Using the Session ID

When your application page reloads, if you have saved the session identifier for the previously created session in your application, use that session identifier to recreate the Session object.

In Example 2-2, an application uses the isPageReload variable to set up the session as necessary. If the value in isPageReload indicates that the page has been reloaded, the application attempts to create the current session by providing the sessionId it had previously stored. Otherwise, it creates a new session.

In this application:

- userName is the user name.

- webSocketUri is the WebSocket connection defined earlier. See "Sample Setup of Global Variables and WebSocket URI".

- successCallback is the function to call if the session object was created successfully.

- failureCallback is the function to call if the session object was not created.

- sessionId is the Session ID stored by the application.

Example 2-2 Recreating the Session Using SessionId Example

var isPageReload = false;
var sessionId = null;
...
...
// Create the session. If the page is reloaded, recreate the current session.
if (isPageReload) {
// Aplication page reload scenario. Input the saved sessionId.
wseSession = new wse.Session(userName, webSocketUri, successCallback, failureCallback, sessionId);
} else {
// This is a new session. Save sessionId if you have extended any API.
wseSession = new wse.Session( userName, webSocketUri, successCallback, failureCallback);
}
...

In addition, this application uses the following functions:

- The onPageLoad function sets the isPageLoad variable to true if the application page is the result of a page reload.

function onPageLoad() {
if (getSavedPageInfo()) {
isPageReload = true;
register();
}
}

- The savePageInfo function saves the sessionId in the HTML sessionStorage object.

function savePageInfo() {
sessionStorage.setItem("sessionId", wseSession.getSessionId());
}

- The getSavedPageInfo function attempts to retrieve the sessionId from the HTML sessionStorage object.

function getSavedPageInfo() {
sessionId = sessionStorage.getItem("sessionId");
if (sessionId != null) {
return true;
}
return null;
}

- The successCallback function invoked when the session is created successfully is not shown here. This function calls the savePageInfo function.

How WebRTC Session Controller JavaScript API Library Restores Application Data

When there is a client rehydration, a network switch over, or a clustered server shut down, the WebRTC Session Controller JavaScript API library attempts to restore your application using the sessionId you provide when you attempt to recreate your current application session. It uses sessionId as the key and loads the saved session data from browser's sessionStorage. It then sends a reconnect message to the WebRTC Session controller Signaling Engine.

If the reconnection request receives a success response from WebRTC Session Controller Signaling Engine, your application's session state goes from wsc.SESSIONSTATE.RECONNECTING to wsc.SESSIONSTATE.CONNECTED. Monitor this change in the callback function you assign to the Session.onSessionStateChange event handler.

When the session regains its wsc.SESSIONSTATE.CONNECTED state, the WebRTC Session Controller JavaScript API library provides the following to your application:

- The rehydrated package data to the appropriate onRehydration event handler in your application:

- CallPackage.onRehydration. See "Restoring CallPackage Data After Pages Reload".

- MessageAlertPackage.onRehydration. See "Restoring Extended MessageAlertPackage Data After Pages Reload".

In each case, your application receives the rehydrated data as the parameter in the callback function.

Important:
If you create a custom package, be sure to implement a custom onRehydration event handler in that package.

- The resurrected call or subscription to the appropriate onResurrect event handler in your application:

- CallPackage.onResurrect. See "Restoring a Call Session".

- MessageAlertPackage.onResurrect. See "Restoring a Subscription Session".

If the WebRTC Session Controller JavaScript API library fails to load data, it invokes the failureCallback function associated with the session creation step.

Restoring Your Application Package Data After Your Application Pages Reload

After your application pages successfully reload and the WebSocket connection has been successfully restored, your application can repopulate the data associated with its WebRTC Session Controller JavaScript API objects by doing the following:

- Restoring CallPackage Data After Pages Reload

- Restoring Extended MessageAlertPackage Data After Pages Reload

Restoring CallPackage Data After Pages Reload

To restore the call package data after your application pages successfully reload, set up appropriate actions within the callback function assigned to your application's CallPackage.onRehydration event handler. This callback function has one parameter, rehydratedData, which contains the data about the call stored in the sessionStorage object of the web browser. Within the callback function you can define the actions with respect to the recovered call. See "Restoring a Call Session".

When you extend the CallPackage object in your application, you can override its onRehydration event handler. See "Extending Objects Using the wsc.extend Method" for more information.

Restoring Extended MessageAlertPackage Data After Pages Reload

To handle the subscription session data after your application pages successfully reload, set up appropriate actions within the callback function assigned to your application's MessageAlertPackage.onRehydration event handler. This callback function has one parameter, rehydratedData which contains the data about the subscription stored in the sessionStorage object of the web browser. Within the callback function you can define the actions with respect to the recovered subscription. See "Restoring a Subscription Session".

When you extend the MesageAlertPackage object, you can override its onRehydration event handler and use this function to refresh the current subscription with the recovered data. See "Extending Objects Using the wsc.extend Method" for more information.

Restoring a Call Session

If a call is recovered following a page reload, network switch over or server fail over, the WebRTC Session Controller JavaScript API library invokes the CallPackage.onResurrect event handler in your application. The resurrected call is provided as the parameter to the callback function. Use the callback function to perform the actions required on the rehydrated call and resume the rehydrated call. See "Resuming Your Application Operation".

In Example 2-3, an application sets up callHandler as an instance of the CallPackage class object and assigns onResurrect as the callback function for its CallPackage.onResurrect event handler. The onResurrect callback function uses the rehydratedCall object.

Example 2-3 Sample onResurrect Function for a CallPackage

callHandler = new wsc.CallPackage(wscSession);
if(callHandler){
callHandler.onResurrect = onResurrect;
}
...
function onResurrect(rehydratedCall) {
// set callback for call state changed
rehydratedCall.onCallStateChange = function(newState) {
...
}
// set callback for media state changed
rehydratedCall.onMediaStreamEvent= function(mediaStreamEvent, stream) {
...
}
// resume the call with setting related callback functions.
rehydratedCall.resume(onResumeCallSuccess, doCallError);
}

Restoring a Subscription Session

If your application user's subscription is recovered following a page reload, network switch over or server fail over, the WebRTC Session Controller JavaScript API library invokes your application's MessageAlertPackage.onResurrect event handler. The rehydrated subscription is provided as the parameter to the callback function. Use the corresponding callback function to perform any action it requires. See "Resuming Your Application Operation".

In Example 2-4, an application sets up subscribeHandler as an instance of the MessageAlertPackage class object and assigns onResurrect as the callback function for its MessageAlertPackage.onResurrect event handler. The onResurrect callback function uses the rehydratedSubscription object to restore the application's current Subscription object.

Example 2-4 Sample onResurrect Function for a MessageAlertPackage

subscribeHandler = new wsc.MessageAlertPackage(wscSession);
if (subscribeHandler) {
subscribeHandler.onResurrect = onResurrect;
}
...
function onResurrect(rehydratedSubscription) {
// reset related callback functions
subscription = rehydratedSubscription;
subscription.onNotification = onNotification;
subscription.onEnd = onEnd;
// initialize other information on page ...
}

Resuming Your Application Operation

To resume your application operation following a page reload, a network switch over, or a server fail over:

- For calls: Resume the current call by invoking its resume method. See "Reconnecting Dropped Calls".

- For subscriptions: Call the subscription's isValid method and take further action. If the user prefers to end the subscription, use the subscription's end method to do so. See "Restoring a Subscription".

Important:
If you create a custom package, be sure to implement the appropriate logic to resume its call or subscription operation.

3 Setting Up Security

This chapter describes how to set up security for the applications you develop using the Oracle Communications WebRTC Session Controller JavaScript application programming interface (API) library. For information about configuring security on the web server, see WebRTC Session Controller Security Guide.

Handling Login to WebRTC Session Controller

By default, the WebRTC Session Controller JavaScript API library supports the following authentication methods for your web applications:

- Basic authentication. See "Login Using Basic Authentication".

- OAuth authentication. See "Login Using OAuth Authentication".

- Form-based authentication. See "Login Using Form-Based Authentication".

Please refer to your server-side configuration documentation to configure authentication-based login and logout on the web server side.

Login Using Basic Authentication

Basic authentication implements access controls using static, standard HTTP headers. This is one of the default authentication methods supported by WebRTC Session Controller Signaling Engine. For more information on Basic authentication, see the Internet Engineering Task Force website at http://tools.ietf.org/html/rfc2617.

When a user attempts to access your application, your application can initiate a login request by sending an HTTPS request to the following uniform resource locator (URL):

https://wsc-host:wsc-port/login

Where:

- wsc-host is the host name where WebRTC Session Controller is running.

- wsc-port is the listening port for WebRTC Session Controller.

When such a request is made to the URL:

1. The web browser displays a basic authentication dialog window.

2. The user enters his credentials.

3. One of the following occurs:

- If the credentials are valid, the user is authenticated.

- If the credentials are not valid, an error response is displayed.

Redirecting After a Successful Login

You can add the following two optional request parameters to the login URL you define in your application to redirect the user after a successful login:

- redirect_uri: Specify the uniform resource identifier (URI) of the page the browser should be redirected to after a successful login.

- wsc_app_uri: Specify the URI of the WebRTC Session Controller application configured in WebRTC Session Controller which will be invoked by this client after logging in, such as /ws/webrtc/sample. The WebRTC Session Controller configuration contains a set of domain names valid for the application. This data is used to validate the domain name in the redirect_uri.

The following is an example of an HTTPS login request that redirects the user to a new web page:

https://wsc-host:wsc-port/login?redirect_uri=https://name_of_theDomain.com/index.html&wsc_app_uri=/ws/webrtc/sample

When you redirect users, WebRTC Session Controller Signaling Engine checks to see if the domain name for redirect_uri is set to one of the configured domains for the WebRTC Session Controller application that will be invoked following successful authentication. Your WebRTC Session Controller administrator will have the information you need to access the application.

See Oracle Communications WebRTC Session Controller Extension Developer's Guide for more information.

Login Using OAuth Authentication

OAuth is an open standard for authentication. OAuth 2.0 is one of the default authentication methods supported by WebRTC Session Controller Signaling Engine.

End users attempting to access your application are redirected to supported third-party websites for authentication. Facebook OAuth token authentication is one example. For information on OAuth authentication, see the OAuth website at http://oauth.net/.

You can set up your web applications to employ the end user's OAuth identity by using the OAuth login mechanism. In this scenario, your web applications can use the user's external OAuth identity, such as Facebook or Google identity, to enable the user to log in to WebRTC Session Controller Signaling Engine. Configure OAuth authentication based on the requirements of the selected OAuth security provider.

From the client side, when the user clicks the Login button on the web page, the OAuth process works in the following way:

1. Your application sends an HTTPS request to the Signaling Engine login URL.

2. WebRTC Session Controller Signaling Engine does the following:

1. Based on the URL query parameters, identifies that the request is for the OAuth login mechanism.

2. Redirects the browser to the OAuth provider's login dialog page.

3. The user provides his or her credentials to the OAuth provider.

4. The OAuth provider authenticates the user and redirects the user back to WebRTC Session Controller with the OAuth access code information.

5. WebRTC Session Controller Signaling Engine retrieves the OAuth token and user information from the OAuth access code and does the following:

1. Logs the user in to the Signaling Engine domain.

2. Redirects the user back to the final redirect URI specified in your application.

For example, the following is a sample authentication/authorization request generated by an example web application. The end user is redirected to the loginRedirect.html page, at the host and port location where your application resides. The request is shown here with carriage returns added to promote its readability:

https://wsc-host:wsc-port/login/google?
client_id=12349876.apps.googleusercontent.com&
redirect_uri=http://wsc-host:wsc-port/login/google&
wsc_app_uri=/ws/webrtc/sample&
response_type=code&
scope=email&
oauth_url=https://accounts.google.com/o/oauth2/auth&
final_redirect_uri=http://custapp-host:custapp-port/wscsample/loginRedirect.html

In the above request:

- client_id specifies the OAuth client ID for the registered WebRTC Session Controller application. This is the client ID you received when you first created and registered the WebRTC Session Controller application with the OAuth provider.

- redirect_uri is the configured login URI in WebRTC Session Controller for a specific OAuth provider.

- wsc_app_uri is your application's URI. In this example, the application is named sample and resides at /ws/webrtc/.

- response_type specifies the supported OAuth response type. The entry code indicates that your server expects to receive an authorization code.

- scope specifies the OAuth scope, indicating which parts of the user's account you wish to access. The value of scope depends on the OAuth provider. This example uses email.

- oauth_url specifies the URL of the OAuth provider's login dialog page.

- final_redirect_uri specifies the location to which Signaling Engine should redirect the user after a successful OAuth login.

Login Using Form-Based Authentication

Form-based authentication requires your application to implement the logic to obtain and authenticate the username and password from the application user.

If you plan to use form-based authentication in your applications, do the following:

1. Create a separate web application which enforces form-based authentication for login. For more information on how to create such an application, see Oracle Fusion Middleware Programming Security for Oracle WebLogic Server at:
http://docs.oracle.com/cd/E24329_01/web.1211/e24485/thin_client.htm#autoId11

2. Deploy this application in the WebRTC Session Controller nodes. For more information, see Oracle Communications WebRTC Session Controller Extension Developer's Guide.

Anyone who logs in to this specific web application is also logged in to WebRTC Session Controller Signalling Engine application.

Login Using REST Authentication

REST stands for representational state transfer, a style of network architecture that complies with the following constraints:

- A uniform separation between client and server so that they need be concerned only about the interface between them.

- Stateless client and server with each request containing all the necessary information so that neither side needs to store context. The state contains links that the client can use in the future to begin a new state-transition.

- Cachable responses that are defined to prevent clients from reusing stale or inappropriate data in responding to further requests.

- A layered system in which the client does not know if it's connected to an end or intermediary server. Layered systems can improve scalability, providing load balancing, shared caching, and so on.

- Optional code-on-demand that enables a server to transfer Java applets or JavaScript code to a client to temporarily enhance its capabilities.

- A uniform interface that enables each part of the architecture to evolve independently.

To enable REST authentication, you must install a REST service provider and enable it through the WLS administration console. See the section on configuring WSC authentication in the WebRTC Session Controller System Administrator's Guide for information on installing and enabling a REST service provider.

When a client logs in, REST authentication occurs as follows:

1. The client sends the request URI to the WebRTC Session Controller, indicating that the request type is REST authentication:

http://wsc-host:wsc-port/login?wsc-app-uri=/ws/webrtc/restauth&redirect-uri=http://successpage.html

Where:

- wsc-host is the host name where WebRTC Session Controller is running

- wsc-port is the listening port for WebRTC Session Controller

- successpage.html is the landing page where the browser should be directed after a successful login

2. WebRTC Session Controller responds and triggers a client authentication pop-up window that prompts the user for a login name and password.

3. The client sends the login name and password to WebRTC Session Controller.

4. The WebRTC Session Controller forwards the login name and password to the REST service provider, which validates them.

5. The REST service provider returns one of the following results:

- A 200 message to indicate that the client authentication was successful

- A 401 message to indicate that the client was not successfully authenticated

6. On successful authentication, WebRTC Session Controller populates the authentication context, AuthenticateContext, which is defined in the Groovy script library.

Handling Logout from WebRTC Session Controller

When your user logs out of your application or leaves the browser page, your application also logs out of WebRTC Session Controller. You can optionally redirect the user to the web page from where he was directed to your application.

In your application, send an HTTPS request to:

https://wsc-host:wsc-port/logout?redirect_uri=url_to_redirect_to_after_logout

The above request logs out the user from the WebRTC Session Controller domain and redirects the browser to the URI specified by redirect_uri. If redirect_uri is not specified, a message saying that the user has been logged out is displayed.

When an application logs into WebRTC Session Controller, the login is valid for one hour. If the WebSocket is disconnected for any reason within that hour, the application can reconnect without logging in again.After one hour, the user needs to login again for new WebSocket connections to be set up. See Oracle Communications WebRTC Session Controller System Administrator's Guide for information on session timeout if the WebSocket loses its connection.

4 Setting Up Audio Calls in Your Applications

This chapter shows how you can use the Oracle Communications WebRTC Session Controller JavaScript application programming interface (API) library to enable your applications users to make and receive audio calls from your applications when your applications run on WebRTC-enabled browsers.

Note:
See Oracle Communications WebRTC Session Controller JavaScript API Reference for more information on the individual WebRTC Session Controller JavaScript API classes.

About Implementing the Audio Call Feature in Your Applications

The WebRTC Session Controller JavaScript API for audio calls enables your web applications to support audio calls made to and received from phones located on applications hosted on other WebRTC-enabled browsers, Session Initialization Protocol (SIP) protocol based applications, and public switched telephone network (PSTN) phones.

To support audio calls in your application, implement the logic to do the following:

- For calls made from by your application user, obtain the callee information and start the process to set up the call session between the caller and callee.

- For calls received by your application user, obtain the callee's response to the incoming call request and respond to the callee accepting or rejecting the incoming call invitation.

- Monitor the call session, taking action to respond to any change in the state of the application session, call session or media stream.

- Take appropriate action when one of the parties ends the call.

This basic logic can be used to support calls with video and data transfers.

About the WebRTC Session Controller JavaScript API Used in Implementing Audio Calls

The following WebRTC Session Controller JavaScript API classes are used to implement audio calls in your web applications:

- wsc.Session for the session object

- wsc.CallPackage for the call package object

- wsc.Call for the call object

- wsc.CallConfig for the media configuration in the calls

- The constants defined in the following enumerators:

- wsc.SESSIONSTATE

- wsc.CALLSTATE

- wsc.MEDIADIRECTION

- wsc.MEDIASTREAMEVENT

- wsc.ERRORCODE

- wsc.LOGLEVEL

You can extend the audio call feature in your application to perform custom tasks by extending these API classes.

Setting Up Audio Calls in Your Applications

Use the WebRTC Session Controller JavaScript API library to set up the audio call feature in your application to suit your deployment environment. The specific logic, web application elements, and controls you implement for the audio call feature in your applications are predicated upon how the audio call feature is used in your web application.

To illustrate the basic logic in setting up call capability in web applications using the WebRTC Session Controller JavaScript API library, this section uses a sample application in which the audio call is its primary and sole feature.

About the Sample Audio Call Application

The sample audio call application referenced in this chapter provides the logic necessary to enable two users to place a call to each other. It uses WebRTC Session Controller JavaScript API and supports audio calls only. The sample audio call application obtains the call information from an input field it provides on the application page. The steps in the development process described below refer to this sample audio call application. See "Sample Audio Call Application" to view the complete code.

Overview of Setting Up the Audio Call Feature in Your Application

To set up an audio call feature in your application, requires implementing logic for the following:

1. Setting Up the General Elements for the Audio Call Feature

2. Enabling Users to Make Audio Calls From Your Application

3. Implementing the Logic to Set Up the Call Session

4. Enabling Your Application Users to Receive Calls

5. Monitoring the Call

6. Ending the Call

Setting Up the General Elements for the Audio Call Feature

To set up the audio call feature in your application, include the following in the <head> section of your application:

- The <audio> element
Set up the <audio> element for the local and remote audio according to your browser's requirements.

- The WebRTC Session Controller JavaScript API support libraries:

- wsc-common.js

- wsc-call.js

If your application uses other supporting libraries, reference them, as well.

See "Sample Audio Call Application".

Setting Up the Main Objects and Values

Use the WebRTC Session Controller JavaScript API to set up the main objects and values at the start of your application:

- Declare a Session object, a CallPackage object, and a variable for the user name.

- Set the log level as required as described in "Debugging Your Application with wsc.LOGLEVEL".

- Set up the web Socket uniform resource identifier (URI) for the WebLogic Server and the login and logout URIs, if your application uses them. The WebSocket URI is required when you create a session object in your application.

Example 4-1 shows how the sample application described in this chapter sets up the WebSocket URI and global variables.

Example 4-1 Sample Setup of Global Variables and WebSocket URI

var wscSession, callPackage, userName, caller, callee;
wsc.setLogLevel(wsc.LOGLEVEL.DEBUG);

// Save the location from where the user accessed this application.
var savedUrl = window.location;

// This application is deployed on WebRTC Session Controller.
var wsUri = "ws://" + window.location.hostname  + ":" + window.location.port + "/ws/webrtc/sample";
...

Here:

- window.location.hostname and window.location.port define the location for Signaling Engine associated with the audio call application.

- /ws/webrtc/sample indicates that the sample application is deployed in WebRTC Session Controller.

Current Stage in the Development of the Audio Call Feature

At this point, you have completed the setup for the general elements required for an audio call application. You now need to enable users to make a call from the audio call application.

Enabling Users to Make Audio Calls From Your Application

To enable users to make a call from your application, complete the following tasks:

- Setting Up the Configuration for Calls Supported by the Application

- Setting Up the Session Object

- Setting Up the Call Package for the Session

- Handling Session State Changes

- Handling Errors Related to Sessions

- Obtaining the Callee Information

Setting Up the Configuration for Calls Supported by the Application

The WebRTC Session Controller JavaScript API library provides the CallConfig class object to define the audio, video, and data channel capabilities of a call. To create a CallConfig class object, use the syntax:

wsc.CallConfig(audioMediaDirection, videoMediaDirection, dataChannelConfig)

When you create your application's CallConfig class object, specify the configuration for the local audio media stream in audioMediaDirection and video media stream in videoMediaDirection as described in "Specifying the Configuration for Calls with wsc.CallConfig".

The dataChannelConfigs parameter is used to define data transfers (as in text messaging sessions), and is an array of JavaScript Object Notation (JSON) objects that describe the configuration of the data channel. See "Setting Up the Configuration for Data Transfers in Chat Sessions" for more information on setting up the configuration for data transfers.

Set the local audio, video stream, and data transfer configuration for calls in your application based on your browser properties and your web application's requirements.

The sample audio call application supports audio calls in both directions and creates a call configuration object called callConfig, as shown below in Example 4-2:

Example 4-2 Sample Call Configuration Object

// Create a CallConfig object.
var audioMediaDirection = wsc.MEDIADIRECTION.SENDRECV;
var videoMediaDirection = wsc.MEDIADIRECTION.NONE;
var callConfig = new wsc.CallConfig(audioMediaDirection, videoMediaDirection);

Setting Up the Session Object

The WebRTC Session Controller JavaScript API library provides the wsc.Session class object to encapsulate the session between your web application and WebRTC Session Controller Signaling Engine. To create an instance of the Session class, use the following syntax:

wsc.Session(userName, webSocketUri, successCallback, failureCallback, sessionId)

Where:

- userName is the user name.

- webSocketUri is the WebSocket connection defined earlier in Example 4-1.

- successCallback is the function to call if the session object was created successfully.

- failureCallback is the function to call if the session object was not created.

- sessionId is the Session Id. It is needed if you are refreshing an existing session.

To set up a session object in your application:

- Create an instance of the wsc.Session object.

- Set up the logic for the successCallback and failureCallback functions.

- If your application authenticates its users before allowing them to make calls:

- Set up an authentication handler for that session. Input the session object when you instantiate the wsc.AuthHandler class.

- Assign the callback function to the refresh field of your application's authentication handler.

- Set up the logic for the callback function. See Example 4-8.

- Specify the values for busyPingInterval, idlePingInterval, and reconnectTime. These settings determine how your application's session is monitored. See "About Monitoring Your Application WebSocket Connection".

- Manage the changes in the state of your application session in the following way:

- Assign a callback function to your application's Session.onSessionStateChange event handler.

- Set up the actions to be performed by the callback function. See "Handling Session State Changes".

The sample audio call application performs these tasks inside a function called setSessionUp. When the sample audio call application page loads, the JavaScript onPageLoad function runs and it calls the setSessionUp function as shown below.

// The onPageLoad event handler.
function onPageLoad() {
setSessionUp();
}

Within the setSessionUp function, the sample audio call application:

- Creates an instance of the Session class object called wscSession, with:

- wsURI as its WebSocket connection.

- sessionSuccessHandler as the callback function for a successful creation of the session.

- sessionErrorHandler as the callback function for a successful creation of the session.

- Registers an authentication handler called authHandler with wscSession.

- Configures the monitoring time intervals for wscSession.

- Assigns a callback function called sessionStateChangeHandler to the application's onSessionStateChange event handler. This callback function manages the changes in the application's session state.

Example 4-3 shows the setSessionUp function implemented in the sample audio call application:

Example 4-3 Sample Session Object Setup

// This function sets up and configures the WebSocket connection.
function setSessionUp() {
console.log("In setSessionUp().");

// Create the session. Here, userName is null.
// WebRTC Session Controller can determine it using the cookie of the request.
wscSession = new wsc.Session(null, wsUri, sessionSuccessHandler, sessionErrorHandler);
// Register a wsc.AuthHandler with session.
// This handler provides customized authentication information, such as
// username and password.
var authHandler = new wsc.AuthHandler(wscSession);
authHandler.refresh = refreshAuth;

// Configure the session.
wscSession.setBusyPingInterval(2 *1000);
wscSession.setIdlePingInterval(6 * 1000);
wscSession.setReconnectTime(2 * 1000);
wscSession.onSessionStateChange = sessionStateChangeHandler;
console.log("Session configured with authhandler, intervals and sessionStateChange handler.\n");
}

Setting Up the Call Package for the Session

The WebRTC Session Controller JavaScript API library provides the CallPackage class to manage the calls and all the messaging workflow with WebRTC Session Controller Signaling Engine. To create an instance of the CallPackage class, use the following syntax:

wsc.CallPackage(session)

Where session is the instance of the Session object in your application.

To configure the call package to manage the audio calls in your application:

- Create an instance of the CallPackage class object for the application session.

- Implement your application logic for incoming calls in the following way:

- Assign a callback function for the CallPackage.onIncomingCall event handler.

- Set up the actions to be performed by the callback function.

- Implement your application logic to refresh a call that was dropped momentarily:

- Assign a callback function for the CallPackage.onResurrect event handler.

- Set up the actions to be performed by the callback function.

The sample audio call application sets up a call package called callPackage. It sets up the call package within a callback function called sessionSuccessHandler which is called when the application session is created. To process incoming calls, the sample audio call application assigns a function named onIncomingCall to the Call.onIncomingCall event handler for incoming calls. This callback function is describer later in "Responding to Your User's Actions on an Incoming Call". Additionally, the sample audio call application retrieves the name of the user.

Example 4-4 shows the sessionSuccessHandler callback function.

Example 4-4 Sample CallPackage Setup

function sessionSuccessHandler() {
console.log(" In sessionSuccesshandler.");

// Create a CallPackage.
callPackage = new wsc.CallPackage(wscSession);
// Bind the event handler of incoming call.
if(callPackage){
callPackage.onIncomingCall = onIncomingCall;
}
console.log(" Created CallPackage..\n");
// Get user Id.
userName = wscSession.getUserName();
console.log (" Our user is " + userName);
}

Handling Session State Changes

When your application's session state changes, the WebRTC Session Controller JavaScript API Library invokes the application session object's Session.onSessionStateChange event handler. The new session state for the call is provided as input to your application.

Monitor the different states in the callback function you assigned to your application session object's Session.onSessionStateChange event handler. Specify the actions your application must take for each of the state changes you include.

The wsc.SESSIONSTATE enumerator contains the different states of a session defined as constants such as NONE when the session is created, CONNECTED when the session connects with the server, CLOSED when the session closes normally, and so on. See Oracle Communications WebRTC Session Controller JavaScript API Reference for more information.

The sample audio call application assigns a callback function named sessionStateChangeHandler to its application session object's Session.onSessionStateChange event handler. In that callback function, the sample audio call application monitors and implements logic for three session states, CONNECTED, FAILED, and RECONNECTING. When the session state is CONNECTED, the sample audio call application calls a function named displayInitialControls to obtain the callee's name.

Example 4-5 shows the sessionStateChangeHandler callback function.

Example 4-5 Sample Session State Handler Callback Function

function sessionStateChangeHandler(sessionState) {
console.log("sessionState : " + sessionState);
switch (sessionState) {
case wsc.SESSIONSTATE.RECONNECTING:
setControls("<h1>Network is unstable, please wait...</h1>");
break;
case wsc.SESSIONSTATE.CONNECTED:
if (wscSession.getAllSubSessions().length == 0) {
displayInitialControls();
}
break;
case wsc.SESSIONSTATE.FAILED:
setControls("<h1>Session Failed, please logout and try again.</h1>");
break;
}
}

Obtaining the Callee Information

Your application can obtain the callee information in a number of ways. Ensure that, if the user is given a choice of controls such as canceling the operation or logging out, the corresponding callback functions are invoked in your application.

The sample audio call application uses a function called displayInitialControls to obtain the callee information. In it, the sample audio call application defines a simple user interface consisting of input fields and control buttons to receive the callee's name. The 'onclick'='functionName()' for each button triggers the next step for that event. For example, the onCallSomeOne() function is invoked when the Call button is selected.

Example 4-6 shows the displayInitialControls callback function.

Example 4-6 Sample displayInitialControls Function

function displayInitialControls() {
console.log ("In displayControls().");
var controls = "Enter Your Callee: <input type='text' name='callee' id='callee'/><br><hr>"
+ "<input type='button' name='callButton' id='btnCall'  value='Call' onclick='onCallSomeOne()'/>"
+ "<input type='button' name='cancelButton' id='btnCancel'  value='Cancel' onclick='' disabled ='true'/><br><br><hr>"
+ "<input type='button' name='logoutButton' id='Logout'  value='Logout' onclick='logout()'/>"
+ "<br><br><hr>";
setControls(controls);
var calleeInput = document.getElementById("callee");

if (calleeInput) {
console.log (" Waiting for Callee Input.");
console.log (" ");
if(userName != calleeInput) {
calleeInput.focus();
}
}
}

Current Stage in the Development of the Audio Call Feature in Your Application

At this stage in the development of the audio call feature in your application:

- The general elements required for audio calls are set.

- Your application can obtain the callee information.

- The application logic for the following functions is implemented:

- successCallback function invoked when the application's session object is created

- failureCallback function invoked when the application's session object is not created

- The callback function assigned to the Session.onSessionStateChange event handler

- The callback function assigned to the CallPackage.onIncomingCall event handler

- The callback function assigned to the CallPackage.onResurrect event handler

Your application now needs the logic to handle both end points, the caller's side which must handle connecting the caller to the callee; and the callee's side which must respond to the callee accepting or declining the incoming call.

Initial Actions of the Sample Audio Call Application

Table 4-1 reports on the sample audio call's actions in enabling a user to make a call from the application. It describes the events that occur on the sample audio call application page, the actions taken by the sample audio call application, and the messages logged by the console.log method for this segment of the application code.

Table 4-1 Initial Actions Performed by the Sample Audio Call Application

Sample Audio Call Application Page Events

Actions Taken by the Sample Audio Call Application

Console Log for the Caller (bob1)

Console Log for the Callee (bob2)

When the page loads, the page displays the control buttons and input fields to allow the user to make a call.

The initial actions taken by the audio call application before the user starts the call or receives a call:

- CallConfig, which defines the calling capability, is configured.

- When the page loads, the wscSession object is created and configured.

- The session is now in a CONNECTED state.

- Controls are displayed on the application page. For the audio call, they consist of a callee input field, Call, Cancel and Logout buttons.

- The call package is created inside the callback for the session success event handler.

The example code retrieves the user Id for debugging purposes.

Created CallConfig with audio stream only.

Page has loaded. Setting up the Session.

In setSessionUp().
Session configured with authhandler,
intervals and sessionStateChange handler.

sessionState : CONNECTED

In displayControls().
Waiting for Callee Input.

In sessionSuccesshandler.
Created CallPackage..

Our user is bob1@example.com

Created CallConfig with audio stream only.

Page has loaded. Setting up the Session.

In setSessionUp().
Session configured with authhandler,
intervals and sessionStateChange handler.

sessionState : CONNECTED

In displayControls().
Waiting for Callee Input.

In sessionSuccesshandler.
Created CallPackage..

Our user is bob2@example.com

Implementing the Logic to Set Up the Call Session

When your application has obtained the callee information, it can start the process to establish a call session between the caller and the callee.

To implement the logic to start a call from your application, complete the following tasks:

- Start the call. See "Starting a Call From Your Application".

- Set up the callback function to handle any failure in creating the call. See "Handling Errors Related to Calls".

- If the browser does not support the media stream, set up your application to respond appropriately. See "Handling Changes in Media Stream States" for more information.

- Set up the authentication handler based on whether your application supports Traversal Using Relays around Network address translation (TURN) or SERVICE authentication. See "Retrieving the Appropriate Authentication Headers".

- Provide the logic for the call state event handler. See "Setting Up the Event Handler for Call State Changes".

- Provide the logic for the media stream event handler. See "Setting Up the Event Handler for the Media Streams".

Starting a Call From Your Application

The WebRTC Session Controller JavaScript API library provides the wsc.Call class object to represent a call with any combination of audio/video/data channel capability. Use the createCall method of the CallPackage class to create your application's call object. The syntax to create your application's Call object is:

callPackage.createCall(target, callConfig, errorCallback)

Where:

- target is the callee.

- callConfig is audio/video/data channel capability of calls defined earlier in Example 4-2.

- errorCallback is the function to call if the call was not created.

When you obtain the callee information, implement the logic to start the call in the following way:

- Create an instance of the wsc.Call object.

- To handle changes in the call session state:

- Assign a callback function for the Call.onCallStateChange event handler.

- Set up the actions to be performed by the callback function.

- To handle changes in the state of the media stream:

- Assign a callback function for the Call.onMediaStreamEvent event handler.

- Set up the actions to be performed by the callback function.

- To handle any updates to the call:

- Assign a callback function for the Call.onUpdate event handler.

- Set up the actions to be performed by the callback function.

- To handle any error in the call creation:

- Set up the actions to be performed by your application's errorCallback function.

- Start the call with the Call.start method.

- Set up other actions as dictated by the environment in which your application is deployed.

The sample audio call application invokes a function called onCallSomeOne, when it receives the callee information. In this onCallSomeOne function, the sample audio call application does the following:

- Sets up a call object named call.

- Configures one function called setEventHandlers which handles the changes to the call states and the media stream states in its call object.
The setEventHandlers function invokes callStateChangeHandler for changes in the call state and mediaStreamEventHandler for media stream or data transfer changes in the call. See "Sample Audio Call Application" for more information on the setEventHandlers function.

- Starts the call using the start method of the call object.

- Sets up the controls which allow the user to hang up or cancel the call.

- If the user prematurely ends the call, ends the call using the end method of its Call object.

Example 4-7 Sample Function to Set Up Call for Caller

function onCallSomeOne() {

// Need the caller callee name. Also storing the caller.
callee = document.getElementById("callee").value;
caller = userName;
console.log ("Name entered is " + callee);

// Check to see if user gave a valid input. Omitted here. See "Sample Audio Call Application".
...
// To call someone, create a Call object first.
var call = callPackage.createCall(callee, callConfig, doCallError);
console.log ("Created the call.");
console.log (" ");

if (call != null) {
console.log ("Calling setEventHandlers from onCallSomeOne() with call data.");
console.log (" ");
setEventHandlers(call);
// Then start the call.
console.log ("In onCallSomeOne(). Starting Call. ");
call.start();
...
}
}

Retrieving the Appropriate Authentication Headers

This section applies to your application if it uses an authentication mechanism before allowing users access to its audio call feature.

If an authentication handler has been assigned to your application's Session object and your application starts a call or receives a call, the authentication function assigned to the AuthHandler.refresh event is called. See Example 4-3.

Set up logic in the callback function assigned to your application's AuthHandler.refresh event.

The sample audio call application uses Representational State Transfer (REST) based authentication. The refreshAuth function shown in Example 4-8 is for your reference. See "Setting Up Security" for more information on the SERVICE and Traversal Using Relays around Network address translation (TURN) authentication seen in the code below.

Example 4-8 Template for the refreshAuth Function()

function refreshAuth(authType, authHeaders) {
//Set up the response object by calling a function.
var authInfo = null;

if(authType==wsc.AUTHTYPE.SERVICE){
// Return JSON object according to the content of the "authHeaders".
// For the digest authentication implementation, refer to RFC2617.
authInfo = getSipAuth(authHeaders);

} else if(authType==wsc.AUTHTYPE.TURN){

//Return JSON object in this format:
// {"iceServers" : [ {"url":"turn:test@<aHost>:<itsPort>", "credential":"nnnn"} ]}.
authInfo = getTurnAuth();
}
return authInfo;
};

If your application uses Digest access authentication, ensure that it sets up the response using the headers in the authHeaders object it retrieves. For more information on Digest access authentication, see http://www.ietf.org/rfc/rfc2617.txt.

About Digest Access Authentication

If a Session Initiation Protocol (SIP) network does not support an identity mapping between a web identity and a SIP identity, it might choose to challenge the messages from the application using a WWW-authenticate header as stipulated by RFC 2617. On receiving the WWW-authenticate header, WebRTC Session Controller Signaling Engine sends a JavaScript Object Notation (JSON) form of this header to the WebRTC Session Controller JavaScript API library. In turn, the WebRTC Session Controller JavaScript API library invokes the callback function assigned to your application's AuthHandler.refresh event handler.

To provide the appropriate challenge response, do the following in the callback function assigned to your application's AuthHandler.refresh event handler:

- Retrieve the appropriate credentials from the user, using your application-specific logic.

- Create your application's challenge response in JSON format and constructed, as stipulated by RFC 2617.

- Return the challenge response to the WebRTC Session Controller JavaScript API library.

This challenge response is used to authenticate your application user with the SIP network.

Example 4-9 shows a sample authHeader received by an application that uses Digest authentication. The authHeader object is in JSON format.

Example 4-9 Digest Authentication Header Received by an Application

{
"scheme": "Digest",
"nonce": "a12e8f74-af01-4e74-9714-4d65bae4e024",
"realm": "example.com",
"qop": "auth",
"challenge_code": "407",
"opaque": "YXBwLTNjOHFlaHR2eGRhcnxiYWNkMTIxMWFmZDlkNmUyMThmZmI0ZDc4ZmY3ZmY1YUAxMC4xODIuMTMuMTh8Mzc3N2E3Nzc0ODYyMGY4",
"charset": "utf-8",
"method": "REGISTER",
"uri": "sip:<host>:<port>"
}

Where:

- <host> is the host name for the SIP registrar.

- <port> is the listening port for the SIP registrar.

Creating the authHeader Object for the Response

Example 4-10 shows a sample function used by an application to set up the authHeaders in its response.

Example 4-10 Sample createResponseHeaders Function

function createResponseHeaders(authHeaders) {
// cnonce is the string provided by the client.
// The application MUST implement the MD5 algorithm.
var
userName = "alice@example.com",
password = "********",
realm = authHeaders['realm'],
method = authHeaders['method'],
uri = authHeaders['uri'],
qop = authHeaders['qop'],
nc = '00000001',
nonce = authHeaders['nonce'],
cnonce = "",
ha1 = hex_md5(userName + ":" + realm + ":" + password),
ha2 = hex_md5(method + ":" + uri),
response;

if(!qop){
response = hex_md5(ha1 + ":" + nonce + ":" + ha2);
} else if(qop=="auth") {
response = hex_md5(ha1 + ":" + nonce + ":" + nc + ":" + cnonce + ":" + qop + ":" + ha2);
}

// add client calculated header to the headers.
authHeaders['username'] = username;
authHeaders['cnonce'] = cnonce;
authHeaders['response'] = response;
authHeaders['nc'] = nc;
return authHeaders;
};

Setting Up the Event Handler for Call State Changes

When your application's call state changes, the WebRTC Session Controller JavaScript API Library invokes your application's Call.onSessionStateChange event handler. The new state for the call is provided as input to your application.

The many states of a call, such as ESTABLISHED, ENDED, and FAILED are defined as constants in the wsc.CALLSTATE enumerator. See WebRTC Session Controller JavaScript API Reference for more information.

Use as many of the constants in wsc.CALLSTATE to meet your application's needs. Specify the actions your application must take for each of the state changes you include in the callback function you assigned to your application's Call.onCallStateChange event handler, as described in "Starting a Call From Your Application".

Example 4-11 shows how the sample audio call application handles call state changes. It sets up a callback function called callStateChangeHandler to monitor for three call states, wsc.CALLSTATE.ESTABLISHED, wsc.CALLSTATE.ENDED, and wsc.CALLSTATE.FAILED. When the sample audio call application's callback function in invoked with wsc.CALLSTATE.ESTABLISHED as the new call state, it calls a function called callMonitor to monitor the call. See Example 4-14. For the remaining two states, this callback function merely displays the user interface required to place a call.

Example 4-11 Sample Call State Change Handler

function callStateChangeHandler(callObj, callState) {
console.log (" In callStateChangeHandler().");
console.log("callstate : " + JSON.stringify(callState));
if (callState.state == wsc.CALLSTATE.ESTABLISHED) {
console.log (" Call is established. Calling callMonitor. ");
console.log (" ");
callMonitor(callObj);
} else if (callState.state == wsc.CALLSTATE.ENDED) {
console.log (" Call ended. Displaying controls again.");
console.log (" ");
displayInitialControls();
} else if (callState.state == wsc.CALLSTATE.FAILED) {
console.log (" Call failed. Displaying controls again.");
console.log (" ");
displayInitialControls();
}
}

Setting Up the Event Handler for the Media Streams

When there is a change in the state of the local or remote media stream, the WebRTC Session Controller JavaScript API Library invokes your application's Call.onMediaStreamEvent event handler. The new state for the media stream is provided as input to your application.

The wsc.MEDIASTREAMEVENT enumerator defines the states of the local or remote media stream as LOCAL_STREAM_ADDED, REMOTE_STREAM_REMOVED, LOCAL _STREAM_ERROR, and so on. See Oracle Communications WebRTC Session Controller JavaScript API Reference for more information.

Use as many of the constants in wsc.MEDIASTREAMEVENT to meet your application's needs. Specify the actions your application must take for each of the state changes you include in the callback function you assigned to your application's Call.onMediaStreamEvent event handler. Whenever this callback function is invoked with a new state for the media stream, your application logic should perform the action required for the new state.

Example 4-11 shows how the sample audio call application handles media stream state changes using a callback function called mediaStreamEventHandler.

Example 4-12 Sample Media Stream Event Handler

// This event handler is invoked when a  media stream event is fired.
// Attach media stream to HTML5 audio element.
function mediaStreamEventHandler(mediaState, stream) {
console.log (" In mediaStreamEventHandler.");
console.log("mediastate : " + mediaState);
console.log (" ");

if (mediaState == wsc.MEDIASTREAMEVENT.LOCAL_STREAM_ADDED) {
attachMediaStream(document.getElementById("selfAudio"), stream);
} else if (mediaState == wsc.MEDIASTREAMEVENT.REMOTE_STREAM_ADDED) {
attachMediaStream(document.getElementById("remoteAudio"), stream);
}
}

Current Stage in the Development of the Audio Call Feature in Your Application

At this stage in the development of the audio call feature in your application:

- The general elements required for audio calls are set.

- Your application can obtain the callee information.

- Your application can retrieve the call information and start a call.

- The application logic for the following functions is implemented:

- errorCallback function invoked when the call is not created

- The callback function assigned to the Call.onCallStateChange event handler

- The callback function assigned to the Call.onMediaStreamEvent event handler

- The callback function assigned to the Call.onDataTransfer event handler

- The callback function assigned to the Call.onUpdate event handler

You can now provide the logic to handle an incoming call.

How the Sample Audio Call Application Starts a Call

Table 4-2 reports on the sample audio call's actions in setting up a call session. It describes the events that occur on the sample audio call application page, the actions taken by the sample audio call application, and the messages logged by the console.log method for this segment of the application code. The focus of actions for this part of the application is the caller.

Table 4-2 Sample Audio Call Application Actions in Setting Up a Call

Sample Audio Call Application Page Events

Actions Taken by the Sample Audio Call Application

Console Log for the Caller (bob1)

Signaling Engine asks the user for permission to use the microphone.

The call workflow starts.

For the caller (bob1) side, the application does the following in the onCallSomeOne() callback function:

- Creates a call object with the callee's id, the configuration for calls in this browser, and the necessary call error handler function.

- Sets up the general event handler to handle changes in the call.

- Issues the command call.start.

- Enables the controls to cancel the call before it is set up.

- Defines the call and media state change handlers.

The browser requests the user to allow access to audio media. If the user gives permission, the local media stream is added.

In onCallSomeOne()
Name entered is bob2
Adding string to name
Caller, bob1@example.com, wants to call bob2@example.com, the Callee.
Creating call object to call bob2@example.com
Created the call.

Calling setEventHandlers from onCallSomeOne() with call data.
In setEventHandlers

In onCallSomeOne(). Starting Call.
Enabled bob1@example.com to cancel call.

In mediaStreamEventHandler.
mediastate : LOCAL_STREAM_ADDED

In callStateChangeHandler().
callstate : {"state":"STARTED","status":
{"code":null,"reason":"start call"}}
In callStateChangeHandler()
callstate : {"state":"RESPONSED","status":
{"code":180,"reason":"Ringing"}}

Enabling Your Application Users to Receive Calls

The focus of the actions taken in this section is the callee.

To enable application users to receive calls, do the following:

1. Provide the logic to respond to the callee's actions with respect to the incoming call. See "Responding to Your User's Actions on an Incoming Call".

2. Verify that you have defined the logic for the following tasks with respect to the callee:

- Setting Up the Event Handler for Call State Changes

- Setting Up the Event Handler for the Media Streams

Responding to Your User's Actions on an Incoming Call

When a user is logged in to your application and WebRTC Session Controller Signaling Engine receives a call for the user, the WebRTC Session Controller JavaScript API library invokes the CallPackage.onIncomingCall event handler in your application. It sends the incoming call object and the call configuration for that incoming call object as parameters to the CallPackage.onIncomingCall event handler.

Define the actions to process the incoming call in the callback function assigned to the onIncomingCall event handler in the following way:

- Provide the interface and logic necessary for the callee to accept or decline the call.

- Provide logic for the following events in association with the incoming call object:

- User accepts the call. Run the accept method for the incoming call object. This will return the success response to the caller.

- User declines the call. Run the decline method for the incoming call object. This will return the failure response to the caller.

- Assign the callback functions to the event handlers of the incoming call object. These should already have been defined earlier. See "Starting a Call From Your Application".

Example 4-13 shows the onIncomingCall callback function used by the sample audio call application:

Note:
Example 4-13 uses the simplest set of controls embedded in the onIncomingCall() function to inform the user that there is an incoming call.
You can set up your application to filter the information in the remote call object and its configuration to determine how to handle the incoming call, prior to informing the user about the call.

Example 4-13 Sample onIncomingCall Function

function onIncomingCall(callObj, callConfig) {

// Draw two buttons for users to accept or decline the incoming call.
// Attach onclick event handlers to these two buttons.
console.log ("In onIncomingCall(). Drawing up Control buttons to accept or decline the call.");
var controls = "<input type='button' name='acceptButton' id='btnAccept' value='Accept "
+ callObj.getCaller()
+ " Incoming Audio Call' onclick=''/><input type='button' name='declineButton' id='btnDecline'  value='Decline Incoming Audio Call' onclick=''/>"
+ "<br><br><hr>";
setControls(controls);

document.getElementById("btnAccept").onclick = function() {
// User accepted the call.

//  Store the caller and callee names.
callee = userName;
caller = callObj.getCaller;
console.log (callee + " accepted the call from caller " + caller);
console.log (" ");

// Send the message back.
callObj.accept(callConfig);
}
document.getElementById("btnDecline").onclick = function() {
// User declined the call. Send a message back.

// Get the caller name.
callee = userName;
caller = callObj.getCaller;
console.log (callee + " declined the call from caller, " + caller);
console.log (" ");

// Send the message back.
callObj.decline();
}

// User accepted the call. Bind the event handlers for the call and media stream.
console.log ("Calling setEventHandlers from onIncomingCall() with remote call object ");
setEventHandlers(callObj);
}

Current Stage in the Development of the Audio Call Feature in Your Application

At this stage in the development of the audio call feature in your application:

- The general elements required for audio calls are set.

- Your application can obtain the callee information.

- Your application can retrieve the call information and start a call.

- Your application can alert the user about an incoming call and respond appropriately to the user accepting or declining the incoming call.

- The application logic for the following functions is implemented:

- Callback functions assigned to the Session Object's event handlers

- The success and error callback functions invoked when a Session object is not created

- Callback functions assigned to the CallPackage Object's event handlers

- Callback functions assigned to the Call Object's event handlers

- The error callback function invoked when a Call object is not created

How the Sample Audio Call Application Handles Incoming Calls

Table 4-3 reports on the sample audio call's actions in enabling a user to receive a call. It describes the events that occur on the sample audio call application page, the actions taken by the sample audio call application, and the messages logged by the console.log method for this segment of the application code. The focus here is on the callee.

Table 4-3 A breakdown of the Application Actions Needed to Receive a Call

Sample Audio Call Application Page Events

Actions Taken by the Sample Audio Call Application

Console Log for the Callee (bob2)

A call is received.

If the user accepts the call, Signaling Engine asks the user for permission to use the microphone.

When permission is given, the local and remote streams are added.

For the callee (bob2) side:

Signaling Engine, on receiving the call invitation from the caller, triggers the function configured in the application to handle incoming calls.

This is the call object's onIncomingCall() callback function that was assigned in Example 4-4.

The application does the following:

- Sets up the actions in the callback function to handle changes in the call.

- Displays control buttons to enable the callee to accept or decline the call.

In onIncomingCall(). Drawing up Control buttons to accept or deny the call.
Calling setEventHandlers from onIncomingCall() with callObj
In setEventHandlers

User Accepted the call.
In callStateChangeHandler().
callstate : {"state":"STARTED","status":
{"code":null,"reason":"receive call"}}
Invoking getTurnAuthInfo
In mediaStreamEventHandler.
mediastate : LOCAL_STREAM_ADDED

In mediaStreamEventHandler.
mediastate : REMOTE_STREAM_ADDED

How a Call is Established in the Sample Audio Call Application

This section uses the sample audio call application as an example to describe what happens during the interval between the caller and callee requesting and accepting the call and when the call actually starts.

At the start of the flow, the sample audio call application on the caller's side sends the START or INVITE message to WebRTC Session Controller Signaling Engine which routes the message through the network to the receiving end point. For more information on this, please see WebRTC Session Controller Extension Developer's Guide.

At appropriate points in the message flow, the caller and callee are requested to allow access to the audio element in the browser.

The log output taken from the console when the sample audio call application was run is shown in Table 4-4. Note the log output from the call state and media state transfer event handlers. All the action is done by Signaling Engine and the sample audio call application merely receives the final state (ESTABLISHED or FAILED).

Table 4-4 A Log of the Call Flow

Sample Audio Call Application Page Events

Actions Taken by the Sample Audio Call Application

Console Log for the Caller (bob1)

Console Log for the Callee (bob2)

(Activity that takes place behind the browser activity)

For the caller, the media state changes to include the remote media stream only after the call is established.

The console log describes the flow of the call to the point where the two parties are connected and can hear each other.

The application displays the control button enabling either party to conclude the call.

In callStateChangeHandler().
callstate : {"state":"RESPONSED","status":
{"code":200,"reason":"got success response"}}
In callStateChangeHandler().
callstate : {"state":"ESTABLISHED","status":
{"code":null,"reason":"sent complete"}}

In callStateChangeHandler().
callstate : {"state":"RESPONSED","status":
{"code":200,"reason":"sent success response"}}

In callStateChangeHandler().
callstate : {"state":"ESTABLISHED","status":
{"code":null,"reason":"got complete"}}

Monitoring the Call

The call is established when the callee accepts the call. However, your application needs to provide some way for both parties to end the call.

Note:
A call can be ended by either party (caller/callee).
When a call is ended by one party, the other party will receive a message from the browser that the call has ended and this ENDED state will trigger the message stream event handler to release the local media stream.

See the Console Log for the Caller and Console Log for the Callee columns in Table 4-6.

To monitor the call and take action, do the following in your application:

- Display the user interface necessary for the user to end the call.

- Provide the logic for the caller or the callee to end the call.

- Take appropriate actions for the following events:

- A user actively ends the call.

- The other party ends the call.

As shown in Example 4-14, the sample audio call application does the following:

- Displays two control buttons for the users: "Hang Up" and "Logout".

- Responds to the selection:

- If Hang Up is clicked, ends the call (which ends the call session and releases the call resources).

- If Logout is selected, ends the session (which ends the call and releases the session's resources).

Example 4-14 Monitoring the Established Call

function callMonitor(callObj) {
console.log ("In callMonitor");
console.log ("Monitoring the call. Setting up controls to Hang Up.");
console.log (" ");

// Draw 2 buttons.
// "Hang Up" button ends the call, but user stays on the application page.
// "Logout" button ends the session, and user leaves the application.
// For the complete code, see "Sample Audio Call Application".
...
document.getElementById("btnHangup").onclick = function() {
....
callObj.end();
};
}

How the Sample Audio Call Application Monitors a Call

Table 4-5 reports on the sample audio call application's actions in monitoring a call session. It describes the events that occur on the sample audio call application page, the actions taken by the sample audio call application, and the messages logged by the console.log method for this segment of the application code.

Table 4-5 How the Sample Audio Call Application Monitors the Call

Sample Audio Call Application Page Events

Actions Taken by the Sample Audio Call Application

Console Log for the Caller (bob1)

Console Log for the Callee (bob2)

The remote stream is added for the caller.

The call takes place.

Control buttons are displayed to enable either party to end the call.

When the call state is ESTABLISHED, the application does the following on the caller's (bob1) side:

- Sets up the controls to enable the caller to end the call.

- Adds the remote media stream enabling the caller to hear the "Hello?"

On the callee's (bob2) side:

Sets up the controls to enable the callee to end the call.

In callStateChangeHandler().
callstate : {"state":"ESTABLISHED","status":
{"code":null,"reason":"sent complete"}}
Call is established. Calling callMonitor.

In callMonitor.
Monitoring the call. Setting up controls to Hang Up.
In mediaStreamEventHandler.
mediastate : REMOTE_STREAM_ADDED

In callStateChangeHandler().
callstate : {"state":"ESTABLISHED","status":
{"code":null,"reason":"got complete"}}
Calling callMonitor.

Call established. Setting up controls to Hang Up.

Ending the Call

When either the callee or caller ends the call, the call state goes to ENDED which triggers the browser to stop the call. The local media stream is removed from each browser application.

Set up the next action according to your application's requirements.

In the sample audio call application as shown in Example 4-11, the application calls the displayInitialControls() function which renders the controls to make calls.

Table 4-6 reports on the sample audio call application's actions in ending a call session. It describes the events that occur on the sample audio call application page, the actions taken by the sample audio call application, and the messages logged by the console.log method for this segment of the application code.

Table 4-6 A Breakdown of How the Sample Audio Call Ends

Sample Audio Call Application Page Events

Actions Taken by the Sample Audio Call Application

Console Log for the Caller (bob1)

Console Log for the Callee (bob2)

One or the other party can end the call.

In this example, bob1, the caller, ended the call.

The console log for the caller from the callMonitor() function specifies who ended the call.

At this point note the differences in the console log entries for the caller and callee.

The example code also once again displays the input buttons for the user to make a call.

- Either the caller or the callee clicks the control button to end the call.

- The state of the call changes to ENDED.

- The local media stream for the browser is disconnected.

- At this point, your application's logic may vary.

- In this example, the controls to make a call are displayed once again.

In callMonitor.
Caller, bob1@example.com, clicked the Hang Up button.
Calling call.end now.

In callStateChangeHandler().
callstate : {"state":"ENDED","status":
{"code":null,"reason":"stop call"}}
Call ended. Displaying controls again.

In displayControls().
Waiting for Callee Input.

In mediaStreamEventHandler.
mediastate : LOCAL_STREAM_REMOVED

In callStateChangeHandler().
callstate : {"state":"ENDED","status":
{"code":null,"reason":"stop call"}}
Call ended. Displaying controls again.

In displayControls().
Waiting for Callee Input.

In mediaStreamEventHandler.
mediastate : LOCAL_STREAM_REMOVED

Current Stage in the Development of the Audio Call Feature in Your Application

At this stage in the development of the audio call feature in your application:

- The general elements required for audio calls are set.

- Your application can obtain the callee information.

- Your application can retrieve the call information and start a call.

- Your application can alert the user about an incoming call and respond appropriately to the user accepting or declining the incoming call.

- The application logic for the following functions should be implemented:

- Callback functions assigned to the Session Object's event handlers

- The success and error callback functions invoked when a Session object is not created

- Callback functions assigned to the CallPackage Object's event handlers

- Callback functions assigned to the Call Object's event handlers

- The error callback function invoked when a Call object is not created

- Your application can monitor the established call, take action as necessary when there is a change to the call in any way.

- When one user ends the call, our application can close the call connection successfully.

Closing the Session When the User Logs Out

The close() method of the Session API is used to close a session with WebRTC Session Controller Signaling Engine. The syntax is:

wscSession.close();

Set up the logic to close the session according to your application's requirements.

In the sample audio call application, when the user clicks the Logout button, the application calls the logout function to close the session as shown in Example 4-15. Additionally, the user is sent back to the location specified in logoutUri (which was defined in Example 4-1 at the start of this sample code).

Example 4-15 Sample Logout Function

function logout() {
if (wscSession) {
wscSession.close();
}
// Send the user back to where he came from.
window.location.href = logoutUri;
}

In your environment, the call feature may be one of the many features of your application. For this example, and at this point, the sample audio call application has completed its task. All that remains is to provide the closing entries for the HTML element tags.

The code for the sample audio call application discussed in this chapter can be seen under "Sample Audio Call Application".

Other Actions on Calls

This section describes some of the other actions your application can take on calls.

Gathering Information on the Current Call

You can obtain the following data about the current call by using the methods of the Call object:

- The caller or the callee by using the Call.getCaller or Call.getCallee method respectively.

- The call configuration by using the Call.getCallConfig method.

- The call state by using the Call.getCallState method.

- The data transfer object by its label using the Call.getDataTransfer(label) method.

- The RTCPeerConnection (peer-to-peer connection) of the current call by using the Call.getPeerConnection method. For example, when the call employs dual-tone multi-frequency (DTMF) signal tones, use its getPeerConnection method to perform operations directly on the WebRTC PeerConnection connection.

Note:
The peer connection for the current call may change. Always retrieve its current value using the getPeerConnection method for your call object, and then use the result.

Supporting Multiple Calls Using CallPackage

Since the CallPackage class object can handle an array of calls, you can configure your application to set up and manage an array of calls (both incoming and outgoing). The basic logic outlined in "Overview of Setting Up the Audio Call Feature in Your Application" can be used in this scenario. Update this logic so that your application properly manages each specific call session in the array of calls with respect to maintaining the details of the call details, handling changes to the call, media or session states.

See "Extending Your Applications Using WebRTC Session Controller JavaScript API" for more information on extending the Call and CallPackage API.

Managing Interactive Connectivity Establishment Interval

Your application can configure the time period within which the WebRTC Session Controller JavaScript API library uses the Interactive Connectivity Establishment (ICE) protocol to set up the call session. This procedure comes into play when your application is the caller and your application starts the call setup with its Call.start command.

About the Use of ICE and ICE Candidate Trickling

ICE is a technique which determines the best possible pairing of the local IP address and the remote IP address that can be used to establish the call session between the two applications associated with the caller and the callee. Each user agent (caller or callee's browser) has an entity (such as WebRTC Session Controller Signaling Engine) which acts as the ICE agent and collects and shares possible IP addresses. The final pair of IP addresses is elected after gathering and checking possible candidates (IP addresses) and taking into account the security of the end point applications and of the call connection. The media connection is established only after the ICE procedure finds an appropriate pair of IP addresses with which to communicate.

About WebRTC Session Controller Signaling Engine and the ICE Interval

WebRTC Session Controller Signaling Engine enables your applications to limit the time taken by the ICE agent to set up a call session by enabling you to specifying the ICE interval your application allows for this deliberation process.

The default value ICE interval for a call setup is 2000 milliseconds.

Signaling Engine checks the status of the ICE candidate periodically. If new candidates are gathered, the ICE agent will attempt to send this information in JSON format in the START message to the other peer.

Retrieving the Current ICE Interval for the Call

To retrieve the current ICE interval, use the getIceCheckInterval method of your application's call object. The interval is returned in milliseconds.

Setting Up the ICE Interval for the Call

To set the current ICE interval, provide the time interval in milliseconds when you call the setIceCheckInterval method of your application's Call object.

Enabling Trickle ICE to Improve Application Performance

To improve performance when Web applications negotiate connections from private networks behind Network Address Translation (NAT)-enabled routers using the Interactive Connectivity Establishment (ICE) protocol, WebRTC Session Controller supports the draft IETF Trickle ICE specification (http://tools.ietf.org/html/draft-ietf-mmusic-trickle-ice-01).

Trickle ICE, when enabled, allows ICE host Traversal Using Relays around NAT (TURN) candidates to be exchanged incrementally rather than requiring a full protocol negotiation which can take some time depending upon network conditions.

Note:
Firefox does not support Trickle ICE.

To enable Trickle ICE functionality, after you have instantiated a CallPackage object, use the setTrickleIceMode method with the appropriate value:

callPackage = new wsc.CallPackage(wscSession);
callPackage.setTricleIceMode(mode);

The mode variable is one of the following values:

- off: Trickle ICE is disabled (default)

- half: for use in cases where full Trickle ICE support cannot be assumed on the receiving endpoint

- full: full Trickle ICE support

Updating a Call

When a call is in an ESTABLISHED state, the caller or the callee may wish to update the call in one of a set of supported or configured ways. For example, one or the other party may select or deselect the mute button on a call, or move from an audio to a video format for the call. As a result, your application may need to update the call for the specific reason.

In order to handle this scenario,

- Set up the necessary interface to capture the information your application user provides on:

- The type of update the user wishes to make

- The accept or decline response to the update request

- From the point of view of the person initiating the update:

- Set up the callback function to invoke when your application user requests the update.

- Configure the parameters (CallConfig, and localStreams) required for the update.

- Invoke the Call.update method with the CallConfig, and localStreams parameters.

- Provide the required logic in the callback function assigned to your application's Call.onCallStateChange event handler for each of the possible call state changes relating to updates, wsc.CALLSTATE.UPDATED and wsc.CALLSTATE.UPDATE_FAILED.

- Save any data specific to your application.

- Set up the actions in response to the other party declining the update.

- From the point of view of the person receiving the update:

- Set up the callback function you assign to the Call.onUpdate event handler when your application receives the update request from Signaling Engine.

- Process the parameters (CallConfig, and localStreams) required for the update.

- Invoke the Call.accept method with CallConfig, and localStreams parameters.

- Set up the required logic in the callback function assigned to your application's Call.onCallStateChange for each of the possible call state changes relating to updates, wsc.CALLSTATE.UPDATED and wsc.CALLSTATE.UPDATE_FAILED.

- Save any data specific to your application.

Reconnecting Dropped Calls

At times, a drop in reception quality or some other event may cause a call that is in progress to be momentarily dropped and reconnected. When a call has been recovered, the WebRTC Session Controller JavaScript API library invokes your application's CallPackage.onResurrect event handler with the rehydrated call as the parameter. Your application can handle this scenario by providing the logic in the callback function assigned to the CallPackage.onResurrect event handler to use the rehydrated call object and resume the call.

Important:
If you create a custom call package, be sure to implement the appropriate logic to resume your application operation and reconnect calls.

To reconnect the call, do the following in your application:

1. If callPackage is the name of your application's CallPackage object, add the following statement to assign a callback function to its onResurrect event handler:

callPackage.onResurrect = onResurrect;

2. Set up the callback function (onResurrect in this case).
In this callback function, be sure to resume the call after you perform any necessary actions. For example,

function onResurrect(resurrectedCall) {
...
resurrectedCall.resume(onResumeCallSuccess, doCallError);
}

3. Set up the onResumeCallsuccess success callback for the Call.resume method.
For example,

function onResumeCallSuccess(callObj) {
// Is the call in an established state?
if (callObj.getCallState().state == wsc.CALLSTATE.ESTABLISHED) {
// Call is in established state. Take action.
...
} else {
// Call is not in established state. Take action.
...
}
}

The doCallError callback function should have been defined earlier when the application's Call object was created.

5 Setting Up Video Calls in Your Applications

This chapter shows how you can use the Oracle Communications WebRTC Session Controller JavaScript application programming interface (API) library to enable your applications users to make and receive video calls from your applications, when your applications run on WebRTC-enabled browsers.

Note:
See Oracle Communications WebRTC Session Controller JavaScript API Reference for more information on the individual WebRTC Session Controller JavaScript API classes.

About Implementing the Video Call Feature in Your Applications

The WebRTC Session Controller JavaScript API associated with video calls enables your web applications to support video calls made to and received from other WebRTC-enabled browsers and Session Initiation Protocol (SIP)-based applications.

To support the video call feature in your application, update the application logic you used to set up audio calls in the following way:

- Setting up the <video> element for the video stream to display optimally on the application page.

- Enabling a user to make or receive a video call.

- Monitoring the video display for the duration of the video call.

- Adjusting the display element when the video call ends.

About the WebRTC Session Controller JavaScript API Used in Implementing Video Calls

The WebRTC Session Controller JavaScript API objects and methods you use in implementing video calls are the same API objects you would use to implement the audio call feature in your applications. See "About the WebRTC Session Controller JavaScript API Used in Implementing Audio Calls". You can extend the video call feature in your application to perform custom tasks by extending these APIs.

Setting Up Video Calls in Your Applications

You can use WebRTC Session Controller JavaScript API to set up the video call feature in your application to suit your deployment environment. The specific logic, web application elements, and controls you implement for the video call feature in your applications are predicated upon how the video call feature is used in your web application.

The logic to set up video calls in your applications is based on the basic logic described in "Overview of Setting Up the Audio Call Feature in Your Application". Supporting video calls becomes a matter of modifying that basic logic to set up, manage, and close video calls using the WebRTC Session Controller JavaScript API library and providing the associated display elements and controls on the application page.

When you have the basic code to place and receive audio calls using the WebRTC Session Controller JavaScript API library, update that application logic by doing the following:

- Setting Up the Video Display

- Specifying the Video Direction in the Call Configuration

- Managing the Video Display on Your Application Page

- Managing the Video Streams in the Media Stream Event Handler

- Provide the associated display elements and controls on the application page as required by your application and its deployment environment.

Setting Up the Video Display

After assessing your browser's support for video, set up the video display settings based on the requirements of your application and the deployment environment.

In Example 5-1, an application sets up the video interface using the attributes of the HTML <video> tag. It uses the width attribute to specify the display area in percentages and the autoplay attribute to specify that the video should start playing as soon as it is ready.

Example 5-1 Sample Video Display Settings

</table>
...
<!-- HTML5 audio element. -->
<tr>
<td width="15%"><video id="selfVideo" autoplay></video></td>
<td width="15%"><video id="remoteAudio" autoplay></video></td>
</tr>
</table>

Specifying the Video Direction in the Call Configuration

The WebRTC Session Controller JavaScript API library provides the videoMediaDirection parameter to specify the video capability for calls in the CallConfig class object.

Enable the video stream in your application when you create the CallConfig object by setting the video media direction variable (videoMediaDirection). See "Setting Up the Configuration for Calls Supported by the Application".

In Example 5-2, an application enables the user to send and receive video objects by setting the video media direction variable to wsc.MEDIADIRECTION.SENDRECV when it creates its CallConfig object.

Example 5-2 Call Configuration Updated to Include Video

// Create a CallConfig object.
var audioMediaDirection = wsc.MEDIADIRECTION.SENDRECV;
var videoMediaDirection = wsc.MEDIADIRECTION.SENDRECV;
var callConfig = new wsc.CallConfig(audioMediaDirection, videoMediaDirection);
console.log("Created CallConfig with video stream.");
console.log(" ");

Managing the Video Display on Your Application Page

Set up the video to display or be hidden as required by your application and your deployment environment. One way to manage your application page optimally would be to enable the video element in your application when the call is in the required state and not otherwise. When your application deals with a new state in the call, specify the hidden attribute for the media element and set it to the required display state of the video media.

In Example 5-3, an application has a callback function called callStateChangeHandler assigned to its Call.onCallStateChange event handler. The application uses this callback function to manage the video display based on the call state changes. The application sets the media.hidden value to:

- false when the call is established

- true for all other call states

Example 5-3 Including Video Display State

function callStateChangeHandler(callObj, callState) {
console.log (" In callStateChangeHandler().");
console.log("callstate : " + JSON.stringify(callState));
if (callState.state == wsc.CALLSTATE.ESTABLISHED) {
console.log (" Call is established. Calling callMonitor. ");
console.log (" ");
callMonitor(callObj);
media.hidden = false;
} else if (callState.state == wsc.CALLSTATE.ENDED) {
console.log (" Call ended. Displaying controls again.");
console.log (" ");
displayInitialControls();
media.hidden = true;
} else if (callState.state == wsc.CALLSTATE.FAILED) {
console.log (" Call failed. Displaying controls again.");
console.log (" ");
displayInitialControls();
media.hidden = true;
}
}

Managing the Video Streams in the Media Stream Event Handler

When the media state changes, the WebRTC session Controller JavaScript API library invokes the event handler you assigned to Call.onMediaStreamEvent in your application and provides it with the new media state. Use this new state to take action on the media stream, attaching or removing it as required.

In Example 5-4, an application has a callback function called mediaStreamEventHandler assigned to its Call.onMediaStreamEvent event handler. The application uses this callback function to manage the video media stream based on the value in mediaState, the new media state the application receives from the WebRTC session Controller JavaScript API library. The callback function retrieves the appropriate video element from document, the Document Object Model (DOM) object and attaches the stream to that video element, using the WebRTC attachmediastream function.

Example 5-4 Attaching Video Streams in the Media Stream Event Handler

// Attach media stream to HTML5 audio element.
function mediaStreamEventHandler(mediaState, stream) {
console.log (" In mediaStreamEventHandler.");
console.log("mediastate : " + mediaState);
console.log (" ");

if (mediaState == wsc.MEDIASTREAMEVENT.LOCAL_STREAM_ADDED) {
attachMediaStream(document.getElementById("selfVideo"), stream);
} else if (mediaState == wsc.MEDIASTREAMEVENT.REMOTE_STREAM_ADDED) {
attachMediaStream(document.getElementById("remoteVideo"), stream);
}
}

6 Setting Up Data Transfers in Your Applications

This chapter shows how you can use the Oracle Communications WebRTC Session Controller JavaScript application programming interface (API) library to send and receive data over the data channel established in calls from your applications, when your applications run on WebRTC-enabled browsers.

Note:
See WebRTC Session Controller JavaScript API Reference for more information on the individual WebRTC Session Controller JavaScript API classes.

About Data Transfers and Signaling Engine

The WebRTC Session Controller JavaScript data transfer API sets up peer to peer data channels based on the WebRTC data channel definition and manages the workflow of the message exchanges such as chat sessions in web applications.

The data being transferred could be a raw data object such as a binary large object (BLOB), DOMString, ArrayBuffer, ArrayBufferView. The WebRTC Session Controller JavaScript API library manages the data transfer only. It does not access the contents of the data object that it transfers.

This chapter describes how you can use the WebRTC Session Controller JavaScript API library to set up and manage call sessions that support data transfers by managing the flow of the data element in the communication, detecting changes in the data flow state, and responding accordingly to the changes.

About Setting Up Data Transfers in Your Applications

The WebRTC Session Controller JavaScript API related to data transfers support text-based communications such as text messaging and chat sessions when data channels are configured in calls connecting browser phones located on web applications hosted at other WebRTC-enabled browsers.

To support data transfers, do the following in your application:

- Set up the required user interface elements, such as for the chat session to display optimally on the application page.

- Enable users to make or receive data transfers in calls.

- Manage calls with data transfers by doing the following:

- Monitoring the state of the data channel.

- Handling the incoming data; and displaying it, if necessary.

- Sending the data object provided by the user.

- Adjust the display elements when the call with data transfer ends.

About the API Used to Manage the Transfer of Data

The following WebRTC Session Controller JavaScript API classes are used to manage the transfer of data in calls made from or received by your web application:

- The dataChannelConfigs parameter associated with the CallConfig class

- The CallPackage.onIncomingCall event handler

- The Call.onDataTransfer event handler

- The data transfer object, wsc.DataTransfer. See "Managing Data Channels Using wsc.DataTransfer".

- The data sender object, wsc.DataSender. See "Sending Data Using wse.DataSender".

- The data receiver object, wsc.DataReceiver. See "Handling Incoming Data Using wsc.DataReceiver".

Managing Data Channels Using wsc.DataTransfer

Set up an instance of the data transfer object, wsc.DataTransfer, to manage data channels between two peers. Table 6-1 lists its states.

Table 6-1 Data Transfer States

Setting for State

Description

none

The DataTransfer object has been created but no data channel has been established or is initializing.

starting

The data channel of DataTransfer object is initializing or is in negotiation to be established.

open

The data channel of DataTransfer object is established. The data channel is ready to send or receive data and data transfers can take place.

closed

The data channel of the DataTransfer object is closed.

Obtain information on the state of the data transfer object using the following:

- DataTransfer.getReceiver()
This method returns data on the receiver as an instance of the DataReceiver class.

- DataTransfer.onOpen
This event handler is invoked when the data channel of the DataTransfer object is open. Data can be sent over or received from the data channel. Assign and define a callback function to this event handler.

- DataTransfer.onClose
This event handler is invoked when the data channel of the DataTransfer object is closed. Data cannot be transferred. Assign and define a callback function to this event handler.

- DataTransfer.onError
This event handler is invoked when the data channel of the DataTransfer object has an error. Assign and define a callback function to this event handler.

See Oracle Communications WebRTC Session Controller JavaScript API Reference for more information on the wsc.DataTransfer class.

Sending Data Using wse.DataSender

Use the wsc.DataSender class object to send raw data.

Obtain the DataSender object from the DataTransfer object by calling the application's DataTransfer.getSender method. This method returns the DataSender object to your application.

Use the DataSender.send method to send raw data such as a text string or a BLOB using the data channel in the data transfer object.

Handling Incoming Data Using wsc.DataReceiver

Use the wsc.DataReciever class object to handle incoming raw data.

Obtain the DataReceiver object from the DataTransfer object by calling the application's DataTransfer.getReceiver method. This method returns the DataReceiver object to your application.

Assign and define a callback function to the DataReceiver.onMessage event handler. This event handler is called when a raw data object is received by the data channel of the DataTransfer object.

In the following example, an application retrieves an instance of the DataTransfer class in receiver. The callback function assigned to the onMessage event handler of the receiver object processes the incoming data.

onDCOpen = function(){
// Set up the receiver object
receiver = dataTransfer.getReceiver();
if(receiver){
receiver.onMessage = function (evt){
// Retrieve the data and assign it.
var rcvdDataElm = document.getElementById("rcvData");
rcvdDataElm.value = evt.data
}
}

See "Sample Event Handler Invoked When the Data Channel is Open" for more information.

The next section uses a chat session to show how the WebRTC Session Controller JavaScript API library can be used to support data transfers in your web applications.

Setting up Data Transfers in Your Application

You can use the WebRTC Session Controller JavaScript API library to set up data transfers in your application to suit your deployment environment. The specific logic, web application elements, and controls you implement for calls with data transfers in your applications are predicated upon how the data transfer feature is used in your web application.

The logic to set up data transfers in calls is based on the basic logic described in "Overview of Setting Up the Audio Call Feature in Your Application". Supporting data transfers in calls becomes a matter of modifying that basic logic to set up, manage, and close data channels using the WebRTC Session Controller JavaScript API library and providing the associated display elements and controls on the application page.

If the callee is not available, you can implement additional logic in your application to store the incoming data transfer (such as a text message) and provide a notification for the receiver. See "Setting Up Message Alert Notifications".

To support video calls in your applications, augment your application's audio call logic by implementing the following logic specific to data transfers:

- Setting Up the General Elements for the Data Transfer Feature

- Declaring Variables Specific to the Chat Sessions

- Setting Up the Configuration for Data Transfers in Chat Sessions

- Assigning the Data Transfer Event Handler to the Call Package

- Obtaining the Callee Information

- Starting the Call with the Data Transfer Feature in the Call

- Responding to Your User's Actions on an Incoming Call

- Setting Up the Chat Session User Interface

- Setting Up the Data Transfer State Event Handler for the Chat Session

- Managing the Flow of Data

- Monitoring the Chat Session

Setting Up the General Elements for the Data Transfer Feature

To set up the data transfer feature in your application, include the following in the <head> section of your application:

- The WebRTC Session Controller JavaScript API support libraries:

- wsc-common.js

- wsc-call.js

If your application uses other supporting libraries, reference them, as well.

Declaring Variables Specific to the Chat Sessions

For each data channel configured in your application's CallConfig object, your application needs a wsc.DataTransfer class object. And each wsc.DataTransfer class object is associated with a wsc.DataSender and a wsc.DataReceiver class object. Declare the variables necessary for the data channels supported by the calls made from or received by your application.

In Example 6-1, an application declares these objects at the start of the application.

Example 6-1 Sample Data Transfer Variables

var dataTransfer, sender, receiver;
var target, buddy1, buddy2;

Setting Up the Configuration for Data Transfers in Chat Sessions

The WebRTC Session Controller JavaScript API library provides the dataChannelConfigs parameter to define the data channel for calls in the CallConfig class object. This dataChannelConfigs parameter is an array of JavaScript Object Notation (JSON) objects that describe the configuration of the data channel.

In order to define just the data channel in the call configuration for the application, input the data channel capability in the dataChannelConfigs parameter when you create the CallConfig object in your application.

In Example 6-2, an application enables the user to send and receive data by setting the data channel capability in the dataChannelConfigs object when it creates its CallConfig object:

Example 6-2 Sample Call Configuration Object for Data Transfers

// create a CallConfig object.
var dtConfigs = new Array();
dtConfigs[0] = {"label":"ChatOverDataChannel", "reliable" : false };
var callConfig = new wsc.CallConfig(null,null,dtConfigs);

Assigning the Data Transfer Event Handler to the Call Package

When the WebRTC Session Controller JavaScript API library receives data transfer object for the user, it invokes the CallPackage.onIncomingCall event handler in your application. Assign a callback function to handle the data transfer object received by your application.

Alternatively, you can assign a single callback function to your application's CallPackage.onIncomingCall event handler and within that callback function implement the logic to handle the incoming audio, video calls or data transfers.

In Example 6-3, an application creates its CallPackage object within a callback function called sessionSuccessHandler which is called when the application Session object is created. In the sessionSuccessHandler function, the application assigns a callback function named onIncomingDataTransferCall to its Call.onIncomingCall event handler.

Example 6-3 Sample sessionSuccessHandler for Data Transfers

function sessionSuccessHandler() {
// Create the CallPackage.
callPackage = new wsc.CallPackage(wseSession);
// Bind event handler of incoming call.
if(callPackage){
callPackage.onIncomingCall = onIncomingDataTransferCall;
}
// Other application-specific logic.
...
}

See Example 6-6 for a description of the onIncomingDataTransferCall function.

Obtaining the Callee Information

Define the user interface to enable the caller to input the callee ID of the person with whom the chat session is to be established. And provide the underlying logic for the appropriate functions to be called when the caller enters text or selects the control buttons. You need to set up the function that will start the chat session.

In Example 6-4, an application calls a function named displayInitialControls to provide the user interface and controls for calls with data transfers. As with the sample audio call application, this application calls the displayInitialControls function when the session state is CONNECTED.

In this function:

- An input field is provided for the callee ID along with the Start a Chat Session control button.

- The onclick= action for the Start a Chat Session control button triggers a function called startDataTransfer to start the setup for the chat session. In addition, it also defines other functions to invoke when the user selects to cancel or log out.

Example 6-4 Sample Code to Receive Callee Information

function displayInitialControls() {
...
var controls = "Enter the Name of Your Chat Buddy: <input type='text' name='dataTarget' id='dataTarget'/><br>"
+ "<input type='button' name='startDataTransfer' id='startDataTransfer' value='Start a Chat Session ' onclick='startDataTransfer()'/><br><br>"
+ "<input type='button' name='cancelButton' id='cancelButton' value='Cancel Chat' onclick='' disabled ='false'/>"
+ "<br><br><br>"
+ "<input type='button' name='logoutButton' id='logoutButton' value='Logout' onclick='logout()'/>"
+ "<hr>";

setControls(controls);
// Verify the input is not blank or invalid number..
...
...
}

Starting the Call with the Data Transfer Feature in the Call

When you receive the callee information, you need to start the setup for the call by creating the Call object, implementing the logic to handle events associated with the Call object, invoking Call.Start, and setting up the required user interface and controls for the chat session.

In Example 6-5, an application uses a function called startDataTransfer to perform these actions. The basic logic is similar to the onCallSomeOne function used in the sample audio call application. See "Starting a Call From Your Application". The application invokes startDataTransfer when it receives the callee information and the user's request to start a chat session.

Example 6-5 Sample startDataTransfer Function

function startDataTransfer() {
// Store the caller and callee names.
...
// Check to see if the user gave a valid input. Omitted here.
...
// Create the  call object.
var call = callPackage.createCall(target, callConfig, doCallError);
// Set up the call object's components.
if (call != null) {

//Call object is valid. Call the required event handlers.
setEventHandlers(call);
....

//Set the event handler to call when a data transfer object is created.
call.onDataTransfer = onDataTransfer;

// Then start the call.
call.start();

// Allow a user to cancel the call before it is set up.
// Disable "Start a Chat Session" button and enable "Cancel" button.
// If a user clicks Cancel, call end() for the call object.
// Call displayInitialControls() to display the initial input fields.
....
}
}

Responding to Your User's Actions on an Incoming Call

When a user who is logged in to your application receives an in-browser call from another user, the WebRTC Session Controller JavaScript API library invokes the CallPackage.onIncomingCall event handler in your application. It sends the incoming call object and the call configuration for that incoming call object as parameters to your application's CallPackage.onIncomingCall event handler.

Define the actions to the incoming call in the callback function assigned to your application's CallPackage.onIncomingCall event handler in the following way:

- Provide the user interface and logic necessary for the callee to accept or decline the call.

- Provide logic for the following events:

- User accepts the call. Run the accept method for the incoming call object. This will return the success response to the caller.

- User declines the call. Run the decline method for the incoming call object. This will return the failure response to the caller.

- Set up the user interface for the data transfers in the call.

- Assign the callback functions to the event handlers of the incoming call object. These should already have been defined.

In Example 6-6, an application uses the onIncomingDataTransferCall callback function assigned to its Call.onDataTransfer event handler. The basic logic is similar to the onCallSomeOne function used in the sample audio call application. See "Responding to Your User's Actions on an Incoming Call". The application uses the incoming call object (dtCall) and the call configuration for that incoming call object (callConfig):

Example 6-6 Sample onIncomingDataTransferCall Function

function onIncomingDataTransferCall(dTCall, callConfig) {

// Assign the event handler onDataTransfer to the call object
dTCall.onDataTransfer = onDataTransfer;

var dElement = document.getElementById("dataTarget");

// We need the user's response.
// Display an interface that lets a user decline or accept a call
// Attach event handlers to these events.
...
document.getElementById("acceptDTBtn").onclick = function() {
// Chat session accepted
dTCall.accept(callConfig, null);

// At this point, update the user interface for the callee
// Display the fields, controls for text and ending the chat session.
...
}
document.getElementById("declineDTBtn").onclick = function() {
dTCall.decline(null);
}
setEventHandlers(dTCall);
call = dTCall;

}

Setting Up the Chat Session User Interface

The design of your application's page determines the type of user interface for the chat session. Use your application's DataSender object and its send method to send the data entered by the user. Assign callback functions for the controls you use in the interface and set up the actions within those callback functions.

Setting Up the Data Transfer State Event Handler for the Chat Session

The DataTransfer class object contains three event handlers:

- onClose which indicates that the data channel of a DataTransfer object is closed.

- onOpen which indicates that the data channel of a DataTransfer object is open.

- onError which indicates that the data channel of a DataTransfer object is in error.

Assign the callback function to handle each of the events and provide the logic for each callback function.

In Example 6-7, an application shows the callback function onDataTransfer which was assigned to Call.onDataTransfer event handler. In this onDataTransfer function, the application assigns a callback function to each of the onOpen, onClose and onError event handlers of the data transfer object.

Example 6-7 Sample onDataTransfer Callback Function

onDataTransfer = function(dT) {
dataTransfer = dT;
dataTransfer.onOpen = onDCOpen;
dataTransfer.onError = onDCError;
dataTransfer.onClose = onDCClose;
};

Managing the Flow of Data

To maintain and manage the flow of data in the data channel, implement the logic in the callback functions to handle the Open, Close, and Error states of the data transfer object.

To do so, provide the logic required to handle the following in your application:

1. The Open state for the data channel. See "Handling the Open State of the Data Channel".

2. The received text. See "Handling the Received Text".

3. Sending the text entered in the text field. See "Sending the Text".

4. The Close state for the data channel. See "Handling the Closed State of the Data Channel".

5. The Error state for the data channel. See "Handling Errors Related to Data Transfers".

Handling the Open State of the Data Channel

When the data channel is open, your application can do the following:

- Retrieve its Datasender and DataReceiver objects from its DataTransfer object.
The DataSender and DataReceiver objects are returned when you call your application's DataTransfer.getSender and DataTransfer.getReceiver methods. For the receiver, the data is from the remote peer of the current data channel session.

- For the receiver of the data, retrieve the data from the remote peer of current data channel session, and display it.

- Other actions as necessary. Your application sets up the logic necessary to save the incoming and outgoing text to display the chat session appropriately.

Provide the logic for your application's DataTransfer.onOpen event handler as required by your application.

In Example 6-8, when the data channel is open in an application, the callback function assigned as the event handler assigned to the application's DataTransfer.onOpen event handler processes the data transfer object.

Example 6-8 Sample Event Handler Invoked When the Data Channel is Open

onDCOpen = function(){
// Set up the receiver object
receiver = dataTransfer.getReceiver();
if(receiver){
receiver.onMessage = function (evt){
// Retrieve the data and assign it.
var rcvdDataElm = document.getElementById("rcvData");
rcvdDataElm.value = evt.data;
}
}

// Retrieve the sender
sender = dataTransfer.getSender();

var dcReadyState = dataTransfer.state;

// Set up the control buttons appropriately
var sendDataBtn = document.getElementById("sendData");
sendDataBtn.hidden = false;
var dataForChannel = document.getElementById("dataForChannel");
dataForChannel.hidden = false;
dataForChannel.value="";
var endButton = document.getElementById("endDataChannel");
endButton.hidden = false;
var rcvdDataElm = document.getElementById("rcvData");
rcvdDataElm.value = "";
rcvdDataElm.hidden = false;

var acceptBtn = document.getElementById("acceptDTBtn");
if(acceptBtn){
acceptBtn.hidden = true;
var declineBtn = document.getElementById("declineDTBtn");
declineBtn.hidden = true;
}
}

Handling the Received Text

Set up the logic to handle the text that is received by your application user.

In Example 6-9, an application uses a utility function named onReceiveDTMsg to handle the received text.

Example 6-9 Sample Function to Assign Received Text

onReceiveDTMsg = function(data) {
var rcvdDataElm = document.getElementById("rcvData");
rcvdDataElm.value = data;
}

Sending the Text

When the user enters text and clicks the control to send the text, provide the logic to send the text entered in the text field using your application's DataSender.send method.

In Example 6-10, an application uses a utility function named send to retrieve the data from the Document Object Model (DOM) object. It calls the method of the application's DataSender.send method with this data.

Example 6-10 Sample Send Function

send = function(){
// get the data from the text field
var data = document.getElementById("dataForChannel").value;
if(sender) {
sender.send(data);
document.getElementById("dataForChannel").value = "";
} else {
console.log("sender is null");
}
}

Handling the Closed State of the Data Channel

Set up the logic to handle the closed state of the data channel.

Example 6-11 shows the function expression for onDCClose to handle the Close state for the data channel.

Example 6-11 Sample Event Handler Invoked When the Data Channel is Closed

onDCClose = function(){
var dcReadyState = dataTransfer.state;
}

Monitoring the Chat Session

Update the logic used to monitor the call by providing some way for both parties to end the chat session.

In the audio call application described in "Setting Up Audio Calls in Your Applications", a function named callMonitor is called by the callback function assigned to the application's Call.onCallStateChange event handler. As shown in Example 4-11, the callMonitor function is called when the call state is WSC.CALLSTATE.ESTABLISHED.

At this point, do the following in your application:

- Display the user interface necessary for the chat session.

- Provide the logic for the actions to take when the chat session ends.

Note:
A chat session can be ended by the caller or the callee.

In Example 6-12, an application does the following:

- Displays the user interface for the chat session.

- Responds to the selection:

- If End Chat Session is clicked, ends the call (which ends the chat session and releases the call resources).

- If Logout is selected, ends the session (which releases the session's resources).

Example 6-12 Monitoring the Chat Session

function callMonitor(callObj) {

// Draw up the user interface for the callee.
...

// Set the button of ending a dataTransfer call
var endBtn = document.getElementById("endDataChannel");
if (endBtn){
// Set the event handler when clicking the end button
endBtn.onclick = function() {
if(dataTransfer != null) {
// There is some data.
// This function merely sets the text to blank.
document.getElementById("dataForChannel").value = "";
}

// End the data channel call.
callObj.end();
};
}
}

7 Setting Up Message Alert Notifications

This chapter shows how you can use the Oracle Communications WebRTC Session Controller JavaScript application programming interface (API) library to enable your application users to subscribe to and receive message alert notifications from your applications.

Note:
See Oracle Communications WebRTC Session Controller JavaScript API Reference for more information on the individual WebRTC Session Controller JavaScript API classes.

About Message Alert Notifications and Signaling Engine

Message alert notifications consist of text, pager, fax, voice, and multimedia message notifications that are useful ways to enable users to access and retrieve such communication at a later time. These messages could be stored on designated message servers for a configurable time to be accessed by the respective recipients.

You can use WebRTC Session Controller JavaScript API to enable your application users to subscribe to notifications.

Note:

- The web user interface aspects required to enable the user to subscribe to or to retrieve notifications are beyond the scope of this document.

- All other aspects of a stored message service system such as creating the message, storing it, accessing the message server, retrieving the message, and forwarding, storing or destroying the message are dependent on the environment where your application is deployed.

Handling Message Notifications in Your Web Applications

To handle message alert notifications, the logic in your application must accomplish the following tasks:

- Include the following WebRTC Session Controller JavaScript API support libraries in the <head> element of your HTML page:

- wsc-common.js

- wsc-msgalert.js

If your application uses other supporting libraries, reference them, as well.

- Enable a user to subscribe to receiving notifications.
To do so, in your application:

- Provide the interface elements necessary for the user to specify the service target.

- Set up the subscription when the service target is received from the subscriber.

- Enable the user to access and process the received notifications.
To do so, in your application:

- Set up the elements necessary to receive the incoming notification.

- Process the information and display it for the user.

- Set up the logic to respond to the user's actions on the subscriptions.

- Respond to the end of a subscription resulting from the following events:

- The user stops the current subscription to notifications.

- The provider of the notification ends the notifications to this subscriber. The WebRTC Session Controller JavaScript API library invokes the event handler which indicates to your application that the subscription has ended.

About the API Used to Manage Message Alert Notifications

In addition to the general WebRTC Session Controller JavaScript API objects, the following API objects are used to manage message alert notifications in your applications:

- wsc.MessageAlertPackage to enable message alert notifications. See "Managing Message Alert Notifications with wsc.MessageAlertPackage".

- wsc.Notification to manage notifications. See "Handling Notifications with wsc.Notification".

- wsc.Subscription to manage subscriptions. See "Subscribing to Notifications with wsc.Subscription".

- wsc.MessageSummary to obtain message summary information. See "Getting Message Summary Information".

- wsc.MessageCounts to obtain the number of messages by the type of message. See "Retrieving Message Counts from Message-Summary Notifications".

See "Extending Your Applications Using WebRTC Session Controller JavaScript API" for information on extending these objects.

Managing Message Alert Notifications with wsc.MessageAlertPackage

Manage messaging alert notifications for pending voice mails, fax messages, and so on during the specified session with an instance of the wsc.MessageAlertPackage class. This object enables message alert notification applications. Use it to create new subscriptions for notifications, manage active subscriptions, and handle received message notifications. When you use wsc.MessageAlertPackage, the WebRTC Session Controller JavaScript API library handles the messaging flow for the notifications.

Create an instance of wsc.MessageAlertPackage, such as messageAlertPackage, using your application's Session object. You can create an array of subscriptions in your application and use the messageAlertPackage object to manage the user's alert and message notifications for each subscription.

If the web page reloads, set up the logic to restore failed subscriptions. To do so, assign a callback function to your application's MessageAlertPackage.onResurrect event handler. The WebRTC Session Controller JavaScript API library provides the rehydrated subscription data as a parameter to the callback function assigned to your application's MessageAlertPackage.onResurrect event handler.

See "Extending and Overriding WebRTC Session Controller JavaScript API Object Methods" for more information on extending the MessageAlertPackage API.

Handling Notifications with wsc.Notification

Use the wsc.Notification class to obtain the information associated with a notification, such as the identity of the sender, the content of the notification, and the identity of the receiver.

If your application receives a message notification for a subscription, the WebRTC Session Controller JavaScript API library provides the notification when it invokes the onNotification event handler for your application's Subscription object.

Inspect the incoming notification in the callback function you assigned to your application's Subscription.onNotification event handler to process the information using:

- The wsc.MessageSummary class, derived from the wsc.Notification class.
It holds the message summary of the incoming notification.

- The wsc.MessageCounts class which holds the number of new and old messages retrieved from the message summary, grouped as regular or urgent.

You can retrieve the following information:

- The number of a specific type of message, such as the number of new and/or old voice message messages in your application's MessageSummary object.
To retrieve the number of a specific type of message, call the getMessageCounts method of your application's MessageSummary object and input the type of message as msgClassType.

- The message content in the incoming notification, by using the getContent method of your application's Notification object. The message content is returned as a JavaScript Object Notation (JSON) object.

- The identity of the receiver of the incoming notification, by using the getReceiver method of your application's Notification object.

- The identity of the sender of the incoming notification, by using the getSender method of your application's Notification object.

Subscribing to Notifications with wsc.Subscription

The wsc.Subscription class can be used to enable your application users to subscribe to notifications.

When your application user provides the service target such as voice_mail@example.com, you can create a Subscription object (for example, subscription) using the MessageAlertPackage.createNewSubscription method. The service target voice_mail@example.com represents a service in the telecommunication network that can send message alert notifications for such a subscription. Note that, WebRTC Session Controller must be configured in order to route the subscription requests to such a service.

Manage subscriptions by providing logic for the following:

- The Subscription.onNotification event handler
Assign and set up the callback function for your application's Subscription.onNotification event handler to handle incoming message notifications for the current subscription.

- The Subscription.onEnd event handler
Assign and set up the callback function for your application's Subscription.onEnd event handler to handle the end message for a subscription.

- The validity of a subscription
Use the Subscription.isValid method to check and take action based on the validity of the current subscription.

- The ending of the current subscription
Use the Subscription.end method to stop the current subscription and end message notifications for it.

Getting Message Summary Information

The wsc.MessageSummary class is extended from wsc.Notification. When the WebRTC Session Controller JavaScript API library receives a notification whose event type is message-summary, the MessageAlertPackage API creates an instance of the MessageSummary object. It provides the MessageSummary object as input to the callback function you assigned to your application's Subscription.onNotification event handler.

In the callback function, you can use the following methods:

- MessageSummary.getMessageAccount
Use the MessageSummary.getMessageAccount method to retrieve the message account for the current message summary notification in a String format.

- MessageSummary.getMessageCounts(msgClassType)
where msgClassType represents the message class type. The count of the number of msgClassType messages is returned to your application in an instance of the wsc.MessageCounts object. Use the methods of wsc.MessageCounts to get more details on the notification.

For example, input the string "voice_message" or "fax_summary" to retrieve the count of the number of voice or fax messages for this subscription. This message class type corresponds to the Session Initiation Protocol (SIP) notification message class type.

- MessageSummary.isMessageWaiting
If there is a message waiting in the incoming notification, the MessageSummary.isMessageWaiting method returns the boolean value true.

Retrieving Message Counts from Message-Summary Notifications

The wsc.MessageCounts class contains the number of msgClassType messages in a message-summary type of notification.

To obtain the message count when your application receives a message-summary notification as a MessageSummary object (for example, msgSummary, do the following in your application:

1. Retrieve the message count by invoking the MessageSummary.getMessageCounts method.
This method returns the message counts as an instance of wsc.MessageCounts, for example, msgCounts.

2. Retrieve the messages by age and urgency. Use:

- MessageCounts.getUrgentNew to retrieve the urgent messages that are new

- MessageCounts.getNew to retrieve the normal messages that are new

- MessageCounts.getUrgentOld to retrieve the urgent messages that are old

- MessageCounts.getOld to retrieve the normal messages that are old

3. Provide the information to the user as required.

In Example 7-1, an application uses a callback function called onNotify to process an incoming notification called incomingNotification. If the instance of the MessageCounts object retrieved from incomingNotification is not null, the function retrieves the number of normal and urgent messages that are new in newnormal and newurgent.

Example 7-1 Obtaining Number of Messages by Type

function onNotify(incomingNotification) {
var msgCount = incomingNotification.getMessageCounts("voice_message");
if(msgCount != null){
// Deal with the New and Old normal and Urgent messages
var newurgent = msgCount.getNewUrgent();
var newnormal = msgCount.getNew();
...
};
}

The application in the above example can then update the display for the device for example, update the audio or visual display for the message-waiting indicator on the browser page.

Managing Subscriptions

Managing user subscriptions to notifications in your applications consists of the following tasks:

- Enabling the User to Subscribe to Notifications

- Setting Up a Subscription

- Handling the Ending of a Subscription

- Restoring a Subscription

Enabling the User to Subscribe to Notifications

To enable your application user to subscribe to notifications:

- Set up your application's message alert notification package using your application's session. In the following example, an application sets up a message alert notification package called MsgAlertHandler with reference its application session, wscSession.

MsgAlertHandler = new wsc.MessageAlertPackage(wscSession);

- Set up the interface for the user to enter the information on the service target.

- Define the logic in the callback functions to respond to the user's actions.

Setting Up a Subscription

To implement the logic to support subscriptions, your application needs to create a subscription when the user enters a target for a subscription service. The target could be for an identity of a service or an account. It should be in the format user@domain. WebRTC Session Controller adds sip: to the target from a web subscribe user (for example, sip:user@domain), if that target is determined to be a SIP notification application. Your application can then notify the user whenever there is a change in the message status for the account.

Creating a Subscription

Use the MessageAlertPackage.createNewSubscription method to create a new subscription. The syntax for the method is:

createNewSubscription(target, subscriber, onSuccess, onError, onNotification, onEnd, extheaders)

Where:

- target is the service target you obtained from the user, the device or the service the user wishes to monitor.

- subscriber is the user identity of this subscriber.

- onSuccess is the event handler called when the application creates the subscription.

- onError is the event handler called when the application fails to create the subscription.

- onNotification is the event handler for a notify message.

- onEnd is the event handler called when the provider of the notification notifies Signaling Engine that this subscription has ended.

- extHeaders is extension header. Extension headers are inserted into the JSON message.

Example 7-2 Creating a Subscription

// Create a message alert package.
msgAlertHandler = new wsc.MessageAlertPackage(wscSession);
...
// Create a new subscription for this target.
subscription = msgAlertHandler.createNewSubscription(target,
userIdentity,onSubscribeSuccess,onSubscribeError,onNotify,onEnd);
// Assign the onNotification event handler for the subscription.
subscription.onNotification = onNotify;
...

If the application user subscribes to notifications from multiple targets such as phones and voice mail storage devices, set up the subscriptions and store the information on the service targets accordingly. Implement the logic to verify and deliver the incoming notification to the appropriate subscription.

You can optionally include extension headers as the last parameter extHeaders when you invoke the MessageAlertPackage.createNewSubscription method shown in Example 7-2. The extHeaders you input must be in JSON format to be inserted in the outgoing message. Here is an example of an extension header:

{'customerKey1':'value1','customerKey2':'value2'}

When you include the extension header as the last parameter in the MessageAlertPackage.createNewSubscription method, it is placed in the header section of the message in the following way:

{ "control" : {}, "header" : {...,'customerKey1':'value1','customerKey2':'value2'}, "payload" : {}}

Verifying that a Subscription is Active

To verify whether a current subscription is active, use the Subscription.isValid() method. The function returns true, if the subscription is active.

Handling the Ending of a Subscription

Set up the functions to handle the following scenarios:

- The user ends the current subscription.
Use the Subscription.end method to stop the current subscription. If your application uses extension headers, input them when you call this method.

- The WebRTC Session Controller JavaScript API library invokes the Subscription.onEnd event handler in your application.
The WebRTC Session Controller JavaScript API library invokes this event handler when it is notified about the end of that specific subscription for the user. Assign a callback function to the Subscription.onEnd event handler. Set up the logic within this function to inform the user appropriately and take action accordingly.

Restoring a Subscription

When a subscription has been recovered, the WebRTC Session Controller JavaScript API library invokes your application's MessageAlertPackage.onResurrect event handler with the rehydrated subscription as the parameter. Your application can call the Subscription.isValid method and take further action. If the user prefers to end the subscription, use the Subscription.end method.

Important:
If you create a custom message alert package, be sure to implement the appropriate logic to resume your application operation and restore subscription operations.

In Example 7-3, an application resets the callback functions to the rehydrated subscription object and proceeds with its actions.

Example 7-3 Sample onResurrect Function for a Subscription

subscribeHandler = new wsc.MessageAlertPackage(wscSession);
if (subscribeHandler) {
subscribeHandler.onResurrect = onResurrect;
}
...
function onResurrect(rehydratedSubscription) {
...
// Reset related callback functions
subscription = rehydratedSubscription;
subscription.onSuccess = onSubscribeSuccess;
subscription.onError = onSubscribeError;
subscription.onNotification = onNotification;
subscription.onShutdown = onShutdown;
// Initialize other parts of the application, such as page
...
}

Managing Notifications

Your application needs to set up the logic required to support the message alert notifications for the event types that must be supported in the environment in which your application is deployed.

In order to do so, implement and extend the wsc.Notification class to handle the notifications for the required event types. Process the incoming notification to update the information on the message counts (for example, how many new and old) and process it to identify the identity of the person or service providing the notification and subscriber of the service and take action accordingly.

Handling Message Notifications

To handle an incoming notification that is not a message summary, set up the callback function to retrieve the message content and the identities of the sender and receiver:

- Notification.getContent
Use the Notification.getContent method to retrieve the contents of the notification as a JSON object.

- Notification.getSender
Use the Notification.getSender method to retrieve the identity of the sender (service) of the notification as a string object.

- Notification.getReceiver
Use the Notification.getRetriever method to retrieve the identity of the receiver of the notification as a string object.

Set up the logic to retrieve handle the information as necessary.

See "Handling Custom Message Notifications" for information on how to handle custom message notifications in your web applications.

8 Developing Rich Communication Services Applications

This chapter shows how you can use the Oracle Communications WebRTC Session Controller JavaScript application programming interface (API) library to develop Rich Communication Services (RCS) applications.

About Rich Communication Services

Rich Communications Services is a system created by the Groupe Speciale Mobile Association (GSMA) which allows telecommunication providers running IP Media Subsystem (IMS) networks to extend those networks with a variety of features, including enhanced phone book capabilities, messaging options, and expanded options during calls. For more details on RCS, see http://www.gsma.com/network2020/rcs/.

About WebRTC Session Controller RCS Support

The WebRTC Session Controller JavaScript SDK provides support for integrating RCS functionality into your WebRTC Session Controller web-based applications. For more details on any of the APIs described in this chapter, see Oracle Communications WebRTC Session Controller JavaScript API Reference.

The following RCS services are implemented:

- Capabilities Exchange: Determine the capabilities of a remote endpoint, such as audio, video or file transfer support. For more information, see "Capabilities Exchange."

- Stand Alone Messaging: Send simple messages between two endpoints. For more information, see "Sending a Standalone Message."

- One on One and Group Chat: Create real-time chat sessions between one or more participants. For more information, see "Creating an RCS Chat Application."

- File Transfer: Transfer files of any type between two endpoints. For more information, see "Implementing File Transfer."

Prerequisites

Before continuing, make sure you thoroughly review and understand the JavaScript API discussed in the following chapters:

- About Using the WebRTC Session Controller JavaScript API

- Setting Up Security

About the Examples in This Chapter

The examples and descriptions in this chapter are kept intentionally straightforward in order to illustrate the functionality of the WebRTC Session Controller JavaScript API without obscuring it with user interface code and other abstractions and indirections. Since it is likely that use cases for production applications will take many forms, the examples assume no pre-existing interface schemas except when absolutely necessary, and then, only with the barest minimum of code. For example, if a particular method requires arguments such as a user name, a code example will show a plain string username such as "bob@example.com" being passed to the method. It is assumed that in a production application, you would retrieve information using some sort of form-based user interface.

Note:
The examples in this chapter are not intended to be "plug-and-play" examples; error checking and security are ignored in favor of concept illustration.

Capabilities Exchange

WebRTC Session Controller implements support for RCS capabilities exchange which lets two endpoints describe their capabilities such as video streaming, audio streaming, and file transfer so that they can negotiate support within a shared application session.

Sample Capability Exchange HTML File

In Example 8-1, the sample HTML file contains three check boxes which let you set local client "capabilities," a button and an associated input text box to submit query enquiries. Two div elements serve as targets for displaying capabilities from the remote host, queryResult, and for showing incoming query requests, queryFromResult.

Note:
The capabilities in this example are simple arbitrary strings and do not actually represent the capabilities of the host browser. They are provided for example purposes only. For information on RCS capabilities strings, see http://www.gsma.com/network2020/rcs/specs-and-product-docs/.

The required SDK files that must be included for this sample are:

- wsc-common.js: Shared common library utility functions.

- wsc-capability.js: Capabilities SDK functions.

Example 8-1 Capability Exchange Sample HTML File

<!DOCTYPE HTML>
<html>
<head>
<title>WebRTC Session Controller Capabilties Exchange Example</title>
<script type="text/javascript" src="/api/wsc-common.js"></script>
<script type="text/javascript" src="/api/wsc-capability.js"></script>
</head>
<body>
<h1>WebRTC Session Controller Capabilties Exchange Example</h1>
<div id="mainPanel">
<div class="container" id="myCapabilities">
<p>My capabilities:</p>
<input type="checkbox" id="audio" checked>IM/Chat (IM)
<input type="checkbox" id="video" checked>Video share (VS)
<input type="checkbox" id="file">File transfer (FT)
</div>

<div class="container" id="query">
<button id="queryBtn">Query: </button>
<input type="text" id="target" size="40">
<div id="queryResult" class="content"></div>
</div>

<div class="container" id="queryFrom">
<p>Capabilties query received from: </p>
<div id="queryFromResult" class="content"></div>
</div>
</div>
</body>
</html>

Initiate a Capability Exchange Query

In Example 8-2, the following occurs:

1. A set of global variables are initialized for a variety of utility values.

2. A new capabilityPackage object is instantiated using the current Session as an argument.

3. A new capabilityExchange object is instantiated using the capabilityPackage object's createCapabilityExchange method.

4. The event handler, onQueryRequest, is bound to the capabilityExchange object's onQueryRequest listener. This event handler processes the capabilities of the remote host. See Example 8-4.

5. The event handler, onQueryResponse, is bound to the capabilityExchange object's onQueryResponse listener. This event handler processes queries from the remote host. See Example 8-3.

6. The event handler, onErrorResponse, is bound to the capabilityExchange object's onErrorResponse listener. This event handler is triggered when any errors occur during the capabilities exchange. See Example 8-5.

7. The queryCapability utility function is bound to the click event of the query button, queryBtn, and the function getMyCapabilties reads the state of each of the three check boxes and creates an array of values.

Example 8-2 Initiating a Capability Exchange Query

var
capabilityPackage,
capabilityExchange,
queryCounter = 0,
queryFromCounter = 0,
_A = "IM/Chat",
_V = "Video share",
_F = "File transfer";

capabilityPackage = new wsc.CapabilityPackage(wscSession);
capabilityExchange = capabilityPackage.createCapabilityExchange();
capabilityExchange.onQueryResponse = onQueryResponse;
capabilityExchange.onQueryRequest = onQueryRequest;
capabilityExchange.onErrorReponse = onErrorResponse;

var queryButton = document.getElementById("queryBtn");
queryButton.addEventListener("click", queryCapability);

function queryCapability() {
var target = document.getElementById("target").value.trim();
console.log("Query capability of:", target);
capabilityExchange.enquiry(getMyCapabilities(), target);
}

function getMyCapabilities() {
var myCs = [];
if (document.getElementById("audio").checked) {
myCs.push(_A);
}
if (document.getElementById("video").checked) {
myCs.push(_V);
}
if (document.getElementById("file").checked) {
myCs.push(_F);
}
return myCs.join(";");
}

The actual query itself is sent using the enquiry method of the capabilityExchange object.

Handle a Capability Query Response

You define the onQueryResponse event handler to process query responses from remote hosts. In Example 8-3, the variable, capabilities, is returned from the incoming query object's targetCapability method. If capabilities exists, the array is unwrapped using a for loop, and the various capabilities are parsed and displayed along with the target name using the queryResult div element as a container. The queryCounter variable is used to prevent naming collisions during multiple requests.

Example 8-3 onQueryResponse Sample Code

function onQueryResponse(query) {
var capabilities = query.targetCapability;
var from = query.target;

var queryResultEle = document.getElementById("queryResult");
queryResultEle.innerHTML = queryItemEle;
document.getElementById("queryName" + queryCounter).textContent = from + ": ";

if (capabilities) {
var cArray = capabilities.split(";");
for (var i = 0; i < cArray.length; i++) {
var c = cArray[i];
if (c == _A) {
document.getElementById("queryCoa" + queryCounter).className += " cEnable";
showElement("queryCoa"+ queryCounter);
} else if (c == _V) {
document.getElementById("queryCov" + queryCounter).className += " cEnable";
showElement("queryCov"+ queryCounter);
} else if (c == _F) {
document.getElementById("queryCof" + queryCounter).className += " cEnable";
showElement("queryCof"+ queryCounter);
} else {
console.log(from, "has capability:", c);
}
}
}
}

Handle an Incoming Capability Query

You define the onQueryRequest event handler to process incoming query requests. In Example 8-4, span elements are concatenated together using the queryFromCounter value to make sure that they are distinct between multiple queries. The span elements are bound to the queryFromResult content div element, and the same for loop from Example 8-3 is used to display each capability entry if it is defined in the capabilities array. Finally, the capabilityExchange object's respond method is called to return the local capabilities to the remote endpoint.

Example 8-4 onQueryRequest Sample Code

function onQueryRequest(query) {
var capabilities = query.initiatorCapability;
var from = query.initiator;

queryFromCounter = queryFromCounter + 1;

var nameS = '<span id="queryFromName' + queryFromCounter + '"></span>&nbsp;&nbsp;';
var coaS = '<span id="queryFromCoa' + queryFromCounter + '"
hidden="true">IM</span>&nbsp;&nbsp;';
var covS = '<span id="queryFromCov' + queryFromCounter + '"
hidden="true">VS</span>&nbsp;&nbsp;';
var cofS = '<span id="queryFromCof' + queryFromCounter + '"
hidden="true">FT</span>';
var queryFromItemEle = nameS + coaS + covS + cofS;

var queryFromResultEle = document.getElementById("queryFromResult");
queryFromResultEle.innerHTML = queryFromItemEle;
document.getElementById("queryFromName" + queryFromCounter).textContent = from + ": ";

if (capabilities) {
var cArray = capabilities.split(";");
for (var i = 0; i < cArray.length; i++) {
var c = cArray[i];
if (c == _A) {
document.getElementById("queryFromCoa" + queryFromCounter).className += " cEnable";
showElement("queryFromCoa"+ queryFromCounter);
} else if (c == _V) {
document.getElementById("queryFromCov" + queryFromCounter).className += " cEnable";
showElement("queryFromCov"+ queryFromCounter);
} else if (c == _F) {
document.getElementById("queryFromCof" + queryFromCounter).className += " cEnable";
showElement("queryFromCof"+ queryFromCounter);
} else {
console.log(from, "has capability:", c);
}
}
}
capabilityExchange.respond(query, getMyCapabilities());
}

Handle Capability Exchange Errors

You define the onErrorResponse event handler to process error conditions.

Example 8-5 onErrorResponse Sample Code

function onErrorResponse (error) {
console.log("Error action: "+error.action);
console.log("Error code: "+error.errorCode);
console.log("Error reason: "+error.errorReason);
}

Initiate a Capability Exchange Request in a Call

To initiate a capability exchange request in an active call, you simply initiate the capabilityPackage using a Call object instead of a session object:

Example 8-6 Initiating a Capability Exchange in a Call

var
audioMediaDirection = wsc.MEDIADIRECTION.SENDRECV,
videoMediaDirection = wsc.MEDIADIRECTION.SENDRECV,
callConfig = new wsc.CallConfig(audioMediaDirection,videoMediaDirection);

var myCall = callPackage.createCall("alice@example.com", callConfig);
myCall.start();

capabilityPackage = new wsc.CapabilityPackage(myCall);
capabilityExchange = capabilityPackage.createCapabilityExchange();
capabilityExchange.onQueryResponse = onQueryResponse;
capabilityExchange.onQueryRequest = onQueryRequest;
capabilityExchange.onErrorReponse = onErrorResponse;

var queryButton = document.getElementById("queryBtn");
queryButton.addEventListener("click", queryCapability);

// Continue with your workflow...

Sending a Standalone Message

The RCS standard defines a simple way an application can send text messages between two endpoints, which is implemented in WebRTC Session Controller in the wsc.MessagingPackage class.

Messaging Sample HTML File

The sample HTML file for messaging examples contains the following elements:

- A div element, statusArea, used to display application status messages.

- A form input text box, msgTarget, used to input a message recipient's ID.

- A div element, history, used as a container to store message history.

- A form input text box, msgContent, used to input a message for the recipient.

- A form input button, msgSend, used to send the content of the msgContent text box to the recipient.

The required SDK files that must be included for this sample are:

- wsc-common.js: Shared common library utility functions.

- wsc-messaging.js: Messaging SDK functions.

Example 8-7 Messaging Sample HTML File

<!DOCTYPE html>
<html>
<head>
<title>WebRTC Session Controller Messaging Example</title>
<script type="text/javascript" src="/api/wsc-common.js"></script>
<script type="text/javascript" src="/api/wsc-messaging.js"></script>
</head>
<body>
<h1>WebRTC Session Controller Messaging Example</h1>
<div id="statusArea"></div>
<h4>Recipient:</h4>
<p><input type="text" name="msgTarget" id="msgTarget" size="40"/></p>
<div id="history"></div>
<h4>Message Content:</h4>
<p>
<input type="text" name="msgContent" id="msgContent" size="50"/>
<input type="button" name="msgSend" id="msgSend" value="Send"/>
</p>
</body>
</html>

Send a Message

In Example 8-8, the following occurs:

1. A new messagePackage object is instantiated using the current Session as an argument.

2. A new messaging object is instantiated using the messagePackage object's createMessaging method.

3. The event handler, onNewMessage, is bound to the messaging object's onNewMessage listener. This event handler processes incoming messages. See Example 8-9.

4. The event handler, onSuccessResponse, is bound to the messaging object's onSuccessResponse listener. This event handler processes success responses. See Example 8-10.

5. The event handler, onErrorResponse, is bound to the messaging object's onErrorResponse listener. This event handler is triggered when any errors occur during the message exchange. See Example 8-11.

6. The sendMsg utility function is bound to the click event of the button, msgSend, and the contents of the msgTarget edit box is read, and assigned as the message recipient, unless the edit box is empty, in which case the statusArea div element is updated with an error.

Example 8-8 Sending a Message

messagePackage = new wsc.MessagingPackage(wscSession);
messaging = messagePackage.createMessaging();
messaging.onNewMessage = onNewMessage;
messaging.onSuccessResponse = onSuccessResponse;
messaging.onErrorResponse = onErrorResponse;

document.getElementById("msgSend").onclick = function() {
sendMsg();
};

function sendMsg() {
var msg = document.getElementById("msgContent").value;
var target = document.getElementById("msgTarget").value;
if (msg && msg != "" && target && target != "") {
var msgId = messaging.send(msg, target);
console.log("The sent message ID is: " + msgId);
} else if (target == "") {
document.getElementById("statusArea").innerHTML = "Please enter a recipient.";
}
}

Handle an Incoming Message

You define the onNewMessage event handler to process incoming messages. When a new message comes in, use the accept method to accept the message or the reject method to reject it. In Example 8-9, depending on the value of the msgRejected boolean which would be handled in additional user interface code you would supply, the message is either accepted or rejected, and, if accepted, the message is added to the history div element using the updateHistory utility function. A message rejection returns an SIP 603 error with the status Decline.

Example 8-9 onNewMessage Sample Code

function onNewMessage(chatMessage) {
var
initiator = chatMessage.initiator,
msg = chatMessage.content,

if (msgRejected) {
messaging.reject(chatMessage, 603, "Decline");
} else {
messaging.accept(chatMessage);
updateHistory(initiator, msg, true);
}
}

function updateHistory(initiator, msg, newMessage) {
var history = document.getElementById("history");
var d = new Date();
var ds = d.toLocaleTimeString();
var newMsg = "(" + ds + ") " + initiator + ": " + msg;
if (newMessage) {
newMsg = "<div id='inChatMessage'>" + newMsg + "</div>";
document.getElementById("msgTarget").value = initiator;
} else {
newMsg = "<div id='outChatMessage'>" + newMsg + "</div>";
}
history.innerHTML = history.innerHTML + newMsg;
};

Handle Messaging Success Events

You define the onSuccessResponse event handler to process a successful message transmission, and update the statusArea div element accordingly.

Example 8-10 onSuccessResponse Sample Code

function onSuccessResponse(message) {
var content = message.content;
document.getElementById("statusArea").innerHTML = "Send message \"" + content
+ "\" succeeded.";
}

Handle Messaging Error Events

You define the onErrorResponse event handler to process a message transmission failure and update the statusArea div element accordingly.

Example 8-11 onErrorResponse Sample Code

function onErrorResponse(message, extHeaders) {
var content = message.content;
document.getElementById("statusArea").innerHTML = "Send message \"" + content
+ "\" failed.";
}

Creating an RCS Chat Application

The WebRTC Session Controller JavaScript SDK lets you implement a one to one or one to many chat application as defined by the RCS specification. For more information on the RCS chat specification, see http://www.gsma.com/network2020/rcs/specs-and-product-docs/.

Chat Sample HTML File

The sample HTML file for chat examples contains the following elements:

- A div element, statusArea, used to display application status messages.

- A form input text box, target, used to input a chat request recipient's ID.

- A form input text box, participants, used to add additional recipients to a group chat.

- A form input button, chatButton, used to initiate a chat session request.

- A form input button, endChatButton, used to terminate a chat session.

- A div element, history, used as a container to display chat message history.

- A form input text box, msgContent, used to enter a chat message.

- A form input button, msgSend, used to send the content of the msgContent text box to the recipient.

The required SDK files that must be included for this sample are:

- wsc-common.js: Shared common library utility functions.

- wsc-chat.js: Chat SDK functions.

Example 8-12 Chat Sample HTML File

<!DOCTYPE HTML>
<html>
<head>
<title>WebRTC Session Controller Chat Example</title>
<script type="text/javascript" src="/api/wsc-common.js"></script>
<script type="text/javascript" src="/api/wsc-chat.js"></script>
</head>
<body>
<div id="mainPanel">
<div id="statusArea"></div>
<br/>
<p>To: <input type='text' name='target' id='target' size='30'/></p>
<p>Add participants: <input type='text' name='participants' id='participants' size='70'/></p>
<p>
<input type='button' name='chatButton' id='chatButton' value='Chat'
onclick='startChat()'/>&nbsp;
<input type='button' name='endCallButton' id='endChatButton' value='End Chat'
onclick='end()'/>
</p>
<div id='history'></div>
<p>
<input type='text' name='msgContent' id='msgContent'/>&nbsp;
<input type='button' name='msgSend' id='msgSend' value='Send'/>
</p>
</div>
</body>
</html>

Implementing Chat

To determine whether a remote endpoint is a WebRTC compliant browser or an RCS compliant application, you can configure a capabilities exchange as described in "Capabilities Exchange." For browser to RCS client, the WebRTC Session Controller JavaScript SDK uses Message Session Relay Protocol (MSRP) and Session Description Protocol (SDP) to negotiate with the target and configure the WebSocket connection with WebRTC Session Controller Media Engine (Media Engine). For browser to browser chat sessions, your application can use the CallPackage data channel functions as described in "Setting Up Data Transfers in Your Applications."

Initiate the Chat Session

In Example 8-13, the following occurs:

1. Global variables for a chat object, wscChat, and a chat package, chatPackage are initialized and the contents of the target text box are retrieved and assigned to the target variable.

2. A new chatPackage object is instantiated using the current Session as an argument.

3. The event handler, onIncomingChat, is bound to the chatPackage object's onIncomingChat listener. This event handler processes incoming chat requests. See Example 8-15.

4. The target variable is tested to make sure it is not zero length, and a chatConfig object, along with an empty array of acceptTypes are declared.

5. The acceptTypes array is initialized, the chatConfig.setMaxSize instance variable is initialized, as is the chatConfig.acceptTypes instance variable is initialized with the acceptTypes array. The possible values for a chatConfig object are as follows:

- acceptTypes: An array of media types the endpoint is willing to accept. May contain zero or more media types or a wildcard, "*".

- acceptWrappedTypes: An array of media types that an endpoint is willing to receive in an MSRP message with multipart content. May not be used as the outermost type of the message. May contain zero or more media types or a wildcard, "*".

- maxSize: A whole numeric value indicating the maximum message size specified in octets the endpoint is capable of receiving.

6. A chat object, wscChat, is created using the chatPackage object's createChat method with the target as an argument.

7. The event handler, onStateChange, is bound to the chat object's onStateChange listener. This event handler handles changes in the state of the chat object. See Example 8-16.

8. The event handler, onConnectionStateChange, is bound to the chat object's onConnectionStateChange listener. This event handler handles changes in the connection state of the chat object. See Example 8-17.

9. The event handler, onChatMessage, is bound to the chat object's onChatMessage listener. This event handler handles incoming chat messages. See Example 8-18.

10. The event handler, onMessageSendSuccess, is bound to the chat object's onMessageSendSuccess listener. This event handler handles successful message transmission events. See Example 8-19.

11. The event handler, onMessageSendFailure, is bound to the chat object's onMessageSendFailure listener. This event handler handles failed message transmission events. See Example 8-20.

12. The event handler, onMessageTyping, is bound to the chat object's onMessageTyping listener. This event handler is triggered when the remote party is actively typing. See Example 8-21.

13. The event handler, onMessageTypingStop, is bound to the chat object's onMessageTypingStop listener. This event handler is triggered when the remote party stops typing. See Example 8-22.

14. Add additional chat participants to the chat using the chat object's addParticipants method.

15. Toggle the security of the chat session's transport layer using the chat object's setSecure method.

16. Finally, the chat object's start method is used to start the chat session taking the chatConfig object as an argument.

Example 8-13 Initiating the Chat Session

var
wscChat,
chatPackage;
target = document.getElementById("target").value;

chatPackage = new wsc.ChatPackage(wscSession);
chatPackage.onIncomingChat = onIncomingChat;

if (target != "") {
var
chatConfig = {},
acceptTypes = [];

acceptTypes.push('text/plain');
acceptTypes.push('message/cpim');

chatConfig.selfMaxSize = 1024;
chatConfig.acceptTypes = acceptTypes;

wscChat = chatPackage.createChat(target);

wscChat.onStateChange = onStateChange;
wscChat.onConnectionStateChange = onConnectionStateChange;
wscChat.onChatMessage = onChatMessage;
wscChat.onMessageSendSuccess = onMessageSendSuccess;
wscChat.onMessageSendFailure = onMessageSendFailure;
wscChat.onMessageTyping = onMessageTyping;
wscChat.onMessageTypingStop = onMessageTypingStop;

wscChat.start(chatConfig);
}

Within the chat session, use the following methods as required:

- send: Send a message in the chat session. See "Send a Chat Message" for more information.

- end: End the chat session.

Once the chat session is ended using the wsc.Chat object end method, use the wsc.ChatPackage close method to terminate all sessions and release resources.

Send a Chat Message

Send a chat message to a target address using the Chat object's send method.

In Example 8-14, the form send button, msgSend, has its onclick event bound to an anonymous function that retrieves the text value from the msgContent form text box, and, if the value is not empty, passes it to the sendChatMessage function.

The sendChatMessage function checks to see if the message is a Common Profile for Instant Messaging (CPIM) format and creates the payload accordingly, or creates a plain text payload if not.

Note:
The isCpimMessage as well as the values of the cpim variable must be set and retrieved using your own mechanisms in your application.

Finally, the message is sent using the Chat objects send method, and a utility function, updateHistory is called to append the message along with a date and message initiator to the history content div element.

Example 8-14 Sending a Chat Message

document.getElementById("msgSend").onclick = function() {
var msg = document.getElementById("msgContent").value;
if (msg && msg != "") {
sendChatMessage(msg);
}
};

function sendChatMessage(msg) {

var chatMessage;

if (isCpimMessage) {
var cpim = "From: alice@example.com\r\n" +
"To: bob@example.com\r\n" +
"DateTime: 2015-12-08T00:00:00-00:00\r\n" +
"Content-Type: text/plain\r\n" +
"Content-Length: 1\r\n\r\n" +
msg;
chatMessage =
{
contentType : 'message/cpim',
content : cpim
};
} else {
chatMessage =
{
contentType : 'text/plain',
content : msg
};
}

wscChat.send(chatMessage);

updateHistory(wscSession.userName, msg);

function updateHistory(initiator, msg) {
var
d = new Date(),
ds = d.toLocaleTimeString(),
title = "(" + ds + ") " + initiator + "\r\n:";
title = "<div id='outChatMessage'>" + title + "</div>";

var newMsg = title + msg;
document.getElementById("history").innerHTML += newMsg;
}
}

Handle Incoming Chat Requests

Define the onIncomingChat event handler to process incoming chat session requests.

When responding to an incoming chat session request, use the following methods as required:

- accept: Accept the chat invitation.

- decline: Decline the chat invitation.

- getInitiator: Return the initiator of the chat session request.

In Example 8-15, the statusArea div element is used as the target of a showRequest function that creates a status message and an interface that allows a user to accept or decline the chat invitation. The status message and user interface are then displayed in the statusArea div element. If the session is accepted, the chat event handlers are initialized in the same manner as Example 8-13.

Example 8-15 onIncomingChat Sample Code

function onIncomingChat(chat) {
document.getElementById("statusArea").innerHTML = showRequest(chat);

document.getElementById("acceptButton").onclick = function() {
chat.accept(chatConfig);
};
document.getElementById("declineButton").onclick = function() {
chat.decline();
};

function showRequest(chat) {
var
initiator = chat.getInitiator(),
message = initiator + " is requesting a chat session.";

var display = message +
"<input type='button' name='acceptButton' id='acceptButton' value='Accept' onclick=''/>" +
"<input type='button' name='declineButton' id='declineButton' value='Decline' onclick=''/>";
return display;
}

chat.onStateChange = onStateChange;
chat.onConnectionStateChange = onChatConnectionStateChange;
// Continue configuring chat callbacks...
}

Handle Chat Signaling State Changes

Define the onStateChange event handler to process changes in the chat signaling state. The wsc.CALLSTATE enum defines the possible call states. For a complete list of wsc.CALLSTATE values see the Oracle Communications WebRTC Session Controller JavaScript API Reference.

Example 8-16 onStateChange Sample Code

function onStateChange(chat, callState) {
console.log("Chat state: " + callState.state);
switch (callState.state) {
case wsc.CALLSTATE.ESTABLISHED:
// Handle an established call (chat) state as required...
break;
case wsc.CALLSTATE.UPDATED:
// Handle an updated call (chat) state as required...
break;
case wsc.CALLSTATE.UPDATE_FAILED:
// Handle an update failed call (chat) state as required...
break;
case wsc.CALLSTATE.ENDED:
// Handle an ended call (chat) state as required...
break;
case wsc.CALLSTATE.FAILED:
// Handle a failed call (chat) state as required...
break;
default:
break;
}
}

Handle Chat Connection State Changes

Define the onConnectionStateChange to process changes in chat connection state over MSRP. The ConnectionStateEnum defines the possible connection states.

Example 8-17 onConnectionStateChange Sample Code

function onConnectionStateChange(state) {
console.log("Chat state: " + state.state);
switch (state.state) {
case wsc.ConnectionStateEnum.INIT:
// Handle the INIT state...
break;
case wsc.ConnectionStateEnum.ESTABLISHED:
// Handle the ESTABLISHED state...
break;
case wsc.ConnectionStateEnum.ERROR:
// Handle the ERROR state...
break;
case wsc.ConnectionStateEnum.CLOSED:
// Handle the CLOSED state...
break;
}
}

Handle Incoming Chat Messages

Define the onChatMessage event handler to process incoming chat messages. In Example 8-18, after initializing a set of variables, the function examines the content type of the message, cType, to see whether it is in a CPIM or plain text, and sets the textContent variable accordingly. It next pulls the initiating user name from either the MSRP message or the JSON header. It replaces angle brackets with their named elements in order to preserve the integrity of the HTML, and then calls the updateHistory function to append an entry to the history content div element, including a date.

Example 8-18 onChatMessage Sample Code

function onChatMessage(msg) {
console.log("Received a chat message: " + msg.content);
var
content = msg.content,
textContent = null,
cType = msg.contentType,
initator = null;

if (cType == 'message/cpim') {
initator = extractText(content, "From:", "\r\n");
var textContent = content.substring(content.indexOf("Content-Type"));
var startIndex = textContent.indexOf("\r\n\r\n");
textContent = textContent.substring(startIndex);
if (textContent.indexOf("\r\n\r\n") == 0) {
textContent.replace("\r\n\r\n", "");
}
} else {
textContent = content;
}

if (!initator) {
if (wscChat.getInitiator() === wscChat.session.getUserName()) {
initator = wscChat.getTarget();
} else {
initator = wscChat.getInitiator();
}
}

textContent = textContent.replace("<", "&lt;");
textContent = textContent.replace(">", "&gt;");

updateHistory(initator, textContent, true);

function updateHistory(initiator, msg) {
var
d = new Date(),
ds = d.toLocaleTimeString(),
title = "(" + ds + ") " + initiator + "\r\n:";

title = "<div id='inChatMessage'>" + title + "</div>";
var newMsg = title + msg;

document.getElementById("history").innerHTML += newMsg;
}
}

Handle Message Transmission Success and Failure Events

Define the onMessageSendSuccess event handler to process notification of a successful message transmission. In Example 8-19, the only result is a log notification, but you might wish to update a status area or provide a more dynamic notification system.

Example 8-19 onMessageSendSuccess Sample Code

function onMessageSendSuccess(msgId) {
console.log("Message successfully sent. ID: " + msgId);
}

Define the onMessageSendFailure event handler to process notification of a failed message transmission. As with Example 8-19, the only result is a log notification, but, again, you may wish to create a customized notification in your own application.

Example 8-20 onMessageSendFailure Sample Code

function onMessageSendFailure(msgId) {
console.log("Message transfer failed. ID: " + msgId);
}

Handle Participant Typing Notifications

Optionally, you can define onMessageTyping and onMessageTypingStop event handlers to process changes in user interface state when tracking a remote user's data input. In Example 8-21 and Example 8-22, only log messages are generated, but you could also update your chat history window or other user interface device with the changing statuses.

Example 8-21 onMessageTyping Sample Code

function onMessageTyping() {
console.log(wscChat.getTarget() + " is typing...");
}

Example 8-22 onMessageTypingStop Sample Code

function onMessageTypingStop() {
console.log(wscChat.getTarget() + " has stopped typing...");
}

Implementing File Transfer

The WebRTC Session Controller JavaScript SDK lets you implement a one to one or one to many file transfer application as defined by the RCS specification. For more information on the RCS chat specification, see http://www.gsma.com/network2020/rcs/specs-and-product-docs/.

Note:
Multiple file transfer in a single session is not supported.

File Exchange Example HTML File

The sample HTML file for messaging examples contains the following elements:

- A div element, statusArea, used to display application status messages.

- A form text input box, target, into which a recipient address is entered.

- A file input button, selectFilesButton, used to select files to transfer to a remote party.

- A button input, filesButton, used to start a file transfer, the onclick event of which is bound to a sendFile function.

- A button input, endFtButton, used to cancel a file transfer, the onclick event of which is bound to the endFt function.

- A button input, cleanButton, used to hide the file transfer progress bar, the onclick event of which is bound to the hideFileTransferProgress function.

- A form input button, msgSend, used to send the content of the msgContent text box to the recipient.

The required SDK files that must be included for this sample are:

- wsc-common.js: Shared common library utility functions.

- wsc-filetransfer.js: Messaging SDK functions.

Example 8-23 File Transfer HTML Sample

<!DOCTYPE HTML>
<html>
<head>
<title>WebRTC Session Controller File Transfer Example</title>
<script type="text/javascript" src="/api/wsc-common.js"></script>
<script type="text/javascript" src="/api/wsc-filetransfer.js"></script>
</head>
<body>
<div id="mainPanel">
<div id="statusArea"></div>
<br/>
<p>To: <input type='text' name='target' id='target' size='30'/></p>
<p>
<input type='file' multiple name='selectFileButton' id='selectFileButton'/>
<input type='button' name='filesButton' id='fileButton' value='Send'
onclick='sendFile()'/>&nbsp;
<input type='button' name='endFtButton' id='endFtButton' value='Cancel transfers'
onclick='endFt()'/>&nbsp;
<input type='button' name='cleanButton' id='cleanButton' value='Clear progress'
onclick='hideFileTransferProgress()'/>
</p>
<div id="messageArea">
</div>
</div>
</body>
</html>

Setup a File Transfer Session

In Example 8-13, the following occurs:

1. Global variables for a file transfer object, wscFileTransfer, a file transfer package, fileTransferPackage, and a fileConfig array are initialized and the contents of the target text box are retrieved and assigned to the target variable.

2. A new fileTransferPackage object is instantiated using the current Session as an argument.

3. The event handler, onFileTransfer, is bound to the fileTransferPackage object's onFileTransfer listener. This event handler processes incoming file transfer requests. See Example 8-26.

4. A message transfer object, wscFileTransfer, is created using the fileTransferPackage object's createFileTransfer method with the target as an argument.

5. The event handler, onStateChange, is bound to the wscFileTransfer object's onStateChange listener. This event handler handles changes in the state of the file transfer object. See Example 8-16.

6. The event handler, onSessionStateChange, is bound to the wscFileTransfer object's onSessionStateChange listener. This event handler handles changes in the session state of the file transfer object. See Example 8-17.

7. The event handler, onFileData, is bound to the wscFileTransfer object's onFileData listener. This event handler handles incoming file data. See Example 8-18.

8. The event handler, onProgress, is bound to the wscFileTransfer object's onProgress listener. This event handler handles file transfer progress events. See Example 8-19.

9. The event handler, onFileTransferSuccess, is bound to the wscFileTransfer object's onFileTransferSuccess listener. This event handler handles successful file transmission events. See Example 8-20.

10. The event handler, onFileTransferFailure, is bound to the wscFileTransfer object's onFileTransferFailure listener. This event handler handles failed file transmission events. See Example 8-20.

11. The fileConfig object is initialized. The file field is the actual instance of the file itself. The props object can have the following properties:

- name: A string containing the file name.

- size: An integer indicating the file size in octets.

- type: A string indicating the MIME type of the file.

- hashes: An array containing the hash computation of the file: {algorithmName: "value: xxxx"}.

- disposition: A string with value render or attachment. The disposition value tells the receiving endpoint how to handle the file. The value render indicates that the file should be automatically rendered by the endpoint, for example a GIF or JPEG image file. The value attachment indicates that the file should not be rendered and should be treated as a downloadable attachment, for example an EXE or other such BLOB. If the disposition attribute is not specified, render is implied.

- description: A string description of the file.

- creationTime: A string containing the file creation date and time.

- modificationTime: A string containing the file modification date and time.

- readTime: A string containing the time and date the file was last read.

- icon: A string containing the Content ID URL (cid:content-id) for the file. In the case of images, usually renders as a file icon.

- startOffset: A string indicating the octet position in the file where the file transfer should start. The first octet of a file is indicated by the ordinal number 1.

- stopOffset: A string indicating the octet position in the file where the file transfer should end, including the specified octet. If the total file size is not known, use the "*" wildcard.

- direction: A string indicating the transfer direction for the file. To push a file, use send and to pull a file use receive.

12. Add additional file transfer recipients to the fileTransfer session using the fileTransfer object's addParticipants method.

13. Toggle the security of the fileTransfer session's transport layer using the fileTransfer object's setSecure method.

14. Finally, the wscFileTransfer object's start method is used to start the file transfer session taking the fileConfig object as an argument.

Example 8-24 Instantiating a File Transfer Session

var
wscFileTransfer,
fileTransferPackage,
fileConfigs = [],
target = document.getElementById("target").value;

fileTransferPackage = new wsc.FileTransferPackage(wscSession);
fileTransferPackage.onFileTransfer = onFileTransfer;

wscFileTransfer = fileTransferPackage.createFileTransfer(target);

wscFileTransfer.onStateChange = onStateChange
wscFileTransfer.onSessionStateChange = onSessionStateChange
wscFileTransfer.onFileData = onFileData;
wscFileTransfer.onProgress = onFileProgress;
wscFileTransfer.onFileTransferSuccess = onFileTransferSuccess;
wscFileTransfer.onFileTransferFailure = onFileTransferFailure;

fileConfig.file = myFileName;
fileConfig.props = null;

wscFileTransfer.start(fileConfig);

Control and Return Information on the File Transfer

Within the file transfer session, use the following methods as required:

- abort: Abort the file transfer session.

- getInitiator: Return the initiating address of the file transfer session.

- getTarget: Return the file transfer session recipient.

Terminate the File Transfer Session

Once the file transfer session is ended using the wscFileTransfer object end method, use the wscFileTransferPackage object close method to terminate all sessions and release resources.

Send a File from Your Application

In Example 8-25, the selectedFiles variable is initialized, the recipient's address is retrieved from the text box, target, and assigned to the variable, recipient, and the selectFiles function is bound to the onchange event of the selectFilesButton input button. When the onchange event fires, the file selected in the file browser of the selectFilesButton input button is assigned to selectedFile.

Next, when the input button, fileButton, is clicked, the sendFile function bound to it is triggered. In the sendFile function, both the recipient and selectedFile variables are checked to make sure they are not empty, and, if valid a new wscFileTransfer object is created and initialized, and the various event handlers for the wscFileTransfer object are bound to their respective listeners as in "Setup a File Transfer Session."

Then, selectedFile is retrieved from the input user interface, using the document object's querySelector method, and a fileConfig object is created.

Finally, the file transfer is started using the wscFileTransfer object's start method.

Example 8-25 Sending One or More Files

var
selectedFile,
recipient = document.getElementById("target").value;

document.querySelector("#selectFilesButton").onchange = selectFile;

function selectFile() {
var
fileInput = document.querySelector("#selectFileButton");

selectedFile = fileInput.file;
}
}

function sendFile() {
if (recipient != "") {
if (selectedFile) {
wscFileTransfer = fileTransferPackage.createFileTransfer(target);

wscFileTransfer.onCallStateChange = onStateChange
wscFileTransfer.onSessionStateChange = onSessionStateChange
wscFileTransfer.onFileData = onFileData;
wscFileTransfer.onProgress = onFileProgress;
wscFileTransfer.onFileTransferSuccess = onFileTransferSuccess;
wscFileTransfer.onFileTransferFailure = onFileTransferFailure;

var fileConfigs = [];
var file = selectedFile[0], fileConfig = {};

fileConfig.file = file;
fileConfig.props = null;
fileConfigs.push(fileConfig);

wscFileTransfer.start(fileConfigs);

}
}
}

Handle Incoming File Transfer Requests

Define the onFileTransfer event handler to process incoming file transfer session requests.

When responding to an incoming file transfer session request, use the following methods as required:

- accept: Accept the file transfer invitation.

- decline: Decline the file transfer invitation.

- getInitiator: Return the initiator of the file transfer session request.

In Example 8-15, the statusArea div element is used as the target of a showRequest function that retrieves the file names for the incoming fileTransfer objects, creates a status message, and an interface that allows a user to accept or decline the file transfer invitation. The status message and interface are rendered in the statusArea div element. If the session is accepted, the event handlers are initialized in the same manner as Example 8-24.

Example 8-26 onFileTransfer Sample Code

function onFileTransfer(fileTransfer) {
document.getElementById("statusArea").innerHTML = showFileRequest(fileTransfer);

document.getElementById("acceptButton").onclick = function() {
fileTransfer.accept();
};

document.getElementById("declineButton").onclick = function() {
fileTransfer.decline();
};

function showFileRequest(fileTransfer) {
var
initiator = fileTransfer.getInitiator(),
fileConfigs = fileTransfer.getFileConfigs();
if (fileConfigs.length > 1) {
message = initiator + " wants to send you some files.";
} else {
message = initiator + " wants to send you a file.";
}

for (var i=0; i<fileConfigs.length; i++) {
message += fileConfigs[i].props.name;
}

var display = message +
"<input type='button' name='acceptButton' id='acceptButton' value='Accept' onclick=''/>" +
"<input type='button' name='declineButton' id='declineButton' value='Decline' onclick=''/>";

return display;
}

wscFileTransfer.onCallStateChange = onStateChange
wscFileTransfer.onSessionStateChange = onSessionStateChange
wscFileTransfer.onFileData = onFileData;
// Continue intializing wscFileTransfer...
}

Handle File Transfer Signaling State Changes

Define the onStateChange event handler to process changes in the chat signaling state. The wsc.CALLSTATE enum defines the possible call states. For a complete list of wsc.CALLSTATE values see the Oracle Communications WebRTC Session Controller JavaScript API Reference.

Example 8-27 onStateChange Sample Code

function onStateChange(ft, callState) {
console.log("File transfer state: " + callState.state);
switch (callState.state) {
case wsc.CALLSTATE.ESTABLISHED:
// Handle an established call (file transfer) state as required...
break;
case wsc.CALLSTATE.UPDATED:
// Handle an updated call (file transfer) state as required...
break;
case wsc.CALLSTATE.RESPONDED:
// Handle an responded call (file transfer) state as required...
break;
case wsc.CALLSTATE.ENDED:
// Handle an ended call (file transfer) state as required...
break;
case wsc.CALLSTATE.FAILED:
// Handle an failed call (file transfer) state as required...
break;
default:
break;
}
}

Handle File Transfer Connection State Changes

Define the onConnectionStateChange to process changes in file transfer connection state over MSRP. The ConnectionStateEnum defines the possible connection states.

Example 8-28 onConnectionStateChange Sample Code

function onConnectionStateChange(state) {
console.log("File transfer state: " + state.state);
switch (state.state) {
case wsc.ConnectionStateEnum.INIT:
// Handle the INIT state...
break;
case wsc.ConnectionStateEnum.ESTABLISHED:
// Handle the ESTABLISHED state...
break;
case wsc.ConnectionStateEnum.ERROR:
// Handle the ERROR state...
break;
case wsc.ConnectionStateEnum.CLOSED:
// Handle the CLOSED state...
break;
}
}

Handle Message Transmission Success and Failure Events

Define the onFileTransferSuccess event handler to process notification of a successful file transmission. In Example 8-29, the only result is a log notification, but you might wish to update a status area or provide a more dynamic notification system.

Example 8-29 onFileTransferSuccess Sample Code

function onFileTransferSuccess(fileTransferId) {
console.log("File successfully sent. ID: " + fileTransferId);
}

Define the onFileTransferFailure event handler to process notification of a failed file transmission. As with Example 8-30, the only result is a log notification, but, again, you may wish to create a customized notification in your own application.

Example 8-30 onFileTransferFailure Sample Code

function onFileTransferFailure(fileTransferId) {
console.log("File transfer failed. ID: " + fileTransferId);
}

Handle File Data Transmission

Define the onFileData event handler to process the data received from a file transmission.

Data is received in a fileData object comprising the following elements:

- fileTransferID: A string containing the file transfer ID (defined by WebRTC Session Controller).

- range: A FileDataRange object containing the total range of data in the file. This object comprises the following properties:

- start: A number indicating the first byte of the data.

- end: A number indicating the final byte of the data.

- total: A number indicating the total size of the data in bytes.

- content: An 8-bit unsigned integer array containing the actual file data.

In Example 8-31, the data object is processed and assigned to cachedFileData as it comes in, pushed onto the cachedFileData array if it is text, or concatenated to the array if it is binary. As the data comes in, the progress bar percentage is calculated using the range.end and range.total properties of the data object. If the progress bar for the currently transferring file has not already been added to the HTML document, the showFileTransferProgress function is called.

The showFileTransferProgress function finds the current fileConfig using its fileTransferId argument and comparing that to the fileTransferIDs of the fileTransfer object. If a fileTransferArea div element does not already exist in the HTML page, one is create and inserted before the buttonArea div element. The insertFileTransferProgress function adds both a progress bar and a cancel button to the fileTransferArea div element, either inserting or appending depending upon the state of the div element.

With the progress bar added, it is updated as the file transfer progresses.

Once the file transfer is complete, the cachedFileData array is assigned to a Binary Large Object (BLOB) file, the file name is pulled from the fileConfigs array, and the saveToDisk function is used to save the BLOB to the user's local disk.

Example 8-31 onFileData Sample Code

var
cachedFileData = [];

function onFileData(data) {
var fileTransferId = data.fileTransferId;
console.log("Received file data. ID: " +
fileTransferId + ", range: " + JSON.stringify(data.range));

if (!cachedFileData[fileTransferId]) {
cachedFileData[fileTransferId] = [];
}

if (data.content instanceof String) {
cachedFileData[fileTransferId].push(data.content);
} else {
cachedFileData[fileTransferId] = cachedFileData[fileTransferId].concat(data.content);
}

// Update the progress bar...
var progressPercent = Math.ceil(data.range.end/data.range.total*100);
if (!document.getElementById(fileTransferId)) {
showFileTransferProgress(fileTransferId);
}

var progressBar = document.getElementById(fileTransferId).childNodes[1];

if (progressBar) {
progressBar.style.width = progressPercent+"%";
}

// File transfer finished...
if (data.range.end == data.range.total) {
var blob = new Blob(cachedFileData[fileTransferId]),
fileConfigs = wscFileTransfer.getFileConfigs(),
fileName = null;

for (var i=0; i<fileConfigs.length; i++) {
if (fileConfigs[i].props.fileTransferId == fileTransferId) {
fileName = fileConfigs[i].props.name;
break;
}
}

blob.url = (window.URL || window.webkitURL).createObjectURL(blob);
if (fileName) {
saveToDisk(blob.url, fileName);
}
var fileTransferProgressElem = document.getElementById(fileTransferId);
if (fileTransferProgressElem) {
fileTransferProgressElem.hidden = true;
var cancelBtn = fileTransferProgressElem.nextSibling;
if (cancelBtn.type == "button") {
cancelBtn.hidden = true;
}
}
}
}

function showFileTransferProgress(fileTransferId) {
var
fileTransferDisplayArea = document.getElementById("fileTransferArea"),
fileConfigs = wscFileTransfer.getFileConfigs(),
fileConfig = null;

for (var i=0; i<fileConfigs.length; i++) {
if (fileConfigs[i].props.fileTransferId == fileTransferId) {
fileConfig = fileConfigs[i];
break;
}
}

if (fileTransferDisplayArea == null) {
var fileTransferArea = document.createElement("div");
fileTransferArea.id = 'fileTransferArea';
var buttonArea = document.getElementById("buttonArea");
buttonArea.parentNode.insertBefore(fileTransferArea, buttonArea.nextSibling);
insertFileTransferProgress(fileTransferArea, fileConfig);
} else {
insertFileTransferProgress(fileTransferDisplayArea, fileConfig);
}

function insertFileTransferProgress(fileTransferDisplayArea, fileConfig) {
var
fileNameNode,
progressBar,
lastProgressChild,
cancelBtn,

fileTransferProgressDisplay = document.createElement("div");
fileTransferProgressDisplay.id = fileTransferId;
fileTransferProgressDisplay.className = "progress";
fileTransferProgressDisplay.style.width = "85%";
fileTransferProgressDisplay.style.float = "left";

fileNameNode = document.createElement("div");
fileNameNode.innerText = fileConfig.props.name;
fileNameNode.style.position = "absolute";
fileNameNode.style.textAlign = "center";
fileNameNode.style.left = "3%";
fileNameNode.style.color = "white";
fileTransferProgressDisplay.appendChild(fileNameNode);

// Append progress bar
progressBar = document.createElement("div");
progressBar.className = "bar";
progressBar.style.width = "0%";
fileTransferProgressDisplay.appendChild(progressBar);

// Append the cancel button
cancelBtn = document.createElement("button");
cancelBtn.id = "cancelBtn";
cancelBtn.type = "button";
cancelBtn.innerText = "Cancel";
cancelBtn.style.marginLeft = "2%";
cancelBtn.style.marginBottom = "20px";
cancelBtn.onclick = function() {
wscFileTransfer.abort(fileConfig);
cancelBtn.disabled = 'true';
};

if (fileTransferDisplayArea.hasChildNodes()) {
lastProgressChild = fileTransferDisplayArea.lastChild;
fileTransferDisplayArea.insertBefore(fileTransferProgressDisplay,
lastProgressChild.nextSibling);
fileTransferDisplayArea.appendChild(cancelBtn);
} else {
fileTransferDisplayArea.appendChild(fileTransferProgressDisplay);
fileTransferDisplayArea.appendChild(cancelBtn);
}
}
}

Handle File Transfer Progress Updates

Define the onProgress event handler for handling file transmission progress data. The onProgress event handler returns a fileProgressData object which is the same as the fileData object but lacks the actual file content data:

- fileTransferID: A string containing the file transfer ID (defined by WebRTC Session Controller).

- range: A FileDataRange object containing the total range of data in the file. This object comprises the following properties:

- start: A number indicating the first byte of the data.

- end: A number indicating the final byte of the data.

- total: A number indicating the total size of the data in bytes.

In Example 8-32, when a progress event occurs, the fileTransferId data object attribute is passed to the showFileTransferProgress function described in "Handle File Data Transmission," and the progress bar updated in the same manner.

Example 8-32 onProgress Sample Code

function onProgress(data) {
var
fileTransferId = data.fileTransferId;

if (!document.getElementById(fileTransferId)) {
showFileTransferProgress(fileTransferId);
}

var
progressPercent = Math.ceil(data.range.end/data.range.total*100),
progressBar = document.getElementById(fileTransferId).childNodes[1];

if (progressBar) {
progressBar.style.width = progressPercent+"%";
}
}

function showFileTransferProgress(fileTransferId) {
// See Example 8-31...
}

9 Creating WebRTC Session Controller Applications Compatible with Internet Explorer

This chapter shows how you can use the Oracle Communications WebRTC Session Controller JavaScript Adobe Flash application programming interface (API) library to develop real time Web communications applications that will work in Microsoft Internet Explorer.

About WebRTC Session Controller Internet Explorer Support

Microsoft Internet Explorer (IE) provides no support for WebRTC protocols. For many enterprise customers, however, IE remains integral to their business operations. In order to allow IE to utilize WebRTC functionality, WebRTC Session Controller provides an extension leveraging the near ubiquitous Adobe Flash plug-in.

System Requirements

The following sections describe the minimum system requirements for the WebRTC Session Controller Flash extension.

Supported Flash Plug-ins

The Adobe Flash plug-in, version 17 or greater, is required for the WebRTC Session Controller Flash extension to function in client browsers.

The Adobe Flash plug-in can be downloaded from https://get.adobe.com/flashplayer/

Note:
Google Chrome has a built-in Flash implementation.

Supported Browsers

The WebRTC Session Controller Flash extension supports IE versions 8 through 11. In addition, the Flash extension will also work with Firefox version 33.1 and above, and Chrome version 40.0.2214.95 and above.

Note:
A third-party WebSockets solution is required for IE versions 8 and 9, and is not a part of the WebRTC Session Controller Flash extension.

Supported Video and Audio Codecs

The WebRTC Session Controller Flash extension supports the following audio and video codecs:

- Video (no transcoding support)

- H.264/MPEG-4

- Audio (transcoding supported)

- Speex

- G.711 u-law (pcmu)

- G.711 a-law (pcma)

Note:
If a non-IE Web browser is initiating a WebRTC call to an IE Web browser, only audio is supported. The reverse is also true, unless the non-IE browser answers the call using the WebRTC Session Controller Flash extension itself.

About the WebRTC Session Controller Flash Interface

The WebRTC Session Controller Flash interface extension consists of the following two JavaScript libraries:

- wsc-flash.js

- wsc-ie-adapter.js

The wsc-flash.js library contains two classes, FlashCall and FlashCallPackage which are subclasses of Call and CallPackage respectively, and which seamlessly handle Flash audio and video call functions. The wsc-ie-adapter.js library contains various IE support functions.

In addition, a new Groovy package, flash, has been added with additional Flash call processing logic.

Installing the Flash Extension Patch

The following sections describe the detailed steps necessary to download and install the Flash extension support for both WebRTC Session Controller Signalling Engine and Media Engine.

Downloading the Flash Extension Patch

To access and download the Flash extension patch, you need a My Oracle Support account. If you do not have one, you can register here, https://profile.oracle.com/myprofile/account/create-account.jspx?nextURL=https%3A//support.oracle.com.

To download the Flash extension patch:

1. Go to https://support.oracle.com and sign in using your Oracle account credentials.

2. Select the Dashboard tab if it is not already selected.

3. In the Knowledge Base pane, select the Search & Browse tab and select Oracle Communications WebRTC Session Controller from the Select a product or product line drop down list.

4. Enter the patch number, 212208789 in the Enter search terms text box and click the Search button.

5. In the KM Search Results page underneath Recommended Links click the entry, WebRTC Session Controller Flash Support.

6. In the right pane, click the Download button and save and extract the patch archive, p21208789_71000_Generic.zip to the local file system of your WebRTC Session Controller installation.

7. Follow the OPatch utility instructions described in README.txt to apply the Signalling Engine system patch.

Note:
The OPatch installation is required for Flash extension support but is distinct from the Flash extension configuration described in the following sections.

Installing the Flash Extension on Signalling Engine

To install the Flash extension on Signalling Engine:

1. Make sure that your WebRTC Session Controller administration server is running. For instructions on starting WebRTC Session Controller, see Oracle Communications WebRTC Session Controller System Administrator's Guide.

2. Run the following commands to set your environment:

cd WebLogic_home/user_projects/domains/My_domain/
source bin/setDomainEnv.sh

Note:
Replace My_domain with the name of your WebRTC Session Controller Domain.

3. Enter the following command to initialize the WebLogic Scripting Tool (WLST) console:

java weblogic.WLST

4. Enter the following command to connect to the WebRTC Session Controller administration server:

connect()

Note:
You will be prompted to enter the user name, password and server URL for your administration server. You can safely ignore any "insecure protocol" warnings.

5. Enter the following command:

execfile("Absolute_path/212208789/custom/scripts/wsc_extension_for_flash_7.1.py")

Note:
Replace Absolute_path with the full and complete path to the extracted patch archive.

You should see the following output from the wsc_extension_for_flash_7.1.py script:

Starting WebRTC Session Controller configuration extension ...

>>>>>> Create new [flash] package
Creating FROM_APP/start/request script ...
Creating FROM_NET/INVITE/request script ...
Creating FROM_APP/start/response script ...
Creating FROM_APP/start/error script ...
Creating FROM_NET/INVITE/response script ...
Creating FROM_APP/complete/message script ...
Creating FROM_NET/ACK/request script ...
Creating FROM_APP/shutdown/message script ...
Creating FROM_NET/BYE/request script ...
Creating FROM_NET/CANCEL/request script ...

>>>>>> Update register package to add capability registration
[Warning] : FROM_APP/connect/request script does not need to be updated again !

>>>>>> Update ScriptLibrary
Updating resolveProcessingParameters method ...
[Warning] : resolvePackageType has already been updated !

WebRTC Session Controller configuration successfully updated.

Disconnected from weblogic server: AdminServer
wls:/offline>

6. Enter the following command to disconnect from the WLST console:

exit("quit")

7. Log in to the WebRTC Session Controller console at http://host:port/wsc-console, where host:port represents the server URL and port number of your administration server.

Note:
The default WebRTC Session Controller administration server port is 7001.

8. Enter the Username and Password for the Administration Server and click Login.

9. Select the Packages tab and verify that flash appears under Package Name in the Packages pane.

Note:
You may need to clear the IE browser cache if you do not see the flash package.

Grant a WebRTC Session Controller Application Access to the Flash extension

To grant a WebRTC Session Controller Application access to the Flash extension:

1. Log in to the WebRTC Session Controller console at http://host:port/wsc-console, where host:port represents the server URL and port number of your administration server.

Note:
The default WebRTC Session Controller administration server port is 7001.

2. Enter the Username and Password for the Administration Server and click Login.

3. Select the Applications tab.

4. Click the Edit button.

5. For the application to which you want to add the WebRTC Session Controller Flash extension, double-click its cell in the Packages column.

6. In the Package mapping dialog, check the box adjacent the flash entry in the Name column and click OK.

7. Click the Save button.

Configuring Flash Extension Support for Media Engine

This section describes how to configure the WebRTC Session Media Engine (ME) for Flash extension support.

Note:
Flash extension support requires ME version 370m3p3.

About ME Flash Extension Configuration

There are three components to configuring the ME for Flash support. You must configure the type of Real-Time Media Protocol (RTMP) to use, create a multimedia-streaming-config server, and then create a named session-config to support Flash calls.

The ME supports the following types of RTMP:

- RTMP: Unencrypted RTMP.

- RTMPS: Encrypted RTMP through a TLS connection.

- RTMPT: Unencrypted RTMP tunneled through HTTP.

Configuring RTMP

To configure RTMP:

1. Select the Configuration tab and click the cluster > box > interface > ip object.

2. Click Configure next to media-server.

3. Click Add rtmp.

4. port: Specify a TCP port. Oracle recommends using the default port, 1935.

5. Click Create.

6. app-name: Specify a unique app-name for this server. Oracle recommends using the default app-name, live.

7. Click Set.

8. Select the vsp object.

9. Click Configure next to multimedia-streaming-config.

10. Click Add server.

11. name: Enter a unique name for this server.

12. host: Enter the RTMP server's IP address or FQDN. The RTMP server can be an external RTMP server or the local ME can act as the RTMP server. If the local ME is acting as the RTMP server, this value should be set to the IP address of the interface on which the media-server is configured.

13. port: Enter the server port. Oracle recommends using the default RTMP port, 1935.

14. protocol: Specify the rtmp protocol.

15. Click Create. Update and save the configuration.

Example 9-1 shows a CLI sample of RTMP configuration:

Example 9-1 RTMP CLI Configuration

config box interface <eth-x> ip <ip-name>
config media-server
config rtmp 1935
return
return
return

config vsp
config multimedia-streaming-config
config server rtmp
set protocol rtmp
set host <rtmp-server>
set port 1935
return
return
return

Configuring RTMPS

This section describes configuring RTMPS on the ME. RTMPS can be used with or without an HTTP proxy to provide secure RTMP traffic. If an HTTP proxy is required, the proxy must be configured to allow SSL connections to traverse the HTTP proxy using the CONNECT method.

RTMPS is RTMP encrypted within TLS. For secure RTMP on the ME, you must copy and configure a certificate to be used for the TLS connection between the RTMP server and the Flash endpoint. If the Flash endpoint is a browser, the you also must import the certificate's root authority into the browser as a "trusted root certification authority".

Configuring a Certificate

To configure the certificate:

1. Copy the TLS certificate into the ME's /cxc/certs directory.

2. Select the Configuration tab and click the vsp > tls object.

3. Click Add certificate.

4. name: Enter a name for the certificate.

5. Click Create.
The certificate screen appears.

6. certificate-file: Browse to the certificate in the /cxc/certs directory.

7. passphrase-tag: Enter a name to associate with the passphrase associated with the certificate file. Use this if the certificate file is encrypted to have its private key information protected. This passphrase must match the string that the certificate was encrypted with.

8. Click Set. Update and save the configuration.
Example 9-2 shows a CLI sample of the certificate configuration.

Example 9-2 Certificate CLI Configuration

config vsp
config tls
config certificate server-cert
set certificate-file /cxc/certs/<certificate-name>
set passphrase-tag <tag>
return
return
return

9. Use the secret action to set the certificate secret.
For more information on the secret action, see the Oracle Communications WebRTC Session Controller Media Engine Object Reference guide.

Example 9-3 shows a CLI sample of the secret action:

Example 9-3 Secret CLI Action

secret set <tag>
password: <password or passphrase>
confirm:   <password or passphrase>

Configuring RTMPS

To configure RTMPS:

1. Select the Configuration tab and click the cluster > box > interface > ip object.

2. Click Configure next to media-server.

3. Click Add rtmps.

4. port: Specify a TCP port.

5. Click Create.

6. app-name: Specify a unique app-name for this server. Oracle recommends using the default app-name, live.

7. certificate: Select the TLS certificate you configured.

8. Click Set.

9. Click Add rtmp.

10. port: Specify a TCP port. Oracle recommends using the default port 1935.

11. Click Create.

12. app-name: Specify a unique app-name for this server. Oracle recommends using the default app-name, live.

13. Click Set.

14. Select the vsp object.

15. Click Configure next to multimedia-streaming-config.

16. Click Add server.

17. name: Enter a unique name for this server.

18. host: Enter the RTMP server's IP address or FQDN. The RTMP server can be an external RTMP server or the local ME can act as the RTMP server. If the local ME is acting as the RTMP server, set this value to the IP address of the interface on which the media-server is configured.

19. port: Enter the server port.

20. protocol: Specify the RTMPS protocol.

21. Click Create. Update and save the configuration.

Example 9-4 shows a sample RTMPS CLI configuration.

Example 9-4 RTMPS CLI Configuration

config box interface <eth-x> ip <ip-name>
config media-server
config rtmp 1935
return
config rtmps <port-number>
set certificate vsp\tls\certificate <certificate-name>
set passphrase-tag <tag>
return
return
return

config vsp
config multimedia-streaming-config
config server rtmps
set protocol rtmps
set host <rtmp-server>
set port <port-number>
return
return
return

Configuring RTMPT

This section describes configuring RTMPT on the ME. RTMPT can be used to tunnel unencrypted RTMP traffic through an HTTP proxy by tunneling the RTMP traffic inside HTTP.

To configure RTMPT:

1. Select the Configuration tab and click the cluster > box > interface > ip object.

2. Click Configure next to media-server.

3. Click Add rtmpt.

4. port: Specify a TCP port.

5. Click Create.

6. app-name: Specify a unique app-name for this server. Oracle recommends using the default app-name, live.

7. Click Set.

8. Click Add rtmp.

9. port: Specify a TCP port. Oracle recommends using the default port 1935.

10. Click Create

11. app-name: Specify a unique app-name for this server. Oracle recommends using the default app-name, live.

12. Select the vsp object.

13. Click Configure next to multimedia-streaming-config.

14. Click Add server.

15. name: Enter a unique name for this server.

16. host: Enter the RTMP server's IP address or FQDN. The RTMP server can be an external RTMP server or the local ME can act as the RTMP server. If the local ME is acting as the RTMP server, set this value to the IP address of the interface on which the media-server is configured.

17. port: Enter the server port.

18. protocol: Specify the RTMPT protocol.

19. Click Create. Update and save the configuration.

Example 9-5 shows a sample RTMPT CLI configuration.

Example 9-5 RTMPT CLI Configuration

config box interface <eth-x> ip <ip-name>
config media-server
config rtmp 1935
return
config rtmpt <port-number>
return
return
return

config vsp
config multimedia-streaming-config
config server rtmpt
set protocol rtmpt
set host <rtmp-server>
set port <port-number>
return
return
return

Adding Flash Support to a Session Config

Once you have configured RTMP, you must create a session-config to refer to the multimedia-streaming-config.

To create a session-config:

1. Select the Configuration tab and click the vsp > session-config-pool object.

2. Click Add entry.

3. name: Specify the name flash for this session-config.

4. Click Create.
The session-config-pool > entry screen appears.

5. Click Configure next to peer.

6. type: Select streamer from the drop-down list.

7. streamer: Select the vsp\multimedia-streaming-config\server <server-name> you created from the drop-down list.

8. Click Create and return to the session-config-pool > entry screen.

9. Click Configure next to media.

10. anchor: Set to enabled.

11. Click Configure next to nat-traversal.

12. symmetricRTP: Set to true.

13. Click Set

14. Return to the session-config-pool > entry screen.

15. Click Configure next to sip-directive.

16. directive: Set to allow and click Set.

17. Click Set. Update and save your configuration.

Example 9-6 shows a sample session-config CLI configuration.

Example 9-6 Session-Config CLI Configuration

config vsp
config session-config-pool
config entry flash
config peer
set value streamer "vsp\multimedia-streaming-config\server <server-name>"
return
config media
set anchor enabled
config nat-traversal
set symmetricRTP true
return
return
config sip-directive
set directive allow
return
return
return

Adding Flash Support to Your WebRTC Web Application

The WebRTC Session Controller JavaScript API has been expanded with additional functionality that lets you add seamless real time Web application audio and video call support for IE browser clients.

This section describes the steps necessary to add the required JavaScript libraries and place and receive WebRTC calls using the Flash extension.

WebRTC Session Controller JavaScript Flash Support Overview

To add Flash support to your Web application, you complete the following general steps:

1. Download the Google SWFObject JavaScript support library.

2. Reference the WebRTC Session Controller Flash JavaScript extension files and the Google SWFObject JavaScript support library in your Web application.

3. Initialize the WebRTC Session Controller Flash extension.

4. Retrieve WebRTC/Flash browser support information so you can handle calls as required.

5. Pass the WebRTC/Flash browser support information to the WebRTC Session Controller Session so that the Groovy script library can relay the support to other callees.

6. Initiate a Flash audio/video call.

7. Terminate the Flash audio/video call.

Additional sections discuss answering incoming Flash-based calls as well as determining whether a particular call was initiated from the Flash extension.

Downloading the Google SWFObject JavaScript Support Library

The WebRTC Session Controller Flash extension requires the use of a third-party JavaScript library from Google, SWFObject. Download swfobject_2_2.zip from https://code.google.com/p/swfobject/downloads/list, and extract swfobject.js to the same location as your other JavaScript libraries.

Referencing the WebRTC Session Controller Flash JavaScript Extension Libraries

Update the JavaScript library references in your WebRTC Session Controller application, including the Flash extension wsc-ie-adapter.js library before any other WebRTC Session Controller JavaScript libraries, and then the Google swfobject.js library before the Flash extension wsc-flash.js library.

Figure 9-0 shows the required ordering.

Example 9-7 Flash Extension JavaScript Library References

<script type="text/javascript" src="js/wsc-ie-adapter.js"></script>
... Include any other WebRTC Session Controller libraries in the ...
<script type="text/javascript" src="JavaScript_path/wsc-common.js"></script>
<script type="text/javascript" src="JavaScript_path/wsc-call.js"></script>
<script type="text/javascript" src="JavaScript_path/swfobject.js"></script>
<script type="text/javascript" src="JavaScript_path/wsc-flash.js"></script>
... Include your own JavaScript libraries here...

For more information on WebRTC Session Controller JavaScript libraries, see "WebRTC Session Controller Support Libraries."

Initializing the Flash JavaScript Extension

You must call wsc_flash.wscFlash.init(0) to initialize WebRTC Session Controller Flash support after all the required JavaScript libraries are loaded.

Figure 9-0 shows the required initialization logic.

Example 9-8 Initializing the Flash Extension

if (typeof wsc_flash != 'undefined') {
console.log ('Initializing the Flash extension...');
wsc_flash.wscFlash._init();
}

Determining Flash Browser Support

In your WebRTC application, you can use the WebRTC Session Controller Flash extension JavaScript function getMediaOptions() to determine whether WebRTC, Flash, or both are supported by the browser.

Example 9-9 shows how you can analyze the return values from getMediaOptions() to determine WebRTC/Flash support in a client browser.

Example 9-9 Determining Flash/WebRTC Support in a Client Browser

var mediaOptions = getMediaOptions();

if (mediaOptions.webrtc && mediaOptions.flash) {
console.log ("Both Flash and WebRTC are supported.");
} else if (mediaOptions.webrtc) {
console.log ("Only WebRTC is supported.");
} else if (mediaOptions.flash) {
console.log ("Only Flash is supported.");
} else {
console.log ("Neither Flash nor WebRTC support detected.");
}

If the client browser is IE, only Flash support is available. If the client browser is Firefox, both WebRTC support and Flash support are available if a Flash plug-in is installed. Since Google Chrome includes its own Flash engine, it always returns support for both WebRTC and Flash.

Passing Flash/WebRTC Support Information to a WebRTC Session Controller Session

The WebRTC/Flash support information returned by getMediaOptions() should be provided to a newly instantiated WebRTC Session Controller session using the extension header, X-MediaOptions. X-MediaOptions are stored in the sessionStore and are used to resolve the incoming call package type (CallPackage or FlashCallPackage). The Flash Groovy code will use information in the sessionStore to determine if the browser supports Flash, WebRTC or both.

Figure 9-0 illustrates passing media options for WebRTC session initialization.

Example 9-10 Determining Flash Browser Support

var mediaOptions = getMediaOptions();

var sessionId = sessionStorage.getItem("sessionId");

// Create a new WebRTC Session Controller session including the mediaOptions...
if (sessionId) {
wscSession = new wsc.Session(userName,
wsUri,
onSessionSuccess,
onSessionError,
sessionId,
{'X-MediaOptions': mediaOptions});
} else {
wscSession = new wsc.Session(userName,
wsUri,
onSessionSuccess,
onSessionError,
undefined,
{'X-MediaOptions': mediaOptions});
}

Initiating a Call Using the Flash Extension

Figure 9-0 illustrates how to make an audio/video call using the Flash extension. Note that the only significant difference is that the FlashCallPackage's createCall method is called rather than CallPackage's.

Example 9-11 Initiating a Call Using the Flash Extension

function makeFlashVideoCall() {
var callee = "alice@example.com";
var audioMediaDirection = wsc.MEDIADIRECTION.SENDRECV;
var videoMediaDirection = wsc.MEDIADIRECTION.SENDRECV;

var callConfig = new wsc.CallConfig(audioMediaDirection,
videoMediaDirection,
undefined);

// The FlashCallPackage is initiated when the Call session is created...
wscCall = flashCallPackage.createCall(callee,
callConfig,
onCallError);

console.log("Initiating a Flash extension audio/video call...");
initWscCall(wscCall);
wscCall.start();

// Update the HTML page's UI as required...
}

function initWscCall(call) {
wscCall = call;
call.onCallStateChange = function(newState) {
onCallStateChange(call, newState);
};
call.onUpdate = function(callConfig) {
onCallUpdate(call, callConfig);
};
call.onMediaStreamEvent= onMediaStreamEvent;
}

Note:
If a non-IE Web browser is initiating a WebRTC call to an IE Web browser, only audio is supported. The reverse is also true, unless the non-IE browser answers the call using the Flash extension itself.

For more information on handling outgoing audio calls, see Chapter 4, "Setting Up Audio Calls in Your Applications." For more information on handling outgoing video calls, see Chapter 5, "Setting Up Video Calls in Your Applications."

Terminating a Flash Extension Call

Figure 9-0 shows a Flash extension call terminated using FlashCall's end() method. There is no functional difference in call termination between a regular WebRTC call and a Flash call.

Example 9-12 Terminating a Flash Extension Call

function end() {
wscFlashCall.end();
// Clean up the application UI as required...
}

Processing an Incoming Audio/Video Call

In your WebRTC application, when handling an incoming call the JavaScript event handler, onMediaStreamEvent, must support the following events:

- wsc.MEDIASTREAMEVENT.LOCAL_STREAM_ADDED

- wsc.MEDIASTREAMEVENT.REMOTE_STREAM_ADDED

Example 9-13 shows the basic logic for handling Flash-based media streams in the onMediaStreamEvent event handler.

Example 9-13 Handling Flash Media Events

function onMediaStreamEvent (mediaEvent, stream) {
console.log ("onMediaStreamEvent: " + mediaEvent.toString ());

if (mediaEvent == wsc.MEDIASTREAMEVENT.LOCAL_STREAM_ADDED) {
console.log ("Handling local stream added event...");
if (typeof flashCallPackage != 'undefined'
&& stream
&& stream instanceof
wsc_flash.wscFlash.FlashMediaStream) {
console.log ("Local flash video stream added...");
// Set up the application UI as required...
}
} else if (mediaEvent == wsc.MEDIASTREAMEVENT.REMOTE_STREAM_ADDED) {
console.log ("Handling remote stream added event...");
if (typeof flashCallPackage != 'undefined'
&& stream
&& stream instanceof
wsc_flash.wscFlash.FlashMediaStream) {
console.log (Remote flash video stream added...");
// Set up the application UI as required...
}
}
}

Note:
If a non-IE Web browser is initiating a WebRTC call to an IE Web browser, only audio is supported. The reverse is also true, unless the non-IE browser answers the call using the Flash extension itself.

For more information on handling incoming audio calls, see Chapter 4, "Setting Up Audio Calls in Your Applications." For more information on handling incoming video calls, see Chapter 5, "Setting Up Video Calls in Your Applications."

Determining Whether a Particular Call is Flash-based

Example 9-14 shows a simple function that returns whether a call is a Flash-based call by examining the CallPackage's packageType instance variable.

Example 9-14 Checking for a Flash-based Call

function _isFlashCall (call) {
var aFlashCall = false;
if (call && call.pkgInstance && call.pkgInstance.packageType == 'flash')
{
aFlashCall = true;
}
return aFlashCall;
}

10 Extending Your Applications Using WebRTC Session Controller JavaScript API

This chapter describes how you can extend the Oracle Communications WebRTC Session Controller JavaScript application programming interface (API) library.

Note:
See WebRTC Session Controller JavaScript API Reference for more information on the individual WebRTC Session Controller JavaScript API classes.

About the Default Messaging Mechanism Used by Your Applications

When your application needs to perform an action such as creating a session, a call or message alert package, starting a call or responding to a notification, it sends a JavaScript message associated with that action to the WebRTC Session Controller JavaScript API library. For its part, the WebRTC Session Controller JavaScript API library converts these messages (for example, Call.start) into signaling messages using a protocol based on JavaScript Object Notation (JSON). For more information, see WebRTC Session Controller Extension Developer's Guide.

The WebRTC Session Controller JavaScript API library contains classes and methods that have a default behavior and others that can be extended. When you use the default classes and methods, the WebRTC Session Controller JavaScript API library handles all of the signaling messages for all the resulting default commands.

When you need to broaden or extend your application logic, you may need to extend the JavaScript message sent by your application. To do so, use those objects and methods in the WebRTC Session Controller JavaScript API that are extensible.

About Extending the WSC Namespace

Your applications can support additional communication-related services in audio, video, and data transfer flows. For example:

- Custom calls
In order to handle custom call flows you can implement logic to prepare the calls, setting up the logic to accept prepared calls, and manage the sequence of messages associated with the prepared calls.

- Custom packages
To support custom services in calls of custom call flows, your application may need to extend the application session.

The WebRTC Session Controller JavaScript API library provides the following objects and functions for this purpose:

- wsc.extend. See "Extending Objects Using the wsc.extend Method".

- wsc.ExtensibleSession. See "Extending Sessions with wsc.ExtensibleSession Class".

- Other extensible methods. See "Extending and Overriding WebRTC Session Controller JavaScript API Object Methods".

Note:
WebRTC Session Controller JavaScript API Reference uses the term "For extensibility" to identify such extensible objects and methods.

Extending Objects Using the wsc.extend Method

The wsc.extend method is a utility you use when you wish to extend a WebRTC Session Controller JavaScript API class object exposed through wsc namespace. The wsc.extend method takes two parameters, child and parent, in that order. The syntax is:

wsc.extend(child, parent);

When you call the wsc.extend method, the constructor of the child object calls the constructor of the parent. All the members that are attached to the prototype object of the parent entry are copied to the prototype object of the child entry. The objects initialized in the parent's constructor code become available and the child can now make use of the objects in the parent class object. You can then override any function in the child object without impacting the parent.

The code sample in Example 10-1 creates the wsc.CallExtension object which extends the wsc.Call object.

Example 10-1 Creating CallExtension from the Call Object

function CallExtension() {
//chain constructor
CallExtension.superclass.constructor.apply(this, arguments)
}

// The following statement makes the CallExtension object a child of wsc.Call
wsc.extend(CallExtension, wsc.Call);

At this point, the inherited members of CallExtension can be overridden without affecting the corresponding members in the parent Call object.

See "Working with Extended Calls" for a description of how the onMessage function is overridden in this newly-created CallExtension class object.

Extending Sessions with wsc.ExtensibleSession Class

The wsc.ExtensibleSession class object provides many critical functions required to extend packages. Use the methods in wsc.ExtensibleSession to access and retrieve information about a subsession using its identifier (sessionId), retrieve a specific package by its type and manage it, and configure custom packages in your application to handle specific set of tasks. See "Creating Custom Packages Using the ExtensibleSession Object".

Extending and Overriding WebRTC Session Controller JavaScript API Object Methods

You can override and extend methods in WebRTC Session Controller JavaScript API objects to do the following:

- Handling Extended Call Sessions with CallPackage.onMessage

- Preparing Custom Calls with CallPackage.prepareCall

- Inserting Calls into a Session with CallPackage.putCall

- Processing Custom Messages for a Call with Call.onMessage

- Extending Headers in Call Messages

- Handling Custom Message Notifications

- Handling Extensions to Notifications with MessageAlertPackage.onMessage

Handling Extended Call Sessions with CallPackage.onMessage

If your application logic uses extended call sessions, set up the required actions in a callback function for the application's CallPackage.onMessage event handler. When call-related messages come in to your application, this callback function will be invoked enabling you to inspect the incoming message and take further action on the call.

When you extend the CallPackage object, you can override the CallPackage.onMessage event handler. See "Extending Objects Using the wsc.extend Method" for more information.

Preparing Custom Calls with CallPackage.prepareCall

By default, your application's Call object is created with reference to the default Session object.

The CallPackage.prepareCall method is a Service Provider interface function which prepares a call with reference to a session. For example:

mycall = callPackage.prepareCall(mysession,CallConfig, caller, callee);

Here, an application has set up the caller, callee, and callConfig objects and uses the CallPackage.prepareCall method to prepare a call called mycall with reference to a specific session, mysession.

Inserting Calls into a Session with CallPackage.putCall

Use the CallPackage.putCall method to place a prepared call object in a specific point in the flow for that call session. To do so, you need:

- The subsession Id (id) for the call session

- The prepared call object.

You can now place the call with the following statement:

putCall(id, call);

Processing Custom Messages for a Call with Call.onMessage

Process custom message content that your application receives for the current call by using the Call.onMessage method. Extend the Call object to do so. See "Working with Extended Calls".

Extending Headers in Call Messages

When you use an extension header in a call session, set up the extension header in the following JavaScript format:

{'label1':'value1','label2':'value2'}

Place the extension header as the last parameter when you invoke the methods that support extension headers. See "Handling Additional Headers" for the complete of objects and methods that support extension headers.

Handling Custom Message Notifications

If the received notification message is not a message summary, your application receives a wsc.Notification object as the parameter to its Subscription.onNotification event handler.

In the callback function you assign to your application's Subscription.onNotification event handler, use this incoming notification to instantiate an extended wsc.Notification class object. Use the methods of the extended class object to parse the supported types of notification messages.

Handling Extensions to Notifications with MessageAlertPackage.onMessage

If your application's MessageAlertPackage object manages an array of subscriptions, then, when a notification comes to your application, the MessageAlertPackage.onMessage event handler is invoked. In the callback function you assign to this event handler, you can process the incoming message notification to identify the subscription object and invoke the appropriate Subscription.onNotification event handler for further processing of that notification.

The MessageAlertPackage.onMessage function can be overridden to handle custom message events. See "Working with Extended CallPackage Objects".

Handling Additional Headers in Messages

Your application may need to allow users to send or receive additional data in the form of an extra header field.

About Additional Headers in Messages

Some methods in the Call and CallPackage class objects can accept an additional argument, as long as it is a JSON object. This additional data is sent as an extension header in the message and received as an extra parameter by the event handler of the incoming call.

For example, when a user navigates your application page designed for an auto dealership, your application may have gathered data on the user's preferences for the make, model, and deal preferences, such as carMaker, Convertible), and Lease.

When the user calls the dealership from your page, your application can pass this information to the dealer in the call. Your application sets up this information as a JSON object.

{'custprefKey1':'BMW','custprefKey2':'Convertible', 'custprefKey2':'Lease'}

This JSON object is now sent in the message as:

{ "control" : {}, "header" : {'custprefKey1':'BMW','custprefKey2':'Convertible', 'custprefKey2':'Lease'}, "payload" : {}, }

At the dealership, when the dealer receives the call, the appropriate function is invoked with the extra information as the last argument, for example,

callObj.accept(callConfig, null, extheader);

In that function, your application takes this extheader JSON object, retrieves the information and takes the actions necessary to display the information for the dealer's use.

Handling Additional Headers

The WebRTC Session Controller JavaScript API library supports extension headers as the parameter in the following:

- Call Methods:

- Call.accept

- Call.decline

- Call.end

- Call.start

- Call.update

- Event Handlers:

- CallPackage.onIncomingCall

- Call.onCallStateChange

- Call.onUpdate

See the discussion on customizing messages for new Session Initialization Protocol (SIP) or JSON data in Oracle Communications WebRTC Session Controller Extension Developer's Guide.

Managing Calls with Additional Headers

The Call API object can be used to send or receive an extension header in its call flow.

For your application to start a call with extension headers:

1. Set up the extension header as a JSON object.

2. Place the JSON object as the last parameter when your application invokes the outgoing call object's start method to start the call.
For example, if call is the call object, lmedstrm is the local media stream object, and extHeader is the extension header in your application, use the following statement to start the call:

call.start(lmedstrm,extHeader)

When your application receives a request for a call with extension headers:

1. Retrieve the extension header from your application's CallPackage.onIncomingCall event handler. The extension header is in JSON format.

2. Perform any actions based on the additional data in the extension header.

3. If the application user accepts the call, do the following:

1. Set up the extension header as a JSON object.

2. Include the JSON object when your application invokes the outgoing call object's start method to start the call.
For example, if call is the call object, callConfig the local media stream and data transfer capability for calls, lmedstrm is the local media stream object, and extHeader is the extension header in your application, use the following statement to accept the call:

call.accept(callConfig, lmedstrm, extHeader)

4. If the application user declines the call, do the following:

1. Obtain the reason the call was declined by the user.

2. Set up the extension header as a JSON object.

3. Include the JSON object when your application invokes the outgoing call object's decline method.
For example, if extCall is the extended call object, reason the reason the call was declined, and extHeader is the extension header:

extCall.decline(reason,extHeader)

Whether your application user is the caller or the callee, your application may need to handle incoming messages and set up outgoing messages associated with the following events. In each case, set up the extension header as described and place it as the last parameter when you invoke the associated function for the extended call.

- Your application user ends the call.
Set up the extension header as described earlier and include it when you invoke the end method for the extended call.

- The call is updated.
If your application user:

- Requests the update.
Set up the extension header as described earlier and include it when you invoke the update method for the extended call.

- Receives the update request.
Process any data in the extension header in the onUpdate event handler. Set up the extension header as described earlier and include it when you invoke the accept or decline method of the extended call object, as appropriate.

- The call state changes.
Process any data in the extension header in the Call.onCallStateChange event handler. Set up the additional data as the extension header in the method for the outgoing call.

Working with wsc.ExtensibleSession

Your applications can use custom session objects to enable users to subscribe to the presence of other users, chat with SIP users, or set up calls that can be transferred to other users. Configure and manage custom flows in your applications by using the wsc.ExtendedSession object.

Creating an Extensible Session in Your Application

To create an extensible session, use the syntax:

wsc.ExtensibleSession(useName, webSocketUri, successCallback, failureCallback, sessionId)

Where:

- useName, is the user name.

- webSocketUri, the predefined web socket connection.

- successCallback, the function to call if the session object was created successfully.

- failureCallback, the function to call if the session object was not created.

- sessionId, if you are refreshing an existing session.

Creating Custom Packages Using the ExtensibleSession Object

You can create custom packages in your application to handle specific set of tasks and expand the scope of your application. To add custom packages, your application needs to use the following objects:

- The ExtensibleSession:
Use this object to do one or more of the following

- Creating an extended session object using the ExtensibleSession method of wsc.

- Retrieving all sub-sessions by using the getAllSubSessions method of your application's ExtensibleSession object.

- Saving session data to the web browser's sessionStorage by using the saveToStorage method of your application's ExtensibleSession object.

For more information on subsessions, see Oracle Communications WebRTC Session Controller JavaScript API Reference.

- The custom package object in the session:
Set up this object by doing the following:

- Creating the custom package object.

- Registering the package by using the registerPackage method of your application's ExtensibleSession object.

- Retrieving the package by its type by using the getPackage method of your application's ExtensibleSession object.

- The message object that the custom package sends or receives:
Manage the message object by doing the following:

- Defining the message object with wsc.Message

- Sending the message using the sendMessage method of your application's ExtensibleSession object.

- Handling an incoming message using the Call.onMessage method in your application's ExtensibleSession object.

- Generating a correlation ID for the message using the genNewCorrelationId method of your application's ExtensibleSession object.
The generated correlation ID is based on the current outbound sequence number sequence of this session. For information on sequence, see Oracle Communications WebRTC Session Controller Extension Developer's Guide.

- The message flow as required by the requirements of the extended session. See "Sending And Receiving Custom Messages".

- The subsession of the ExtensibleSession by:

- Retrieving the session Id of the subsession using getSubSessionId of your application's ExtensibleSession object.

- Retrieving all subsessions that belong to a specific package using getSubSessionsByPackageType method of your application's ExtensibleSession object.

- Placing a subsession object into the session with putSubSession method of your application's ExtensibleSession object.

- Removing subsession object giving its id using removeSubSession method of your application's ExtensibleSession object.

Saving Your Custom Session

When you create applications using the default or custom behavior of WebRTC Session Controller JavaScript API, the library automatically saves the data for the sessions.

If you need your application to handle the data associated with custom sessions or subsessions, save the corresponding data in the HTML SessionStorage area using the ExtensibleSession.saveToStorage method. Your session data should be stored in JSON format. Ensure that your application saves the session data such that it captures the changes so as to maintain the session's current state for use in dealing with connectivity issues.

Important:
When your application uses a custom package and/or subsession object save the subsession's state to support rehydration. Monitor the change in the subsession's state and call your application's ExtensibleSession.saveToStorage() method to save the data.

Sending And Receiving Custom Messages

When you create messages independent of the default call or message alert package, you need to set up logic to handle the flow of such messages and the resulting actions your application needs to take.

You can send custom messages within a sub-session by providing a Message object as an argument when you call your application's ExtensibleSession#sendMessage method. Ensure that your application's Message object has the control, header, and payload blocks. For example, to send INFO messages as part of an ongoing call, your application can extend its Call and CallPackage objects and use them to support sending and receiving INFO messages while delegating all other functionality to the existing Call and CallPackage. See the discussion on extension points in Oracle Communications WebRTC Session Controller JavaScript API Reference.

About the API Classes Used to Create Custom Message

At times, you may need to create you create custom packages and use custom message flows in your applications. Use the following:

- wsc.Message

- wsc.Message#control

- wsc.Message#header

- wsc.Message#payload

Note:
For information on the wsc.Map utility you can use when you set up custom messages, see Oracle Communications WebRTC Session Controller JavaScript API Reference.

wsc.Message

The wsc.Message class object encapsulates a message and contains two sections of headers and the payload, if necessary. All messages between your application and WebRTC Session Controller are sent in this format. Create the control header, general header and the payload sections of message object in your application. Example 10-2 shows the header sections of a message object which initiates a WebSocket connection:

Example 10-2 The Header Sections of a Message Object

{
"control": {
"type":"request",
"sequence":"1",
"version":"1.0"
},
"header": {
"action":"connect",
"initiator":"bob@someCompany.com",
}
}

Note:
When you need to create messages independent of the default call or message alert package, use the wsc.Message object and manage the messaging workflow using the wsc.ExtensibleSession object. See "Working with wsc.ExtensibleSession".

wsc.Message#control

Use the wsc.Message#control object to define the control header in a message.

A control header contains information required for WebSocket reconnection, reliability, timeouts, error, the state of the message, type of the message, and so on. For information on the headers supported in the Control section, see Oracle Communications WebRTC Session Controller JavaScript API Reference and Oracle Communications WebRTC Session Controller Extension Developer's Guide.

wsc.Message#header

Use the wsc.Message#header object to specify the specific action involved in the message. For example, for a START request, such information would contain who initiated the request, for whom it is intended, and so on. Your application can add additional headers to the this section. Such headers may be mapped by a gateway server to a SIP header or a parameter. For information on the headers supported in the Header section, see Oracle Communications WebRTC Session Controller JavaScript API Reference and Oracle Communications WebRTC Session Controller Extension Developer's Guide.

wsc.Message#payload

Use the wsc.Message#payload object to specify the payload section of the protocol specific to the "package". For:

- CallPackage, the payload contains the offer or answer in Session Description Protocol (SDP)

- MessageAlertPackage, the payload contains the exact message alerts in JSON format.

If you create a "Presence" package, the payload for messages associated with this package should contain the presence information.

Managing Custom Message Data Flows

When you use custom message flows, set up your application with the appropriate logic required to send and receive messages from Signaling Engine. Ensure that the correlation Ids, the sequencing and other details of the outgoing message are appropriate.

Sending a Custom Message to Signaling Engine

Complete the following tasks to send a custom message to Signaling Engine:

- Set up the data as "key" : "value" pairs in

- wsc.Message#control()

- wsc.Message#header()

- Set up the payload using wsc.Message#payload

- Use JSON.stringify method to set up the message data in msg.

- Create the message to be sent using wsc.Message(msg), where msg is message data.

- Send the message using the sendMessage method of your application's ExtensibleSession object.

- Monitor the message flow to take further action.

- Save the session and subsession data, as required. See "Saving Your Custom Session".

Processing an Incoming Custom Message

Process a custom message that your application receives from Signaling Engine in the following way:

- Set up the callback function for the onMessage event handler of the extended CallPackage object in your application. The custom message is provided in the event handler as a wsc.Message object.

- Take appropriate action. Set up your application's response in the outgoing message.

- Monitor the message flow to take further action.

- Save the session and subsession data, as required. See "Saving Your Custom Session".

Customizing Your Applications by Extending the Package Objects

This section describes how you can customize your application by extending the WebRTC Session Controller JavaScript API library's default call and message alert package API objects.

Working with Extended CallPackage Objects

Working with extended CallPackage objects involves the following:

- Creating an Extended Call Package

- Registering the Extended Package with the Session

- Extending the Methods and Event Handlers in the Extended Call Package

- Working with Extended Calls

Creating an Extended Call Package

You can create an extended call package when you instantiate a session, such as wscSession as shown below:

Example 10-3 Creating an Extended Call Package

var CallPackageExtension = function() {

//sub-class must invoke the superclass's constructor
CallPackageExtension.superclass.constructor.apply(this, arguments);
};
CallPackageExtension.prototype.prepareCall = function(wseSession, callConfig, caller, callee) {
return new CallExtension(session, callConfig, caller, callee);
};
wsc.extend(CallPackageExtension, wsc.CallPackage);

Registering the Extended Package with the Session

Register the extended call package with the Session object you instantiated. For example:

// Create a extended CallPackage.

extcallPackage = new CallPackageExtension(wscSession);

Call objects created from this extended call package can handle additional headers.

Extending the Methods and Event Handlers in the Extended Call Package

When you extend the call package, extend the required methods and event handlers:

- prepareCall

- putCall

- onMessage

- onRehydration. Extend this event handler so that your application can re-create the subsession object based on the rehydrated data your application receives through this event handler. When the subsession object is recreated, WebRTC Session Controller JavaScript API library invokes the onResurrect event handler of the call object.

Working with Extended Calls

To work with extended calls:

1. Extend the CallPackage object:

wsc.extend(CallPackageExtension, wsc.CallPackage);

2. Create an instance of the extended call package CallPackageExtension and register it with the session.

CallPackage = new CallPackageExtension(wscSession);

Use this instance of the call package to expand the way your application handles calls.

The code sample in Example 10-4 adds support to handle INFO messages as part of a call by extending the Call and CallPackage objects. If the incoming message has extra data, the prepareCall function is overridden.

Example 10-4 Extending the Call and CallPackage Objects

//CallExtension is the child object which extends Call object and overrides a function
//The constructor of the child object calls the constructor of the parent so that the objects
//initialized in the parent's constructor code is available to the child.

function CallExtension() {
//chain constructor
CallExtension.superclass.constructor.apply(this, arguments)
}

//The following statement makes the CallExtension object as a child of wsc.Call
wsc.extend(CallExtension, wsc.Call);

//override the method onMessage to support handling INFO messages

CallExtension.prototype.onMessage = function (message) {
//check if this is an INFO message, if so, handle it here
if (this.isInfoMessage(message)) {
handleInfoMessage(message);
} else {
// delegate the handling to the base class
CallExtension.superclass.onMessage.call(this, message)
}
};

CallExtension.prototype.isInfoMessage = function (message) {
var action = message.header.action,
type = message..control.type;
return action === "info" && type === "message";
};

//Extend and CallPackage object and override the prepareCall function such that
//A CallExtension object is created instead of the default Call object
function CallPackageExtension() {
CallPackageExtension.superclass.constructor.apply(this, arguments)
}

wsc.extend(CallPackageExtension, wsc.CallPackage);

//override prepareCall function
CallPackageExtension.prototype.prepareCall = function (session, callConfig, caller, callee) {
return new CallExtension(session, callConfig, caller, callee);
};

Working with Extended MessageAlertPackage Objects

Working with extended CallPackage objects involves the following:

- Creating an extended message alert package. The process is similar to creating an extended call package. See "Creating an Extended Call Package".

- Registering the extended package with the session. The process is similar to registering an extended call package. See "Registering the Extended Package with the Session".

- Extending the Methods and Event Handlers

- Extending the MessageAlertPackage to Support Other Message Events

Extending the Methods and Event Handlers

When you extend the MessageAlertPackage class object, extend the required methods and event handlers:

- onMessage

- onRehydration. Extend this event handler so that your application can re-create the subsession object based on the rehydrated data your application receives through this event handler. When the subsession object is recreated, WebRTC Session Controller JavaScript API library invokes the onResurrect event handler of the rehydrated Subscription object.

Extending the MessageAlertPackage to Support Other Message Events

You can extend the wsc.MessageAlertPackage class object to support other message event types.

To do so:

- Use wsc.extend method to set up an extended MessageAlertPackage object.

- Override the onMessage event handler of the extended MessageAlertPackage object. Your application can now handle notifications other than the default MessageSummary type.

- Assign a callback function to handle the overridden onMessage event handler of the extended MessageAlertPackage object. In this callback function, process the new type of notification message.

- Define a custom class extended from the Notification class object. This new type of notification object will store the notification messages made available by the overridden onMessage event handler.

- Define a new class similar to MessageCounts and set it up to store the information on the new notification messages.

11 WebRTC Session Controller JavaScript API Error Codes and Errors

This chapter describes the error handlers and error codes provided in the Oracle Communications WebRTC Session Controller JavaScript application programming interface (API) library.

Note:
See Oracle Communications WebRTC Session Controller JavaScript API Reference for more information on the individual WebRTC Session Controller JavaScript API classes.

About wsc.ERRORCODE

The WebRTC Session Controller JavaScript API library provides the wsc.ERRORCODE enumerator object for the possible error codes. When there is an error, the appropriate error handler is called with the specific error code.

About the Error Codes

Table 11-1 lists the possible error codes and their descriptions.

Table 11-1 Error Codes and Their Descriptions

Error Code

Error Constant

Description

401

UNAUTHORIZED

The request requires user authentication.

403

FORBIDDEN

The server understood the request, but is refusing to fulfill it.

404

RESOURCE_UNAVAILABLE

The server has definitive information that the user does not exist at the domain specified in the Request-URI.

407

PROXYAUTH_REQUIRED

This code is similar to 401 (UNAUTHORIZED), but indicates that the client MUST first authenticate itself with the proxy.

480

TEMPORARILY_UNAVAILABLE

The callee's end system was contacted successfully but the callee is currently unavailable.

486

BUSY_HERE

The callee's end system was contacted successfully, but the callee is currently not willing or able to take additional calls at this end system.

487

REQUEST_TERMINATED

The request was terminated.

500

SYSTEM_ERROR

The server encountered an unexpected condition that prevented it from fulfilling the request.

600

BUSY_EVERYWHERE

The callee's end system was contacted successfully but the callee is busy and does not wish to take the call at this time.

603

DECLINED

The callee's machine was successfully contacted but the user explicitly does not wish to or cannot participate.

1001

WEBSOCKET_ERROR

The websocket has an error or the connection has failed.

1101

PEERCONNECTION_ERROR

The peerConnection has encountered an error.

1201

MEDIA_ERROR

The media stream has an error.

1301

RESTORE_FAILED

The session state could not be reloaded.

1302

SAVE_FAILED

The session state could not be saved.

Using wsc.ErrorInfo

The wsc.ErrorInfo object enables you to handle error scenarios in your application. use the code and reason properties to retrieve the error code and reason and process the failure scenario accordingly.

About the Error Handlers

Assign callback functions and implement the logic to perform the following tasks:

- Handling Errors Related to Sessions

- Handling Errors Related to Calls

- Handling Errors Related to Data Transfers

- Handling Errors Related to Subscriptions

Handling Errors Related to Sessions

In our base case example, we created the wseSession object using the following statement:

wseSession = new wsc.Session(null, wsUri, sessionSuccessHandler, sessionErrorHandler);

When wseSession has an error, WebRTC Session Controller JavaScript API library invokes the callback function sessionErrorHandler() and provides the error as error, the argument in the sessionErrorHandler() callback function.

In the callback function assigned in your application to handle session-related errors, use the error.code property to display the error code and error.reason property to display the reason for the specific error as shown below in Example 11-1.

Example 11-1 Session Creation Error Handler

function sessionErrorHandler(error) {
console.log("onSessionError: error code=" + error.code + ", reason=" + error.reason);
setControls("<h1>Session Failed, please logout and try again.</h1>");
...
}

Take any other action as appropriate for the session-related error.

Handling Errors Related to Calls

Suppose your application uses the following statement is used to create an instance of a Call object named call:

var call = callPackage.createCall(callee, callConfig, failureCallback);

Your application may be required to handle errors related to calls the following scenarios:

- If the call object named call is not created for some reason, Signaling Engine invokes the callback function failureCallback and provides the error as error, the argument in the failureCallback callback function.

- Your application invokes the Call.start method for this call and the WebRTC Session Controller JavaScript API library attempts to send the request to start the call. If an exception occurs:

- Before the WebRTC Session Controller JavaScript API library sends the request to start the call, then the failureCallback function is invoked.
In the callback function assigned in your application to handle call-related errors, use the ErrorInfo.reason property to display the reason for the specific error as shown below in Example 11-2.

Example 11-2 Handling Call-Related Error

function failureCallback(error) {
alert('Call error reason:'+error.reason);
}

- After the WebRTC Session Controller JavaScript API library sends the request to start the call, then the Signaling Engine invokes the Call.onCallStateChange event handler of the call with the call state as wsc.CALLSTATE_FAILED.
Set up the appropriate actions in the callback function assigned in your application to Call.onCallStateChange to handle this call state.

Handling Errors Related to Data Transfers

In "Setting Up the Data Transfer State Event Handler for the Chat Session", the logic in the onDataTransfer callback function assigns onDCError as the callback function for data channel errors with the following statement:

dataTransfer.onError = onDCError;

If there is an issue in a chat session, in sending a text message or a data file, the WebRTC Session Controller JavaScript API library triggers onDCError, the error event handler and provides the appropriate error constant from the WSC.ERRORCODE enumerator object.

In the callback function assigned in your application to handle call-related errors, use the ErrorInfo.reason property to display the reason for the specific error. Take any other action as appropriate for the error.

Handling Errors Related to Subscriptions

If there is an issue in creating a subscription, Signaling Engine triggers the error event handler onError with the appropriate constant defined in the WSC.ERRORCODE enumerator object.

The following statement creates an instance of the Subscription class called subscription:

subscription = MsgAlertHandler.createNewSubscription(
target,subscriber,onSubscribeSuccess,onSubscribeError,onNotification,onEnd, extHeaders);

Where:

- target is the service target you obtained from the user, the device or the service the user wishes to monitor.

- subscriber is the user identity of this subscriber.

- onSubscribeSuccess is the event handler called when the application creates the subscription.

- onSubscribeError is the event handler called when the application fails to create the subscription.

- onNotification is the event handler for a notify message.

- onEnd, is the event handler called when the provider of the notification notifies Signaling Engine that this subscription has ended.

- extHeaders are the extension headers.

Example 11-3 shows the error callback function onSubscribeError called by an application. This function processes the error by calling removeSubscriptionInfoElem(). In this case, the removeSubscriptionInfoElem() function removes the information element for the subscription from the web application page.

Example 11-3 Subscription Creation Error

function onSubscribeError(errorObj) {
console.log("Error code: "+errorObj.code);
removeSubscriptionInfoElem();
};

12 Sample Audio Call Application

This chapter shows the sample audio call application developed using the Oracle Communications WebRTC Session Controller JavaScript application programming interface (API) library.

Note:
See Oracle Communications WebRTC Session Controller JavaScript API Reference for more information on the individual WebRTC Session Controller JavaScript API classes.

About the Sample Audio Call Application

The sample audio call application supports audio calls only.

This application provides the logic necessary to enable two users who are in the same domain to place a call to each other. In this application, two users bob1 and bob2, access our application from the example.com domain.

See "Setting Up Audio Calls in Your Applications" for more information on logic underlying this application logic.

Note:
This sample audio call application does not use extension headers. As a result, the extHeaders parameter is not used in this application code.

The Sample Audio Call Application Code

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Audio Demo</title>

<script type="text/javascript" src="/api/wsc-common.js"></script>
<script type="text/javascript" src="/api/wsc-call.js"></script>

</head>

<body onload="onPageLoad()">
<h2 id="heading">Welcome to SDP InfoDev Demo 1 -- Audio Call</h2>
<hr>

<!-- Button for login. This is a start point of this page.
Method register is invoked when the button is clicked. -->
<div id="controlsArea">

</div>

<br>
<br>
<table hidden="true" id="media">
<tr>
<td>You</td>
<td>Remote</td>
</tr>
<!-- HTML5 audio element. -->
<tr>
<td width="15%"><audio id="selfAudio" autoplay></audio></td>
<td width="15%"><audio id="remoteAudio" autoplay></audio></td>
</tr>
</table>

<script type="text/javascript">

/** This app checks media stream support in Chrome or Firefox 23+  */
// In your application, please use appropriate API to verify media stream support.
var attachMediaStream = null;
if (navigator.mozGetUserMedia) {
console.log("Attaching media stream");
// Attach a media stream to an element.
attachMediaStream = function(element, stream) {
console.log("Application using Mozilla browser");
element.mozSrcObject = stream;
element.play();
};
} else if (navigator.webkitGetUserMedia) {
console.log("Application using Chrome browser");
// Attach a media stream to an element.
attachMediaStream = function(element, stream) {
element.src = webkitURL.createObjectURL(stream);
};
} else {
// The browser does not support media streams
reptBrowserIssue();
}

//*************security login****************
var demoName = " Audio Call Demo ";
var wscSession, callPackage, userName, caller, callee;
wsc.setLogLevel(wsc.LOGLEVEL.DEBUG);

// Save where the user came from.
var savedUrl = window.location;

// This application is deployed on WebRTC Session Controller.
var wsUri = "ws://" + window.location.hostname  + ":" + window.location.port + "/ws/webrtc/sample";

// login and logout URI to redirect the user.
//var loginUri = "http://" + window.location.hostname + ":" + window.location.port + "/infodev/wscdemo.html";
var logoutUri = "http://" + window.location.hostname + ":" + window.location.port + "/infodev/demos/wscdemo.html";

// Configuring the audio and video settings in the CallConfig object.
var audioMediaDirection = wsc.MEDIADIRECTION.SENDRECV;
var videoMediaDirection = wsc.MEDIADIRECTION.NONE;
var callConfig = new wsc.CallConfig(audioMediaDirection, videoMediaDirection);
console.log("Created CallConfig with audio stream only.");
console.log(" ");

// The onPageLoad event handler.
function onPageLoad() {
console.log("Page has loaded. Setting up the Session.");
setSessionUp();
}

// This function sets up and configures the WebSocket connection.
function setSessionUp() {
console.log("In setSessionUp().");

// Create the session. Here, userName is null.
// wsc can determine userName using the cookie of the request.
wscSession = new wsc.Session(null, wsUri, sessionSuccessHandler, sessionErrorHandler);
// Register a wsc.AuthHandler with session.
// It provides customized info of authentication, such as username/password.
var authHandler = new wsc.AuthHandler(wscSession);
authHandler.refresh = refreshAuth;
// Configure the session.
wscSession.setBusyPingInterval(2 *1000);
wscSession.setIdlePingInterval(6 * 1000);
wscSession.setReconnectTime(2 * 1000);
wscSession.onSessionStateChange = sessionStateChangeHandler;

console.log("Session configured with authhandler, intervals and sessionStateChange handler.");
console.log(" ");
}

// The function called when a session is instantiated.
// The next steps are processed here.
function sessionSuccessHandler() {
console.log(" In sessionSuccesshandler.");

// Create a CallPackage.
callPackage = new wsc.CallPackage(wscSession);
// Bind the event handler of incoming call.
if(callPackage){
callPackage.onIncomingCall = onIncomingCall;
}
console.log(" Created CallPackage..");
console.log (" ");
// Get user Id.
userName = wscSession.getUserName();
console.log (" Our user is " + userName);
console.log (" ");
}

// The function called when a session is not instantiated.
function sessionErrorHandler(error) {
console.log("onSessionError: error code=" + error.code + ", reason=" + error.reason);
setControls("<h1>Session Failed, please logout and try again.</h1>");
}

// This is a sample function. It requests the number to call.
// 'onclick'='functionName()' for each button triggers the next step for the code.

function displayInitialControls() {
console.log ("In displayControls().");
var controls = "Enter Your Callee: <input type='text' name='callee' id='callee'/><br><hr>"
+ "<input type='button' name='callButton' id='btnCall'  value='Call' onclick='onCallSomeOne()'/>"
+ "<input type='button' name='cancelButton' id='btnCancel'  value='Cancel' onclick='' disabled ='true'/><br><br><hr>"
+ "<input type='button' name='logoutButton' id='Logout'  value='Logout' onclick='logout()'/>"
+ "<br><br><hr>";
setControls(controls);
var calleeInput = document.getElementById("callee");

if (calleeInput) {
console.log (" Waiting for Callee Input.");
console.log (" ");
if( userName != calleeInput) {
calleeInput.focus();
}

}
}

// This example does not use either TURN or SERVICE authentication.
// This function is provided as a reference for your use.
function refreshAuth(authType, authHeaders) {
var authInfo = null;

if(authType==wsc.AUTHTYPE.SERVICE){
//Return JSON object according to the content of the "authHeaders".
// For the digest authentication implementation, refer to RFC2617.
authInfo = getSipAuth(authHeaders);

} else if(authType==wsc.AUTHTYPE.TURN){

//Return JSON object in this format:
// {"iceServers" : [ {"url":"turn:test@<aHost>:<itsPort>", "credential":"nnnn"} ]}.
authInfo = getTurnAuth();
}
return authInfo;
};

// This function manages the session states.
function sessionStateChangeHandler(sessionState) {
console.log("sessionState : " + sessionState);
switch (sessionState) {
case wsc.SESSIONSTATE.RECONNECTING:
setControls("<h1>Network is unstable, please wait...</h1>");
break;
case wsc.SESSIONSTATE.CONNECTED:
if (wscSession.getAllSubSessions().length == 0) {
displayInitialControls();
}
break;
case wsc.SESSIONSTATE.FAILED:
setControls("<h1>Session Failed, please logout and try again.</h1>");
break;
}
}

// This function is the incoming call callback
// wsc triggers this function when it receives the invite from the remote caller.
function onIncomingCall(callObj, callConfig) {
// We need the user's response. In this example code, we do the following:
// We draw two buttons for users to accept or decline the incoming call.
// Attach onclick event handlers to these two buttons.
console.log ("In onIncomingCall(). Drawing up Control buttons to accept or decline the call.");
var controls = "<input type='button' name='acceptButton' id='btnAccept' value='Accept "
+ callObj.getCaller()
+ " Incoming Audio Call' onclick=''/><input type='button' name='declineButton' id='btnDecline'  value='Decline Incoming Audio Call' onclick=''/>"
+ "<br><br><hr>";
setControls(controls);

document.getElementById("btnAccept").onclick = function() {
// User accepted the call.

//  Store the caller and callee names.
callee = userName;
caller = callObj.getCaller;
console.log (callee + " accepted the call from caller " + caller);
console.log (" ");

// Send the message back.
callObj.accept(callConfig);
}
document.getElementById("btnDecline").onclick = function() {
// User declined the call. Send a message back.

// Get the caller name.
callee = userName;
caller = callObj.getCaller;
console.log (callee + " declined the call from caller, " + caller);
console.log (" ");

// Send the message back.
callObj.decline();
}

// User accepted the call. Bind the event handlers for the call and media stream.
console.log ("Calling setEventHandlers from onIncomingCall() with remote call object ");
setEventHandlers(callObj);
}

// This function binds the call and media state event handlers to the call object.
// It is called by when user is the caller or the callee.
function setEventHandlers(callobj) {
console.log ("In setEventHandlers");
console.log (" ");
callobj.onCallStateChange = function(newState){
callStateChangeHandler(callobj, newState);

};
callobj.onMediaStreamEvent= mediaStreamEventHandler;
}

// This function is an event handler for changes of call state.
function callStateChangeHandler(callObj, callState) {
console.log (" In callStateChangeHandler().");
console.log("callstate : " + JSON.stringify(callState));
if (callState.state == wsc.CALLSTATE.ESTABLISHED) {
console.log (" Call is established. Calling callMonitor. ");
console.log (" ");
callMonitor(callObj);
} else if (callState.state == wsc.CALLSTATE.ENDED) {
console.log (" Call ended. Displaying controls again.");
console.log (" ");
displayInitialControls();
} else if (callState.state == wsc.CALLSTATE.FAILED) {
console.log (" Call failed. Displaying controls again.");
console.log (" ");
displayInitialControls();
}
}

// This event handler is invoked when "Call" button is clicked.
function onCallSomeOne() {
console.log ("In onCallSomeOne()");

// Need the caller callee name. Also storing caller.
callee = document.getElementById("callee").value;
caller = userName;
console.log ("Name entered is " + callee);

// Did the user enter a blank ?
if (callee === "") {
setControls("<h1>Invalid entry. Please enter the number you wish to call.</h1>");
setTimeout(function(){ displayInitialControls();}, 2000)
return;
}

// Same domain case. The caller may not have given the entire name.
if (callee.indexOf("@") < 0) {
console.log (" ");
callee = callee + "@example.com";
console.log("Complete caller ID is " + callee);
}
// Did the user enter his own number?
if (callee == userName) {
setControls("<h1>You cannot call yourself. Please enter the number you wish to call.</h1>");
return;
}

console.log(" Caller, " + caller + ", wants to call " + callee + ", the Callee.");
console.log (" ");

console.log("Creating call object to call  " + callee);

// To call someone, create a Call object first.
var call = callPackage.createCall(callee, callConfig, doCallError);
console.log ("Created the call.");
console.log (" ");

if (call != null) {
console.log ("Calling setEventHandlers from onCallSomeOne() with call data.");
console.log (" ");
setEventHandlers(call);
// Then start the call.
console.log ("In onCallSomeOne(). Starting Call. ");
call.start();
// Allow the user to cancel call before it is set up. End the call.
// Disable "Call" button and enable "Cancel" button.
var btnCall = document.getElementById("btnCall");
btnCall.disabled = true;
var btnCancel = document.getElementById("btnCancel");
btnCancel.disabled = false;
console.log ("Enabled " + caller + " to cancel call.");
btnCancel.onclick = function() {
console.log ("In onCallSomeOne().");
console.log (caller + " clicked the Cancel button. Ending call. ");
console.log (" ");
call.end();
console.log (" If user logs out, the user will be sent back to " + logoutUri);

}
}
}

// This function monitors the call when call is established.
function callMonitor(callObj) {
console.log ("In callMonitor");
console.log ("Monitoring the call. Setting up controls to Hang Up.");
console.log (" ");

// We need the user's response.
//In this example code, we draw 2 buttons.
// "Hang Up" button ends the call, but user stays on the application page.
// "Logout" button ends the session, and user leaves the application.
// Attach onclick event handler to each button.
var controls = "<input type='button' name='hangup' id='btnHangup' value='Hang Up' onclick=' '/><br><br>"
+ "<input type='button' name='logoutButton' id='Logout'  value='Logout' onclick='logout()'/>"
+ "<br><br><hr>";
setControls(controls);
document.getElementById("btnHangup").onclick = function() {
console.log (" In callMonitor.");
// Who ended the call?
if (userName == caller) {
console.log ("Caller, " + caller + ", clicked the Hang Up button. Calling call.end now.");
console.log (" ");
} else {
console.log ("Callee, " + callee + ", clicked the Hang Up button. Calling call.end now.");
console.log (" ");
}
callObj.end();
};

}

// This event handler is invoked when a  media stream event is fired.
// Attach media stream to HTML5 audio element.
function mediaStreamEventHandler(mediaState, stream) {
console.log (" In mediaStreamEventHandler.");
console.log("mediastate : " + mediaState);
console.log (" ");

if (mediaState == wsc.MEDIASTREAMEVENT.LOCAL_STREAM_ADDED) {
attachMediaStream(document.getElementById("selfAudio"), stream);
} else if (mediaState == wsc.MEDIASTREAMEVENT.REMOTE_STREAM_ADDED) {
attachMediaStream(document.getElementById("remoteAudio"), stream);
}
}

// This function displays the controls set by the application.
function setControls(controls) {
var controlsArea = document.getElementById("controlsArea");
controlsArea.innerHTML = controls;
}

// This function is called when the call is not created.
function doCallError(error) {
alert('Call error reason:' + error.reason);
}

// The browser does not support media streams
// Use this function to exit gracefully.
function reptBrowserIssue() {
console.log("In reptBrowserIssue");
console.log("Browser does not appear to be WebRTC-capable");
logout();
}

// This function logs the user out.
// For 3rd party authentication use login uri to send user back to where he came from.
function logout() {
console.log("In logout(). Closing session.");
console.log (" ");
if (wscSession) {
wscSession.close();
}
// Send the user back to where he came from.
console.log (" In logout(). Sending user back to " + logoutUri);
window.location.href = logoutUri;
}
</script>
</body>
</html>

13 Developing WebRTC-enabled Android Applications

This chapter shows how you can use the Oracle Communications WebRTC Session Controller Android application programming interface (API) library to develop WebRTC-enabled Android applications.

About the Android SDK

The WebRTC Session Controller Android SDK enables you to integrate your Android applications with core WebRTC Session Controller functions. You can use the Android SDK to implement the following features:

- Audio calls between an Android application and any other WebRTC-enabled application, a Session Initialization Protocol (SIP) endpoint, or a Public Switched Telephone Network endpoint using a SIP trunk.

- Video calls between an Android application and any other WebRTC-enabled application, with suitable video conferencing support.

- Seamless upgrading of an audio call to a video call and downgrading of a video call to an audio call.

- Support for Interactive connectivity Establishment (ICE) server configuration, including support for Trickle ICE.

- Transparent session reconnection following network connectivity interruption.

The WebRTC Session Controller Android SDK is built upon several additional libraries and modules as shown in Figure 13-1.

Figure 13-1 Android SDK Architecture

The WebRTC Java binding enables Java access to the native WebRTC library which itself provides WebRTC support. The Tyrus websocket client enables the websocket access required to communicate with WebRTC Session Controller. Finally, the SLF4J logging library enables you to plug in a logging framework of your choice to create persistent log files for application monitoring and troubleshooting.

For more details on any of the APIs described in this document, see Oracle Communications WebRTC Session Controller Android API Reference.

About the Android SDK WebRTC Call Workflow

The general workflow for using the WebRTC Session Controller Android SDK is:

1. Authenticate against WebRTC Session Controller using the HttpContext class. You initialize the HttpContext with necessary HTTP headers and optional SSLContext information in the following manner:

1. Send an HTTP GET request to the login URI of WebRTC Session Controller

2. Complete the authentication process based upon your authentication scheme

3. Proceed with the WebSocket handshake on the established authentication context

2. Establish a WebRTC Session Controller session using the WSCSession class. Two additional classes must be implemented:

- ConnectionCallback: An interface that reports on the success or failure of the session creation.

- WSCSession.Observer: An abstract class that signals on various session state changes, including CLOSED, CONNECTED, FAILED, and others.

3. Once a session is established, create a CallPackage which manages Call objects in a WSCSession.

4. Create a Call using the CallPackage createCall method with a callee ID as its argument, for example, alice@example.com.

5. Create a Call.Observer class which attaches to the Call to monitor call events such as ACCEPTED, REJECTED, RECEIVED.

6. Create a new CallConfig object to determine the nature of the WebRTC call, whether bi or mono-directional audio or video or both.

7. Create and configure a new PeerConnectionFactory object and start the Call using the Call object's start method.

8. When the call is complete, terminate the Call object using its end method.

Prerequisites

Before continuing, make sure you thoroughly review and understand the JavaScript API discussed in the following chapters:

- About Using the WebRTC Session Controller JavaScript API

- Setting Up Security

- Setting Up Audio Calls in Your Applications

- Setting Up Video Calls in Your Applications

The WebRTC Session Controller Android SDK is closely aligned in concept and functionality with the JavaScript SDK to ensure a seamless transition.

In addition to an understanding of the WebRTC Session Controller JavaScript API, you are expected to be familiar with:

- Java and object oriented programming concepts

- General Android SDK programming concepts including event handling, and activities

There are many excellent online resources for learning Java programming, and, for a practical introduction to Android programming, see http://developer.android.com/guide/index.html.

Android SDK System Requirements

In order to develop applications with the WebRTC Session Controller SDK, you must meeting the following software/hardware requirements:

- Java Development Kit (JDK) 1.6 or higher installed with all available security patches: http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase6-419409.html

Note:
OpenJDK is not supported.

- The latest version of the Android SDK available from http://developer.android.com/sdk/installing/index.html, running on a supported version of Windows, Mac OS X, or Linux.

- If you are using the Android SDK command line tools, you must have Apache ANT 1.8 or later: http://ant.apache.org/.

- A installed and fully configured WebRTC Session Controller installation. See the WebRTC Session Controller Installation Guide.

- An actual Android hardware device. While you can test the general flow and function of your Android WebRTC Session Controller application using the Android emulator, a physical Android device such as a phone or tablet is required to utilize audio or video functionality.

About the Examples in This Chapter

The examples and descriptions in this chapter are kept intentionally straightforward in order to illustrate the functionality of the WebRTC Session Controller Android SDK API without obscuring it with user interface code and other abstractions and indirections. Since it is likely that use cases for production applications will take many forms, the examples assume no pre-existing interface schemes except when absolutely necessary, and then, only with the barest minimum of code. For example, if a particular method requires arguments such as a user name, a code example will show a plain string username such as "alice@example.com" being passed to the method. It is assumed that in a production application, you would interface with the Android device's contact manager.

General Android SDK Best Practices

When designing and implementing your WebRTC-enabled Android application, keep the following best practices in mind:

- Following Android application development general guidelines, do not invoke any networking operations in the main Application UI thread. Instead, run network operations on a separate background thread, using the supplied Observer mechanisms to handle any necessary responses.

- The Observers themselves run on a separate background thread, and your application should not make any user interface updates on that thread since the Android user interface toolkit is not thread safe. For more information, see https://developer.android.com/training/multiple-threads/communicate-ui.html.

- In any class that extends or uses the android.app.Application class or any initial Activity class, initialize the WebRTC PeerConnectionFactory only once during its lifetime:

PeerConnectionFactory.initializeAndroidGlobals(context, true /* initializeAudio */, true /* initializeVideo */);

- Since the signaling communications takes place over a background thread, initialize and create WebRTC Session Controller sessions using an Android background service to prevent communications disruption. The background service can maintain a reference to the Session object and share that among all of your Android application's activities, fragments and other components. The service can also be run at a higher priority and be used to handle notifications. For more information, see https://developer.android.com/training/best-background.html.

Installing the Android SDK

To install the WebRTC Session Controller Android SDK, do the following:

1. After you have installed your Android development environment, use the Android SDK Manager to download the required SDK tools and platform support: http://developer.android.com/sdk/installing/adding-packages.html.

Note:
Android API level 17 (4.2.2 Jellybean) is the minimum required by the WebRTC Session Controller Android SDK for full functionality. Generally, you should target the lowest API level possible to ensure the broadest application compatibility.

2. Configure virtual and hardware devices as required for your application: http://developer.android.com/tools/devices/index.html and http://developer.android.com/tools/device.html.

3. Create a new Android project using the Android development environment of your choice: http://developer.android.com/tools/projects/index.html.

4. Download and extract the libs folder from the WebRTC Session Controller Android SDK zip file into the libs folder of your Android application. Create the libs folder if it does not already exist.

Note:
Both debug and release versions of the WebRTC peer connection library are included. Choose the correct one for the development state of your project.

5. Depending on your Android development environment, add the path to the libs folder to your Android project as indicated in your Android development environment documentation.

WebRTC Session Controller SDK Required Permissions

The WebRTC Session Controller SDK requires the following Android permissions to function correctly:

- android.permission.INTERNET

- android.permission.ACCESS_NETWORK_STATE

- android.permission.CAMERA

- android.permission.RECORD_AUDIO

Additionally, if your logging subsystem requires access to an external SD card (or a different storage volume) also grant the android.permission.WRITE_EXTERNAL_STORAGE permission.

Configuring Logging

The WebRTC Session Controller Android SDK includes support for the Simple Logging Facade for Java (SLF4J) which lets you plug in your preferred logging framework.

Examples in this chapter use the popular Log4J logging framework which requires the addition of the following libraries to your project, where n indicates a version number:

- slf4j-log4jn-n.n.n.jar

- log4j-n.n.n.jar

- android-logging-log4j-n.n.n.jar

Example 13-1 Configuring Log4J

public class ConfigureLog4J {
public void configureLogging() {
Log.i(MyApp.TAG, "Configuring the Log4J logging framework...");
final LogConfigurator logConfigurator = new LogConfigurator();
logConfigurator.setFileName(Environment.getExternalStorageDirectory()
+ File.separator
+ "sample_android_app.log");
logConfigurator.setRootLevel(Level.DEBUG);
logConfigurator.setFilePattern("%d %-5p [%c{2}]-[%L] %m%n");
logConfigurator.setMaxFileSize(1024 * 1024 * 5);
logConfigurator.setImmediateFlush(true);
logConfigurator.configure();
}
}

Note:
If you want to write log files to any location other than an Android device's internal storage, you must grant the WRITE_EXTERNAL_STORAGE permission.

For more information on configuring and using Log4J, see http://logging.apache.org/log4j/.

Authenticating with WebRTC Session Controller

You use the class HttpContext to set up an authentication context. The authentication context contains the necessary HTTP headers and SSLContext information, and is used when setting up a wsc.Session.

Initialize the CookieManager

You initialize the cookie manager to handle storage of authentication headers and URIs. For more information on the Android CookieManager class, see http://developer.android.com/reference/android/webkit/CookieManager.html.

Example 13-2 Initializing the CookieManager

Log.i(MyApp.TAG, "Initialize the cookie manager...");
CookieManager cookieManager = new CookieManager(null, CookiePolicy.ACCEPT_ALL);
java.net.CookieHandler.setDefault(cookieManager);

Initialize a URL Connection

You then create a new URL object using the URI to your WebRTC Session Controller endpoint and open a urlConnection using the URL object openConnection method.

Example 13-3 Initializing a URL Connection

try {
url = new URL("http://server:port/login?wsc_app_uri=/ws/webrtc/myapp");
} catch (MalformedURLException e1) {
Log.i(MyApp.TAG, "Malformed URL.");
}
try {
urlConnection = (HttpURLConnection) url.openConnection();
} catch (IOException e) {
Log.i(MyApp.TAG, "IO Exception.");
}

Note:
The default WebRTC Session Controller port is 7001.

Configure Authorization Headers if Required

You then configure authorization headers as required by your authentication scheme. The following example uses Basic authentication; OAuth and other authentication schemes will be similarly configured. For more information on WebRTC Session Controller authentication, see "Setting Up Security."

Example 13-4 Initializing Basic Authentication Headers

String name = "username";
String password = "password";
String authString = "Basic " + name + ":" + password;
byte[] authEncBytes = Base64.encode(authString.getBytes(), 0);
String authHeader = new String(authEncBytes);
urlConnection.setRequestProperty(HttpContext.AUTHORIZATION_HEADER, authHeader);

Note:
If you are using Guest authentication, no headers are required.

Configure the SSL Context if Required

If you are using Secure Sockets Layer (SSL), configure the SSL context, including the TrustManager if required. Example 13-6 expects as URL object and passes that object to a custom getNullHostVerifier method, whose job is to validate that the URL is actually live.

Example 13-5 Configuring the SSL Context

if (HTTPS.equals(url.getProtocol())) {
Log.i(MyApp.TAG, "Configuring SSL context...");
HttpsURLConnection.setDefaultHostnameVerifier(getNullHostVerifier());
SSLContext ctx = null;
try {
ctx = SSLContext.getInstance("TLS");
} catch (NoSuchAlgorithmException e) {
Log.i(MyApp.TAG, "No Such Algorithm.");
}
try {
ctx.init(null, getTrustAllManager(), new SecureRandom());
} catch (KeyManagementException e) {
Log.i(MyApp.TAG, "Key Management Exception.");
}
final SSLSocketFactory sslFactory = ctx.getSocketFactory();
HttpsURLConnection.setDefaultSSLSocketFactory(sslFactory);
}

Example 13-6 is a stub method in which you can implement a routine to test the validity of the input URL object, and handle program flow based upon HTTP return codes.

Example 13-6 Host Name Verification

private HostnameVerifier getNullHostVerifier() {
return new HostnameVerifier() {
@Override
public boolean verify(final String hostname, final SSLSession session) {
Log.i(MyApp.TAG, "Stub verification for " + hostname +
" for session: " + session);
return true;
}
};
}

Finally, if your implementation depends upon a Java Secure Socket Extension implementation, configure the Android TrustManager class as required. For more information on the Android TrustManager class, see http://developer.android.com/reference/android/webkit/CookieManager.html.

Example 13-7 Configuring the TrustManager

public static TrustManager[] getTrustAllManager() {
return new X509TrustManager[] { new X509TrustManager() {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}

@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}

@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
} };
}

Build the HTTP Context

Next you build the HTTP context, retrieving the authorization headers using the CookieManager class you instantiated in "Initialize the CookieManager."

Example 13-8 Building the HTTP Context

Log.i(MyApp.TAG, "Building the HTTP context...");
Map<String, List<String>> headers = new HashMap<String, List<String>>();

HttpContext httpContext = null;

try {
httpContext = HttpContext.Builder.create()
.withHeaders(cookieManager.get(url.toURI(), headers))
.build();
} catch (IOException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}

Connect to the URL

With your authentication parameters configured, you can now connect to the WebRTC Session Controller URL using the UrlConnection object's connect method.

Example 13-9 Connecting to the WebRTC Session Controller URL

try {
urlConnection.connect();
} catch (IOException e) {
e.printStackTrace();
}

Configuring Interactive Connectivity Establishment (ICE)

If you have access to one or more STUN/TURN ICE servers, you can implement the IceServerConfig interface. For details on ICE, see "Managing Interactive Connectivity Establishment Interval."

Example 13-10 Configuring the ICE Server Config Class

class MyIceServerConfig implements IceServerConfig {
public Set<IceServer> getIceServers() {
Log.i(MyApp.TAG, "Setting up ICE servers...");
Set<IceServer> iceServers = new HashSet<IceServer>();
iceServers.add(new IceServerConfig.IceServer(
"stun:stun-relay.example.net:3478", "admin", "password"));
iceServers.add(new IceServerConfig.IceServer(
"turn:turn-relay.example.net:3478", "admin", "password"));
return iceServers;
}
}

Creating a WebRTC Session Controller Session

Once you have configured your authentication method and connected to your WebRTC Session Controller endpoint, you can instantiate a WebRTC Session Controller session object. Before instantiating a session object you configure the following elements:

- To handle the results of a session creation request, you "Implement the ConnectionCallback Interface."

- To monitor and respond to changes in session state, you "Create a Session Observer Object."

- To configure specific session object behaviors and performance parameters, you "Configure Session Properties."

Implement the ConnectionCallback Interface

You must implement the ConnectionCallback interface to handle the results of your session creation request. The ConnectionCallback interface has two event handlers:

- onSuccess: Triggered upon a successful session creation.

- onFailure: Returns a an enum of type StatusCode. Triggered when session creation fails. For a listing of status code, see Oracle Communications WebRTC Session Controller Android API Reference.

Example 13-11 Implementing the ConnectionCallback Interface

public class MyConnectionCallback implements ConnectionCallback {
@Override
public void onFailure(StatusCode arg0) {
Log.i(MyApp.TAG, "Handle a connection failure...");
}

@Override
public void onSuccess() {
Log.i(MyApp.TAG, "Handle a connection success...");
}
}

Create a Session Observer Object

You must create a session Observer object to monitor and respond to changes in session state.

Example 13-12 Instantiating a Session Observer

public class MySessionObserver extends Observer {
@Override
public void stateChanged(final SessionState state) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Log.i(MyApp.TAG, "Session state changed to " + state);
switch (state) {
case CONNECTED:
break;
case RECONNECTING:
break;
case FAILED:
Log.i(MyApp.TAG,
"Send events to various active activities as required...");
shutdownCall();
break;
case CLOSED:
default:
break;
}
}
});
}
}

Build the Session Object

With the ConnectionCallback and Session Observer configured, you now build a WebRTC Session Controller session using the session Builder method.

Example 13-13 Building the Session Object

Log.i(MyApp.TAG, "Creating a WebRTC Session Controller session...");
WSCSession.Builder builder = null;
try {
builder = WSCSession.Builder.create(new java.net.URI(webSocketURL))
.withUserName(userName)
.withPackage(new CallPackage())
.withHttpContext(httpContext)
.withConnectionCallback(new MyConnectionCallback())
.withIceServerConfig(new MyIceServerConfig())
.withObserver(new MySessionObserver());
} catch (URISyntaxException e) {
e.printStackTrace();
}

WSCSession session = builder.build();

In Example 13-13, note that the withPackage method registers a new CallPackage with the session that will be instantiated when creating voice or video calls. Also registered are the ConnectionCallback, IceServerConfig, and SessionObserver objects created earler.

Configure Session Properties

You can configure additional properties when creating a session using the withProperty method.

For a complete list of properties and their descriptions, see the Oracle Communications WebRTC Session Controller Android SDK API Reference.

Example 13-14 Configuring Session Properties

WSCSession.Builder builder = WSCSession.Builder.create(...)
.withUserName(userName)
...
.withProperty(WSCSession.PROP_RECONNECT_INTERVAL, 5000)
.withProperty(WSCSession.PROP_IDLE_PING_INTERVAL, 15000));
WSCSession session = sessionbuilder.build();

Adding WebRTC Voice Support to your Android Application

This section describes adding WebRTC voice support to your Android application.

Initialize the CallPackage Object

When you created your Session, you registered a new CallPackage object using the Session object's withPackage method. You now instantiate that CallPackage.

Example 13-15 Initializing the CallPackage

String callType = CallPackage.PACKAGE_TYPE;
CallPackage callPackage = (CallPackage) session.getPackage(callType);

Note:
Use the default PACKAGE_TYPE call type unless you have defined a custom call type.

Place a WebRTC Voice Call from Your Android Application

Once you have configured your authentication scheme, created a Session, and initialized a CallPackage, you can place voice calls from your Android application.

Initialize the Call Object

With the CallPackage object created, initialize a Call object, passing the callee's ID as an argument.

Note:
In a production application you may wish to integrate with the Android contacts provider or another enterprise directory system, rather than passing a bare string to the createCall method. For more information on integrating with the Android contacts provider, see http://developer.android.com/guide/topics/providers/contacts-provider.html.

Example 13-16 Initializing the Call Object

String calleeId = "bob@example.com";
call = callPackage.createCall(calleeId);

Configure Trickle ICE

To improve ICE candidate gathering performance, you can choose to enable Trickle ICE in your application using the Call object's setTrickleIceMode method. For more information see "Enabling Trickle ICE to Improve Application Performance."

Example 13-17 Configuring Trickle ICE

Log.i(MyApp.TAG, "Configure Trickle ICE options, OFF, HALF, or FULL...");
call.setTrickleIceMode(Call.TrickleIceMode.FULL);

Create a Call Observer Object

You next create a CallObserver object so you can respond to Call events. Example 13-18 provides a skeleton with the appropriate call update, media, and call states, which you can use to handle updates to, and input from, your application accordingly.

Example 13-18 Creating a CallObserver Object

Create a Call Observer Object
You next create a CallObserver object so you can respond to Call events. Example 12–18 provides a skeleton with the appropriate call update, media, and call states, which you can use to handle updates to, and input from, your application accordingly.
Creating a CallObserver Object
public class MyCallObserver extends oracle.wsc.android.call.Call.Observer {
@Override
public void callUpdated(final CallUpdateEvent state, final CallConfig callConfig, Cause cause) {
Log.i(MyApp.TAG, "Call updated: " + state);
runOnUiThread(new Runnable() {

@Override
public void run() {
switch (state) {
case SENT:
break;
case RECEIVED:
break;
case ACCEPTED:
break;
case REJECTED:
break;
default:
break;
}
}
});
}

@Override
public void mediaStateChanged(MediaStreamEvent mediaStreamEvent, MediaStream mediaStream) {
Log.i(MyApp.TAG, "Media State " + mediaStreamEvent
+ " for media stream " + mediaStream.label());
}

@Override
public void stateChanged(final CallState state, Cause cause) {
runOnUiThread(new Runnable() {
@Override
public void run() {
switch (state) {
case ESTABLISHED:
Log.i(MyApp.TAG, "Update the UI to indicate that the call has been accepted...");
break;
case ENDED:
Log.i(MyApp.TAG, "Update the UI and possibly close the activity...");
break;
case REJECTED:
break;
case FAILED:
break;
default:
break;
}
}
});
}
}

Register the CallObserver with the Call Object

Once you've implemented the CallObserver, register it with the Call object.

Example 13-19 Registering a Call Observer

call.setObserver(new MyCallObserver());

Create a CallConfig Object

You create a CallConfig object to determine the type of call you wish to make. The CallConfig constructor takes two parameters, both named MediaDirection. The first parameter configures an audio call while the second configures a video call:

CallConfig(MediaDirection audioMediaDirection, MediaDirection videoMediaDirection)

The values for each MediaDirection parameter are:

- NONE: No direction; media support disabled.

- RECV_ONLY: The media stream is receive only.

- SEND_ONLY: The media stream is send only.

- SEND_RECV: The media stream is bi-directional.

Example 13-20 shows the configuration for a bi-directional, audio-only call.

Example 13-20 Creating an Audio CallConfig Object

CallConfig callConfig = new CallConfig(MediaDirection.SEND_RECV,
MediaDirection.NONE);

Configure the Local MediaStream for Audio

With the CallConfig object created, you then configure the local audio MediaStream using the WebRTC PeerConnectionFactory. For information on the WebRTC SDK API, see http://www.webrtc.org/reference/native-apis.

Example 13-21 Configuring the Local MediaStream for Audio

Log.i(MyApp.TAG, "Get the local media streams...");
PeerConnectionFactory pcf = call.getPeerConnectionFactory();
mediaStream = pcf.createLocalMediaStream("ARDAMS");
AudioSource audioSource = pcf.createAudioSource(new MediaConstraints());
mediaStream.addTrack(pcf.createAudioTrack("ARDAMSa0", audioSource));

Start the Audio Call

Finally, you start the audio call using the Call object's start method and passing it the CallConfig object and the MediaStream object.

Example 13-22 Starting the Audio Call

Log.i(MyApp.TAG, "Start the audio call...");
call.start(callConfig, mediaStream);

Terminating the Audio Call

To terminate the audio call, use the Call object's end method:

call.end()

Note:
You may want to explicitly set the MediaStream object to null as well to reclaim any resources it is using.

Receiving a WebRTC Voice Call in Your Android Application

This section configuring your Android application to receive WebRTC voice calls.

Create a CallPackage Observer

To be notified of an incoming call, create a CallPackageObserver and attach it to your CallPackage. The CallPackageObserver lets you intercept and respond to changes in the CallPackage object's state.

Example 13-23 A CallPackage Observer

public class MyCallPackageObserver extends oracle.wsc.android.call.CallPackage.Observer {
@Override
public void callArrived(Call call, CallConfig callConfig, Map<String, ?> extHeaders) {

Log.i(MyApp.TAG, "Registering a call observer...");
call.setObserver(new MyCallObserver());

Log.i(MyApp.TAG, "Getting the local media stream...");
PeerConnectionFactory pcf = call.getPeerConnectionFactory();
MediaStream mediaStream = pcf.createLocalMediaStream("ARDAMS");
AudioSource audioSource = pcf.createAudioSource(new MediaConstraints());
mediaStream.addTrack(pcf.createAudioTrack("ARDAMSa0", audioSource));

Log.i(MyApp.TAG, "Accept or reject the call...");
if (answerTheCall) {
Log.i(MyApp.TAG, "Answering the call...");
call.accept(callConfig, mediaStream);
} else {
Log.i(MyApp.TAG, "Declining the call...");
call.decline(StatusCode.DECLINED.getCode());
}
}
}

In Example 13-23, the callArrived event handler processes an incoming call request:

1. The method registers a CallObserver for the incoming call. In this case, it uses the same CallObserver, myCallObserver, from the example in "Create a Call Observer Object."

2. The method then configures the local media stream, in the same manner as the example in "Configure the Local MediaStream for Audio."

3. The method determines whether to accept or reject the call based upon the value of the answerTheCall boolean using either Call object's accept or decline methods.

Note:
The answerTheCall boolean will most likely be set by a user interface element in your application such as a button or link.

Bind the CallPackage Observer to the CallPackage

With the CallPackageObserver object created, you bind it to your CallPackage object:

callPackage.setObserver(new MyCallPackageObserver());

Adding WebRTC Video Support to your Android Application

This section describes how you can add WebRTC video support to your Android application. While the methods are almost completely identical to adding voice call support to an Android application, additional preparation is required.

Find and Return the Video Capture Device

Before your application tries to initialize a video calling session, it should verify that the Android device it is running on actually has a video capture device available. Find the video capture device and return a VideoCapturer object. For more information on handling an Android device's camera, see http://developer.android.com/guide/topics/media/camera.html.

Example 13-24 Finding a Video Capture Device

private VideoCapturer getVideoCapturer() {
Log.i(MyApp.TAG,
"Cycle through likely device names for a camera and return the first "
+ "available capture device. Throw an exception if none exists.");

final String[] cameraFacing = { "front", "back" };
final int[] cameraIndex = { 0, 1 };
final int[] cameraOrientation = { 0, 90, 180, 270 };

for (final String facing : cameraFacing) {
for (final int index : cameraIndex) {
for (final int orientation : cameraOrientation) {
final String name = "Camera " + index + ", Facing "
+ facing + ", Orientation " + orientation;
final VideoCapturer capturer = VideoCapturer.create(name);
if (capturer != null) {
Log.i(MyApp.TAG, "Using camera: " + name);
return capturer;
}
}
}
}
throw new RuntimeException("Failed to open a capture device.");
}

Note:
Example 13-24 is not a robust algorithm for video capturer detection is not recommended for production use.

Create a GLSurfaceView in Your User Interface Layout

Your application must provide a container to display a local or remote video feed. To do that, you add an OpenGL SurfaceView container to your user interface layout. In Example 13-25 a GLSurfaceView container is created with the ID, video_view. For more information on GLSurfaceView containers, see http://developer.android.com/reference/android/opengl/GLSurfaceView.html.

Note:
You, of course, customize the GLSurfaceView container for the requirements of your specific application.

Example 13-25 A Layout Containing a GLSurfaceView Element

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MyActivity"
android:orientation="vertical" >

<android.opengl.GLSurfaceView
android:id="@+id/video_view"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>

Initialize the GLSurfaceView Control

Next, you initialize the GLSurfaceView container by finding its ID in your Android application's resource list, video_view, and creating a VideoRenderer object using the control ID as an argument.

Example 13-26 Initializing the GLSurfaceView Control

Log.i(MyApp.TAG,"Initialize the video view control in your main layout...");
mVideoView = (GLSurfaceView) findViewById(R.id.video_view);
myVideoRenderer = new VideoRendererGUI(mVideoView);
localRender = myVideoRenderer.create(70, 70, 25, 25);

Note:
The VideoRendererGUI class is freely available. Use Google Code search to find the latest version.

Placing a WebRTC Video Call from Your Android Application

To place a video call from your Android application, complete the coding tasks contained in the following sections:

- Authenticating with WebRTC Session Controller

- Configuring Interactive Connectivity Establishment (ICE) (if required)

- Creating a WebRTC Session Controller Session

In addition, complete the coding tasks for an audio call contained in the following sections:

- Initialize the Call Object

- Configure Trickle ICE (if required)

- Create a Call Observer Object

- Register the CallObserver with the Call Object

Note:
Audio and video call work flows are identical with the exception of media directions, local media stream configuration, and the additional considerations described earlier in this section.

Create a CallConfig Object

You create a CallConfig object as described in "Create a CallConfig Object," in the audio call section, setting both arguments to MediaDirection.SEND_RECV.

Example 13-27 Creating an Audio/Video CallConfig Object

CallConfig callConfig = new CallConfig(MediaDirection.SEND_RECV,
MediaDirection.SEND_RECV);

Configure the Local MediaStream for Audio and Video

With the CallConfig object created, you then configure the local video and audio MediaStream objects using the WebRTC PeerConnectionFactory. For information on the WebRTC SDK API, see http://www.webrtc.org/reference/native-apis.

Example 13-28 Configuring the Local MediaStream for Video

Log.i(MyApp.TAG, "Get the local media streams...");
PeerConnectionFactory pcf = call.getPeerConnectionFactory();
mediaStream = pcf.createLocalMediaStream("ARDAMS");

Log.i(MyApp.TAG, "Attach the audio source...");
AudioSource audioSource = pcf.createAudioSource(new MediaConstraints());
mediaStream.addTrack(pcf.createAudioTrack("ARDAMSa0", audioSource));

Log.i(MyApp.TAG, "Attach the video source...");
videoCapturer = getVideoCapturer();
videoSource = pcf.createVideoSource(videoCapturer, new MediaConstraints());
final VideoTrack videoTrack = pcf.createVideoTrack("ARDAMSv0", videoSource);

videoTrack.addRenderer(new VideoRenderer(localRender));
mediaStream.addTrack(videoTrack);

In Example 13-28, of note is that the WebRTC SDK PeerConnectionFactory adds both an audio and a video stream to the MediaStream object. For the VideoStream object, a videoCapturer object is returned from the getVideoCapturer method described in Example 13-24. In addition, the VideoTrack object is bound to the localRender object created in Example 13-26.

Start the Video Call

Finally, start the audio/video call using the Call object's start method and passing it the CallConfig object and the MediaStream object.

Example 13-29 Starting the Video Call

Log.i(MyApp.TAG, "Start the video call...");
call.start(callConfig, mediaStream);

Terminate the Video Call

To terminate the video call, reinitialize the appropriate objects to reclaim their resources, and use the Call object's end method as with an audio only call.

Example 13-30 Terminating the Video Call

Log.i(MyApp.TAG, "Shutting down the call...");
if (videoCapturer != null) {
videoCapturer.dispose();
videoCapturer = null;
videoSource.dispose();
videoSource = null;
}

call.end();
mVideoView = null;
localRender = null;
mediaStream = null;

Receiving a WebRTC Video Call in Your Android Application

Receiving a video call is identical to receiving an audio call as decribed here, "Receiving a WebRTC Voice Call in Your Android Application." The only difference is the configuration of the MediaStream object, as described in "Configure the Local MediaStream for Audio and Video."

Upgrading and Downgrading Calls

This section describes how you can handle upgrading an audio call to an audio video call and downgrading a video call to an audio-only call in your Android application.

Handle Upgrade and Downgrade Requests from Your Application

To upgrade from a voice call to a video call, you can bind a user interface element such as a button or link to a class containing the Call update logic using the interface object's setOnClickListener method:

myButton.setOnClickListener(new CallUpdateHandler());

You handle the upgrade or downgrade workflow in the onClick event handler of the CallUpdateHandler class. In Example 13-31 the myButton object simply serves to toggle video support on and off for the current call object. Once the CallConfig object is reconfigured, the actual state change for the call is initiated using the Call object's update method.

Example 13-31 Handling Upgrade Downgrade Requests from Your Application

class CallUpdateHandler implements View.OnClickListener {
@Override
public void onClick(final View v) {
// Toggle between video on/off
MediaDirection videoDirection;
if (call.getCallConfig().shouldSendVideo()) {
videoDirection = MediaDirection.NONE;
} else {
videoDirection = MediaDirection.SEND_RECV;
}

Log.i(MyApp.TAG, "Toggle Video");
CallConfig callConfig = new CallConfig(MediaDirection.SEND_RECV,
videoDirection);
MediaStream mediaStream = getLocalMediaStreams(call
.getPeerConnectionFactory());
try {
call.update(callConfig, mediaStream);
} catch (IllegalStateException e) {
Log.e(MyApp.TAG, "Invalid state", e);
}
}
}

Handle Incoming Upgrade Requests

You configure the callUpdated method of your CallObserver class to handle incoming upgrade requests in the case of a RECEIVED state change. See Example 13-18 for the complete CallObserver framework. In Example 13-32, a simple Yes/No dialog is presented when an upgrade request is received. Clicking the Yes button accepts the upgrade request, while clicking no declines it.

Example 13-32 Handling an Incoming Upgrade Request

case RECEIVED:
String mediaConfig = "Video - " + callConfig.getVideoConfig().name();
new AlertDialog.Builder(CallProgressActivity.this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle("Incoming Call Update")
.setMessage("Do you want you accept this update: " + mediaConfig + " ?")
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(
DialogInterface dialog, int which) {
MediaStream mediaStream = getLocalMediaStreams(call.getPeerConnectionFactory());
call.accept(callConfig, mediaStream);
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
call.decline(StatusCode.DECLINED.getCode());
}
}).show();
break;

14 Developing WebRTC-enabled iOS Applications

This chapter shows how you can use the Oracle Communications WebRTC Session Controller iOS application programming interface (API) library to develop WebRTC-enabled iOS applications.

About the iOS SDK

The WebRTC Session Controller iOS SDK enables you to integrate your iOS applications with core WebRTC Session Controller functions. You can use the iOS SDK to implement the following features:

- Audio calls between an iOS application and any other WebRTC-enabled application, a Session Initialization Protocol (SIP) endpoint, or a Public Switched Telephone Network endpoint using a SIP trunk.

- Video calls between an iOS application and any other WebRTC-enabled application, with suitable video conferencing support.

- Seamless upgrading of an audio call to a video call and downgrading of a video call to an audio call.

- Support for Interactive connectivity Establishment (ICE) server configuration, including support for Trickle ICE.

- Transparent session reconnection following network connectivity interruption.

The WebRTC Session Controller iOS SDK is built upon several additional libraries and modules as shown in Figure 14-1.

Figure 14-1 iOS SDK Architecture

The WebRTC iOS binding enables the WebRTC Session Controller iOS SDK access to the native WebRTC library which itself provides WebRTC support. The Socket Rocket WebSocket library enables the WebSocket access required to communicate with WebRTC Session Controller.

For additional information on any of the APIs used in this document, see Oracle WebRTC Session Controller iOS API Reference.

Supported Architectures

The WebRTC Session Controller iOS SDK supports the following architectures:

- armv7

- armv7s

- arm64

- i386

About the iOS SDK WebRTC Call Workflow

The general workflow for using the WebRTC Session Controller iOS SDK to place a call is:

1. Authenticate against WebRTC Session Controller using the WSCHttpContext class. You initialize the WSCHttpContext with necessary HTTP headers and optional SSLContextRef in the following manner:

1. Send an HTTP GET request to the login URI of WebRTC Session Controller

2. Complete the authentication process based upon your authentication scheme

3. Proceed with the WebSocket handshake on the established authentication context

2. Establish a WebRTC Session Controller session using the WSCSession class.
Two protocols must be implemented:

- WSCSessionConnectionDelegate: A delegate that reports on the success or failure of the session creation.

- WSCSessionObserverDelegate: A delegate that signals on various session state changes, including CLOSED, CONNECTED, FAILED, and others.

3. Once a session is established, create a WSCCallPackage class which manages WSCCall objects in the WSCSession.

4. Create a WSCCall using the WSCCallPackage createCall method with a callee ID as its argument, for example, alice@example.com.

5. Implement a WSCCallObserver protocol which attaches to the Call to monitor call events such as ACCEPTED, REJECTED, RECEIVED.

6. Create a new WSCCallConfig class to determine the nature of the WebRTC call, whether bi or mono-directional audio or video or both.

7. Create and configure a new RTCPeerConnectionFactory object and start the WSCCall using the start method.

8. When the call is complete, terminate the call using the WSCCall object's end method.

Prerequisites

Before continuing, make sure you thoroughly review and understand the JavaScript API discussed in the following chapters:

- About Using the WebRTC Session Controller JavaScript API

- Setting Up Security

- Setting Up Audio Calls in Your Applications

- Setting Up Video Calls in Your Applications

The WebRTC Session Controller iOS SDK is closely aligned in concept and functionality with the JavaScript SDK to ensure a seamless transition.

In addition to an understanding of the WebRTC Session Controller JavaScript API, you are expected to be familiar with:

- Objective C and general object oriented programming concepts

- General iOS SDK programming concepts including event handling, delegates, and views.

- The functionality and use of XCode.

For an introduction to programming iOS apps using XCode, see . For additional background on all areas of iOS app development, see: https://developer.apple.com/library/ios/referencelibrary/GettingStarted/RoadMapiOS/WhereToGoFromHere.html#/apple_ref/doc/uid/TP40011343-CH12-SW1.

iOS SDK System Requirements

In order to develop applications with the WebRTC Session Controller SDK, you must meeting the following software/hardware requirements:

- A installed and fully configured WebRTC Session Controller installation. See the Oracle Communications WebRTC Session Controller Installation Guide.

- A Macintosh computer capable of running XCode version 5.1 or later.

- An actual iOS hardware device.
While you can test the general flow and function of your iOS WebRTC Session Controller application using the iOS simulator, a physical iOS device such as an iPhone or an iPad is required to fully utilize audio and video functionality.

About the Examples in This Chapter

The examples and descriptions in this chapter are kept intentionally straightforward in order to illustrate the functionality of the WebRTC Session Controller iOS SDK API without obscuring it with user interface code and other abstractions and indirections. Since it is likely that use cases for production applications will take many forms, the examples assume no pre-existing interface schemas except when absolutely necessary, and then, only with the barest minimum of code. For example, if a particular method requires arguments such as a user name, a code example will show a plain string username such as "bob@example.com" being passed to the method. It is assumed that in a production application, you would interface with the iOS device's contact manager.

Installing the iOS SDK

To install the WebRTC Session Controller iOS SDK, do the following:

1. Install XCode from the Apple App store: https://developer.apple.com/library/ios/referencelibrary/GettingStarted/RoadMapiOS/index.html#/apple_ref/doc/uid/TP40011343-CH2-SW1.

Note:
The WebRTC Session Controller iOS SDK requires XCode version 5.1 or higher.

2. Create a new iOS project using xCode, adding any required targets: https://developer.apple.com/library/ios/referencelibrary/GettingStarted/RoadMapiOS/FirstTutorial.html#/apple_ref/doc/uid/TP40011343-CH3-SW1.

Note:
iOS version 6 is the minimum required by the WebRTC Session Controller iOS SDK for full functionality.

3. Download and extract the WebRTC Session Controller iOS SDK zip file. There are two subfolders, in the archive, include and lib.

- Within the include folder are two folders, wsc and webrtc containing, respectively, the header files for the WebRTC Session Controller iOS SDK, and the WebRTC SDK.

- Within the lib folder, are two folders, debug and release, each of which contain wsc and webrtc folders with WebRTC Session Controller iOS SDK, and the WebRTC SDK libraries for either debug or release builds depending upon your state of development.

4. Import the WebRTC Session Controller iOS SDK .a lib files:

1. Select your application target in XCode project navigator.

2. Click Build Settings in top of the editor pane.

3. Expand Link Binary With Libraries.

4. Drag the .a lib files from the lib folders of webrtc and wsc_sdk into the expanded panel.

Note:
The webrtc folder contains two sets of lib files, one for iOS devices in the ios folder and one for the iOS simulator in the sim folder. Make sure you choose the correct lib files for your target.
In addition, make sure you include either debug or release libraries as appropriate for your development target.

5. Import any other system frameworks you require. The following additional frameworks are recommended:

- CFNetwork.framework: zero-configuration networking services. For more information, see https://developer.apple.com/library/ios/documentation/CFNetwork/Reference/CFNetwork_Framework/index.html.

- Security.framework: General interfaces for protecting and controlling security access. For more information see: https://developer.apple.com/library/ios/documentation/Security/Reference/SecurityFrameworkReference/index.html.

- CoreMedia.framework: Interfaces for playing audio and video assets in an iOS application. For more information see: https://developer.apple.com/library/mac/documentation/CoreMedia/Reference/CoreMediaFramework/index.html.

- GLKit.framework: Library that facilitates and simplifies creating shader-based iOS applications (useful for video rendering). For more information see: https://developer.apple.com/library/ios/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/DrawingWithOpenGLES/DrawingWithOpenGLES.html.

- AVFoundation.framework: A framework that facilities managing and playing audio and video assets in iOS applications. For more information see: https://developer.apple.com/library/ios/documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/00_Introduction.html#/apple_ref/doc/uid/TP40010188.

- AudioToolbox.framework: A framework containing interfaces for audio playback, recording and media stream parsing. For more information see: https://developer.apple.com/library/ios/documentation/MusicAudio/Reference/CAAudioTooboxRef/index.html#/apple_ref/doc/uid/TP40002089.

- libicucore.dylib: A unicode support library. For more information see: http://icu-project.org/apiref/icu4c40/.

- libsqlite3.dylib: A framework providing a SQLite interface. For more information, see: https://developer.apple.com/technologies/ios/data-management.html.

6. Import the header files from include/webrtc and include/wsc by dragging the wsc and webrtc folders directly onto your project in the XCode project navigator.

7. Click Build Settings in the top of the editor toolbar.

8. Expand Linking and set -ObjC as Other Linker Flags for both Debug and Release. For more information on setting XCode build settings, see: https://developer.apple.com/library/ios/recipes/xcode_help-project_editor/Articles/EditingBuildSettings.html.

9. If you are targeting iOS version 8 or above, add the libstdc++.6.dylib.a framework to prevent linking errors.

Authenticating with WebRTC Session Controller

You use the WSCHttpContext class to set up an authentication context. The authentication context contains the necessary HTTP headers and SSLContext information, and is used when setting up a wsc.Session.

Initialize a URL Object

You then create a new NSURL object using the URL to your WebRTC Session Controller endpoint.

Example 14-1 Initializing a URL Object

NSString *urlString=*"http://server:port/login?wsc_app_uri=/ws/webrtc/myapp";
NSURL authUrl=[NSURL URLWithString:urlString];

Configure Authorization Headers if Required

Configure authorization headers as required by your authentication scheme. The following example uses Basic authentication; OAuth and other authentication schemes will be similarly configured.

Example 14-2 Initializing Basic Authentication Headers

NSString *authType = @"Basic ";
NSString *username = @"username";
NSString *password = @"password";
NSString * authString = [authType stringByAppendingString:[username
stringByAppendingString:[@":"
stringByAppendingString:[password]]];

Note:
If you are using Guest authentication, no headers are required.

Connect to the URL

With your authentication parameters configured, you can now connect to the WebRTC Session Controller URL using sendSynchronousRequest. or NSURlRequest, and NSURlConnection, in which case the error and response are returned in delegate methods.

Example 14-3 Connecting to the WebRTC Session Controller URL

NSHTTPURLResponse * response;NSError * error;authUrlNSMutableURLRequest *loginRequest = [NSMutableURLRequest requestWithURL:];
[loginRequest setValue:authString forHTTPHeaderField:@"Authorization"];
[NSURLConnection sendSynchronousRequest:loginRequest returningResponse:&response error:&error];

Configure the SSL Context if Required

If you are using Secure Sockets Layer (SSL), configure the SSL context, using the SSLCreateContext method, depending upon whether the URL connection was successful. For more information on SSLCreateContext, see https://developer.apple.com/library/mac/documentation/Security/Reference/secureTransportRef/index.html#/apple_ref/c/func/SSLCreateContext.

Example 14-4 Configuring the SSLContext

if (error) {
// Handle an error..
NSLog("The following error occurred: %@", error.description);
} else {

// Configure the SSLContext if required...
SSLContextRef sslContext = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
// Copy the SSLContext configuration to the httpContext builder...
[builder withSSLContextRef:&sslContext];

...
}

Retrieve the Response Headers from the Request

Depending upon the results of the authentication request, you retrieve the response headers from the URL request and copy the cookies to the httpContext builder.

Example 14-5 Retrieving the Response Headers from the URL Request

if (error) {
// Handle an error..
NSLog("The following error occurred: %@", error.description);
} else {

// Configure the SSLContext if required, from Example 14-4...
SSLContextRef sslContext = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
// Copy the SSLContext configuration to the httpContext builder...
[builder withSSLContextRef:&sslContext];

// Retrieve all the response headers...
NSDictionary *respHeaders = [response allHeaderFields];
WSCHttpContextBuilder *builder = [WSCHttpContextBuilder create];
// Copy all cookies from respHeaders to the httpContext builder...
[builder withHeader:key value:headerValue];

...
}

Build the HTTP Context

Depending upon the results of the authentication request, you then build the WSCHttpContext using WSCHttpContextBuilder.

Example 14-6 Building the HttpContext

if (error) {
// Handle an error..
NSLog("The following error occurred: %@", error.description);
} else {

// Configure the SSLContext if required, from Example 14-4...
SSLContextRef sslContext = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
// Copy the SSLContext configuration to the httpContext builder...
[builder withSSLContextRef:&sslContext];

// Retrieve all the response headers from Example 14-5...

// Build the httpContext...
WSCHttpContext *httpContext = [builder build];

...
}

Configure Interactive Connectivity Establishment (ICE)

If you have access to one or more STUN/TURN ICE servers, you can initialize the WSCIceServer class. For details on ICE, see "Managing Interactive Connectivity Establishment Interval."

Example 14-7 Configuring the WSCIceServer Class

WSCIceServer *iceServer1 = [[WSCIceServer alloc] initWithUrl:@"stun:stun-server:port"];
WSCIceServer *iceServer2 = [[WSCIceServer alloc] initWithUrl:@"turn:turn-server:port",
@"admin", @"password"];
WSCIceServerConfig *iceServerConfig = [[WSCIceServerConfig alloc]
initWithIceServers: iceServer1, iceServer2, NIL];

Creating a WebRTC Session Controller Session

Once you have configured your authentication method and connected to your WebRTC Session Controller endpoint, you can instantiate a WebRTC Session Controller session object.

Implement the WSCSessionConnectionDelegate Protocol

You must implement the WSCSessionConnectionDelegate protocol to handle the results of your session creation request. The WSCSessionConnectionDelegate protocol has two event handlers:

- onSuccess: Triggered upon a successful session creation.

- onFailure: Returns a failure status code. Triggered when session creation fails.

Example 14-8 Implementing the WSCSessionConnectionDelegate Protocol

#pragma mark WSCSessionConnectionDelegate
-(void)onSuccess {
NSLog(@"WebRTC Session Controller session connected.");
NSLog(@"Connection succeeded. Continuing...");
}

-(void)onFailure:(enum WSCStatusCode)code {
switch (code) {
case WSCStatusCodeUnauthorized:
NSLog(@"Unable to connect. Please check your credentials.");
break;
case WSCStatusCodeResourceUnavailable:
NSLog(@"Unable to connect. Please check the URL.");
break;
default:
// Handle other cases as required...
break;
}
}

Implement the WSCSession Connection Observer Protocol

Create a WSCSessionConnectionObserver protocol to monitor and respond to changes in session state.

Example 14-9 Implementing the WSCSessionConnectionObserver Protocol

#pragma mark WSCSessionConnectionDelegate
-(void)stateChanged:(WSCSessionState) sessionState {
switch (sessionState) {
case WSCSessionStateConnected:
NSLog(@"Session is connected.");
break;
case WSCSessionStateReconnecting:
NSLog(@"Session is attempting reconnection.");
break;
case WSCSessionStateFailed:
NSLog(@"Session connection attempt failed.");
break;
case WSCSessionStateClosed:
NSLog(@"Session connection has been closed.");
break;
default:
break;
}
}

Build the Session Object and Open the Session Connection

With the connection delegate and connection observer configured, you now build a WebRTC Session Controller session and open a connection with the server.

Example 14-10 Building the Session Object and Opening the Session Connection

if (error) {
// Handle an error..
NSLog("The following error occurred: %@", error.description);
} else {

// Configure the SSLContext if required, from Example 14-4...
...

// Retrieve all the response headers from Example 14-5...
...

// Build the httpContext from Example 14-6...
...

NSString *userName = @"username";
self.wscSession = [[[[[[[[[[[[WSCSessionBuilder create:urlString]
withConnectionDelegate:WSCSessionConnectionDelegate]
withUserName:userName]
withObserverDelegate:WSCSessionConnectionObserverDelegate]
withPackage:[[WSCCallPackage alloc] init]]
withHttpContext:httpContext]
withIceServerConfig:iceServerConfig]
build];
// Open a connection to the server...
[self.wscSession open];

In Example 14-10, note that the withPackage method registers a new WSCCallPackage with the session that will be instantiated when creating voice or video calls.

Configure Additional WSCSession Properties

You can configure additional properties when creating a session using the WSCSessionBuilder withProperty method.

For a complete list of properties see the Oracle Communications WebRTC Session Controller iOS SDK API Reference.

Example 14-11 Configuring WSCSession Properties

if (error) {
// Handle an error..
NSLog("The following error occurred: %@", error.description);
} else {

// Configure the SSLContext if required, from Example 14-4...
...

// Retrieve all the response headers from Example 14-5...
...

// Build the httpContext from Example 14-6...
...

self.wscSession = [[[[[[[[[[[[WSCSessionBuilder create:urlString]
...
withProperty:WSC_PROP_IDLE_PING_INTERVAL value:[NSNumber numberWithInt: 20]]
withProperty:WSC_PROP_RECONNECT_INTERVAL value:[NSNumber numberWithInt:10000]]
...
build];
[self.wscSession open];
}

Adding WebRTC Voice Support to your iOS Application

This section describes how you can add WebRTC voice support to your iOS application.

Initialize the CallPackage Object

When you created your Session, you registered a new WSCCallPackage object using the Session object's withPackage method. You now instantiate that WSCCallPackage.

Example 14-12 Initializing the CallPackage

WSCCallPackage *callPackage = (WSCCallPackage*)[wscSession getPackage:PACKAGE_TYPE_CALL];

Note:
Use the default PACKAGE_TYPE_CALL call type unless you have defined a custom call type.

Place a WebRTC Voice Call from Your iOS Application

Once you have configured your authentication scheme, and created a Session, you can place voice calls from your iOS application.

Add the Audio Capture Device to Your Session

Before continuing, in order to stream audio from your iOS device you initialize a capture session and add an audio capture device.

Example 14-13 Adding an Audio Capture Device to Your Session

- (instancetype)initAudioDevice
{
self = [super initAudioDevice];
if (self) {
self.captureSession = [[AVCaptureSession alloc] initAudioDevice];
[self.captureSession setSessionPreset:AVCaptureSessionPresetLow];

// Get the audio capture device and add to our session.
self.audioCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
NSError *error = nil;
AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput
deviceInputWithDevice:self.audioCaptureDevice error:&error];
if (audioInput) {
[self.captureSession addInput:audioInput];
}
else {
NSLog(@"Unable to find audio capture device : %@", error.description);
}

return self;
}

Initialize the Call Object

Now, with the WSCCallPackage object created, you then initialize a WSCCall object, passing the callee's ID as an argument.

Example 14-14 Initializing the Call Object

String callee = @"bob@example.com";
WSCCall *call = [callPackage createCall:callee];

Configure Trickle ICE

To improve ICE candidate gathering performance, you can choose to enable Trickle ICE in your application using the WSCCall object's setTrickleIceMode method. For more information see "Enabling Trickle ICE to Improve Application Performance."

Example 14-15 Configuring Trickle ICE

NSLog(@"Configure Trickle ICE options, WSCTrickleIceModeOFF, WSCTrickleIceModeHalf, or WSCTrickleIceModeFull...");
[call setTrickleIceMode: WSCTrickleIceModeFull];

Create a CallObserverDelegate Protocol

You create a CallObserverDelegate protocol so you can respond to the following WSCCall events:

- callUpdated: Triggered on incoming and outgoing call update requests.

- mediaStateChanged: Triggered on changes to the WSCCall media state.

- stateChanged: Triggered on changes to the WSCCall state.

Example 14-16 Creating a CallObserverDelegate Protocol

#pragma mark CallObserverDelegate

-(void)callUpdated:(WSCCallUpdateEvent)event
callConfig:(WSCCallConfig *)callConfig
cause:(WSCCause *)cause
{
NSLog("callUpdate request with config: %@", callConfig.description);
switch(event){
case WSCCallUpdateEventSent:
break;
case WSCCallUpdateEventReceived:
NSLog("Call Update event received for config: %@", callConfig.description);
break;
case WSCCallUpdateEventAccepted:
NSLog("Call Update accepted for config: %@", callConfig.description);
break;
case WSCCallUpdateEventRejected:
NSLog("Call Update event rejected for config: %@", callConfig.description);
break;
default:
break;
}
}

-(void)mediaStateChanged:(WSCMediaStreamEvent)mediaStreamEvent
mediaStream:(RTCMediaStream *)mediaStream
{
NSLog(@"mediaStateChanged : %u", mediaStreamEvent);
}

-(void)stateChanged:(WSCCallState)callState
cause:(WSCCause *)cause
{
NSLog(@"Call State changed : %u", callState);
switch (callState) {
NSLog(@"stateChanged: %u", callState);
case WSCCallStateNone:
NSLog(@"stateChanged: %@", @"WSC_CS_NONE");
break;
case WSCCallStateStarted:
NSLog(@"stateChanged: %@", @"WSC_CS_STARTED");
break;
case WSCCallStateResponded:
NSLog(@"stateChanged: %@", @"WSC_CS_RESPONDED");
break;
case WSCCallStateEstablished:
NSLog(@"stateChanged: %@", @"WSC_CS_ESTABLISHED");
break;
case WSCCallStateFailed:
NSLog(@"stateChanged: %@", @"WSC_CS_FAILED");
break;
case WSCCallStateRejected:
NSLog(@"stateChanged: %@", @"WSC_CS_REJECTED");
break;
case WSCCallStateEnded:
NSLog(@"stateChanged: %@", @"WSC_CS_ENDED");
break;
default:
break;
}
}

Register the CallObserverDelegate Protocol with the Call Object

You register the CallObserverDelegate protocol with the WSCCall object.

Example 14-17 Registering a CallObserverDelegate Protocol

call.observerDelegate = CallObserverDelegate;

Create a WSCCallConfig Object

You create a WSCCallConfig object to determine the type of call you wish to make. The WSCCallConfig constructor takes two parameters, audioMediaDirection and videoMediaDirection. The first parameter configures an audio call while the second configures a video call.

The values for audioMediaDirection and videoMediaDirection parameters are:

- WSCMediaDirectionNone: No direction; media support disabled.

- WSCMediaDirectionRecvOnly: The media stream is receive only.

- WSCMediaDirectionSendOnly: The media stream is send only.

- WSCMediaDirectionSendRecv: The media stream is bi-directional.

Example 14-18 shows the configuration for a bi-directional, audio-only call.

Example 14-18 Creating an Audio CallConfig Object

WSCCallConfig *callConfig = [[WSCCallConfig alloc] initWithAudioVideoDirection:WSCMediaDirectionSendRecv video:WSCMediaDirectionNone];

Configure the Local MediaStream for Audio

With the WSCCallConfig object created, you then configure the local audio MediaStream using the WebRTC PeerConnectionFactory. For information on the WebRTC SDK API, see http://www.webrtc.org/reference/native-apis.

Example 14-19 Configuring the Local MediaStream for Audio

RTCPeerConnectionFactory *)pcf = [call getPeerConnectionFactory];
RTCMediaStream* localMediaStream = [pcf mediaStreamWithLabel:@"ARDAMS"];
[localMediaStream addAudioTrack:[pcf audioTrackWithID:@"ARDAMSa0"]];
NSArray *streamArray = [[NSArray alloc] initWithObjects:localStream, nil];

Start the Audio Call

Finally, you start the audio call using the Call object's start method and passing it the WSCCallConfig object and the streamArray.

Example 14-20 Starting the Audio Call

[call start:callConfig streams:streamArray];

Terminating the Audio Call

To terminate the audio call, use the WSCCall object end method:

[call end];

Receiving a WebRTC Voice Call in Your iOS Application

This section describes configuring your iOS application to receive WebRTC voice calls.

Create a CallPackageObserverDelegate

To be notified of an incoming call, create a CallPackageObserverDelegate and attach it to your WSCCallPackage.

Example 14-21 Creating a CallPackageObserver Delegate

Creating a CallPackageObserver Delegate
#pragma mark CallPackageObserverDelegate
-(void)callArrived:(WSCCall *)call
callConfig:(WSCCallConfig *)callConfig
extHeaders:(NSDictionary *)extHeaders {

NSLog(@"Registering a CallObserverDelegate...");
call.setObserverDelegate = CallObserverDelegate;

NSLog(@"Configuring the media streams...");
RTCPeerConnectionFactory *)pcf = [call getPeerConnectionFactory];
RTCMediaStream* localMediaStream = [pcf mediaStreamWithLabel:@"ARDAMS"];
[localMediaStream addAudioTrack:[pcf audioTrackWithID:@"ARDAMSa0"]];

if (answerTheCall) {
NSLog(@"Answering the call...");
[call accept:self.callConfig streams:localMediaStream];
} else {
NSLog(@"Declining the call...");
[call decline:WSCStatusCodeBusyHere];
}
}
}

In Example 14-21, the callArrived event handler processes an incoming call request:

1. The method registers a CallObserverDelegate for the incoming call. In this case, it uses the same CallObserverDelegate, from the example in "Create a CallObserverDelegate Protocol."

2. The method then configures the local media stream, in the same manner as "Configure the Local MediaStream for Audio."

3. The method determines whether to accept or reject the call based upon the value of the answerTheCall boolean using either Call object's accept or decline methods.

Note:
The answerTheCall boolean will most likely be set by a user interface element in your application such as a button or link.

Bind the CallPackage Observer to the CallPackage

With the CallPackage observer created, you bind it to your CallPackage object:

[callPackage setObserverDelegate:CallPackageObserverDelegate;

Adding WebRTC Video Support to your iOS Application

This section describes how you can add WebRTC video support to your iOS application. While the methods are almost completely identical to adding voice call support to an iOS application, additional preparation is required.

Add the Audio and Video Capture Devices to Your Session

As with an audio call, you initialize the audio capture device as shown in "Add the Audio Capture Device to Your Session." In addition, you initialize the video capture device and add it to your session.

Example 14-22 Adding the Audio and Video Capture Devices to Your Session

- (instancetype)initAudioVideo
{
self = [super initAudioVideo];
if (self) {
self.captureSession = [[AVCaptureSession alloc] initAudioVideo];
[self.captureSession setSessionPreset:AVCaptureSessionPresetLow];

// Get the audio capture device and add to our session.
self.audioCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
NSError *error = nil;
AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput
deviceInputWithDevice:self.audioCaptureDevice error:&error];
if (audioInput) {
[self.captureSession addInput:audioInput];
}
else {
NSLog(@"Unable to find audio capture device : %@", error.description);
}

// Get the video capture devices and add to our session.
for (AVCaptureDevice* videoCaptureDevice in [AVCaptureDevice
devicesWithMediaType:AVMediaTypeVideo]) {
if (videoCaptureDevice.position == AVCaptureDevicePositionFront) {
self.frontVideCaptureDevice = videoCaptureDevice;
AVCaptureDeviceInput *videoInput = [AVCaptureDeviceInput
deviceInputWithDevice:videoCaptureDevice error:&error];
if (videoInput) {
[self.captureSession addInput:videoInput];
} else {
NSLog(@"Unable to get front camera input : %@", error.description);
}
} else if (videoCaptureDevice.position == AVCaptureDevicePositionBack) {
self.backVideCaptureDevice = videoCaptureDevice;
}
}
}
return self;
}

Configure a View Controller and a View Display Incoming Video

You add a view object to a view controller to display the incoming video. In Example 14-23, when the MyWebRTCApplicationViewController view controller is created, its view property is nil, which triggers the loadView method

Example 14-23 Creating a View to Display the Video Stream

@implementation MyWebRTCApplicationViewController

- (void)loadView {

// Create the view, videoView...
CGRect frame = [UIScreen mainScreen].bounds;
MyWebRTCApplicationView *videoView = [[MyWebRTCApplication alloc] initWithFrame:frame];

// Set videoView as the main view of the view controller...
self.view = videoView;
}

@end

Next you set the view controller as the rootViewController, which adds videoView as a subview of the window, and automatically resizes videoView to be the same size as the window.

Example 14-24 Setting the Root View Controller

#import "MyWebRTCApplicationAppDelegate.h"
#import "MyWebRTCApplicationViewController.h"

@implementation MyWebRTCApplicationAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:
(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

MyWebRTCApplicationViewController *myvc = [[MyWebRTCApplicaitonViewController alloc] init];
self.window.rootVewController = myvc;

self.window.backgroundColor = [UIColor grayColor];
return YES;
}

Placing a WebRTC Video Call from Your iOS Application

To place a video call from your iOS application, complete the coding tasks contained in the following sections:

- Authenticating with WebRTC Session Controller

- Configure Interactive Connectivity Establishment (ICE) (if required)

- Creating a WebRTC Session Controller Session

In addition, complete the coding tasks for an audio call contained in the following sections:

- Initialize the Call Object

- Configure Trickle ICE (if required)

- Create a CallObserverDelegate Protocol

- Register the CallObserverDelegate Protocol with the Call Object

Note:
Audio and video call work flows are identical with the exception of media directions, local media stream configuration, and the additional considerations described earlier in this section.

Create a WSCCallConfig Object

You create a WSCCallConfig object as described in "Create a WSCCallConfig Object," in the audio call section, setting both arguments to WSCMediaDirectionSendRecv.

Example 14-25 Creating an Audio/Video WSCCallConfig Object

WSCCallConfig *callConfig = [[WSCCallConfig alloc] initWithAudioVideoDirection:WSCMediaDirectionSendRecv video:WSCMediaDirectionSendRecv];

Configure the Local WSCMediaStream for Audio and Video

With the CallConfig object created, you then configure the local video and audio MediaStream objects using the WebRTC PeerConnectionFactory. In Example 14-26, the PeerConnectionFactory is used to first configure a video stream using optional constraints and mandatory constraints (as defined in the getMandatoryConstraints method), and is then added to the localMediaStream using its addVideoTrack method. Two boolean arguments, hasAudio and hasVideo, enable the calling function to specify whether audio or video streams are supported in the current call. The audioTrack is added as well and the localMediaStream is returned to the calling function.

For information on the WebRTC PeerConnectionFactory and mandatory and optional constraints, see http://www.webrtc.org/reference/native-apis.

Example 14-26 Configuring the Local MediaStream for Audio and Video

-(RTCMediaStream *)getLocalMediaStreams:(RTCPeerConnectionFactory *)pcf
enableAudio:(BOOL)hasAudio enableVideo:(BOOL)hasVideo {
NSLog(@"Getting local media streams");
if (!localMediaStream) {
NSLog("PeerConnectionFactory: createLocalMediaStream() with pcf : %@", pcf);
localMediaStream = [pcf mediaStreamWithLabel:@"ALICE"];
NSLog(@"MediaStream1 = %@", localMediaStream);
}

if(hasVideo && (localMediaStream.videoTracks.count <= 0)){
if (hasVideo) {
RTCVideoCapturer* capturer = [RTCVideoCapturer
capturerWithDeviceName:[avManager.frontVideCaptureDevice localizedName]];
RTCPair *dtlsSrtpKeyAgreement = [[RTCPair alloc] initWithKey:@"DtlsSrtpKeyAgreement"
value:@"true"];
NSArray * optionalConstraints = @[dtlsSrtpKeyAgreement];
NSArray *mandatoryConstraints = [self getMandatoryConstraints];
RTCMediaConstraints *videoConstraints = [[RTCMediaConstraints alloc]
initWithMandatoryConstraints:mandatoryConstrainta
optionalConstraints:optionalConstraints];
RTCVideoSource *videoSource = [pcf videoSourceWithCapturer:capturer
constraints:videoConstraints];
RTCVideoTrack *videoTrack = [pcf videoTrackWithID:@"ALICEv0" source:videoSource];
if (videoTrack) {
[localMediaStream addVideoTrack:videoTrack];
}
}
}

if (localMediaStream.audioTracks.count <= 0 && hasAudio) {
[localMediaStream addAudioTrack:[pcf audioTrackWithID:@"ALICEa0"]];
}

if (!hasVideo && localMediaStream.videoTracks.count > 0) {
for (RTCVideoTrack *videoTrack in localMediaStream.videoTracks) {
[localMediaStream removeVideoTrack:videoTrack];
}
}

if (!hasAudio && localMediaStream.audioTracks.count > 0) {
for (RTCAudioTrack *audioTrack in localMediaStream.audioTracks) {
[localMediaStream removeAudioTrack:audioTrack];
}
}

NSLog(@"MediaStream = %@", localMediaStream);
return localMediaStream;
}

-(NSArray *)getMandatoryConstraints {

RTCPair *localVideoMaxWidth = [[RTCPair alloc] initWithKey:@"maxWidth" value:@"640"];
RTCPair *localVideoMinWidth = [[RTCPair alloc] initWithKey:@"minWidth" value:@"192"];
RTCPair *localVideoMaxHeight = [[RTCPair alloc] initWithKey:@"maxHeight" value:@"480"];
RTCPair *localVideoMinHeight = [[RTCPair alloc] initWithKey:@"minHeight" value:@"144"];
RTCPair *localVideoMaxFrameRate = [[RTCPair alloc] initWithKey:@"maxFrameRate" value:@"30"];
RTCPair *localVideoMinFrameRate = [[RTCPair alloc] initWithKey:@"minFrameRate" value:@"5"];
RTCPair *localVideoGoogLeakyBucket = [[RTCPair alloc]
initWithKey:@"googLeakyBucket" value:@"true"];

return @[localVideoMaxHeight,
localVideoMaxWidth,
localVideoMinHeight,
localVideoMinWidth,
localVideoMinFrameRate,
localVideoMaxFrameRate,
localVideoGoogLeakyBucket];
}

Bind the Video Track to the View Controller

Finally you bind the video track to the view controller you created in "Configure a View Controller and a View Display Incoming Video."

Example 14-27 Binding the Video Track to the View Controller

if(localMediaStream.videoTracks.count >0) {  [MyWebRTCApplicationViewController
localVideoConnected:localMediaStream.videoTracks[0]];}

Start the Video Call

Finally, start the audio/video call using the Call object's start method and passing it the WSCCallConfig object and the MediaStream stream array.

Example 14-28 Starting the Video Call

[call start:callConfig streams:streamArray];

Terminate the Video Call

To terminate the video call, use the WSCCall object's end method:

Example 14-29 Terminating the Video Call

[self.call end];

Receiving a WebRTC Video Call in Your iOS Application

Receiving a video call is identical to receiving an audio call as described here, "Receiving a WebRTC Voice Call in Your iOS Application." The only difference is the configuration of the WSCMediaStream object, as described in "Configure the Local WSCMediaStream for Audio and Video."

Upgrading and Downgrading Calls

This section describes how you can handle upgrading an audio call to an audio video call and downgrading a video call to an audio-only call in your iOS application.

Handle Upgrade and Downgrade Requests from Your Application

To upgrade from a voice call to a video call as a request from your application, you can bind a user interface element such as a button class containing the WSCCall update logic using the forControlEvents action:

[requestUpgradeButton addTarget:self action:@selector(videoUpgrade)
forControlEvents:UIControlEventTouchUpInside];
[requestDowngradeButton addTarget:self action:@selector(videoDowngrade)
forControlEvents:UIControlEventTouchUpInside];

You handle the upgrade or downgrade workflow in the videoUpgrade and videoDowngrade event handlers for each button instance.

Example 14-30 Sending Upgrade/Downgrade Requests from Your Application

- (void) videoUpgrade: {
// Set the criteria for the current call...
self.hasVideo = NO;
self.hasAudio = YES;

// Fetch local streams using the the getLocalMediaStreams function from Example 14-26
[self getLocalMediaStreams:[self.call getPeerConnectionFactory] enableVideo:hasVideo
enableAudio:hasAudio];

// Bind the video stream to the view controller as in Example 14-27
if(localMediaStream.videoTracks.count >0) {    [MyWebRTCApplicationViewController
localVideoConnected:localMediaStream.videoTracks[0]];  }

// Audio -> Video upgrade
WSCCallConfig *newConfig = [[WSCCallConfig alloc]
initWithAudioVideoDirection:WSCMediaDirectionSendRecv
video:WSCMediaDirectionSendRecv]];
[call update:newConfig headers:nil streams:@[localMediaStream]];
}

- (void) videoDowngrade: {
// Set the criteria for the current call...
self.hasVideo = YES;
self.hasAudio = YES;

// Fetch local streams using the the getLocalMediaStreams function from Example 14-26
[self getLocalMediaStreams:[self.call getPeerConnectionFactory] enableVideo:hasVideo
enableAudio:hasAudio];

// Bind the video stream to the view controller as in Example 14-27
if(localMediaStream.videoTracks.count >0) {    [MyWebRTCApplicationViewController
localVideoConnected:localMediaStream.videoTracks[0]];  }

// Video -> Audio downgrade
WSCCallConfig *newConfig = [[WSCCallConfig alloc]
initWithAudioVideoDirection:WSCMediaDirectionSendRecv
video:WSCMediaDirectionNone]];
[call update:newConfig headers:nil streams:@[localMediaStream]];
}

Handle Incoming Upgrade Requests

You configure the callUpdated method of your CallObserverDelegate class to handle incoming upgrade requests in the case of a WSCCallUpdateEventReceived state change.

Note:
The declineUpgrade boolean must be set by some other part of your application's user interface.

Example 14-31 Handling an Incoming Upgrade Request

- (void)callUpdated:(WSCCallUpdateEvent)event
callConfig:(WSCCallConfig *)callConfig
cause:(WSCCause *)cause
{
NSLog("callUpdate request with config: %@", callConfig.description);
switch(event){
case WSCCallUpdateEventSent:
break;
case WSCCallUpdateEventReceived:
if(declineUpgrade) {
NSLog(@"Declining upgrade.");
[self.call decline:WSCStatusCodeDeclined];
} else {
NSLog(@"Accepting upgrade.");
NSLog(@"Call config: %@", updateConfig.description);
BOOL hasAudio;
BOOL hasVideo;
if (updateConfig.audioConfig == WSCMediaDirectionNone) {
hasAudio = NO;
}
if (updateConfig.videoConfig == WSCMediaDirectionNone) {
hasVideo = NO;
}
self.callConfig = updateConfig;
[self getLocalMediaStreams:[self.call getPeerConnectionFactory] enableAudio:hasAudio
enableVideo:hasVideo];
[self.call accept:updateConfig streams:localMediaStream];
[callViewController updateView:self.callConfig];
}
case WSCCallUpdateEventAccepted:
break;
case WSCCallUpdateEventRejected:
break;
default:
break;
}

Oracle Legal Notices

Copyright Notice

Copyright © 1994-2016, Oracle and/or its affiliates. All rights reserved.

License Restrictions Warranty/Consequential Damages Disclaimer

This software and related documentation are provided under a license agreement containing restrictions on use and disclosure and are protected by intellectual property laws. Except as expressly permitted in your license agreement or allowed by law, you may not use, copy, reproduce, translate, broadcast, modify, license, transmit, distribute, exhibit, perform, publish, or display any part, in any form, or by any means. Reverse engineering, disassembly, or decompilation of this software, unless required by law for interoperability, is prohibited.

Warranty Disclaimer

The information contained herein is subject to change without notice and is not warranted to be error-free. If you find any errors, please report them to us in writing.

Restricted Rights Notice

If this is software or related documentation that is delivered to the U.S. Government or anyone licensing it on behalf of the U.S. Government, then the following notice is applicable:

U.S. GOVERNMENT END USERS: Oracle programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, delivered to U.S. Government end users are "commercial computer software" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations. As such, use, duplication, disclosure, modification, and adaptation of the programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, shall be subject to license terms and license restrictions applicable to the programs. No other rights are granted to the U.S. Government.

Hazardous Applications Notice

This software or hardware is developed for general use in a variety of information management applications. It is not developed or intended for use in any inherently dangerous applications, including applications that may create a risk of personal injury. If you use this software or hardware in dangerous applications, then you shall be responsible to take all appropriate fail-safe, backup, redundancy, and other measures to ensure its safe use. Oracle Corporation and its affiliates disclaim any liability for any damages caused by use of this software or hardware in dangerous applications.

Trademark Notice

Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.

Intel and Intel Xeon are trademarks or registered trademarks of Intel Corporation. All SPARC trademarks are used under license and are trademarks or registered trademarks of SPARC International, Inc. AMD, Opteron, the AMD logo, and the AMD Opteron logo are trademarks or registered trademarks of Advanced Micro Devices. UNIX is a registered trademark of The Open Group.

Third-Party Content, Products, and Services Disclaimer

This software or hardware and documentation may provide access to or information about content, products, and services from third parties. Oracle Corporation and its affiliates are not responsible for and expressly disclaim all warranties of any kind with respect to third-party content, products, and services unless otherwise set forth in an applicable agreement between you and Oracle. Oracle Corporation and its affiliates will not be responsible for any loss, costs, or damages incurred due to your access to or use of third-party content, products, or services, except as set forth in an applicable agreement between you and Oracle.

Alpha and Beta Draft Documentation Notice

If this document is in preproduction status:

This documentation is in preproduction status and is intended for demonstration and preliminary use only. It may not be specific to the hardware on which you are using the software. Oracle Corporation and its affiliates are not responsible for and expressly disclaim all warranties of any kind with respect to this documentation and will not be responsible for any loss, costs, or damages incurred due to the use of this documentation.

Private Alpha and Beta Draft Documentation Notice

If this document is in private preproduction status:

The information contained in this document is for informational sharing purposes only and should be considered in your capacity as a customer advisory board member or pursuant to your beta trial agreement only. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, and timing of any features or functionality described in this document remains at the sole discretion of Oracle.

This document in any form, software or printed matter, contains proprietary information that is the exclusive property of Oracle. Your access to and use of this confidential material is subject to the terms and conditions of your Oracle Master Agreement, Oracle License and Services Agreement, Oracle PartnerNetwork Agreement, Oracle distribution agreement, or other license agreement which has been executed by you and Oracle and with which you agree to comply. This document and information contained herein may not be disclosed, copied, reproduced, or distributed to anyone outside Oracle without prior written consent of Oracle. This document is not part of your license agreement nor can it be incorporated into any contractual agreement with Oracle or its subsidiaries or affiliates.

Documentation Accessibility

For information about Oracle's commitment to accessibility, visit the Oracle Accessibility Program website at http://www.oracle.com/pls/topic/lookup?ctx=acc&id=docacc.

Access to Oracle Support

Oracle customers that have purchased support have access to electronic support through My Oracle Support. For information, visit http://www.oracle.com/pls/topic/lookup?ctx=acc&id=info or visit http://www.oracle.com/pls/topic/lookup?ctx=acc&id=trs if you are hearing impaired.