Blind Call Transfer in Asterisk | ari-client (Node.js) - node.js

Precise overview about the flow:
I am calling my initial extension(100) using Zoiper through Twilio sip domain using Zoiper as soft phone which actually direct the call to my asterisk server.
Now when my call is in asterisk server I'm trying to forward it to another extension using Zoiper. I have already configured it according to documentation provided by asterisk will also be attaching the reference links.
I just want to forward the current call to a particular extension. So please can anyone guide me that how it can be possibly done?
ari-client
bridge.once(‘BridgeAttendedTransfer’, event => {
var transferee = new ari.Channel(event.transferee.id);
transferee.continueInDialplan({
context: event.context,
extension: event.exten,
priority: 1
});
});
extension.conf
exten => 201,1,Dial(SIP/201,20,tT)
features.conf
blindxfer = #2 ("#2" or "##" instead of "#1")
atxfer = *2
transferdigittimeout = 1; Number of seconds to wait between digits when transferring a call
xfersound = beep ; to indicate an attended transfer is complete
xferfailsound = beeperr ; to indicate a failed transfer
transferdialattempts = 3 ; Number of times that a transferer may attempt to dial an extension before
being kicked back to the original call.
transferretrysound = "beep" ; Sound to play when a transferer fails to dial a valid extension.
transferinvalidsound = "beeperr" ; Sound to play when a transferer fails to dial a valid extension
Using Zoiper to make a transfer
References:
https://wiki.asterisk.org/wiki/display/AST/Feature+Code+Call+Transfers
https://www.aska-ltd.jp/en/blog/185
https://community.asterisk.org/t/call-transfer-not-working-on-softphones/33817
https://asteriskfaqs.org/2020/12/22/uncategorized/handling-transfers-with-ari.html
Trying to implement blind call transfer.

Related

Dial pad implementation for reply extensions in Twilio SDK

I'm implementing call based application using twilio SDK and Ract + Node.js. I have the following requirement.
During an incoming or outgoing (audio) call, a user(any user that’s using the system to call) should be able to see the number pad button.A user should be able to open a popup with the number pad and be able to press numbers. When a user uses the dial pad to press numbers the pressed numbers should be communicated to the other end.
I tried searching the documentation for related methods. found that we can use SendDigits function and implemented some basic logic to trigger when click on a custom button on call screen. but it seems it is not sending the data to other end.
const sendDigit = () => {
console.log("Press 1");
outboundCall.sendDigit('1');
};
if anyone can guide me on how to do this would be a great help. basically, I want to have a dial pad on incoming and outgoing calls and then send press buttons according to the request by other end.
Your code has a function call to sendDigit but the function is called sendDigits.
const sendDigit = () => {
console.log("Press 1");
outboundCall.sendDigits('1');
};

Transfer a call programmatically inside a FreeSWITCH node-esl server when it is already bridged to another endpoint

I am trying to transfer the call that is connected to node-esl. I have successfully bridged that call to another endpoint. Now, I want to programatically transfer that call over to another extension or another number without the call flow being cut.
I had set the hangup after bridge to be false. However, I am not able to transfer the calls. The npm package I use is "modesl".
I had also tried to bridge the calls (which is not the requirement, since the call should be live when it is transferred).
I have the UUID of that call, which can be transferred as conn. execute or as conn.api.
var esl = require('modesl');
var esl_server = new esl.Server({port: 8085, myevents:true}, function(){
console.log("esl server is up");
});
esl_server.on('connection::ready', function(conn, id) {
conn.execute('answer');
conn.execute('set',"hangup_after_bridge=false");
conn.execute('bridge','name_of_the_bridge'); `
// conn.api('uuid_transfer',uuid,'-bleg or both',description,dialplan, context
conn.api('uuid_transfer',id,'-bleg',1000,'XML','default');}
The calls get disconnected as the commands get executed. Please look into this and let me know your answers.
You need to attach parameters as one string argument. Like:
esl_server.on('connection::ready', function(conn, id) {
conn.execute('answer');
conn.execute('set',"hangup_after_bridge=false");
conn.execute('bridge','name_of_the_bridge'); `
conn.api('uuid_transfer',id + ' -bleg 1000 XML default');
}

how to make outgoing call from freeswitch and play file after destination answer call?

I want to write a web app that connects to freeswitch and makes outgoing call to some destination number (gateway for landline or internal sip devices) and plays some sounds (may be do some logic in lua script).
After reading freeswitch wiki, I found originate command but it doesn't work for me (I just test for internal sip number - sofia/internal/username#ip ). If originate command can do this, how to use it properly? If there is another way please tell me.
Originate command is used to make the call and bridge command is used to bridge the call. You can call originate command externally by using esl socket.
Examples:
originate {ignore_early_media=true,originate_timeout=60}sofia/gateway/name/number &playback(message)
Refer to this for esl written in node.js
https://github.com/englercj/node-esl
one way that I test and it work is run a lua script from freeswitch console or ESL:(ex "luarun test.lua")
https://freeswitch.org/confluence/display/FREESWITCH/Lua+API+Reference#LuaAPIReference-session:hangupCause
obSession = freeswitch.Session("sofia/192.168.0.4/1002")
-- Check to see if the call was answered
if obSession:ready() then
-- Play file here
else
-- This means the call was not answered ... Check for the reason
local obCause = obSession:hangupCause()
freeswitch.consoleLog("info", "obSession:hangupCause() = " .. obCause )
if ( obCause == "USER_BUSY" ) then -- SIP 486
-- For BUSY you may reschedule the call for later
elseif ( obCause == "NO_ANSWER" ) then
-- Call them back in an hour
elseif ( obCause == "ORIGINATOR_CANCEL" ) then -- SIP 487
-- May need to check for network congestion or problems
else
-- Log these issues
end
end
You can do it very easily from dial plan:
<action function="play-file" data="myfile.wav"/>
You can make the wav play when someone start a call, follow these steps.
Place your wave into your freeswitch/conf folder.
Add the code bellow to your freeswitch/conf/autoload_configs
Run a HTTP server that receives a POST request and returns your dialplan(which tells freeswitch to play your wav).
Make sure your freeswitch/conf/autoload_configs/xml_curl.conf.xml looks like this
<param name="gateway-url" value="http://yourIP:yourServerPort/dialplan.xml" bindings="dialplan"/>
Hope this helps.
you can achieve By using a socket[ESL] application.
https://wiki.freeswitch.org/wiki/Event_Socket_Outbound

How to post from MetaTrader Terminal 5 MQL 5 a request to my nodejs server, which is running locally on my MT5 host?

I'm trying to get FX rates in my nodejs server and socke.io emit them to the client, while running MetaTrader Terminal 5 or 4.
So I guess I have to use MQL4/5. I know how the handle the request in my nodejs server. What I dont know is where to write the MQL4 code, what to config in my MetaTrader Terminal.
Lets say I want to send EUR/USD bid rate to my nodejs server everytime it gets changed. How do I achieve that, using MT4/5 and MQL4/5?
My nodejs code:
app.post('/fxroute', (req, res) => {
console.log(req);
let fxRates = req.body // dont know if the payload will be in body
socket.emit('fxRates', fxRates);
});
MQL5 script:
#property copyright "Copyright 2017, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart(){
string headers;
char data[],
result[];
string str = "data=value"; // POST-data, variables to send
StringToCharArray( str, data );
string b = CharArrayToString( data );
Print( "Test:", b ); // just a test of data, if good ... OK, data was setup correctly.
WebRequest( "POST",
"http://localhost:3000/fxroute",
NULL,
NULL,
3000,
data,
ArraySize( data ),
result,
headers
);
Print( CharArrayToString( result ) ); // see the results
// it returns
// "Results:" No posted data.
}
When I compile and run, I see that it was executed in MT Experts tab, but on my nodejs server, console logs nothing.
Plan of work:
Enable MT4/5 to use {http:|https:} transport-class to selected targets
Create MT4/5 code to execute some kind of {http:|https:} based service
Implement end-to-end logic to be wrapped + hidden inside the dumb http-protocol exchanges
1) Terminal permissions:
Using Terminal->Tools->Options enable [x] "Allow a WebRequest URL" to use a localhost {http:|https:} URL of your choice, matching the nodejs-server setup, in the list
2) WebRequest() code inside event-loop
Given your intentions, create an MQL4 script, using either a built-in IDE F4 or using an external editor of your choice and save the produced .mq4 script file in ~an_MT4_Terminal_Home_Directory/MQL4/Scripts directory
The event-loop is principally your design job:
int start() {
while !isStopped() { // ACK LOOP
if ( RefreshRates() ) { // NEW QUOTE has arrived
... // JOB PROCESS Bid
int aHttpRetCODE = WebRequest(...); // SIG-> NodeJS Server
... // JOB PROCESS Response ( if a bi-directional service )
}
else {
Sleep(...); // NOP on NACK, Terminal has nothing to do
}
}
}
For further details, may like to check my other posts on WebRequest() use-cases and warnings about it's principal limitations.
3) end-to-end logic
Here comes the creme-ala-creme of your design.
Is there any other way?
Yes, there is. That would be the one of my choice - using ZeroMQ or nanomsg on both sides ( MT4/5 Terminal & NodeJS ), thus being able to fully enjoy the freedom of a full-scale distributed systems design ( check the principal aMiniRESPONDER()-prototype example structure for [SIG,MSG] jobs in fully distributed systems ) .
You can also try MetaApi https://metaapi.cloud cloud service which provides REST API and WebSocket API access to both MetaTrader 4 and MetaTrader 5 accounts.
Official REST API documentation: https://metaapi.cloud/docs/client
SDKs: https://metaapi.cloud/sdks (javascript, python and Java SDKs are provided as per April 2021)
It supports reading account information, positions, orders, trade history, receiving quotes, and accessing market data.
The service also provides copy trading API https://metaapi.cloud/docs/copyfactory and API to calculate forex trading metrics on a MetaTrader account https://metaapi.cloud/docs/metastats.

Issue with dialing REGISTERED (but offline) users

i'm facing the following scenario:
we have to local (REGISTERED) users (iOS apps pjSIP) which initiating local calls between each other.
the problem arise when one of the users (let's say user B) is closing the application few minutes after he successfully REGISTERS.
now, when user A tries to call user B we see that the INVITE is sent but we got no reply (e.g 180 ringing) from User B.
Note: when we are sending an invite to User B he get's Push notification to his device what cases him to open the app (and to Re-REGISTER)
our targets are:
1. determinate if user B (e.g the callee) is reachable before we are sending an INVITE in cases User B App is closed and his extension is still REGISTERED
2. be able to send invite to user B right after he REGISTER
we tried to solve this issue from many directions:
1.Qualify - tried to decrease the qualify time of the registersion period so user B will be UNAVAILABLE as soon as possible (and we will check the device state before we will dial) but it may cause to massive OPTIONS on our network, and it's not going to solve target #2
2.AMI Service - it can catch events like: User A Dials user B , User B is Ringing (180 Ringing) and save those statuses to ASTDB . all this logic will be prefomed before we will launch the dial.
this solution is clumsy and to cmplicated and it requires to watch yet another service
after some research i'v got to the conclusion that the most suitable solution will be to store the time of the last OPTIONS reply of each extension(requires a patch in chan_sip.c) . re-trigger sip options qualify request to user B before User A Dials . if the original value (e.g before we re-triggered the OPTIONS) is equal the value after we trigged the OPTIONS it means that User B has not replied OPTIONS.
i'm attaching the changes i'v preformed to complete this task.
i would like to know if solution for the issue is suitable and valid and of course if there is a better way to preform it.
These is the change in chan_sip (using asterisk 11.7)
i'v prefomed changes only on the following lines:
23492 to 23500
23485 /*! \brief Handle qualification responses (OPTIONS) */
23486 static void handle_response_peerpoke(struct sip_pvt *p, int resp, struct sip_request *req)
23487 {
23488 struct sip_peer *peer = /* sip_ref_peer( */ p->relatedpeer /* , "bump refcount on p, as it is being used in this function(handle_response_peerpoke)")*/ ; /* hope this is already refcounted! */
23489 int statechanged, is_reachable, was_reachable;
23490 int pingtime = ast_tvdiff_ms(ast_tvnow(), peer->ps);
23491
23492 time_t result = time(NULL);
23493 result = (int)result;
This is how should implement dialplan with the patch:
Dial(SIP/${dest},10,Rgb(check_extension,s,1));
I'm sending the call to context before inviting ( with the "b" option)
context check_extension {
s => {
Set(IS_REACHABLE=0);
Verbose(KOLA/LastQualify/${DEST}); // Display User B initial quliafy
Set(INITIAL_QUALIFY=${DB(KOLA/LastQualify/${DEST})}); // Store it
for(loop=0;${loop}<60;dialLoop=${loop}+1) { // Loop untill the qualify will be changes
System(/usr/sbin/asterisk -rx "sip qualify peer ${DEST}");
Wait(2); // we need to wait a while for a response
Set(LAST_QUALIFY=${DB(KOLA/LastQualify/${DEST})}); // set the new qualify
if (${LAST_QUALIFY} > ${INITIAL_QUALIFY}) { // if the new qualify is newer, User B is reachable
Set(IS_REACHABLE=1);
break;
}
}
if (${IS_REACHABLE} = 0) {
Verbose(Peer is not reachable);
Hangup();
}
}
}
Best option for that is not use asterisk.
Use kamailio or opensips project, it can handle thousands of options packets.
Also you HAVE rewrite your app so when it closed it UNREGISTER, as that described in sip RFC.
To summarize: you are using buggy application, and triing do on asterisk thing it not designed to(large amount of users with options). So correct answer - use correct tools for this task.

Resources