An EventMachine-based Ruby library for interacting with the open source telephony platform FreeSWITCH.
Librevox eventually came to life during a major rewrite of Freeswitcher. Not everything would fit into the existing architecture, and I felt that a blank slate was needed. Librevox and Freeswitcher looks much alike on the outside, but Librevox tries to take a simpler approach on the inside.
Librevox lets you interact with FreeSWITCH through mod_event_socket. You should know how the event socket works, and the differences between inbound and outbound event sockets before proceeding. The wiki page on mod_event_socket is a good place to start.
Librevox is Ruby 1.9-only.
To create an inbound listener, you should subclass Librevox::Listener::Inbound
and add custom behaviour to it. An inbound listener subscribes to all events
from FreeSWITCH, and lets you react on events in two different ways:
-
By overiding
on_event
which gets called every time an event arrives. -
By adding an event hook with
event
, which will get called every time an event with the specified name arrives.
The header and content of the event is accessible through event
.
Below is an example of an inbound listener utilising all the aforementioned techniques:
require 'librevox'
class MyInbound < Librevox::Listener::Inbound
# Events to listen for (default is ALL)
events ['CHANNEL_EXECUTE', 'CUSTOM foo']
# Filters to apply (optional)
filter 'Caller-Context' => ['default', 'example'], 'Caller-Privacy-Hide-Name' => 'no'
def on_event e
puts "Got event: #{e.content[:event_name]}"
end
# You can add a hook for a certain event:
event :channel_hangup do
# It is instance_eval'ed, so you can use your instance methods etc:
do_something
end
# If your hook block takes an argument, a Librevox::Response object for
# the given event is passed on:
event :channel_bridge do |e|
...
end
def do_something
...
end
end
You create an outbound listener by subclassing Librevox::Listener::Outbound
.
An outbound listener has the same event functionality as the inbound listener, but it only receives events related to that given session.
When a call is made and Freeswitch connects to the outbound event listener,
session_initiated
is called. This is where you set up your dialplan:
def session_initiated
answer do
set "some_var", "some value" do
playback "path/to/file" do
hangup
end
end
end
end
All channel variables are available as a hash named session
.
When using applications that expect a reply, such as play_and_get_digits
,
you have to use callbacks to read the value, as the function itself returns
immediately due to the async nature of EventMachine:
def session_initiated
answer do
play_and_get_digits "enter-number.wav", "error.wav" do |digit|
puts "User pressed #{digit}"
playback "thanks-for-the-input.wav" do
hangup
end
end
end
end
You can also use the commands defined in Librevox::Command
, which, to avoid
namespace clashes, are accessed through the api
object:
def session_initiated
answer do
api.status
end
end
They can be used in conjunction with applications, and do also take a block, passing the response to an eventual block argument.
To start a single listener, connection/listening on localhost on the default port is quite simple:
Librevox.start SomeListener
it takes an optional hash with arguments:
Librevox.start SomeListener, :host => "1.2.3.4", :port => "8087", :auth => "pwd"
Multiple listeners can be started at once by passing a block to Librevox.start
:
Librevox.start do
run SomeListener
run OtherListener, :port => "8080"
end
After a session has finished, e.g. because the calling part hangs up, an
outbound socket still has its connection to FreeSWITCH open, so we can get post-
session events. Therefore it is important that you close the connection manually
when you are done. Otherwise you will have 'hanging' sessions, cloggering up
your system. This can safely be done with close_connection_after_writing
,
which will wait for all outgoing data to be send before closing the connection.
It is aliased as done
for convenience.
Unless you are doing something specific, closing the connection on CHANNEL_HANGUP is most likely sufficient:
class MyListener < Librevox::Listener::Outbound
event :channel_hangup do
done
end
end
By default Librevox uses the Logger
class from the Ruby standard library. You
can configure the path to the log file and the log level through Librevox.options
:
Librevox.options[:log_file] = "my_log_file.log"
Librevox.options[:log_level] = Logger::DEBUG
If you start Librevox with Librevox.start
, the log file will be reopened if you
send SIGHUP
to the Librevox process. This makes it easy to rotate logs with the
standard logrotate(1)
.
Librevox also ships with a CommandSocket class, which allows you to connect to the FreeSWITCH management console, from which you can originate calls, restart FreeSWITCH etc.
>> require "librevox/command_socket"
=> true
>> socket.originate('sofia/user/coltrane', :extension => "1234")
>> #<Librevox::Response:0x10179d388 @content="+OK de0ecbbe-e847...">
>> socket.status
>> > #<Librevox::Response:0x1016acac8 ...>
>> socket.raw('sendevent SEND_MESSAGE\nprofile: internal\n...Content-Length: #{body.length}\n\n#{body}\n\n')
>> > #<Librevox::Response:0x1023baca2 ...>
## Further documentation
All applications and commands are documented in the code. You can run
`yardoc` from the root of the source tree to generate YARD docs. Look under
the `Librevox::Commands` and `Librevox::Applications` modules.
## Extras
* Source: [http://github.com/vangberg/librevox](http://github.com/vangberg/librevox)
* API docs: [http://rdoc.info/projects/vangberg/librevox](http://rdoc.info/projects/vangberg/librevox)
* Mailing list: librevox@librelist.com
* IRC: #librevox @ irc.freenode.net
## License
(c) 2009-2014 Harry Vangberg <harry@vangberg.name>
(c) 2011-2014 Firmafon ApS <info@firmafon.dk>
Librevox was inspired by and uses code from Freeswitcher, which is distributed
under the MIT license and (c) 2009 The Rubyists (Jayson Vaughn, Tj Vanderpoel,
Michael Fellinger, Kevin Berry), Harry Vangberg, see `LICENSE-Freeswitcher`.
Librevox is distributed under the terms of the MIT license, see `LICENSE`.