Replicating Freeswitch's Default Dialplan in Adhearsion

133 views
Skip to first unread message

Chirag

unread,
Aug 28, 2014, 3:57:26 AM8/28/14
to adhea...@googlegroups.com
Hi all,

I'm new to adhearsion (using with freeswitch / rayo).

I'm able to match a number dialled (using the router), play a little music and even do text to speech.

However I'm a little bit stumped about best practices.

For example if I want to send the user to an echo test, or a conference. This was easy using the default dial plan from freeswitch.

Now that adhearsion controls the call before Freeswitch's dialplan has a chance, how do I offer similar functionality?

Do I use Sofia (via adhearsion) to dial an extension for a an echo test in the default dial plan (XML) or do I have to write echo test functionality in adhearsion?

Some examples would be most appreciated.

Kind regards,

Chirag

ik

unread,
Aug 28, 2014, 6:45:55 PM8/28/14
to Adhearsion
The dial string is the same as the originate/bridge syntax:
dial('user/2000')

For echo test, you should run your own code using ahn.


Ido  



--
You received this message because you are subscribed to the Google Groups "Adhearsion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to adhearsion+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Ben Klang

unread,
Aug 28, 2014, 7:00:32 PM8/28/14
to adhea...@googlegroups.com
On Aug 28, 2014, at 3:57 AM, Chirag <c.d...@rxhost.co.uk> wrote:

Hi all,

I'm new to adhearsion (using with freeswitch / rayo).

I'm able to match a number dialled (using the router), play a little music and even do text to speech.

However I'm a little bit stumped about best practices.

For example if I want to send the user to an echo test, or a conference. This was easy using the default dial plan from freeswitch.


I don’t think Adhearsion has any echo test built in, though it would be pretty easy to build. Something like this:

answer
result = record max_duration: 5
play result.recording.uri


I know FreeSWITCH has a built-in echo test, but we don’t currently have a way to directly invoke FreeSWITCH apps.  Part of Adhearsion’s promise is to be compatible across supported telephony engine (Asterisk, FreeSWITCH or any Rayo server), and this means providing methods that can work on any of those.


Conferencing is easier.  Just join the call to a mixer:

answer
join mixer_name: “my_conf_room”

This does not include any admin functions though like muting or unmuting based on key press. Those would need to be created separately, probably with something like Matrioska.

Now that adhearsion controls the call before Freeswitch's dialplan has a chance, how do I offer similar functionality?

Do I use Sofia (via adhearsion) to dial an extension for a an echo test in the default dial plan (XML) or do I have to write echo test functionality in adhearsion?

The best practice would be to write the code in Adhearsion and not route the call to FreeSWITCH XML, though you’re welcome to do so. The main reason is again portability, but also keeping all application logic  in one place.  This way, if you ever need to deploy the application to a new server, you don’t have to remember to set up both the application and its dependent diaplan XML; you just deploy one thing.

/BAK/
-- 
Ben Klang
Principal/Technology Strategist, Mojo Lingo

Mojo Lingo -- Voice applications that work like magic
Twitter: @MojoLingo



Some examples would be most appreciated.

Kind regards,

Chirag

signature.asc

Chirag

unread,
Aug 28, 2014, 7:45:11 PM8/28/14
to adhea...@googlegroups.com
Hi Ben and Ido,

Thanks so much for your responses.

Ben, I tried your sample code but I get the following error:

/usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/celluloid-0.15.2/lib/celluloid/responses.rb:29:in `value'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/celluloid-0.15.2/lib/celluloid/calls.rb:92:in `value'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/celluloid-0.15.2/lib/celluloid/proxies/sync_proxy.rb:33:in `method_missing'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/adhearsion-2.5.4/lib/adhearsion/call.rb:26:in `method_missing'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/adhearsion-2.5.4/lib/adhearsion/router/route.rb:37:in `dispatch'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/adhearsion-2.5.4/lib/adhearsion/router.rb:34:in `handle'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/adhearsion-2.5.4/lib/adhearsion/punchblock_plugin/initializer.rb:137:in `block in dispatch_offer'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/adhearsion-2.5.4/lib/adhearsion/foundation/exception_handler.rb:5:in `catching_standard_errors'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/adhearsion-2.5.4/lib/adhearsion/punchblock_plugin/initializer.rb:129:in `dispatch_offer'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/adhearsion-2.5.4/lib/adhearsion/punchblock_plugin/initializer.rb:62:in `block in init'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/has-guarded-handlers-1.6.0/lib/has_guarded_handlers.rb:117:in `call'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/has-guarded-handlers-1.6.0/lib/has_guarded_handlers.rb:117:in `call_handler'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/adhearsion-2.5.4/lib/adhearsion/events.rb:85:in `call_handler'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/has-guarded-handlers-1.6.0/lib/has_guarded_handlers.rb:96:in `block (3 levels) in trigger_handler'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/has-guarded-handlers-1.6.0/lib/has_guarded_handlers.rb:91:in `catch'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/has-guarded-handlers-1.6.0/lib/has_guarded_handlers.rb:91:in `block (2 levels) in trigger_handler'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/has-guarded-handlers-1.6.0/lib/has_guarded_handlers.rb:89:in `each'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/has-guarded-handlers-1.6.0/lib/has_guarded_handlers.rb:89:in `find'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/has-guarded-handlers-1.6.0/lib/has_guarded_handlers.rb:89:in `block in trigger_handler'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/has-guarded-handlers-1.6.0/lib/has_guarded_handlers.rb:88:in `catch'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/has-guarded-handlers-1.6.0/lib/has_guarded_handlers.rb:88:in `trigger_handler'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/adhearsion-2.5.4/lib/adhearsion/events.rb:65:in `handle_message'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/adhearsion-2.5.4/lib/adhearsion/events.rb:58:in `work'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/adhearsion-2.5.4/lib/adhearsion/events.rb:53:in `block in reinitialize_queue!'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/girl_friday-0.11.2/lib/girl_friday/work_queue.rb:147:in `call'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/girl_friday-0.11.2/lib/girl_friday/work_queue.rb:147:in `block (2 levels) in start'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/girl_friday-0.11.2/lib/girl_friday/actor.rb:86:in `call'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/girl_friday-0.11.2/lib/girl_friday/actor.rb:86:in `block in spawn_link'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/girl_friday-0.11.2/lib/girl_friday/actor.rb:69:in `call'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/girl_friday-0.11.2/lib/girl_friday/actor.rb:69:in `block (2 levels) in spawn'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/girl_friday-0.11.2/lib/girl_friday/actor.rb:212:in `block in initialize'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/girl_friday-0.11.2/lib/girl_friday/actor.rb:377:in `watchdog'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/girl_friday-0.11.2/lib/girl_friday/actor.rb:212:in `initialize'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/girl_friday-0.11.2/lib/girl_friday/actor.rb:66:in `new'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/girl_friday-0.11.2/lib/girl_friday/actor.rb:66:in `block in spawn'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/logging-1.8.2/lib/logging/diagnostic_context.rb:323:in `call'
    /usr/local/rvm/gems/ruby-2.1.2@adhearsionrb212/gems/logging-1.8.2/lib/logging/diagnostic_context.rb:323:in `block in create_with_logging_context'

The code in routes.rb is:

route 'Callers to echo test', :to => /9196/ do
   #execute 'Echo'
   say 'echo test'

   result = record max_duration: 5
   play result.recording.uri
 end

If i comment out the two lines you provided I hear "echo test". If i uncomment, I get the above error. Any ideas?

Thanks

Chirag

Ben Klang

unread,
Aug 28, 2014, 8:06:35 PM8/28/14
to adhea...@googlegroups.com
That stack trace looks incomplete - the top line should have been application code.

Can you gist your config/adhearsion.rb and whatever call controller you created? Even more helpful would be full trace-level logs. 

/BAK/

Chirag

unread,
Aug 28, 2014, 8:13:28 PM8/28/14
to adhea...@googlegroups.com
Please forgive the stupidity.

How do I give you a gist and trace?

My adhearsion.rb is vanilla (pretty much) after install.

Ben Klang

unread,
Aug 28, 2014, 8:28:32 PM8/28/14
to adhea...@googlegroups.com
Gist: https://gist.github.com

Trace logs: either edit config/adhearsion.rb and set the log level to :trace, or set the environment variable before starting your app: AHN_PLATFORM_LOGGING_LEVEL=trace

/BAK/
-- 
Ben Klang
Principal/Technology Strategist, Mojo Lingo

Mojo Lingo -- Voice applications that work like magic
Twitter: @MojoLingo

signature.asc

Chirag

unread,
Aug 30, 2014, 10:00:56 AM8/30/14
to adhea...@googlegroups.com

Chirag

unread,
Aug 30, 2014, 10:18:34 AM8/30/14
to adhea...@googlegroups.com
Hi,

I think I got it working. Somehow I managed to have two instances of the same adhearsion app running. One daemon, on in the foreground and I didn't realise the daemon one was answering the calls with the old code and therefore recording was not working.

I can now record for 5 seconds and play it back, however this doesn't simulate the "echo" functionality I was looking to replicate.

I'm looking to do a never-ending get sound in, and play it back. I guess I could do this by setting the recording time to something really small like a fraction of a second and running it in a loop forever. I'm worried though that I'll end up with many recording files and I'll have to clean them up on the fly too.

Any ideas?

Ben Klang

unread,
Aug 30, 2014, 1:35:38 PM8/30/14
to adhea...@googlegroups.com
Il giorno Aug 30, 2014, alle ore 10:18 AM, Chirag <c.d...@rxhost.co.uk> ha scritto:

Hi,

I think I got it working. Somehow I managed to have two instances of the same adhearsion app running. One daemon, on in the foreground and I didn't realise the daemon one was answering the calls with the old code and therefore recording was not working.

I can now record for 5 seconds and play it back, however this doesn't simulate the "echo" functionality I was looking to replicate.

I'm looking to do a never-ending get sound in, and play it back. I guess I could do this by setting the recording time to something really small like a fraction of a second and running it in a loop forever. I'm worried though that I'll end up with many recording files and I'll have to clean them up on the fly too.


You can use a basic loop. Try something like:

say 'echo test'
while call.active?
   result = record max_duration: 5
   play result.recording.uri
end

/BAK/
signature.asc

Ben Klang

unread,
Aug 30, 2014, 1:39:49 PM8/30/14
to adhea...@googlegroups.com
Il giorno Aug 30, 2014, alle ore 1:35 PM, Ben Klang <bkl...@mojolingo.com> ha scritto:

Il giorno Aug 30, 2014, alle ore 10:18 AM, Chirag <c.d...@rxhost.co.uk> ha scritto:

Hi,

I think I got it working. Somehow I managed to have two instances of the same adhearsion app running. One daemon, on in the foreground and I didn't realise the daemon one was answering the calls with the old code and therefore recording was not working.

I can now record for 5 seconds and play it back, however this doesn't simulate the "echo" functionality I was looking to replicate.

I'm looking to do a never-ending get sound in, and play it back. I guess I could do this by setting the recording time to something really small like a fraction of a second and running it in a loop forever. I'm worried though that I'll end up with many recording files and I'll have to clean them up on the fly too.


You can use a basic loop. Try something like:

say 'echo test'
while call.active?
   result = record max_duration: 5
   play result.recording.uri
end


Oh, and if you’re concerned about leaving files around you can call File.unlink on the recording URI (you may have to strip off “file://“ from the front) after each playback.
signature.asc

Chirag

unread,
Aug 31, 2014, 8:24:03 AM8/31/14
to adhea...@googlegroups.com
Thanks Ben.

New question. I use kamailio in front of freeswitch.

Kamailio decides whether users are offline or online and routes calls to the users phone if online or to their voicemail if offline.

When sending calls to voicemail for offline users I prefix their extension with vb e.g. vb-1000 for extension 1000.

I'm trying to pick this up using the regex in routes.rb, but it seems to be skipped everytime no matter what I try. I'm sure it's just a syntax issue. This is what I've tried so far:

route 'Callers to voicemail', :to => /vb-(.+)/ do
#do something
end

I've also tried
to => /*vb-(.+)$/
to => vb-(.+)
to => to => *vb-(.+)$

What's the correct syntax? Thanks.

Chirag

unread,
Aug 31, 2014, 8:51:14 AM8/31/14
to adhea...@googlegroups.com
I'm still curious about the regular expression syntax.

However, in addition, it looks like adhearsion isn't picking up the fact that vb-xxx is called by kamailio, even though freeswitch seems to realise.

Adhearsion

[2014-08-31 13:43:18.556] DEBUG Adhearsion::Call: @: Receiving message: #<Punchblock::Event::Offer target_call_id="61251d66-310c-11e4-95b0-cd8fc479562e", target_mixer_name=nil, component_id=nil, source_uri="xmpp:61251d66-310c-11e4-95b0-cd8fc479562e@public_ip", domain="public_ip", transport="xmpp", timestamp=Sun, 31 Aug 2014 13:43:18 +0100, headers={"from"=>"<sip:1000@sip_domain>;tag=kpsni2zgl7", "to"=>"<sip:124@sip_domain;user=phone>", "via"=>"SIP/2.0/UDP public_ip;branch=z9hG4bK67a8.148581b3b7bc6394bec471a3767e7426.0;i=f41,SIP/2.0/TCP 192.168.0.5:49971;received=device_ip;branch=z9hG4bK-ihtg4p5axv6k;rport=50291", "X-Serialnumber"=>"000413712AD7", "P-Key-Flags"=>"resolution=\"31x13\", keys=\"4\"", "P-Accountcode"=>"removed", "P-Pricelist_id"=>"removed", "X-AUTH-IP"=>"device_ip"}, to="sip:124@sip_domain", from="sip:1000@sip_domain">

Freeswitch

2014-08-31 13:43:16.711211 [NOTICE] switch_channel.c:1053 New Channel sofia/internal/1000@sip_domain [61251d66-310c-11e4-95b0-cd8fc479562e]
2014-08-31 13:43:16.711211 [INFO] mod_dialplan_xml.c:558 Processing 1000 <1000>->vb-124 in context public
2014-08-31 13:43:18.071173 [NOTICE] switch_ivr.c:1838 Transfer sofia/internal/1000@sip_domain to XML[vb-124@multitenant]
2014-08-31 13:43:18.071173 [INFO] mod_dialplan_xml.c:558 Processing 1000 <1000>->vb-124 in context multitenant
2014-08-31 13:43:18.571174 [INFO] mod_rayo.c:1526 username@public_ip/host-23980 has control of call
2014-08-31 13:43:18.571174 [INFO] mod_rayo.c:1844 Sending early media
2014-08-31 13:43:18.571174 [NOTICE] sofia_media.c:92 Pre-Answer sofia/internal/1000@sip_domain!
2014-08-31 13:43:18.611167 [NOTICE] mod_rayo.c:1863 Channel [sofia/internal/1000@sip_domain] has been answered
2014-08-31 13:43:18.931175 [INFO] switch_rtp.c:5540 Auto Changing port from 192.168.0.5:54084 to device_ip:54404
2014-08-31 13:43:20.431176 [NOTICE] sofia.c:927 Hangup sofia/internal/1000@sip_domain [CS_EXECUTE] [NORMAL_CLEARING]
2014-08-31 13:43:20.791175 [NOTICE] switch_core_session.c:1611 Session 170 (sofia/internal/1000@sip_domain) Ended
2014-08-31 13:43:20.791175 [NOTICE] switch_core_session.c:1615 Close Channel sofia/internal/1000@sip_domain [CS_DESTROY]
2014-08-31 13:47:42.771173 [INFO] xmpp_streams.c:1211 username@public_ip/mars-23980, iks_recv() error = NET_RWERR, ending session

Ideas welcome!

Thanks,

Chirag

Chirag

unread,
Aug 31, 2014, 2:10:16 PM8/31/14
to adhea...@googlegroups.com
One more thing:

In my freeswitch dialplan I can dial a another local extension and I hear ringing until the call is answered by the dialled extension.

In adhearsion, I have the exact same thing (dialling via sofia) however there is no "ringing" played to the caller until the callee picks up. Why is this?

I know I can explicity tell adhearsion to play a ringing sound as early media but if I'm not mistaken the phone (Snom) I'm using should generate it's own ringing sound based on the sip messages it receives - why doesn't this happen with adhearsion?

Thanks for all the help so far,

Chirag

Chirag

unread,
Sep 3, 2014, 6:03:39 PM9/3/14
to adhea...@googlegroups.com
So I looked at the sip messages and noticed the to still says the extension and the invite is to vb-extension.

Any ideas on how I can get adhearsion to respond to the user (e.g. vb-extension instead of extension) being called in the 'invite' rather than the 'to' header?

Thanks,

Chirag

On Sunday, August 31, 2014 1:51:14 PM UTC+1, Chirag wrote:

Ben Langfeld

unread,
Sep 4, 2014, 8:08:30 AM9/4/14
to adhea...@googlegroups.com
The voicemail plugin is almost certainly written assuming that Adhearsion is the B2BUA rather than kamailio. You'll probably need to make some minor modifications to support calling direct to voicemail. I'll get you a fuller response shortly with some ideas.

You might want to consider using Mojo Lingo's professional support services to make these modifications for you if you can't or don't want to do it yourself: http://mojolingo.com/

Ben Langfeld

Christopher Rienzo

unread,
Sep 4, 2014, 9:08:00 AM9/4/14
to adhea...@googlegroups.com
In rayo.conf.xml, set the offer-uri param to false.  It should then just contain the caller ID and dialed number as determined by FS endpoint.
Reply all
Reply to author
Forward
0 new messages