Skip to main content

Compiling ESL Library

The Event Socket Library (ESL) is a key component that allows communication with FreeSWITCH using socket-based interactions. This guide provides comprehensive steps to compile and install the Python or Java ESL library as part of a FreeSWITCH installation.

tip

For a comprehensive guide on compiling ESL libraries, including for other programming languages such as Perl, Ruby, and PHP, please refer to the official Event Socket Library documentation. This documentation provides detailed instructions and insights for integrating the Event Socket Library with various programming environments.

warning

To avoid compatibility and linking issues with FreeSWITCH core libraries and system core libraries, it's highly recommended to compile the ESL library with each FreeSWITCH installation.

Compiling Java ESL Library

The Java ESL (Event Socket Library) allows you to control and interact with FreeSWITCH using Java programming language. This guide walks you through the process of compiling and installing the Java ESL library from source.

Prerequisites

  • Java Development Kit (JDK) 17 or above: Ensure you have Java 17 (or higher) installed on your system. For this guide, we'll assume you're using JDK 17, but the process is similar for any version starting from Java 8.

  • FreeSWITCH Source Code: You need to have the FreeSWITCH source code downloaded and extracted. We will assume the path is /usr/local/src/freeswitch-1.10.12-release/.

  • Required Build Tools:

    • GNU Make: Used to compile the code.
    • SWIG (Simplified Wrapper and Interface Generator): For generating Java wrappers.
    • GCC/G++: C++ compiler for building the native code.

Install Dependencies

  • Install SWIG:

    If SWIG is not installed, you can install it via your package manager:

    sudo apt-get install swig3.0
  • Install GNU Compiler Collection (GCC) and Make:

    if GCC is installed in your system then you can install it using following command.

    sudo apt-get install build-essential
  • Verify Java Installation:

    Ensure that Java 17 (or higher) is installed and properly configured. To check:

    java -version
    javac -version

    The output should indicate that Java 17 (or the version you're using) is installed, such as:

    openjdk version "17.0.4" 2022-07-19

    If Java is not installed, you can install OpenJDK 17 with:

    sudo apt install openjdk-17-jdk

Set Up the ESL Source Directory

Navigate to the libs/esl directory inside your FreeSWITCH source folder:

cd /usr/local/src/freeswitch-1.10.12-release/libs/esl

This folder contains the Makefile and necessary source files for compiling the ESL Java client.

Modify Makefile

Since the Makefile is written for older versions of Java (such as Java 6), we need to update it for Java 17 or any version above Java 8.

  • Update Java Include Paths and Compilation Settings:

    Edit the Makefile in the java directory:

    vim java/Makefile
    • Update Java Include Paths: Modify the LOCAL_CFLAGS variable to point to the Java 17 include directories. Assuming you’re using OpenJDK 17, your LOCAL_CFLAGS should look like this:

      LOCAL_CFLAGS=-I../src/include \
      -I/usr/lib/jvm/java-17-openjdk-amd64/include \
      -I/usr/lib/jvm/java-17-openjdk-amd64/include/linux

      If you are using a different installation path, adjust the paths accordingly.

    • Update javac Compilation Flags: Update the javac compilation flags to use -source 17 and -target 17:

      esl.jar: libesljni.so
      mkdir -p classes
      javac -sourcepath org -d classes -source 17 -target 17 $(CLASSES)
      jar cf esl.jar -C classes org
    • After these changes, your updated Makefile should look like this:

      LOCAL_CFLAGS=-I../src/include \
      -I/usr/lib/jvm/java-17-openjdk-amd64/include \
      -I/usr/lib/jvm/java-17-openjdk-amd64/include/linux
      GCC_WARNING_JUNK=-w
      CLASSES=org/freeswitch/esl/*

      all: esl.jar

      esl_wrap.cpp:
      swig3.0 -module esl -java -c++ $(LOCAL_CFLAGS) -package org.freeswitch.esl \
      -outdir org/freeswitch/esl -o esl_wrap.cpp ../ESL.i

      esl_wrap.o: esl_wrap.cpp
      $(CXX) $(CXX_CFLAGS) $(LOCAL_CFLAGS) $(CXXFLAGS) $(GCC_WARNING_JUNK) \
      -c esl_wrap.cpp -o esl_wrap.o

      libesljni.so: esl_wrap.o
      $(CXX) $(SOLINK) -o libesljni.so esl_wrap.o $(MYLIB)

      esl.jar: libesljni.so
      mkdir -p classes
      javac -sourcepath org -d classes -source 17 -target 17 $(CLASSES)
      jar cf esl.jar -C classes org

      clean:
      rm -f _.o _.so _~ _.jar

      swigclean:
      rm -f esl_wrap.\*

      reswig: swigclean esl_wrap.cpp

      Note: If you're using Java 8, change the -source and -target flags to 8.

Compile

After updating the Makefile, you are ready to compile the Java ESL client.

  • Clean Previous Build Artifacts:

    It’s always a good idea to clean previous builds:

    make clean
  • Compile the Java Module:

    Now, run the command to build the Java module:

    make javamod

    Execution of above command will:

    • Generate the Java bindings using SWIG.
    • Compile the native C++ code.
    • Generate the Java .jar file and the shared library (libesljni.so).

Verify the Output

After the compilation is complete, verify that the following files are generated:

  1. libesljni.so: The shared library that contains the native C++ bindings.
  2. esl.jar: The Java archive (JAR) file that contains the Java classes.

You can check their existence with:

ls -l java/libesljni.so java/esl.jar

If both files are present, the build was successful.

Installation

  • For Non-Maven/Gradle Projects:

    warning

    Using the FreeSWITCH ESL Java library in a core Java project that does not utilize Maven, Gradle, or Spring Boot is generally not recommended.

    If you’re using the ESL library in a project that does not use Maven or Gradle, follow these steps:

    1. Locate and Copy the org Directory:

      • Navigate to the ESL FreeSWITCH source directory:

        cd /usr/local/src/freeswitch-1.10.12-release/libs/esl/java
      • Inside this directory, you'll find the org directory which contains the necessary Java classes for the ESL library.

      • Copy the org directory to your project’s source code directory. This should be done in a way that maintains the directory structure relative to your project’s source path.

    2. Load the Native Library:

      • In your Java code, you need to load the native library. Add the following line:

        System.load("/path/to/libesljni.so");
      • Replace "/path/to/libesljni.so" with the actual path to the native library file (libesljni.so). The libesljni.so file is typically found in the libs directory of your ESL installation.

  • For Maven/Gradle Projects (Recommended Approach):

    If you're using Maven or Gradle for your project, follow these steps to include the ESL library:

    1. Install the JAR into Your Local Maven Repository:

      • Open a terminal or command prompt.

      • Run the following command to install the ESL JAR file into your local Maven repository:

        Using Maven:

        mvn install:install-file -Dfile=/path/to/esl.jar -DgroupId=org.freeswitch.esl -DartifactId=esl -Dversion=1.0.0 -Dpackaging=jar

        Using Maven Wrapper (mvnw): If your project includes a Maven Wrapper script, use it instead:

        ./mvnw install:install-file -Dfile=/path/to/esl.jar -DgroupId=org.freeswitch.esl -DartifactId=esl -Dversion=1.0.0 -Dpackaging=jar
      note

      Replace /path/to/esl.jar with the actual path to your ESL JAR file.

    2. Add the Dependency to Your Maven/Gradle Project:

      • For Maven Projects: Open your pom.xml file and add the following dependency:

        <dependencies>
        <dependency>
        <groupId>org.freeswitch.esl</groupId>
        <artifactId>esl</artifactId>
        <version>1.0.0</version>
        </dependency>
        </dependencies>
      • For Gradle Projects: Open your build.gradle file and add the following dependency:

        dependencies {
        implementation 'org.freeswitch.esl:esl:1.0.0'
        }

    For more details on using Maven or Gradle, consult their respective documentation.

Usage

TO use this maven library in your project, use following:

<dependencies>
<dependency>
<groupId>org.freeswitch.esl</groupId>
<artifactId>esl</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>

Compiling Python ESL Library

The Python ESL (Event Socket Library) allows you to control and interact with FreeSWITCH using Python. This guide walks you through the process of compiling and installing the Python ESL library from source.

Install Python and Python Development Libraries

Make sure you have Python 3 and the necessary Python development libraries installed.

sudo apt install python3 python3-dev python3-pip

Compile the ESL Library

Now, compile the ESL library, including the Python bindings.

  • Navigate to FreeSWITCH source code. It is typically located in /usr/local/src/freeswitch-1.10.12.-release

    cd /usr/local/src/freeswitch-1.10.12.-release
  • Navigate to the ESL directory:

    cd libs/esl
  • Compile the ESL Python library:

    make pymod

    This will compile the Python ESL module (_ESL.so) located in python directory.

  • After compiling the library, install it so Python can import the ESL module.

    1. Locate the compiled Python module (_ESL.so). It should be in:

      /usr/local/src/freeswitch-1.10.12.-release/libs/esl/python/_ESL.so
    2. Copy the ESL Python files to your Python installation:

      sudo cp python/_ESL.so /usr/local/lib/python3.12/dist-packages/
      sudo cp python/ESL.py /usr/local/lib/python3.12/dist-packages/

      Ensure you're copying the Python files to the correct Python version path (in this example, Python 3.12).

Fix Compatibility Issues with Python 3.12

The ESL Python bindings might use outdated libraries that are incompatible with modern Python versions. In our case, we encountered a deprecated imp module. Here’s how we fixed it:

  • Edit the ESL.py file:

    sudo vi /usr/local/lib/python3.12/dist-packages/ESL.py
  • Replace the deprecated imp module with importlib. Here's the code for the updated ESL.py file:

    from sys import version_info
    import importlib.util
    import os

    if version_info >= (2, 6, 0):
    def swig_import_helper():
    module_name = '_ESL'
    module_path = os.path.join(os.path.dirname(__file__), '_ESL.so')

    if importlib.util.find_spec(module_name) is None:
    # Module not found, try to load it dynamically
    if os.path.exists(module_path):
    spec = importlib.util.spec_from_file_location(module_name, module_path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module
    else:
    raise ImportError(f"Module '{module_name}' not found at '{module_path}'")
    else:
    # Module is already found in the search path
    import _ESL
    return _ESL

    _ESL = swig_import_helper()
    del swig_import_helper
    else:
    import _ESL

    del version_info

    def _swig_setattr_nondynamic(self, class_type, name, value, static=1):
    if name == "thisown":
    return self.this.own(value)
    if name == "this":
    if type(value).__name__ == 'SwigPyObject':
    self.__dict__[name] = value
    return
    method = class_type.__swig_setmethods__.get(name, None)
    if method:
    return method(self, value)
    if not static:
    self.__dict__[name] = value
    else:
    raise AttributeError(f"You cannot add attributes to {self}")

    def _swig_setattr(self, class_type, name, value):
    return _swig_setattr_nondynamic(self, class_type, name, value, 0)

    def _swig_getattr(self, class_type, name):
    if name == "thisown":
    return self.this.own()
    method = class_type.__swig_getmethods__.get(name, None)
    if method:
    return method(self)
    raise AttributeError(name)

    def _swig_repr(self):
    try:
    strthis = "proxy of " + self.this.__repr__()
    except:
    strthis = ""
    return f"<{self.__class__.__module__}.{self.__class__.__name__}; {strthis} >"

    class ESLevent:
    __swig_setmethods__ = {}
    __setattr__ = lambda self, name, value: _swig_setattr(self, ESLevent, name, value)
    __swig_getmethods__ = {}
    __getattr__ = lambda self, name: _swig_getattr(self, ESLevent, name)
    __repr__ = _swig_repr
    __swig_setmethods__["event"] = _ESL.ESLevent_event_set
    __swig_getmethods__["event"] = _ESL.ESLevent_event_get
    __swig_setmethods__["serialized_string"] = _ESL.ESLevent_serialized_string_set
    __swig_getmethods__["serialized_string"] = _ESL.ESLevent_serialized_string_get
    __swig_setmethods__["mine"] = _ESL.ESLevent_mine_set
    __swig_getmethods__["mine"] = _ESL.ESLevent_mine_get

    def __init__(self, *args):
    this = _ESL.new_ESLevent(*args)
    try:
    self.this.append(this)
    except:
    self.this = this

    __swig_destroy__ = _ESL.delete_ESLevent
    __del__ = lambda self: None

    def serialize(self, format=None):
    return _ESL.ESLevent_serialize(self, format)

    def setPriority(self, *args):
    return _ESL.ESLevent_setPriority(self, *args)

    def getHeader(self, *args):
    return _ESL.ESLevent_getHeader(self, *args)

    def getBody(self):
    return _ESL.ESLevent_getBody(self)

    def getType(self):
    return _ESL.ESLevent_getType(self)

    def addBody(self, *args):
    return _ESL.ESLevent_addBody(self, *args)

    def addHeader(self, *args):
    return _ESL.ESLevent_addHeader(self, *args)

    def pushHeader(self, *args):
    return _ESL.ESLevent_pushHeader(self, *args)

    def unshiftHeader(self, *args):
    return _ESL.ESLevent_unshiftHeader(self, *args)

    def delHeader(self, *args):
    return _ESL.ESLevent_delHeader(self, *args)

    def firstHeader(self):
    return _ESL.ESLevent_firstHeader(self)

    def nextHeader(self):
    return _ESL.ESLevent_nextHeader(self)

    ESLevent_swigregister = _ESL.ESLevent_swigregister
    ESLevent_swigregister(ESLevent)

    class ESLconnection:
    __swig_setmethods__ = {}
    __setattr__ = lambda self, name, value: _swig_setattr(self, ESLconnection, name, value)
    __swig_getmethods__ = {}
    __getattr__ = lambda self, name: _swig_getattr(self, ESLconnection, name)
    __repr__ = _swig_repr

    def __init__(self, *args):
    this = _ESL.new_ESLconnection(*args)
    try:
    self.this.append(this)
    except:
    self.this = this

    __swig_destroy__ = _ESL.delete_ESLconnection
    __del__ = lambda self: None

    def socketDescriptor(self):
    return _ESL.ESLconnection_socketDescriptor(self)

    def connected(self):
    return _ESL.ESLconnection_connected(self)

    def getInfo(self):
    return _ESL.ESLconnection_getInfo(self)

    def send(self, *args):
    return _ESL.ESLconnection_send(self, *args)

    def sendRecv(self, *args):
    return _ESL.ESLconnection_sendRecv(self, *args)

    def api(self, *args):
    return _ESL.ESLconnection_api(self, *args)

    def bgapi(self, *args):
    return _ESL.ESLconnection_bgapi(self, *args)

    def sendEvent(self, *args):
    return _ESL.ESLconnection_sendEvent(self, *args)

    def sendMSG(self, *args):
    return _ESL.ESLconnection_sendMSG(self, *args)

    def recvEvent(self):
    return _ESL.ESLconnection_recvEvent(self)

    def recvEventTimed(self, *args):
    return _ESL.ESLconnection_recvEventTimed(self, *args)

    def filter(self, *args):
    return _ESL.ESLconnection_filter(self, *args)

    def events(self, *args):
    return _ESL.ESLconnection_events(self, *args)

    def execute(self, *args):
    return _ESL.ESLconnection_execute(self, *args)

    def executeAsync(self, *args):
    return _ESL.ESLconnection_executeAsync(self, *args)

    def setAsyncExecute(self, *args):
    return _ESL.ESLconnection_setAsyncExecute(self, *args)

    def setEventLock(self, *args):
    return _ESL.ESLconnection_setEventLock(self, *args)

    def disconnect(self):
    return _ESL.ESLconnection_disconnect(self)

    ESLconnection_swigregister = _ESL.ESLconnection_swigregister
    ESLconnection_swigregister(ESLconnection)

    def eslSetLogLevel(*args):
    return _ESL.eslSetLogLevel(*args)
  • Save the file and exit.

Verify the ESL Module

Now, verify that the Python ESL module works.

  • Open a Python 3 terminal:

    python3
  • Import the ESL module:

    import ESL

    If the module imports without errors, the ESL library is successfully compiled and installed!

Troubleshooting

  • No Module Named ESL Error: If you get a "ModuleNotFoundError," check if the _ESL.so and ESL.py files are in your Python's site-packages or dist-packages directory.

    python3 -m site
  • Module _ESL Not Found: If Python complains about _ESL, make sure that the _ESL.so file is copied correctly to the directory where Python is looking for it.

Conclusion

By following this guide, you have now successfully compiled and installed the Python ESL library for FreeSWITCH! You should be able to integrate FreeSWITCH with Python and start developing your own telephony applications.

If you encounter any issues, check the paths and ensure that the compiled ESL files are in the correct Python directories. Feel free to modify the process to suit your specific Python version or system setup.