How to configure WCS5 for Freepbx

Max

Administrator
Staff member
Hello

1. You can pass account details directly to JavaScript

- SIP username
- SIP authname
- SIP password
- SIP domain
- SIP proxy
- SIP port

2. You can implement custom /connect endpoint

WCS will call your /connect endpoint, i.e.

POST

Your endpoint should reply 200 OK and SIP details

Full request response examples:

Code:
{
  "nodeId" : "fTS3zN0ouFNT9Nzji5y6SSCaupOLzscL@188.40.244.249",
  "appKey" : "defaultApp",
  "sessionId" : "/115.221.214.167:37018/188.40.244.249:8443-8f47f720-e7b3-4ae0-b4aa-6f139d562700",
  "sipRegisterRequired" : true,
  "sipLogin" : "10001",
  "sipAuthenticationName" : "10001",
  "sipPassword" : "xaPK345iGjv5458",
  "sipDomain" : "voip.mycompany.com",
  "sipOutboundProxy" : "voip.mycompany.com",
  "sipPort" : 5060,
  "useWsTunnel" : false,
  "useWsTunnelPacketization2" : false,
  "msePacketizationVersion" : 2,
  "useBase64BinaryEncoding" : false,
  "mediaProviders" : [ "WebRTC", "MSE", "WSPlayer" ],
  "clientVersion" : "2.0",
  "clientOSVersion" : "5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36",
  "clientBrowserVersion" : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36",
  "keepAlive" : true,
  "origin" : "https://demo.flashphoner.com"
}
Code:
{
  "nodeId" : "fTS3zN0ouFNT9Nzji5y6SSCaupOLzscL@188.40.244.249",
  "appKey" : "defaultApp",
  "sessionId" : "/115.221.214.167:37018/188.40.244.249:8443-8f47f720-e7b3-4ae0-b4aa-6f139d562700",
  "sipRegisterRequired" : true,
  "sipLogin" : "10001",
  "sipAuthenticationName" : "10001",
  "sipPassword" : "xaPK345iGjv5458",
  "sipDomain" : "voip.mycompany.com",
  "sipOutboundProxy" : "voip.mycompany.com",
  "sipPort" : 5060,
  "useWsTunnel" : false,
  "useWsTunnelPacketization2" : false,
  "msePacketizationVersion" : 2,
  "useBase64BinaryEncoding" : false,
  "mediaProviders" : [ "WebRTC", "MSE", "WSPlayer" ],
  "restClientConfig" : {
    "ConnectionStatusEvent" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "RegistrationStatusEvent" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "sendXcapRequest" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "XcapStatusEvent" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "sendDtmf" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "call" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "OnCallEvent" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "answer" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "hangup" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "hold" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "unhold" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "transfer" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "OnTransferEvent" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "TransferStatusEvent" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "CallStatusEvent" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "sendMessage" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "OnMessageEvent" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "MessageStatusEvent" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "publishStream" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "unPublishStream" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "playStream" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "stopStream" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "StreamStatusEvent" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "subscribe" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "SubscriptionStatusEvent" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "OnDataEvent" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "DataStatusEvent" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "submitBugReport" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "BugReportStatusEvent" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "pushLogs" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "RecordingStatusEvent" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "ErrorStatusEvent" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "disconnect" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    },
    "StreamKeepAliveEvent" : {
      "restExclude" : "",
      "clientExclude" : "",
      "restOverwrite" : "",
      "restOnError" : "FAIL",
      "restPolicy" : "NOTIFY"
    }
  },
  "clientVersion" : "2.0",
  "clientOSVersion" : "5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36",
  "clientBrowserVersion" : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36",
  "keepAlive" : true,
  "origin" : "https://demo.flashphoner.com"
}
 
Last edited:

JBDiesel

New Member
Perhaps I am not stating what I need correctly.
We already have: wss://ebtsweb.xposeurope.eu:8443 as u have previously helped me with and it is Working but this is direct to my provider going around my Freepbx system.

I wish to create something like wss://pbx1web.xposeurope.eu:8443 & wss://pbx2web.xposeurope.eu:8443
To send traffic over my two Freepbx installations also located on AWS Germany and Ireland

I can create the new pbx1web and pbx2web fwd in godaddy for this but I am not sure what is needed for WSS to work with freepbx as such.

Many thanks in Advance,

Jason
 

Max

Administrator
Staff member
I wish to create something like wss://pbx1web.xposeurope.eu:8443 & wss://pbx2web.xposeurope.eu:8443
To send traffic over my two Freepbx installations also located on AWS Germany and Ireland
You don't need to set up a new WCS instance to make a calls via another PBX. You can just use a SIP outbound proxy needed as we described above. In this case all WebRTC traffic goes through single WCS instance, but SIP traffic goes through selected PBX.
I can create the new pbx1web and pbx2web fwd in godaddy for this but I am not sure what is needed for WSS to work with freepbx as such.
If you want to separate a SIP calls depending on server address, you should check the Origin header in you Javascript code and set up SIP credentials depending on the header value.
 

Max

Administrator
Staff member
If you want just force particular PBX, you can add two lines into config file /usr/local/FlashphonerWebCallServer/conf/flashphoner.properties
Then restart server process: systemctl restart webcallserver

Code:
outbound_proxy = my.pbx.com
outbound_port = 5060
Here my.pbx.com - is IPv4 address or FQDN (domain name) of your PBX server.
 

Max

Administrator
Staff member
Good day.
You've sent an access to one server, IP address for second server and SIP credentials. Please clarify what exactly you want us to do. Also, to test a SIP call we need two SIP accounts: caller and callee.
 

Max

Administrator
Staff member
You have sent access to Asterisk servers. But all setup should be done at WCS side by two possible ways:
1. Set the needed outbound proxy in frontend Javascript code (Phone Min example)
Code:
    var outboundProxy;
    
    if (window.location.hostname === "pbx1web.xposeurope.eu") {
        outboundProxy = "ebtspbx1.xposeurope.eu";
    } else if (window.location.hostname === "pbx2web.xposeurope.eu") {
        outboundProxy = "ebtspbx2.xposeurope.eu";
    }
    var sipOptions = {
        login: sipLogin,
        authenticationName: sipLogin,
        password: sipPassword,
        domain: outboundProxy,
        outboundProxy: outboundProxy,
        port: sipPort,
        registerRequired: true
    };

    var connectionOptions = {
        urlServer: url,
        keepAlive: true
        sipOptions: sipOptions
    };

    //create session
    console.log("Create new session with url " + url);
    Flashphoner.createSession(connectionOptions).on(SESSION_STATUS.ESTABLISHED, function(session, connection){
        setStatus("#regStatus", SESSION_STATUS.ESTABLISHED);
        $("#authToken").val(connection.authToken);
        onConnected(session);
        if (!registerRequired) {
            disableOutgoing(false);
        }
    }).on(SESSION_STATUS.REGISTERED, function(session){
        ...
    });
}
So you should deploy a two web servers (or one web server with two domain names for users to open in browsers) pbx1web.xposeurope.eu and pbx2web.xposeurope.eu to place a web page with a modified Javascript code
2. Use the REST hook /connect to set the needed outbound proxy depending on web page domain. In this case you should deploy a separate backend server to handle REST hooks (see a backend script example)
 

JBDiesel

New Member
Sorry I have been ill last weeks - But I did make this for use for WCS - normally u have all login / key info - Can we send ANY CLI over this as it is a backup sytem for Purecloud PBX Service?

pbx1web.logistixcall.com
1711372387252.png
 

JBDiesel

New Member
to logisitxcall domain vs test XPOS Domain via DIDWW- which can stay Live - Freepbx instances go to logistixcall domain
But Normall All should flow thru Logistixcall domain
 

JBDiesel

New Member
The Plan is to have PBX 1 as primary and PBX 2 as Failover/Backup via FreePBX. These instances allow for Any CLI to be sent as client owns Multiple CLI's and should their Purecloud PBX go down - as it does they send traffic via my PBX as well as Premium number dialing overall. So they are asking for a web based solution via our PBX system to go around Purecloud when it is not available and have all the features and functions of my platform. However they are standoffish on bringing all a whole new set of DID's for backup. So they want to use our platform to complete open repair cases, this is short sighted indeed which is why we setup the 1st system allowing me to give new DID's in place of non-working ones via Purecloud. That said I allow premium number calling via my PBX system and they would like to expand my services to them but using only a web interface vs physical phones used with Purecloud and not being able to call some premium / toll charged numbers - something only I provide to them via Trunk to Purecloud but not stand alone. I would like to make a stand alone backup platform for them in all respects. That said I can only provided 2ndary DID's with current setup for IN/OUT this config is for OUT Only with ANY CLI depending on the nation they are providing contracted support.

So for example:
1711375182351.png

But we don't resolve with DNS we use IP/IP Auth. this is just a nonused backup way in DNS Table for our Trunk to Purecloud. As due to hacking we have found this most secure P to P IP.
 
Last edited:

Max

Administrator
Staff member
If you have two PBX domains, and you want to connect one of them to make a call, you should use RegistrationStatusEvent REST hook to check if connection to PBX is successful. Your backend receives ConnectionStatusEvent then RegistrationStatusEvent if PBX is available and ConnectionStatusEvent only if not
Code:
08:16:53,523 INFO            RestClient - API-ASYNC-pool-7-thread-16 SEND REST OBJECT ==>
URL:http://localhost:8081/apps/EchoApp/ConnectionStatusEvent
OBJECT:
{
  "nodeId" : "d2hxbqNPE04vGeZ51NPhDuId6k3hUrBB@95.191.130.39",
  "appKey" : "defaultApp",
  "sessionId" : "/*.*.*.*:50150/*.*.*.*:8443-21d8ffe5-add4-497d-a484-c0dee0dde05a",
  "sipRegisterRequired" : true,
  "sipLogin" : "10006",
  "sipAuthenticationName" : "10006",
  "sipPassword" : "*******",
  "sipDomain" : "pbx1.flashphoner.com",
  "sipOutboundProxy" : "pbx1.flashphoner.com",
  "sipPort" : 5060,
  "useWsTunnel" : false,
  "useWsTunnelPacketization2" : false,
  "msePacketizationVersion" : 2,
  "useBase64BinaryEncoding" : false,
  "mediaProviders" : [ "WebRTC", "MSE", "WSPlayer" ],
  "authToken" : "42e0ed52-bb95-49c4-88a7-cf3ad729b910",
  "status" : "ESTABLISHED",
  "clientVersion" : "2.0",
  "clientOSVersion" : "5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
  "clientBrowserVersion" : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
  "keepAlive" : true,
  "origin" : "https://wcs:8444"
}
...
08:16:53,766 INFO            RestClient - API-ASYNC-pool-7-thread-14 SEND REST OBJECT ==>
URL:http://localhost:8081/apps/EchoApp/RegistrationStatusEvent
OBJECT:
{
  "nodeId" : "d2hxbqNPE04vGeZ51NPhDuId6k3hUrBB@95.191.130.39",
  "appKey" : "defaultApp",
  "sessionId" : "/*.*.*.*:50150/*.*.*.*:8443-21d8ffe5-add4-497d-a484-c0dee0dde05a",
  "status" : "REGISTERED"
}
So if you have REGISTERED status, you can make a call. Otherwise, you should disconnect the session and try to register to pbx2.
Read more about REST hooks here
 
Last edited:
Top