A Scala 3 library for communicating with FreeSWITCH via the Event Socket Layer (ESL) protocol. Built on Apache Pekko Streams for reactive, backpressure-aware communication.
- Inbound mode — connect to FreeSWITCH's event socket (port 8021) to send commands and receive events
- Outbound mode — accept connections from FreeSWITCH's
socketdialplan application - Comprehensive ESL command set —
api,bgapi,event,filter,execute,sendmsg,sendevent, and more - Pekko Streams native — protocol codec exposed as
BidiFlow, events asSource[EslEvent, NotUsed] - Automatic protocol handling — auth handshake (inbound), connect/myevents handshake (outbound), nested
text/event-plainparsing
- Scala 3.8+
- sbt 1.x
- JDK 21+
Connect to a running FreeSWITCH instance:
import com.megafarad.esl4s.connection.InboundConnection
import com.megafarad.esl4s.model.*
import org.apache.pekko.actor.typed.ActorSystem
import org.apache.pekko.actor.typed.scaladsl.Behaviors
given system: ActorSystem[Nothing] = ActorSystem(Behaviors.empty, "esl4s")
import system.executionContext
val settings = InboundConnection.Settings(
host = "127.0.0.1",
port = 8021,
password = "ClueCon"
)
InboundConnection.connect(settings).foreach { session =>
// Subscribe to events
session.sendCommand(EventCommand("plain", Seq("ALL")))
// Listen for events
session.events.runForeach { event =>
println(s"Event: ${event.eventName}")
}
// Send a command
session.sendCommand(ApiCommand("status")).foreach { reply =>
println(s"Reply: ${reply.asInstanceOf[EslEvent].body}")
}
}Accept connections from FreeSWITCH's socket dialplan app:
import com.megafarad.esl4s.connection.OutboundServer
import com.megafarad.esl4s.model.*
import org.apache.pekko.Done
import scala.concurrent.Future
OutboundServer.bind(OutboundServer.Settings(port = 8084)) { session =>
println(s"Call from: ${session.channelData.header("Channel-Name")}")
// Execute an application
session.sendCommand(Execute(
uuid = session.channelData.uniqueId.getOrElse(""),
app = "playback",
arg = "/usr/share/freeswitch/sounds/hello.wav"
))
// Hang up when done
session.hangup().map(_ => Done)
}For custom stream graphs, use the BidiFlow codec directly:
import com.megafarad.esl4s.codec.EslCodec
import org.apache.pekko.stream.scaladsl.Tcp
val codec = EslCodec()
val tcpFlow = Tcp()(using system.classicSystem).outgoingConnection("127.0.0.1", 8021)
val eslFlow = codec.join(tcpFlow) // Flow[EslCommand, EslFrame, _]sbt compile # compile
sbt test # run tests
sbt console # Scala 3 REPLMIT