Web Call

This section describes how to use the SIP.js web plugin to interconnect to Opentact's SIP Gateway. You can use this demo to connect to your SIP Domain using the SIP User you created.

Fetch SIP.js sources

git clone https://github.com/onsip/SIP.js.git SIP.js

Install dependencies

cd SIP.js
npm install

Edit a demo-1.html

Demos placed in SIP.js/demo folder

Add CryptoJS library

<head>
  <meta charset="utf-8" />
  <title>SIP.js Demo 1</title>
  <link rel="stylesheet" type="text/css" href="./demo-1.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/core.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/md5.js"></script>
</head>

Add some input boxes

<ol>
    <li><button id="connect" disabled>Connect</button> with <code><input type="text" size="12" id="username" placeholder="user" value="anne">:<input type="text" size="12" id="password" value="Test123" placeholder="password">@<input type="text" size="48" id="server" placeholder="wss server"></code></li>
    <li><button id="call" disabled>Place Call</button> with <code><input type="text" size="48" id="target" placeholder="sip address"></code></li>
    <li><button id="hangup" disabled>Hangup Call</button></li>
    <li><button id="disconnect" disabled>Disconnect</button></li>
</ol>

Edit demo-1.ts

Add input boxes helpers

// const serverSpan = getSpan("server");
// const targetSpan = getSpan("target");
const connectButton = getButton("connect");
const callButton = getButton("call");
const hangupButton = getButton("hangup");
const disconnectButton = getButton("disconnect");
const audioElement = getAudio("remoteAudio");
const keypad = getButtons("keypad");
const dtmfSpan = getSpan("dtmf");
const holdCheckbox = getInput("hold");
const muteCheckbox = getInput("mute");

// here is new
const serverInput = getInput("server");
const usernameInput = getInput("username");
const passwordInput = getInput("password");
const targetInput = getInput("target");

Edit a connection settings

// WebSocket Server URL
const webSocketServer = "wss://my_domain.sip.opentact.org:5443";
// serverSpan.innerHTML = webSocketServer;
serverInput.value = webSocketServer;

// Destination URI
const target = "sip:user2@my_domain.sip.opentact.org";
// targetSpan.innerHTML = target;
targetInput.value = target;

// Name for demo user
const displayName = "User1 Name";

Add answer confirm question

// SimpleUser delegate
const simpleUserDelegate: SimpleUserDelegate = {
    onCallCreated: (): void => {
    console.log(`[${displayName}] Call created`);
    callButton.disabled = true;
    hangupButton.disabled = false;
    keypadDisabled(true);
    holdCheckboxDisabled(true);
    muteCheckboxDisabled(true);
  },
  onCallAnswered: (): void => {
    console.log(`[${displayName}] Call answered`);
    keypadDisabled(false);
    holdCheckboxDisabled(false);
    muteCheckboxDisabled(false);
  },
  onCallHangup: (): void => {
    console.log(`[${displayName}] Call hangup`);
    callButton.disabled = false;
    hangupButton.disabled = true;
    keypadDisabled(true);
    holdCheckboxDisabled(true);
    muteCheckboxDisabled(true);
  },
  onCallHold: (held: boolean): void => {
    console.log(`[${displayName}] Call hold ${held}`);
    holdCheckbox.checked = held;
  },
  
  // Here is changes
  onCallReceived: async (): Promise<void> => {
    console.log(`[${displayName}] Call received`);
    keypadDisabled(false);
    holdCheckboxDisabled(false);
    muteCheckboxDisabled(false);
    if (confirm("ACCEPT INCOMING CALL?")) await simpleUser.answer();
  }
};

Change auth method

// SimpleUser construction
let simpleUser: SimpleUser; // change SU object creation

// Add click listener to connect button
connectButton.addEventListener("click", () => {
  // here is changes

  // eslint-disable-next-line @typescript-eslint/prefer-regexp-exec
  const domain = serverInput.value.match(/^.+:\/\/([^:]+):?\d*$/)?.[1] || "";

  const aor = `sip:${usernameInput.value}@${domain}`;

  // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
  // @ts-ignore
  const ha1 = CryptoJS.MD5(`${usernameInput.value}:${domain}:${passwordInput.value}`).toString(); // md5(<login>:<domain>:<password>)
  console.log("HA1:", `${usernameInput.value}:${domain}:${passwordInput.value}`, ha1, aor);

  simpleUser = new SimpleUser(serverInput.value, {
    ...simpleUserOptions,
    userAgentOptions: {
      ...simpleUserOptions.userAgentOptions,
      authorizationHa1: ha1,
      authorizationUsername: usernameInput.value,
      authorizationPassword: passwordInput.value
    },
    aor
  });
  

  connectButton.disabled = true;
  disconnectButton.disabled = true;
  callButton.disabled = true;
  hangupButton.disabled = true;
  simpleUser
    .connect()
    // register SU after connecting
    .then(() => simpleUser.register())
    .then(() => {
      connectButton.disabled = true;
      disconnectButton.disabled = false;
      callButton.disabled = false;
      hangupButton.disabled = true;
    })
    .catch((error: Error) => {
      connectButton.disabled = false;
      console.error(`[${simpleUser.id}] failed to connect`);
      console.error(error);
      alert("Failed to connect.\n" + error);
    });
});

Change call button event

// Add click listener to call button
callButton.addEventListener("click", () => {
  callButton.disabled = true;
  hangupButton.disabled = true;
  simpleUser.call(getInput("target").value).catch((error: Error) => {
    console.error(`[${simpleUser.id}] failed to place call`);
    console.error(error);
    alert("Failed to place call.\n" + error);
  });
});

Build and deploy demos

npm run build-demo

Finally, you can put the demo folder to website.

Last updated