[ previous ] [ next ] [ threads ]
 To :  Michael Tremer <michael.tremer@i...>
 From :  Marian Podgoreanu <marian@v...>
 Subject :  Re: [yate] Initiating outgoing calls with Javascript
 Date :  Fri, 13 Mar 2015 09:35:28 +0200
Hi,

The id parameter is correct.

The 'target' parameter is used when you want someone to route the call 
for you.
This is not the situation.
The message should contain a 'callto' parameter with the call target.
If you don't know it use call.route to obtain a callto for call.execute.

Keep in mind the following:
The 'target' parameter of call.execute is used by some utility modules 
like dumbchan or wavefile to build a new call.
'Real' modules (like sip, iax ...) expects a 'callto' parameter whose 
value starts with their prefix (e.g. sip/).

Marian

On 12.03.2015 01:59, Michael Tremer wrote:
> Hello Marian,
>
> thanks again for the help.
>
> I suggest we fix one thing at a time. The CDR thing and the fork/ thing
> are not that important right now and I will look at them later again.
>
> I changed the id/peerid thing which works equally well. The main thing
> that is not working any more now is the chan.masquerade bit. I am so
> confused about all the IDs now :)
>
> On call.answered this is executed. msg is the call.answered message:
>
>    m = new Message("chan.masquerade");
>    m.message = "call.execute";
>    m.auth = true;
>    m.id = msg.id;
>    //m.callto = target;
>    m.target = channel.called;
>    m.caller = channel.caller;
>    m.called = channel.called;
>
>    success = m.dispatch();
>
>
> Generating this message:
>
> Sniffed 'chan.masquerade' time=1426116185.798231
>    thread=0x209fa40 'Engine Worker'
>    data=(nil)
>    retval='(null)'
>    param['message'] = 'call.execute'
>    param['auth'] = 'true'
>    param['id'] = 'sip/8'
>    param['target'] = '9999'
>    param['caller'] = '1000'
>    param['called'] = '9999'
>
> Directly after that comes this:
>
> Returned false 'call.execute' delay=0.000536
>    thread=0x209fa40 'Engine Worker'
>    data=0x7f25e400be00
>    retval='(null)'
>    param['auth'] = 'true'
>    param['id'] = 'sip/8'
>    param['target'] = '9999'
>    param['caller'] = '1000'
>    param['called'] = '9999'
>    param['handlers'] =
> 'tone:10,jingle:10,dumb:10,mgcpgw:10,sig:10,analog:10,filetransfer:10,iax:10,callfork:10,analyzer:10,conf:10,wave:10,sip:10,javascript:15,gvoice:20,queues:45,cdrbuild:50,yrtp:50,lateroute:7
> 5,tone:90,jingle:90,dumb:90,mgcpgw:90,sig:90,analog:90,filetransfer:90,iax:90,analyzer:90,conf:90,wave:90,sip:90,dbwave:90,callgen:100,moh:100,park:100,pbx:100,extmodule:100,callfork:100'
>    param['module'] = 'sip'
>    param['status'] = 'answered'
>    param['address'] = 'A.B.C.D:5060'
>    param['targetid'] = 'dumb/4'
>    param['billid'] = '1426110505-7'
>    param['peerid'] = 'dumb/4'
>    param['lastpeerid'] = 'dumb/4'
>    param['answered'] = 'true'
>    param['direction'] = 'outgoing'
>    param['domain'] = 'ipfire.org'
>    param['callid'] = 'sip/ABC@i.../DEF/GHI'
>
> No proper error message. Nothing really. It works well if I route the
> call first and then execute it by using callto. Although I am not so
> sure about whether I am using the right ID in the chan.masquerade
> message. Which one should this be?
>
> Best,
> -Michael
>
> On Mon, 2015-03-09 at 10:29 +0200, Marian Podgoreanu wrote:
>> Hi,
>>
>> For fork: when the dumb chan will be connected to answered channel it
>> will send a chan.connected message: this way you will know the new peer
>> of the dumb channel.
>> The fork module will send a 'chan.replaced' message after connect, you
>> may use it also.
>>
>> When a fork slave is answered the dumb chan will be connected to it
>> before you will handle the call.answered message.
>> You don't need to check the 'id' parameter of the call.answered message,
>> check the 'peerid' one: it will be the id of the dumb channel.
>>
>> On call execute failure: maybe you should post a yate log with message
>> sniffer enabled and debug level at 10 (-vvvvv command line option).
>>
>> I'm not sure I understand what are the issues related to cdr.
>> If you don't want some cdr entries in your database you can always catch
>> the cdr messages in your script and set 'cdrwrite' parameter to false.
>> If you want to use some custom cdr logging (e.g. choose what to log
>> based on your own criteria) you must implement the logic.
>>
>> Marian
>>
>> On 07.03.2015 18:45, Michael Tremer wrote:
>>> Hi Marian,
>>>
>>> thank you for your answers. Unfortunately I ran into new problems. Not
>>> sure how easy this is to fix.
>>>
>>> On Fri, 2015-03-06 at 10:19 +0200, Marian Podgoreanu wrote:
>>>> Hi,
>>>>
>>>> There is no need to route the call: the dumb channel will do it.
>>>>
>>>> This will be a global script, not a routing one.
>>>> You need to:
>>>> - Install handlers for chan.disconnected and call.answered without filters
>>>
>>> Done this.
>>>
>>>> - Remember tracked channels' id in a global variable (you may store
>>>> additional info also: like caller/called number)
>>>
>>> Done that.
>>>
>>>> - Remove tracked channels when handling chan.disconnected
>>>
>>> Done this as well.
>>>
>>> This is working well for plain SIP channels. I am using "fork" to allow
>>> users to register multiple phones. In that case, call.answered will have
>>> the ID of the call leg of the fork where I picked of the call and the
>>> peer ID of my initiated call is fork/7 or something.
>>>
>>> I assume that this is why you suggested to track chan.connected. I just
>>> don't see what I am supposed to do with it. When using the message
>>> sniffer I can see that call.answered is fired before chan.connected and
>>> therefore I cannot update my stored information about the initiated
>>> call.
>>>
>>>> - You may need to track chan.connected also (the second call will lead
>>>> to dumb chan to be disconnected)
>>>> - Keep in mind: the chan.disconnected message is sent only by the
>>>> channel beeing disconnected, it is not sent by both channels
>>>
>>> This is fine for me I guess.
>>>
>>>> About regexroute rule forbidding unauthorized calls:
>>>> I suppose it is set in route section so it won't affect the second call:
>>>> this one is executed, not routed
>>>
>>> It still didn't work for me. I had to add that all dumb/ channels are
>>> permitted to execute calls:
>>>
>>> [check_auth]
>>> ; Accept calls initiated by a script or a dumb channel
>>> ${auth}^true$=return
>>> ${driver}^dumb$=return
>>>
>>> ; Reject all the rest
>>> .*=echo Rejecting call ${caller} (${callername}, ${address}) -> ${called}
>>> .*=-;error=noauth
>>>
>>> [default]
>>> ; Check if the call is authorized
>>> ${username}^$=call check_auth
>>>
>>> I also cannot execute the second call. I have to route it first and then
>>> set callto to the result of the call.route message. I thought that this
>>> should work well with using chan.masquerade but it doesn't.
>>>
>>>           m = new Message("chan.masquerade");
>>>           m.message = "call.execute";
>>>           m.auth = true;
>>>           m.id = msg.id;
>>>           m.caller = channel.caller;
>>>           m.called = channel.called;
>>>           //m.target = channel.called;
>>>           m.callto = target;
>>>
>>>           success = m.dispatch();
>>>
>>>> CDR:
>>>> Yate creates an entry for each call leg.
>>>> Try to use the cdrcombine module if you want to put together a call.
>>>> See http://docs.yate.ro/wiki/CDRcombine_Module
>>>
>>> I changed my database layout and used the cdr_combine action now which
>>> is basically fine. The downside of that is that I am not able to do
>>> anything against having rejected calls in my log. Every time someone
>>> executes a call the user needs to authorize and that makes two SIP
>>> INVITE messages. The first one will always be logged.
>>>
>>> I also use linetracker to store in my database which calls are currently
>>> going on. This is very troublesome as well. I often get entries left
>>> over in the database and tons of error messages for rejected calls. This
>>> does not seem to be the solution for me.
>>>
>>> Any suggestions how I can generate a proper call log in my database of
>>> the calls that actually happened or timed out because nobody picked up
>>> or the line was busy and how I can have a table with the currently
>>> ongoing calls?
>>>
>>> This is my current setup:
>>>
>>> [call.cdr]
>>> ; Queries for the CDR updating message
>>>
>>> ; critical: boolean: Reject all registrations and routing if query fails
>>> critical=yes
>>>
>>> ;initquery=UPDATE cdr SET ended=true WHERE ended IS NULL OR NOT ended
>>>
>>> ;cdr_initialize=INSERT INTO cdr VALUES(TIMESTAMP 'EPOCH' + INTERVAL '${time} s', '${chan}', \
>>> ; '${address}', '${direction}', '${billid}', '${caller}', '${called}', INTERVAL '${duration} s', \
>>> ; INTERVAL '${billtime} s', INTERVAL '${ringtime} s', '${status}', '${reason}', false)
>>>
>>> ;cdr_update=UPDATE cdr SET address='${address}', direction='${direction}', billid='${billid}', \
>>> ; caller='${caller}', called='${called}', duration=INTERVAL '${duration} s', \
>>> ; billtime=INTERVAL '${billtime} s', ringtime=INTERVAL '${ringtime} s', status='${status}', \
>>> ; reason='${reason}' WHERE chan='${chan}' AND time=TIMESTAMP 'EPOCH' + INTERVAL '${time} s'
>>>
>>> ;cdr_finalize=UPDATE cdr SET address='${address}', direction='${direction}', \
>>> ; billid='${billid}', caller='${caller}', called='${called}', duration=INTERVAL '${duration} s', \
>>> ; billtime=INTERVAL '${billtime} s', ringtime=INTERVAL '${ringtime} s', status='${status}', \
>>> ; reason='${reason}', ended=true WHERE chan='${chan}' AND time=TIMESTAMP 'EPOCH' + INTERVAL '${time} s'
>>>
>>> cdr_combined=INSERT INTO cdr VALUES(TIMESTAMP 'EPOCH' + INTERVAL '${time} s', '${chan}', \
>>>    '${address}', '${caller}', '${called}', INTERVAL '${duration} s', INTERVAL '${billtime} s', \
>>>    INTERVAL '${ringtime} s', '${status}', '${reason}', '${out_leg.chan}', '${out_leg.addres}', \
>>>    INTERVAL '${out_leg.billtime} s', INTERVAL '${out_leg.ringtime} s', \
>>>    INTERVAL '${out_leg.duration} s', '${out_leg.reason}')
>>>
>>>
>>> [linetracker]
>>> ; Queries for the line usage tracker
>>>
>>> ; critical: boolean: Reject all registrations and routing if query fails
>>> ;critical=no
>>> critical=yes
>>>
>>> initquery=DELETE FROM channels WHERE nodename = '${nodename}'
>>> cdr_initialize=INSERT INTO channels(nodename, channel, caller, called, time, address) \
>>>    VALUES('${nodename}', '${chan}', '${caller}', '${called}', TIMESTAMP 'EPOCH' + INTERVAL '${time} s', '${address}')
>>> cdr_finalize=DELETE FROM channels WHERE nodename = '${nodename}' AND channel = '${chan}'
>>>
>>>
>>> I must say that I run into more and more problems the more I am working
>>> with Yate. I just cannot figure out if I am the only one who is missing
>>> some fundamental information or if it is just *that* difficult to get
>>> some extra features running.
>>>
>>> Best,
>>> -Michael
>>>
>>>>
>>>> Marian
>>>>
>>>> On 28.02.2015 18:15, Michael Tremer wrote:
>>>>> Hey Marian,
>>>>>
>>>>> thanks for getting back. Here is what I made with your advice. The other
>>>>> functions are unchanged.
>>>>>
>>>>> function onCallInvite(msg) {
>>>>> 	var m, success;
>>>>>
>>>>> 	Engine.output("Initiating dialout " + msg.caller + " -> " + msg.called);
>>>>>
>>>>> 	m = new Message("call.route");
>>>>> 	m.auth = true;
>>>>> 	m.caller = msg.called;
>>>>> 	m.called = msg.caller;
>>>>>
>>>>> 	success = m.dispatch();
>>>>> 	if (!success) {
>>>>> 		Engine.output("Call was not successful: " + m.error);
>>>>> 		return false;
>>>>> 	}
>>>>>
>>>>> 	// The SIP/IAX2 id of the calling user
>>>>> 	var target = m.retValue();
>>>>>
>>>>> 	// Create a new dumb channel which calls the caller
>>>>> 	m = new Message("call.execute");
>>>>> 	m.callto = "dumb/";
>>>>> 	m.cdrtrack = false;
>>>>> 	m.direct = target;
>>>>> 	m.target = msg.caller;
>>>>>
>>>>> 	// Set the real caller and called party
>>>>> 	m.caller = msg.called;
>>>>> 	m.called = msg.called;
>>>>>
>>>>> 	success = m.dispatch();
>>>>>
>>>>> 	if (!success) {
>>>>> 		Engine.output("Error executing call to " + target + ": " + m.error);
>>>>> 		return false;
>>>>> 	}
>>>>>
>>>>> 	Engine.debug("Got a new channel:");
>>>>> 	Engine.debug("       ID: " + m.id);
>>>>> 	Engine.debug("  peer ID: " + m.peerid);
>>>>>
>>>>> 	Message.install(onCallerAnswered,   "call.answered",     1, "id", m.peerid);
>>>>> 	Message.install(onChanDisconnected, "chan.disconnected", 1, "id", m.peerid);
>>>>>
>>>>> 	return true;
>>>>> }
>>>>>
>>>>> function onCallerAnswered(msg) {
>>>>> 	Engine.debug("ON CALLER ANSWERED");
>>>>> 	Engine.print_r(msg);
>>>>>
>>>>> 	var m = new Message("chan.masquerade");
>>>>> 	m.message = "call.execute";
>>>>> 	m.id = msg.id;
>>>>> 	m.caller = "1000";
>>>>> 	m.callto = "sip/sip:9999@XXX";
>>>>> 	//m.target = "9999";
>>>>> 	m.dispatch();
>>>>>
>>>>> 	return true;
>>>>> }
>>>>>
>>>>> function onChanDisconnected(msg) {
>>>>> 	Engine.debug("ON HANGUP");
>>>>> 	Engine.print_r(msg);
>>>>>
>>>>> 	return false;
>>>>> }
>>>>>
>>>>> So I execute call.route for the calling party, get back the target,
>>>>> create the dumb channel and the phone is ringing. Great. I get the ID
>>>>> and peer ID on the console.
>>>>>
>>>>> As soon as I pick up the phone onCallerAnswered() is executed. I am not
>>>>> entirely sure if the Message.install() method is what you meant. It
>>>>> works although I have not tried what would happen if I executed a
>>>>> thousand calls this way. Would this be a problem? Should I call
>>>>> Message.uninstall() as first thing in onCallerAnswered() or
>>>>> onChanDisconnected()?
>>>>>
>>>>> What else must I take care of on chan.disconnected?
>>>>>
>>>>> If I execute the code above a call to extension "9999" is established. I
>>>>> guess I first would need to do the call.route thing once again to find
>>>>> out the "callto" bit. However, I don't have the "caller" and "called"
>>>>> set to the originally called parties at this point. What would be the
>>>>> most elegant way to pass them to this point in code?
>>>>>
>>>>> I also have some difficulties with executing the second call on behalf
>>>>> of the user that has been called first. In my regex dialplan I use a
>>>>> line that refuses unauthorized calls which I need to circumvent at this
>>>>> point. I also get different entries in the CDR log. Is there any chance
>>>>> that I can improve this situation? "caller" always equals the username
>>>>> of the user initiating the call.
>>>>>
>>>>> This is also my implementation of one party calling an other. I guess
>>>>> that there is no good way to put this and the conference invitation code
>>>>> in one file as it is a completely different approach and only shares
>>>>> very few lines of code.
>>>>>
>>>>> Thank you so much for your patient help.
>>>>>
>>>>> -Michael
>>>>>
>>>>> On Wed, 2015-02-25 at 09:58 +0200, Marian Podgoreanu wrote:
>>>>>> Hi,
>>>>>>
>>>>>> You may:
>>>>>> Call the target using dumbchan: send a call.execute with callto=dumb/
>>>>>> and direct=YOUR_TARGET
>>>>>>
>>>>>> Track the returned id's (remember them in some list):
>>>>>>        The call.execute message (on success) will contain:
>>>>>>        id=the id of the dumb channel
>>>>>>        peerid: The id of the outgoing channel
>>>>>>
>>>>>> Track the channels for chan.disconnected: this will indicate call hangup
>>>>>>
>>>>>> You may add a call to a conference using the call.conference message
>>>>>>
>>>>>> If you want to play a prompt you may attach a wave source using chan.attach
>>>>>>
>>>>>> Some documentation:
>>>>>> http://docs.yate.ro/wiki/Dumbchan
>>>>>> http://docs.yate.ro/wiki/Call.conference
>>>>>> http://docs.yate.ro/wiki/Chan.attach
>>>>>>
>>>>>> Marian
>>>>>>
>>>>>> On 22.02.2015 18:16, Michael Tremer wrote:
>>>>>>> Hello *,
>>>>>>>
>>>>>>> we have been using Yate for a long time in the IPFire project for
>>>>>>> internal communications. Developers can phone each other and so on. It
>>>>>>> is working really great.
>>>>>>>
>>>>>>> Now I would like to add a new feature for us. Yate should be able to
>>>>>>> initiate calls by itself to invite people to calls or conferences. This
>>>>>>> topic is touched very often on this list, but I could not find a really
>>>>>>> proper solution.
>>>>>>>
>>>>>>> Here is what I want to do: We have a web user interface where people can
>>>>>>> log on to and click on a "call" button next to a contact in the address
>>>>>>> book. Yate should then call the caller. As soon as he or she picks up
>>>>>>> the phone, a call to the called party should be executed. This is pretty
>>>>>>> standard.
>>>>>>>
>>>>>>> When someone invites somebody else to a conference this should work very
>>>>>>> similar: The invited party is called and a short message is played back
>>>>>>> saying something along the lines "You have been invited to a conference=