/*jslint browser: true, devel: true, node: true, debug: true, todo: true, indent: 2, maxlen: 150*/
/*jslint browser: true, devel: true, node: true, debug: true, todo: true, indent: 2, maxlen: 150*/
Make JSLint aware of variables and functions that are defined in other files.
/*global ATT, unsupportedBrowserError, loadSampleApp, checkEnhancedWebRTCSession, addCall,
onSessionReady, onSessionDisconnected, onSessionExpired, onAddressUpdated, onError, onWarning, onDialing,
onIncomingCall, onConnecting, onCallConnected, onMediaEstablished, onEarlyMedia, onAnswering, onCallMuted,
onCallUnMuted, onCallHeld, onCallResumed, onCallDisconnecting, onCallDisconnected, onCallCanceled,
onCallRejected, onConferenceConnected, onConferenceDisconnected, onConferenceInvite, onConferenceCanceled,
onConferenceEnded, onJoiningConference, onInvitationSent, onInviteAccepted, onInviteRejected,
onParticipantRemoved, onConferenceDisconnecting, onConferenceHeld, onConferenceResumed, onNotification,
onCallSwitched, onCallRingBackProvided, onTransferring, onTransferred, onCallMoved, onMediaModification,
onStateChanged, onModificationInProgress, onToneSent, onToneSending, onGatewayUnreachable, onNetworkOn, onNetworkOff*/
'use strict';
var phone,
version,
bWebRTCSupportExists;
Check to see whether browser has WebRTC support using Media Service API
bWebRTCSupportExists = ('Not Supported' !== ATT.browser.hasWebRTC());
if (!bWebRTCSupportExists) {
throw unsupportedBrowserError();
}
Example 1: Getting virtual numbers list
function setDropdownData(virtualNumbers) { var virtualNumbersDropdown; virtualNumbersDropdown = document.getElementById("virtual-numbers"); for (var i=0; i < virtual_numbers.length; i++) { addOption(virtualNumberDropdown, virtualNumbers[i]); } } var xhrConfig = new XMLHttpRequest(); xhrConfig.open('GET', '/config'); xhrConfig.onreadystatechange = function() { if (xhrConfig.readyState == 4) { if (xhrConfig.status == 200) { var config = JSON.parse(xhrConfig.responseText); virtualNumbers = config.virtual_numbers_pool; setDropdownData(virtualNumbers) } else { console.log(xhrConfig.responseText); } } } xhrConfig.send();
Example 2: Getting domain name for account id users
function displayAccountId(accountIdDomain) { var userIdElement, userId; userId = document.getElementById("user-id").value; userIdElement = document.getElementById("account-id"); userIdElement.innerHTML = userId + "@" + accountIdDomain; } var xhrConfig = new XMLHttpRequest(); xhrConfig.open('GET', '/config'); xhrConfig.onreadystatechange = function() { if (xhrConfig.readyState == 4) { if (xhrConfig.status == 200) { var config = JSON.parse(xhrConfig.responseText); ewebrtc_domain = config.ewebrtc_domain; displayAccountId(ewebrtc_domain); } else { console.log(xhrConfig.responseText); } } } xhrConfig.send();
Example 1: Create access token as a mobile number user
function success(data) { // do something ... } function error(errorData) { // do something ... } var xhrToken = new XMLHttpRequest(); xhrToken.open('POST', '/tokens'); xhrToken.setRequestHeader("Content-Type", "application/json"); xhrToken.onreadystatechange = function() { if (xhrToken.readyState == 4) { if (xhrToken.status == 200) { success(JSON.parse(xhrToken.responseText)); } else { error(xhrToken.responseText); } } } xhrToken.send(JSON.stringify({ app_scope: "MOBILE_NUMBER", auth_code: "authorization_code" }));
Example 2: Create access token as a virtual number user
function success(data) { // do something ... } function error(errorData) { // do something ... } var xhrToken = new XMLHttpRequest(); xhrToken.open('POST', '/tokens'); xhrToken.setRequestHeader("Content-Type", "application/json"); xhrToken.onreadystatechange = function() { if (xhrToken.readyState == 4) { if (xhrToken.status == 200) { success(JSON.parse(xhrToken.responseText)); } else { error(xhrToken.responseText); } } } xhrToken.send(JSON.stringify({ app_scope: "VIRTUAL_NUMBER" }));
Example 3: Create access token as an account id user
function success(data) { // do something ... } function error(errorData) { // do something ... } var xhrToken = new XMLHttpRequest(); xhrToken.open('POST', '/tokens'); xhrToken.setRequestHeader("Content-Type", "application/json"); xhrToken.onreadystatechange = function() { if (xhrToken.readyState == 4) { if (xhrToken.status == 200) { success(JSON.parse(xhrToken.responseText)); } else { error(xhrToken.responseText); } } } xhrToken.send(JSON.stringify({ app_scope: "ACCOUNT_ID" }));
The e911id can only be created for mobile number users or virtual number users.
Example
function success(data) { // do something ... } function error(errorData) { // do something ... } var xhrE911 = new XMLHttpRequest(); xhrE911.open('POST', '/e911ids'); xhrE911.setRequestHeader("Content-Type", "application/json"); xhrE911.onreadystatechange = function() { if (xhrE911.readyState == 4) { if (xhrE911.status == 200) { success(JSON.parse(xhrE911.responseText)); } else { error(xhrE911.responseText); } } } xhrE911.send(JSON.stringify({ token: accessToken, address: address, is_confirmed: false }));
The access token can be refreshed for mobile number users, virtual number users and account id users.
Example
function success(data) { // do something ... } function error(errorData) { // do something ... } var xhrToken = new XMLHttpRequest(); xhrToken.open('POST', '/tokens'); xhrToken.setRequestHeader("Content-Type", "application/json"); xhrToken.onreadystatechange = function() { if (xhrToken.readyState == 4) { if (xhrToken.status == 200) { success(JSON.parse(xhrToken.responseText)); } else { error(xhrToken.responseText); } } } xhrToken.send(JSON.stringify({ refresh_token: accessToken }));
The access token can be revoked for mobile number users, virtual number users and account id users.
Example
function success(data) { // do something ... } function error(errorData) { // do something ... } var xhrToken = new XMLHttpRequest(); xhrToken.open('DELETE', '/tokens'); xhrToken.setRequestHeader("Content-Type", "application/json"); xhrToken.onreadystatechange = function() { if (xhrToken.readyState == 4) { if (xhrToken.status == 200) { success(JSON.parse(xhrToken.responseText)); } else { error(xhrToken.responseText); } } } xhrToken.send(JSON.stringify({ token: accessToken }));
Every action for Call & Conference Management is done via the Phone’s interface.
Phone object is the main interface for making a call. This will be our instance of the Phone object.
phone = ATT.rtc.Phone.getPhone();
Once you have the phone object, you can use the phone.getVersion method on the Phone object to get the version number of the SDK.
version = phone.getVersion();
document.getElementById('version').innerHTML = version;
Here the error event is published after receiving an error
Callback function example:
function onError(data) { error = data.error }
phone.on('error', onError);
Here the warning event is published after receiving a warning
Callback function example:
function onWarning(data) { var message = data.message; }
phone.on('warning', onWarning);
All Network status events of the Phone object are published via the connectivity event.
Here the connectivity:on event is published when network changes from offline to online
Callback function example:
function onNetworkOn() { }
phone.on('connectivity:on', onNetworkOn);
Here the connectivity:off event is published when network changes from online to offline
Callback function example:
function onNetworkOff() { }
phone.on('connectivity:off', onNetworkOff);
The address-updated event is published after successfully updating your E911 ID.
Callback function example:
function onAddressUpdated(data) { timestamp = data.timestamp; }
phone.on('address-updated', onAddressUpdated);
The session:ready event is published after successfully logged in to the Enhanced WebRTC. This event indicates that the SDK is ready to make or receive calls.
Callback function example:
function onSessionReady(data) { sessionId = data.sessionId; profile = data.name; userid = data.userid; type = data.type; message = data.message; }
phone.on('session:ready', onSessionReady);
The notification event publishes SDK notifications about the unhandled SDK behavior that is not an error.
Callback function example:
function onNotification(data) { message = data.message; }
phone.on('notification', onNotification);
function associateAccessToken(userId, accessToken, success, error) {
ATT.rtc.associateAccessToken associates an access token to a user id that is needed before you can login.
userId
is the user id that you want to associate the access token to
token
is the access token you want to associate
success
is the success callback
error
is the failure callback
phone.associateAccessToken({
userId: userId,
token: accessToken,
success: success,
error: error
});
}
function loginEnhancedWebRTC(token, e911Id, userId) {
phone.login establishes Enhanced WebRTC session so that the user can start making Enhanced WebRTC calls.
token
is the oAuth token you get from the consent
‘[userId]’ is the user
[e911Id]
is e911 address identifier
phone.login({
token: token,
e911Id: e911Id ? e911Id.e911Locations.addressIdentifier : null
});
}
function associateE911Id(e911Id) {
Given that the user is logged in, you can use the phone.associateE911Id method to update the user’s e911 linked address like:
phone.associateE911Id({
e911Id: e911Id
});
}
The session:disconnected event is published after logging out from Enhanced WebRTC session. This event is published to indicate that the session was successfully deleted.
phone.on('session:disconnected', onSessionDisconnected);
The session:expired event is published when session is expired in the backend. This event is published to indicate that there is a session deleted from the backend due to some reason.
phone.on('session:expired', onSessionExpired);
The gateway:unreachable event is published when gateway is unreachable. This event is published to indicate the client cannot get connected to the gateway due to some reason.
phone.on('gateway:unreachable', onGatewayUnreachable);
function phoneLogout() {
if (checkEnhancedWebRTCSession()) {
phone.on('error', function (data) {
if (data.error && data.error.JSMethod === 'logout') {
onSessionDisconnected();
}
});
phone.logout logs out the user from Enhanced WebRTC session.
phone.logout();
}
}
A call object will publish various events as it progresses through its lifecycle. In order to handle those events you must register handlers as follows:
Here the call:connecting event is published after successfully dialing out.
Callback function example:
function onConnecting(data) { to = data.to; mediaType = data.mediaType; timestamp = data.timestamp; }
phone.on('call:connecting', onConnecting);
Here the call:ringback-provided event is published if early media (such as a ring-tone) becomes available during the initial call setup.
Callback function example:
function onCallRingBackProvided(data) { timestamp = data.timestamp; }
phone.on('call:ringback-provided', onCallRingBackProvided);
The call:connected event is published when a connection is established between two parties.
Callback function example:
function onCallConnected(data) { mediaType = data.mediaType; timestamp = data.timestamp; }
phone.on('call:connected', onCallConnected);
The media:established event is published when media begins to play.
Callback function example:
function onMediaEstablished(data) { to = data.to; mediaType = data.mediaType; timestamp = data.timestamp; codec = data.codec; }
phone.on('media:established', onMediaEstablished);
The call:disconnected event is published after successfully disconnecting the call.
phone.on('call:disconnected', onCallDisconnected);
The call:canceled event is published after successfully canceling a call.
Callback function example:
function onCallCanceled(data) { to = data.to; mediaType = data.mediaType; timestamp = data.timestamp; }
phone.on('call:canceled', onCallCanceled);
phone.on('dialing', onDialing);
function dial(destination, mediaType, localMedia, remoteMedia) {
Once you have registered handlers for all appropriate events you can use the phone.dial method on Phone to start a call.
If there’s already a call in progress
if (phone.isCallInProgress()) {
handle this call with the phone.addCall method
addCall(destination, mediaType, localMedia, remoteMedia);
} else {
otherwise just the phone.dial method. You need to pass:
phone.dial({
11231231234
,123*321-1234
user@domain.com
1800CALLFED
911
destination: destination,
audio
for audio-only calls andvideo
for video calls mediaType: mediaType,
HTMLVideoElement
to use for the local stream, localMedia: localMedia,
HTMLVideoElement
to use for the remote stream. remoteMedia: remoteMedia
});
}
}
In order to handle incoming calls, you need to register a handler for the call:incoming event on the Phone object.
phone.on('call:incoming', onIncomingCall);
You also need to register handlers for the other events that are published during the process of answering a call.
phone.on('answering', onAnswering);
function answer(localMedia, remoteMedia) {
Once you have registered to receive calls, you can use the phone.answer method on the Phone object to answer an incoming call, it receives:
phone.answer({
HTMLVideoElement
object to use for the local stream localMedia: localMedia,
HTMLVideoElement
object to use for the remote stream. remoteMedia: remoteMedia
});
}
Once a call is in progress, you can make a second call or receive a second incoming call. Use phone.isCallInProgress to check whether there is a call in progress.
The second call will publish the same events that we have already covered in previous sections of the tutorial.
function addCall(callee, mediaType, localMedia, remoteMedia) {
Use the phone.addCall method to make a second call when there is a first call in progress. You need to pass:
phone.addCall({
11231231234
,123*321-1234
user@domain.com
1800CALLFED
911
destination: callee,
audio
for audio-only calls andvideo
for video calls mediaType: mediaType,
HTMLVideoElement
to use for the local stream, localMedia: localMedia,
HTMLVideoElement
to use for the remote stream. remoteMedia: remoteMedia
});
}
Once you have an active call, you can handle a second incoming call using the phone.answer method.
function answer2ndCall(localMedia, remoteMedia, action) {
The phone.answer method receives:
phone.answer({
HTMLVideoElement
object to use for the local stream localMedia: localMedia,
HTMLVideoElement
object to use for the remote stream. remoteMedia: remoteMedia,
action
(hold
or end
) to indicate whether to hold or end the current call.
Use phone.isCallInProgress to check whether there is a call in progress. action: action
});
}
Once a call is ongoing, you can perform basic operations with them like muting, unmuting, holding, resuming, canceling and hanging up.
Register for call:rejected event, it is published the call is rejected by the receiving party
phone.on('call:rejected', onCallRejected);
function reject() {
Use the phone.reject method to reject the incoming call
phone.reject();
}
Register for call:muted event, it is published when phone.mute is invoked
phone.on('call:muted', onCallMuted);
function mute() {
Then use the phone.mute method to mute the current call.
phone.mute();
}
Register for call:unmuted event, it is published when phone.unmute is invoked.
phone.on('call:unmuted', onCallUnMuted);
function unmute() {
Use the phone.unmute method to unmute the current call
phone.unmute();
}
phone.on('call:held', onCallHeld);
function hold() {
Use the phone.hold method to put the current call or conference on hold.
phone.hold();
}
Register for call:resumed event, it is published when phone.resume is invoked
phone.on('call:resumed', onCallResumed);
function resume() {
Use the phone.resume method to resume the current call or conference.
phone.resume();
}
function cancel() {
Use the phone.cancel method to cancel the outgoing call.
phone.cancel();
}
Register for call:disconnecting event, it is published immediately after invoking phone.hangup
phone.on('call:disconnecting', onCallDisconnecting);
function hangupCall() {
Use the phone.hangup method to hang up the current call.
phone.hangup();
}
Use the phone.move method to move the call to another client. All clients currently logged in with the same Id will receive a call. This method can also be used to move a call to a handheld device.
The call:moved
event is published after a call has been successfully moved
Callback function example:
function onCallMoved(data) { from = data.from; to = data.to; timestamp = data.timestamp; }
phone.on('call:moved', onCallMoved);
function move() {
The other devices will start ringing, i.e., the Phone object in the other clients will emit a call:incoming. Phone will emit the same events as if it was a regular call.
phone.move();
}
The session:call-switched event is published when the current active call is switched
Callback function example:
function onCallSwitched(data) { from = data.from; to = data.to; timestamp = data.timestamp; }
phone.on('session:call-switched', onCallSwitched);
Use the phone.switchCall method to switch between two ongoing calls/conferences.
function switchCalls() {
The foreground call/conference wil be put on hold and will be moved to background, and the background call/conference will be brought to foreground.
phone.switchCall();
}
The call:transferring
event is published when call transfer is initiated
Callback function example:
function onTransferring(data) { from = data.from; to = data.to; timestamp = data.timestamp; }
phone.on('call:transferring', onTransferring);
The call:transferred
event is published after a call has been successfully transferred
Callback function example:
function onTransferred(data) { from = data.from; to = data.to; timestamp = data.timestamp; }
phone.on('call:transferred', onTransferred);
function transfer() {
Use the phone.transfer method to transfer existing call to another
phone.transfer();
}
If Bob and Alice are in a call, then they may want to change their media constraints:
Before a user can start processing media modifications they need to register to the call:media-modification, call:modification-in-progress and call:state-changed events.
phone.on('call:modification-in-progress', onModificationInProgress);
phone.on('call:media-modification', onMediaModification);
phone.on('call:state-changed', onStateChanged);
call:modification-in-progress
indicates that the media modification is taking place but has not completed.call:media-modification
is only fired for the user receiving the modification request when user consent is necessary.call:state-changed
is fired for both users when the modification is complete.If Bob and Alice are in a video call, then Alice can disable her video and start sending only her audio.
function downgrade() {
In order to stop sending her video Alice can use the phone.downgrade method.
phone.downgrade();
At this point Bob will receive the call:media-modification
event and may be promted to
accept or reject depending on the current state of his media.
If the downgrade is successfull, then:
}
If Bob and Alice are in an audio-only call, then Bob can request to upgrade the call to video.
function upgrade() {
In order to start the upgrade Bob will use the phone.upgrade method.
phone.upgrade();
At this point Alice will receive the call:media-modification event, which this application uses to prompt Alice for confirmation.
If the upgrade is successful, then:
}
If Bob is in a call with Alice and he receives a media modification request
from from Alice, the call:media-modification
event will fire.
function acceptModification() {
In order to accept the modification request, Bob can use the phone.acceptModification method.
phone.acceptModification();
After successfully accepting the modification, then:
call:state-changed
event will fire for both users.}
If Bob is in a call with Alice and he receives a media modification request
from from Alice, the call:media-modification
event will fire.
function rejectModification() {
In order to reject the modification request, Bob can use the phone.rejectModification method.
phone.rejectModification();
After successfully rejecting the modification, then:
call:state-changed
event will fire for both users.}
A conference will publish various events as it progresses its lifecycle. In order to handle those events you must register handlers as follows:
Here the conference:connecting event is published while starting a conference.
Callback function example:
function onConnecting(data) { to = data.to; mediaType = data.mediaType; timestamp = data.timestamp; }
phone.on('conference:connecting', onConnecting);
The conference:connected event is published when the conference has been created or joined.
Callback function example:
function onConferenceConnected(data) { mediaType = data.mediaType; timestamp = data.timestamp; }
phone.on('conference:connected', onConferenceConnected);
The conference:canceled event is published after the conference is canceled.
Callback function example:
function onConferenceCanceled(data) { timestamp = data.timestamp; }
phone.on('conference:canceled', onConferenceCanceled);
The conference:ended event is published after successfully ending the conference.
Callback function example:
function onConferenceEnded(data) { timestamp = data.timestamp; }
phone.on('conference:ended', onConferenceEnded);
The conference:held event is published after a conference is successfully put on hold.
Callback function example:
function onConferenceHeld(data) { mediaType = data.mediaType; timestamp = data.timestamp; }
phone.on('conference:held', onConferenceHeld);
The conference:resumed event is published when a conference is successfully resumed.
Callback function example:
function onConferenceResumed(data) { mediaType = data.mediaType; timestamp = data.timestamp; }
phone.on('conference:resumed', onConferenceResumed);
function startConference(mediaType, localMedia, remoteMedia) {
Once you have registered handlers for all appropriate events you can use the phone.startConference method to create a conference. You must pass:
phone.startConference({
mediaType: mediaType,
the HTMLVideoElement
to use for the local stream,
localMedia: localMedia,
and the HTMLVideoElement
to use for the remote stream.
remoteMedia: remoteMedia
});
}
In order to handle conference invites, you must register for the following events on the Phone object:
The conference:invitation-received event is published when the other party receives invitation
phone.on('conference:invitation-received', onConferenceInvite);
The conference:joining event is published immediately when the other party accepts to join the conference
phone.on('conference:joining', onJoiningConference);
function joinConference(localMedia, remoteMedia) {
Use the phone.joinConference method to join a conference by accepting the invite. You must pass in:
phone.joinConference({
a valid HTMLVideoElement
for the local media stream and
localMedia: localMedia,
a valid HTMLVideoElement
for the remote media stream.
remoteMedia: remoteMedia
});
}
Once you have an active call or conference, you can handle a second incoming conference using the phone.joinConference method.
function joinSecondConference(localMedia, remoteMedia, action) {
The phone.joinConference method receives:
phone.joinConference({
HTMLVideoElement
object to use for the local stream localMedia: localMedia,
HTMLVideoElement
object to use for the remote stream. remoteMedia: remoteMedia,
action
(hold
or end
) to indicate whether to hold or end the current call.
Use phone.isCallInProgress to check whether there is a call in progress. action: action
});
}
As the host of a Conference you can perform basic operations with them like:
First you must register handlers for the events published during the process of adding a participant:
The conference:invitation-sent event is published when the invitation was sent successfully.
phone.on('conference:invitation-sent', onInvitationSent);
The conference:invitation-accepted event is published when the invitation is accepted by the other party.
phone.on('conference:invitation-accepted', onInviteAccepted);
The conference:invitation-rejected event is published when the invitation is rejected by the other party.
phone.on('conference:invitation-rejected', onInviteRejected);
Then use the phone.addParticipant method to adds participant, e.g.,
function addParticipant(participant) {
phone.addParticipant('11231231234');
phone.addParticipant(participant);
}
First register for conference:participant-removed event, which is published when the participant is successfully removed from the current conference.
phone.on('conference:participant-removed', onParticipantRemoved);
function removeParticipant(participant) {
Use the phone.removeParticipant method with the participant’s ID to remove a participant from the current conference, e.g.,
phone.removeParticipant(participant);
phone.removeParticipant('john@domain.com');
}
function getParticipants() {
Use the phone.getParticipants method to get the list of active participants.
return phone.getParticipants();
}
function rejectConference() {
Use the phone.rejectConference method to reject the incoming conference invite.
phone.rejectConference();
}
Register for conference:disconnecting event; it is published immediately after invoking phone.endConference.
phone.on('conference:disconnecting', onConferenceDisconnecting);
function endConference() {
Use the phone.endConference method to end the current conference.
phone.endConference();
}
The phone object provides utility methods for common tasks related phone number parsing and formatting.
function cleanPhoneNumber(phoneNum) {
In order to get the phone number in a format that the library can use to
dial, use the phone.cleanPhoneNumber method, it will convert numbers like
+1 (123) 123 1234
to 11231231234
,
and 1800CALFEDX
to 18002253339
.
return phone.cleanPhoneNumber(phoneNum);
}
function getCallerInfo(callerUri) {
In order to get the caller information like protocol, caller-id and domain we can use
the phone.getCallerInfo method,
it will convert callerUri like
sip:+1111@icmn.api.att.com
to an object like
{
protocol: 'sip',
callerId: '+1111',
domain: 'icmn.api.att.com'
}
.
return phone.getCallerInfo(callerUri);
}
The phone object provides methods to use DTMF functionality when in a call..
The dtmf:tone-sending event is published immediately after tone request is sent.
phone.on('dtmf:tone-sending', onToneSending);
The dtmf:tone-sent event is published immediately after signal is passed into streams successfully.
phone.on('dtmf:tone-sent', onToneSent);
function sendDTMFTone(tone) {
Once you have registered handlers for all appropriate events you can use the phone.sendDTMFTone method on Phone to start send a DTMF tone.
phone.sendDTMFTone({
input: tone,
gap: 60
});
}
loadSampleApp();