Reader small image

You're reading from  Mastering FreeSWITCH

Product typeBook
Published inJul 2016
Reading LevelExpert
PublisherPackt
ISBN-139781784398880
Edition1st Edition
Languages
Concepts
Right arrow
Authors (8):
Darren Schreiber
Darren Schreiber
author image
Darren Schreiber

Darren Schreiber is the CEO and Co-founder of 2600 Hz. He began working heavily in open source voice with the FreeSWITCH project, where he engaged with Brian, Mike, and Anthony. His projects have since evolved into two enterprise VoIP platforms that allow a multitude of development of voice, SMS, and video applications to be delivered to customers.He has 15 years of voice and IT experience including developing multiple enterprise SaaS infrastructures for hosting and remotely managing IT, voice, and e-commerce services. He is a guest lecturer at major universities on VoIP technology and leads paid international VoIP trainings. As a serious telephony enthusiast since a young age, he has worked extensively with VoIP technologies. He graduated from Rensselaer Polytechnic Institute with a degree in Computer Science and Business Management.He is also a co-author of FreeSWITCH Cookbook, Packt Publishing.
Read more about Darren Schreiber

View More author details
Right arrow

Chapter 11. Write Your FreeSWITCH Module in C

Modules are where you add functionalities to FreeSWITCH.

Is not very easy to write or modify a module, but neither is rocket science (by the way, as in real life, it always depends on what kind of rocket you want to build). And you can always find professional help by contacting the core FreeSWITCH developers.

This chapter will lay down all of the basic techniques needed to develop a new module:

  • Reading XML configuration

  • Adding a dialplan application

  • Adding an API command

  • Adding an event hook

  • Adding a channel state change hook

  • Firing an event

What is a FreeSWITCH module?


FreeSWITCH proper, the core FreeSWITCH, is a switching and mixing fabric with some message queues and a lot of very abstract APIs that define concepts and actions. The only possible interaction with the core is via those APIs and message queues; there is no access whatsoever to internal data, structure, functions, and so on. Everything is completely opaque and protected; there is no way to harm the stability and performance of core. From the outside, core is a blackbox able to accept commands and return results via APIs.

All functionalities are implemented in modules.

A FreeSWITCH module is a shared library to be loaded by core. A module provides additional features, APIs, and implementations. Usually, a module is the low-level plumbing needed to interact with the real world.

In core you have the concepts of channel, session, call, message, codec, and many others. These are just concepts, well thought-out and articulated abstractions useful to describe real-time...

Developing a module


As we commoners always do, and which sets us apart from Jedis such as Anthony Minessale II, we start developing our new FreeSWITCH module by copying from a working one.

You can start by copying the one I'm presenting here, mod_example. I have started copying mod_skel, removing complex things from it, then I added simple things. I like simple things.

You copy the entire directory and rename it, you delete Makefile.in and Makefile (for example, you only leave and edit Makefile.am) and you rename all occurrences of the same name in each of the files contained in that directory. In my case, mod_skel.c was renamed mod_example, and all instances of skel were modified to example inside all other files. At the end of this process, if you grep in the new directory, you don't find any more mention of skel (the original module name).

You then go in the main FreeSWITCH sources directory, edit modules.conf file, and add a line for your new module. After that, from that same main sources...

Mod_Example outline


mod_example has been written to be, huh, an example, so I tried to stuff in it many useful features, in the simplest way. You can use it as a base, adding and subtracting features:

mod_example.c code layout:

  • Declarations:

    • The module's mandatory three functions (example_load, example_runtime, example_shutdown)

    • Module definition

    • A data structure (globals) we'll use to keep state and configuration

    • The function (example_on_state_change) we'll execute when channel state changes

    • The table (example_state_handler) describing which function to execute at which state change

  • Implementations:

    • The function (example_on_state_change) we'll execute when channel state changes

    • The function (do_config) we use to read values from config file and initialize the globals data structure

    • The function (example_api) we use to implement an API command

    • The function (example_event_handler) we use to implement reactions to events

    • The function (example_app) we use to implement a dialplan application

    • Modules' mandatory...

Mandatory functions


Each FreeSWITCH module must at least declare three functions, LOAD, RUNTIME, and SHUTDOWN:

The LOAD and SHUTDOWN functions must be implemented, and are called at startup and when unloading the module. In LOAD you create and initialize the module's data structures, get values from the configuration file, and get your module ready for work. In SHUTDOWN you do any housekeeping needed to happily forget about your module, and in particular you release any resources you may have locked or allocated during module initialization and lifespan.

RUNTIME function implementation is not mandatory. For example, you must declare it, but you can avoid implementing it. If you implement it, the RUNTIME function will be executed in its own thread after the LOAD function has finished execution, for example, when the module has been successfully loaded by FreeSWITCH.

RUNTIME is often (not always) implemented as a looping function that will continue to run until module unloads.

Load function

Let...

Configuration using XML


FreeSWITCH uses XML to represent its configuration, because XML lends itself perfectly (and directly) to a tree representation in which you can add and delete branches and leaves and easily locate sections, parameters, and values. Optimized XML routines are able to parse, create an in-memory representation, and manipulate that representation.

So, you'd better stop whining and learn to love XML.

There are many advanced facilities to help parse FreeSWITCH's configuration files; check syntax; associate settings, parameters, names, descriptions, allowed values' ranges; and many more.

In our implementation we keep it simple to the max (we love kisses), and only use the most basic XML related functions.

We create our XML pointers, then we raze the globals data structure we'll use to store state and configuration (you'd better do this razing, or you'll end up with stale values if you unload then reload the module).

switch_xml_open_cfg() will read our XML configuration file and...

Reacting to channel state changes


FreeSWITCH channels are always, deterministically, in one specific state of a finite state machine. There are rules for going from one state to another, and you can ask FreeSWITCH core to alert your module whenever a channel changes state.

There are 12 states a channel can be in (init, routing, execute, hangup, exchange_media, soft_execute, consume_media, hibernate, reset, park, reporting, destroy), plus the state none, which a channel is supposed to never assume.

State changes are important moments, particularly for billing and accounting (start of media flows, hangup), but you may want to trigger some procedures in other cases too, for example, when a channel is parked.

Our implementation first declares which state changes we want to deal with (LOAD function will register this table with FreeSWITCH core), INIT, and HANGUP.

Then it defines the function we'll use to react to those changes (you can have different functions for each state). Inside the function...

Receiving and firing events


Events are FreeSWITCH's nervous system. They carry around information, commands, and feedback.

Tapping into the event flow will give your module a complete and real-time view of what's happening in each of the many components and subsystems of FreeSWITCH, from channels to reporting.

Firing events enables your module to actively participate in this flow, making information available that other modules can act upon in real time, or sending API commands as if typed in the console.

Events come in various types and subcategories. Each module can subscribe to ALL events or only to a certain subset, and then further filter to which event to react to based on the content of the event's oh so many fields:

In our implementation, we subscribed to ALL events during the LOAD function.

Then, in the example_event_handler(), function we filter the events flow based on event_id (the specific kind of event), and if the event is suitable, then we get a particular header (for example...

Dialplan application


Modules can add applications to those available to be called in dialplan.

Applications in dialplan are invoked as actions and can have arguments in the data string. An example of application and arguments is the bridge app, which takes the dialstring as the argument to be used to originate the call leg to be bridged to:

In our implementation, we registered a dialplan app with FreeSWITCH core during the LOAD function. Here, we'll have a look at how we implemented the actual application's inner workings.

We get the channel object from the session object we were passed.

Then we check if the arg string we were passed is empty (zero length). If it's empty, we assign a default value to how many loops we'll execute. If it's not empty, we convert it into a number, assigning a default in case of error, and enforcing value boundaries.

For each loop we then print a log line that pretty much displays all the entities we used.

From dialplan, you invoke this application as follows:

<...

API command


API commands are the way to interact in real time with FreeSWITCH. You can use API commands to originate a call, to answer, to gather statistics, to write accounting data, to shutdown the entire system, and more.

API commands are commands you can type while you're connected to FreeSWITCH's console, or via fs_cli. You can send API commands by firing events, both from a module and via an ESL TCP connection.

Modules can add new such functionalities; actually, pretty much all API commands come from modules:

We registered our API command during the LOAD function, as per the dialplan application.

example_api() is the function that implements the API command. We use it as a demonstration of how to send an event from a module.

First, you create the event pointer, then you give it an earthly existence with switch_event_create(), passing the event-specific kind as an argument.

At this point you have an empty event, a skeleton event with only the standard minimal headers (fields). You can flesh...

Summary


In this chapter, we gave you a complete and detailed view of the module development process.

We described the approach we take (copying an existing, working module, and then modifying it) and then guided you through the various sections of the new module's source code.

We saw how to implement the load, runtime, and shutdown functions that are the foundation of every module. In those functions we initialized our data structures and registered hooks and callbacks in FreeSWITCH core.

Then we implemented all functionalities with simple and straightforward code that will serve you well as a base for building your own modules.

If your new module does something that could be useful to others, don't forget to contribute it back to the FreeSWITCH project, for mainline inclusion. Many useful modules were born this way!

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Mastering FreeSWITCH
Published in: Jul 2016Publisher: PacktISBN-13: 9781784398880
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Authors (8)

author image
Darren Schreiber

Darren Schreiber is the CEO and Co-founder of 2600 Hz. He began working heavily in open source voice with the FreeSWITCH project, where he engaged with Brian, Mike, and Anthony. His projects have since evolved into two enterprise VoIP platforms that allow a multitude of development of voice, SMS, and video applications to be delivered to customers.He has 15 years of voice and IT experience including developing multiple enterprise SaaS infrastructures for hosting and remotely managing IT, voice, and e-commerce services. He is a guest lecturer at major universities on VoIP technology and leads paid international VoIP trainings. As a serious telephony enthusiast since a young age, he has worked extensively with VoIP technologies. He graduated from Rensselaer Polytechnic Institute with a degree in Computer Science and Business Management.He is also a co-author of FreeSWITCH Cookbook, Packt Publishing.
Read more about Darren Schreiber