Integrating WebRTC Phone into Web Pages Using CommPeak

Learn how to configure calling functionality in your web-based software using WebRTC via CommPeak.

If your SIP account is configured with JWT authentication, you can integrate calling functionality directly into your web page using WebRTC technology via CommPeak. This allows users to make and receive calls directly from their browser.

Using JsSIP for WebRTC Integration

Before integrating JsSiP for WebRTC Calling, ensure you have the following prerequisites:

  1. SIP Account with JWT Authentication Enabled
    You'll need a SIP account configured to use JWT authentication. Follow this guide if you haven't set one up yet.

  2. JWT Token Generation Endpoint
    Set up an HTTP endpoint capable of generating and signing JWT tokens using the secret key configured for your SIP account.

  3. Secure Hosting with HTTPS
    WebRTC requires a secure context, so your web application MUST be served over HTTPS.

  4. Basic Knowledge of JavaScript
    A working understanding of JavaScript is helpful, as you'll need to write scripts to initialize and control the WebRTC Softphone with CommPeak.

  5. Modern Web Browser
    Ensure you're using an up-to-date browser that supports WebRTC (e.g., Chrome, Firefox, Edge).

Creating Your First WebRTC Softphone

Adding Required HTML Elements

To start using the JsSIP library on your website, insert the following snippet into your HTML page. This will load JsSIP directly from a CDN and add the necessary HTML elements for operating the WebRTC Softphone, so you're ready to go without any additional setup.

<!-- Add JsSIP script from CDN -->
<script type="text/javascript" src="https://jssip.net/download/releases/jssip-3.10.0.min.js"></script>

<!-- HTML Element to handle the Audio Stream (required) -->
<audio id="remoteAudio"></audio>

<!-- DIV element holding current connection status (optional) -->
<div id="callStatus">offline</div>
<!-- DIV element holding current call duration (optional) -->
<div id="durationTimer">N/A</div>

Defining the Authentication Function

To authenticate your application, you'll need to fetch a JWT token. The code below uses the fetch function, as outlined in the official documentation:

const getJwtToken = async function() { 
  try {
    const response = await fetch('https://your-auth-endpoint.com/token');

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    // Handle response from your endpoint, this is a simple example of a plain text answer
    const token = await response.text();
    return token; 
  } catch (error) {
    console.error('Failed to retrieve JWT token:', error);
  }
}
❗️

IMPORTANT

Ensure that the JWT token payload includes the sub specified for your SIP account (Edit SIP Account > Authentication section, next to the JWT signature secret)

Editing SIP account: allowing JWT authentication

Editing SIP account: allowing JWT authentication

An expiration timestamp (exp) is also required. Best practice is to set it to 1 minute.

For detailed reference about JWT payload, refer to the official documentation.

Initializing WebRTC Softphone for CommPeak Cloud

To initialize the library and establish a connection with CommPeak Cloud, follow these instructions:

// Function to update contents of status DIV
let updateCallStatus = function(msg) {
  document.getElementById('callStatus').innerText = msg;
}

// Variable holding WebRTC phone
let commpeakPhone = null;

// Function updating JWT token for connection
let updateJwtToken = async function() { 
  const token = await getJwtToken(); 
  commpeakPhone.set('authorization_jwt', `Bearer ${token}`);
}

async function initializeJsSIP() {
  // Getting initial JWT Token
  const token = await getJwtToken(); // We defined this function in the previous step

  // Defining websocket connection to connect to
  const socket = new JsSIP.WebSocketInterface('wss://sip.commpeak.com:7443');
  // Setting configuration for WebRTC Phone
  const configuration = {
    sockets: [socket],
    uri: 'sip:[email protected]', // Replace your_username with actual SIP Account username
    authorization_jwt: `Bearer ${token}`,
    session_timers: true,
    register_expires: 60
  };

  // Initializing CommPeak WebRTC Softphone
  commpeakPhone = new JsSIP.UA(configuration);
  commpeakPhone.start();
  
  // Defining basic events for the CommPeak WebRTC Softphone
  commpeakPhone.on('connected', function() {
    updateCallStatus('Connected to CommPeak Cloud');
  });

  commpeakPhone.on('registered', function() {
    updateCallStatus('Successfully registered');
  });

  commpeakPhone.on('registrationFailed', function(e) {
    updateCallStatus('Registration failed:', e.cause);
  });

  commpeakPhone.on('disconnected', function() {
    updateCallStatus('Disconnected from CommPeak Cloud');
  });
  
  // Setting interval to preserve validity of JWT Token every 50 seconds, since the token is typically defined to be valid for 60 seconds only
  let timer = setInterval(updateJwtToken, 50000);
}

// Variable holding audio element for attaching audio streams
let remoteAudio = document.getElementById('remoteAudio');

// Audio stream related variables
var onplaying = true, 
    onpause = false;

// Toggle variables for audio
remoteAudio.onplaying = function() {
  onplaying = true;
  onpause = false;
};

// Toggle variables for audio
remoteAudio.onpause = function() {
  onplaying = false;
  onpause = true;
};

// Starting CommPeak WebRTC Phone
await initializeJsSIP();

Adding Dialing Functionality to CommPeak WebRTC Softphone

After initializing and registering your WebRTC Softphone with CommPeak Cloud, you can enable dialing to start making calls directly from your browser.

Follow these steps to add calling functionality to your CommPeak WebRTC Softphone:

// Variable that will hold the actual running call
var callSession = null;
// Variables that will hold duration timer function interval and actual duration counter
var durationInterval = null, callDuration = 0;

// Function to originate an outgoing call
let issueCall = function(destination) {
  if (!commpeakPhone.isConnected() || !commpeakPhone.isRegistered()) {
    alert("Phone is not connected");
    return;
  }
  callSession = commpeakPhone.call(
    `sip:${destination}`,
    {
      mediaConstraints: { audio: true, video: false },
    }
  );
};

// Function that hangs up active call
let hangup = function () {
  if (callSession != null) {
    callSession.terminate();
  }
}

// Function handling duration counter
let tickDuration = function() {
  callDuration += 1;
  document.getElementById('durationTimer').innerText = `${callDuration} seconds`;
}

// Function to be executed after call is answered in order to enable counter
let callStartEvent = function() {
  durationInterval = setInterval(tickDuration, 1000);
}

// Function to be executed after call hangup, resets variables and stops duration timer interval
let callEndEvent = function() {
  callSession = null;
  clearInterval(durationInterval);
  document.getElementById('durationTimer').innerText = 'N/A';
  callDuration = 0;
};

// Function handling normal or error hangup
let getCallEndReason = function (data) {
    var msg = 'Call Ended';
    if (data.message != null && typeof data.message.status_code != 'undefined' && data.message.status_code != 200) {
      // Getting call error in case session failed
      msg += `: ${data.message.status_code} ${data.message.reason_phrase}`;
    }
    updateCallStatus(msg);
  }

// Handler of new call event for both incoming and outgoing calls, only outgoing call is described here
commpeakPhone.on('newRTCSession', function(e) {
  if (callSession != null) {
    // This is required to handle a second call while one is already ongoing, callSession holds actively running call, so we will hang up another session
    e.session.terminate();
    return;
  }

  // Assigning current session to globally available variable
  callSession = e.session;

  updateCallStatus('dialing');

  callSession.connection.ontrack = function(e){
    // Handle remote audio stream to connect it to local audio
    remoteAudio.srcObject = e.streams[0];
    if (remoteAudio.paused && !onplaying) {
      remoteAudio.play();
    }
  };

  // Fired when remote side starts ringing
  callSession.on('progress', function(data) {
    updateCallStatus('ringing');
  });

  // Fired when the call is answered
  callSession.on('accepted', function(data) {
    callStartEvent();
    updateCallStatus('answered');
  });
  // Fired when a running call ends.
  callSession.on('ended', function(data) {
    callEndEvent();
    getCallEndReason(data);
  });
  // Fired when the session was unable to establish (before an answer was received).
  callSession.on('failed', function(data) {
    callEndEvent();
    getCallEndReason(data);
  });
});

Making Your First WebRTC Call via CommPeak Cloud

By executing this function, you will dial CommPeak's special number to perform an echo test call, allowing you to verify audio quality and connectivity:

issueCall('07777712125552665')

To end the active call session, use the hangup function:

hangup()