diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/VoiceApp2x.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/VoiceApp2x.scala
index 571c4db2bd6ed088ea9783a0e50e14de9015df73..c5f0662066d8730f4da62c12e9094d3f885c1697 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/VoiceApp2x.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/VoiceApp2x.scala
@@ -3,6 +3,13 @@ package org.bigbluebutton.core.apps.voice
 import org.bigbluebutton.core.running.MeetingActor
 import org.bigbluebutton.core2.message.handlers.RecordingStartedVoiceConfEvtMsgHdlr
 
+object VoiceCallState {
+  val NOT_IN_CALL = "NOT_IN_CALL"
+  val IN_ECHO_TEST = "IN_ECHO_TEST"
+  val IN_CONFERENCE = "IN_CONFERENCE"
+  val CALL_STARTED = "CALL_STARTED"
+  val CALL_ENDED = "CALL_ENDED"
+}
 trait VoiceApp2x extends UserJoinedVoiceConfEvtMsgHdlr
   with UserJoinedVoiceConfMessageHdlr
   with UserLeftVoiceConfEvtMsgHdlr
@@ -11,6 +18,7 @@ trait VoiceApp2x extends UserJoinedVoiceConfEvtMsgHdlr
   with RecordingStartedVoiceConfEvtMsgHdlr
   with VoiceConfRunningEvtMsgHdlr
   with SyncGetVoiceUsersMsgHdlr
+  with VoiceConfCallStateEvtMsgHdlr
   with UserStatusVoiceConfEvtMsgHdlr {
 
   this: MeetingActor =>
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/VoiceConfCallStateEvtMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/VoiceConfCallStateEvtMsgHdlr.scala
new file mode 100755
index 0000000000000000000000000000000000000000..b82ddc6468f934706fb7819c23338b217a8a5ed9
--- /dev/null
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/voice/VoiceConfCallStateEvtMsgHdlr.scala
@@ -0,0 +1,42 @@
+package org.bigbluebutton.core.apps.voice
+
+import org.bigbluebutton.common2.msgs.{ BbbClientMsgHeader, BbbCommonEnvCoreMsg, BbbCoreEnvelope, MessageTypes, Routing, VoiceCallStateEvtMsg, VoiceCallStateEvtMsgBody, VoiceConfCallStateEvtMsg }
+import org.bigbluebutton.core.models.{ VoiceUserState, VoiceUsers }
+import org.bigbluebutton.core.running.{ LiveMeeting, MeetingActor, OutMsgRouter }
+
+trait VoiceConfCallStateEvtMsgHdlr {
+  this: MeetingActor =>
+
+  val liveMeeting: LiveMeeting
+  val outGW: OutMsgRouter
+
+  def handleVoiceConfCallStateEvtMsg(msg: VoiceConfCallStateEvtMsg): Unit = {
+    val routing = Routing.addMsgToClientRouting(
+      MessageTypes.BROADCAST_TO_MEETING,
+      liveMeeting.props.meetingProp.intId,
+      msg.body.voiceConf
+    )
+    val envelope = BbbCoreEnvelope(
+      VoiceCallStateEvtMsg.NAME,
+      routing
+    )
+    val header = BbbClientMsgHeader(
+      VoiceCallStateEvtMsg.NAME,
+      liveMeeting.props.meetingProp.intId,
+      msg.body.voiceConf
+    )
+
+    val body = VoiceCallStateEvtMsgBody(
+      meetingId = liveMeeting.props.meetingProp.intId,
+      voiceConf = msg.body.voiceConf,
+      clientSession = msg.body.callSession,
+      userId = msg.body.userId,
+      callerName = msg.body.callerName,
+      callState = msg.body.callState
+    )
+
+    val event = VoiceCallStateEvtMsg(header, body)
+    val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
+    outGW.send(msgEvent)
+  }
+}
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala
index 7dd24a7fa959786fdb198491c8b14a4caaa9167a..2db88ad68a864743cf8573346cc29b3a23f8a8a3 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala
@@ -152,6 +152,8 @@ class ReceivedJsonMsgHandlerActor(
         routeVoiceMsg[CheckRunningAndRecordingVoiceConfEvtMsg](envelope, jsonNode)
       case UserStatusVoiceConfEvtMsg.NAME =>
         routeVoiceMsg[UserStatusVoiceConfEvtMsg](envelope, jsonNode)
+      case VoiceConfCallStateEvtMsg.NAME =>
+        routeVoiceMsg[VoiceConfCallStateEvtMsg](envelope, jsonNode)
 
       // Breakout rooms
       case BreakoutRoomsListMsg.NAME =>
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala
index b6e32aab55b961116fe513bdb0aad2fd5b7d68c3..5ea402cddedb021d0cbdde7cdbd8b7cfb38a1173 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala
@@ -384,6 +384,7 @@ class MeetingActor(
         state = updateInactivityTracker(state)
         updateVoiceUserLastActivity(m.body.voiceUserId)
         handleUserTalkingInVoiceConfEvtMsg(m)
+      case m: VoiceConfCallStateEvtMsg        => handleVoiceConfCallStateEvtMsg(m)
 
       case m: RecordingStartedVoiceConfEvtMsg => handleRecordingStartedVoiceConfEvtMsg(m)
       case m: MuteUserCmdMsg =>
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/AnalyticsActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/AnalyticsActor.scala
index c7b4b094865e1b0edd11770f392ee1f58556d7ce..f65e7bf7276f5d7050fccbb073220b95c23edf5d 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/AnalyticsActor.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/AnalyticsActor.scala
@@ -93,6 +93,8 @@ class AnalyticsActor extends Actor with ActorLogging {
       // Voice
       case m: UserMutedVoiceEvtMsg =>
         logMessage(msg)
+      case m: VoiceConfCallStateEvtMsg => logMessage(msg)
+      case m: VoiceCallStateEvtMsg => logMessage(msg)
 
       // Breakout
       case m: BreakoutRoomEndedEvtMsg => logMessage(msg)
diff --git a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/FreeswitchConferenceEventListener.java b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/FreeswitchConferenceEventListener.java
index 0d165a9a5c28a471fc4c9fc374ebd7d97b754b49..48012683bf1f00b429d9d723ff5ade3f1b359f84 100755
--- a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/FreeswitchConferenceEventListener.java
+++ b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/FreeswitchConferenceEventListener.java
@@ -100,6 +100,19 @@ public class FreeswitchConferenceEventListener implements ConferenceEventListene
         } else if (event instanceof VoiceUsersStatusEvent) {
           VoiceUsersStatusEvent evt = (VoiceUsersStatusEvent) event;
           vcs.voiceUsersStatus(evt.getRoom(), evt.confMembers, evt.confRecordings);
+        } else if (event instanceof VoiceCallStateEvent) {
+          VoiceCallStateEvent evt = (VoiceCallStateEvent) event;
+          vcs.voiceCallStateEvent(evt.getRoom(),
+                  evt.callSession,
+                  evt.clientSession,
+                  evt.userId,
+                  evt.callerName,
+                  evt.callState,
+                  evt.origCallerIdName,
+                  evt.origCalledDest);
+        } else if (event instanceof FreeswitchStatusReplyEvent) {
+          FreeswitchStatusReplyEvent evt = (FreeswitchStatusReplyEvent) event;
+          vcs.freeswitchStatusReplyEvent(evt.jsonResponse);
         }
 
       }
diff --git a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/IVoiceConferenceService.java b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/IVoiceConferenceService.java
index e91692493935e1a363ccd32eecd48d115657b02e..cd42bfbaa1822e6ade6aa53abb21add3adccd017 100755
--- a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/IVoiceConferenceService.java
+++ b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/IVoiceConferenceService.java
@@ -65,4 +65,14 @@ public interface IVoiceConferenceService {
                                     Boolean isRecording,
                                     java.util.List<ConfRecording> confRecording);
 
+  void voiceCallStateEvent(String conf,
+                           String callSession,
+                           String clientSession,
+                           String userId,
+                           String callerName,
+                           String callState,
+                           String origCallerIdName,
+                           String origCalledDest);
+
+  void freeswitchStatusReplyEvent(String json);
 }
diff --git a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/events/FreeswitchStatusReplyEvent.java b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/events/FreeswitchStatusReplyEvent.java
new file mode 100755
index 0000000000000000000000000000000000000000..d8ae7f3541ac887a8ca29ef1389aceb318a44d1d
--- /dev/null
+++ b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/events/FreeswitchStatusReplyEvent.java
@@ -0,0 +1,11 @@
+package org.bigbluebutton.freeswitch.voice.events;
+
+public class FreeswitchStatusReplyEvent extends VoiceConferenceEvent {
+
+    public final String jsonResponse;
+
+    public FreeswitchStatusReplyEvent(String json) {
+        super("unused");
+        this.jsonResponse = json;
+    }
+}
diff --git a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/events/VoiceCallStateEvent.java b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/events/VoiceCallStateEvent.java
new file mode 100755
index 0000000000000000000000000000000000000000..9d0a9277e66cc43d76b3222ab1eac93092c21c09
--- /dev/null
+++ b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/events/VoiceCallStateEvent.java
@@ -0,0 +1,30 @@
+package org.bigbluebutton.freeswitch.voice.events;
+
+public class VoiceCallStateEvent extends VoiceConferenceEvent {
+    public final String callSession;
+    public final String clientSession;
+    public final String userId;
+    public final String callerName;
+    public final String callState;
+    public final String origCallerIdName;
+    public final String origCalledDest;
+
+    public VoiceCallStateEvent(
+            String conf,
+            String callSession,
+            String clientSession,
+            String userId,
+            String callerName,
+            String callState,
+            String origCallerIdName,
+            String origCalledDest) {
+        super(conf);
+        this.callSession = callSession;
+        this.clientSession = clientSession;
+        this.userId = userId;
+        this.callerName = callerName;
+        this.callState = callState;
+        this.origCallerIdName = origCallerIdName;
+        this.origCalledDest = origCalledDest;
+    }
+}
diff --git a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/ConnectionManager.java b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/ConnectionManager.java
index 47a6b8e32ec5b213b19438f2dfbb4575550f8705..a194ffa16c99f10d67b1fb724ff9d34a12d0bc49 100755
--- a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/ConnectionManager.java
+++ b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/ConnectionManager.java
@@ -34,6 +34,7 @@ import org.bigbluebutton.freeswitch.voice.freeswitch.actions.*;
 import org.freeswitch.esl.client.inbound.Client;
 import org.freeswitch.esl.client.inbound.InboundConnectionFailure;
 import org.freeswitch.esl.client.manager.ManagerConnection;
+import org.freeswitch.esl.client.transport.CommandResponse;
 import org.freeswitch.esl.client.transport.message.EslMessage;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -81,10 +82,18 @@ public class ConnectionManager {
 				if (!subscribed) {
 					log.info("Subscribing for ESL events.");
 					c.cancelEventSubscriptions();
-					c.setEventSubscriptions("plain", "all");
-					//c.addEventFilter(EVENT_NAME, "heartbeat");
-					c.addEventFilter(EVENT_NAME, "custom");
-					c.addEventFilter(EVENT_NAME, "background_job");
+					CommandResponse response = c.setEventSubscriptions("plain", "all");
+					if (response.isOk()) {
+						log.info("Subscribed to ESL events." +
+								" Command: [" + response.getCommand() + "] " +
+								" Response: [" + response.getReplyText() + "]");
+					}
+
+					//c.addEventFilter(EVENT_NAME, "HEARTBEAT");
+					//c.addEventFilter(EVENT_NAME, "custom");
+					//c.addEventFilter(EVENT_NAME, "background_job");
+					c.addEventFilter(EVENT_NAME, "CHANNEL_EXECUTE");
+					c.addEventFilter(EVENT_NAME, "CHANNEL_STATE");
 					subscribed = true;
 				} else {
 					// Let's check for status every minute.
diff --git a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/ESLEventListener.java b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/ESLEventListener.java
index d18b994b2129e539882b6230648b18c26ac32599..fb204b984dd1e703bb7a6900c2de32146d2f299a 100755
--- a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/ESLEventListener.java
+++ b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/ESLEventListener.java
@@ -1,6 +1,7 @@
 package org.bigbluebutton.freeswitch.voice.freeswitch;
 
 
+import java.util.Iterator;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
@@ -52,6 +53,8 @@ public class ESLEventListener implements IEslEventListener {
     private static final Pattern GLOBAL_AUDION_PATTERN = Pattern.compile("(GLOBAL_AUDIO)_(.*)$");
     private static final Pattern CALLERNAME_PATTERN = Pattern.compile("(.*)-bbbID-(.*)$");
     private static final Pattern CALLERNAME_WITH_SESS_INFO_PATTERN = Pattern.compile("^(.*)_(\\d+)-bbbID-(.*)$");
+    private static final Pattern CALLERNAME_LISTENONLY_PATTERN = Pattern.compile("^(.*)_(\\d+)-bbbID-LISTENONLY-(.*)$");
+    private static final Pattern ECHO_TEST_DEST_PATTERN = Pattern.compile("^9196(\\d+)$");
     
     @Override
     public void conferenceEventJoin(String uniqueId, String confName, int confSize, EslEvent event) {
@@ -92,6 +95,22 @@ public class ESLEventListener implements IEslEventListener {
                 voiceUserId = "v_" + memberId.toString();
             }
 
+            String coreuuid = headers.get("Core-UUID");
+            String clientSession = "0";
+            String callState = "IN_CONFERENCE";
+            String origCallerIdName = headers.get("Caller-Caller-ID-Name");
+            String origCallerDestNumber = headers.get("Caller-Destination-Number");
+            VoiceCallStateEvent csEvent = new VoiceCallStateEvent(
+                    confName,
+                    coreuuid,
+                    clientSession,
+                    voiceUserId,
+                    callerIdName,
+                    callState,
+                    origCallerIdName,
+                    origCallerDestNumber);
+            conferenceEventListener.handleConferenceEvent(csEvent);
+
             String callerUUID = this.getMemberUUIDFromEvent(event);
             log.info("Caller joined: conf=" + confName +
                     ",uuid=" + callerUUID +
@@ -111,6 +130,8 @@ public class ESLEventListener implements IEslEventListener {
                     speaking,
                     "none");
             conferenceEventListener.handleConferenceEvent(pj);
+
+
         }
     }
 
@@ -243,13 +264,187 @@ public class ESLEventListener implements IEslEventListener {
     
     @Override
     public void eventReceived(EslEvent event) {
-        //System.out.println("ESL Event Listener received event=[" + event.getEventName() + "]" +
-        //        event.getEventHeaders().toString());
-        if (event.getEventName().equals("heartbeat")) {
-            log.info("Received heartbeat from FreeSWITCH");
-////           setChanged();
-//           notifyObservers(event);
-//           return; 
+//        System.out.println("*********** ESL Event Listener received event=[" + event.getEventName() + "]" +
+//                event.getEventHeaders().toString());
+
+        /**
+        Map<String, String> eventHeaders1 = event.getEventHeaders();
+         StringBuilder sb = new StringBuilder("");
+         sb.append("\n");
+         for (Iterator it = eventHeaders1.entrySet().iterator(); it.hasNext(); ) {
+         Map.Entry entry = (Map.Entry)it.next();
+         sb.append(entry.getKey());
+         sb.append(" => '");
+         sb.append(entry.getValue());
+         sb.append("'\n");
+         }
+
+         System.out.println("##### ===>>> " + sb.toString());
+         System.out.println("<<<=== #####");
+        **/
+
+        if (event.getEventName().equals("HEARTBEAT")) {
+            //log.info("Received heartbeat from FreeSWITCH");
+        } else if (event.getEventName().equals( "CHANNEL_EXECUTE" )) {
+            Map<String, String> eventHeaders = event.getEventHeaders();
+
+            String application = (eventHeaders.get("Application") == null) ? "" : eventHeaders.get("Application");
+            String channelCallState = (eventHeaders.get("Channel-Call-State") == null) ? "" : eventHeaders.get("Channel-Call-State");
+            String varvBridge = (eventHeaders.get("variable_vbridge") == null) ? "" : eventHeaders.get("variable_vbridge");
+
+            if ("echo".equalsIgnoreCase(application) && !varvBridge.isEmpty()) {
+                String origCallerIdName = eventHeaders.get("Caller-Caller-ID-Name");
+                String origCallerDestNumber = eventHeaders.get("Caller-Destination-Number");
+                String coreuuid = eventHeaders.get("Core-UUID");
+
+                //System.out.println("******** uuid=" + coreuuid + " " + origCallerIdName + " is in echo test " + origCallerDestNumber + " vbridge=" + varvBridge);
+
+                String voiceUserId = "";
+                String callerName = origCallerIdName;
+                String clientSession = "0";
+                String callState = "IN_ECHO_TEST";
+
+                Matcher callerListenOnly = CALLERNAME_LISTENONLY_PATTERN.matcher(origCallerIdName);
+                Matcher callWithSess = CALLERNAME_WITH_SESS_INFO_PATTERN.matcher(origCallerIdName);
+                if (callWithSess.matches()) {
+                    voiceUserId = callWithSess.group(1).trim();
+                    clientSession = callWithSess.group(2).trim();
+                    callerName = callWithSess.group(3).trim();
+                } else if (callerListenOnly.matches()) {
+                    voiceUserId = callerListenOnly.group(1).trim();
+                    clientSession = callWithSess.group(2).trim();
+                    callerName = callerListenOnly.group(3).trim();
+                }
+
+                VoiceCallStateEvent csEvent = new VoiceCallStateEvent(varvBridge,
+                        coreuuid,
+                        clientSession,
+                        voiceUserId,
+                        callerName,
+                        callState,
+                        origCallerIdName,
+                        origCallerDestNumber);
+                conferenceEventListener.handleConferenceEvent(csEvent);
+
+            } else if ("RINGING".equalsIgnoreCase(channelCallState) && !varvBridge.isEmpty()) {
+                String origCallerIdName = eventHeaders.get("Caller-Caller-ID-Name");
+                String origCallerDestNumber = eventHeaders.get("Caller-Destination-Number");
+                String coreuuid = eventHeaders.get("Core-UUID");
+                //System.out.println("******** uuid=" + coreuuid + " " + origCallerIdName + " is in ringing " + origCallerDestNumber + " vbridge=" + varvBridge);
+
+                String voiceUserId = "";
+                String callerName = origCallerIdName;
+                String clientSession = "0";
+                String callState = "CALL_STARTED";
+
+                Matcher callerListenOnly = CALLERNAME_LISTENONLY_PATTERN.matcher(origCallerIdName);
+                Matcher callWithSess = CALLERNAME_WITH_SESS_INFO_PATTERN.matcher(origCallerIdName);
+                if (callWithSess.matches()) {
+                    voiceUserId = callWithSess.group(1).trim();
+                    clientSession = callWithSess.group(2).trim();
+                    callerName = callWithSess.group(3).trim();
+                } else if (callerListenOnly.matches()) {
+                    voiceUserId = callerListenOnly.group(1).trim();
+                    clientSession = callWithSess.group(2).trim();
+                    callerName = callerListenOnly.group(3).trim();
+                }
+
+                VoiceCallStateEvent csEvent = new VoiceCallStateEvent(varvBridge,
+                        coreuuid,
+                        clientSession,
+                        voiceUserId,
+                        callerName,
+                        callState,
+                        origCallerIdName,
+                        origCallerDestNumber);
+                conferenceEventListener.handleConferenceEvent(csEvent);
+            }
+        } else if (event.getEventName().equalsIgnoreCase("CHANNEL_STATE")) {
+            Map<String, String> eventHeaders = event.getEventHeaders();
+            String channelCallState = (eventHeaders.get("Channel-Call-State") == null) ? "" : eventHeaders.get("Channel-Call-State");
+            String channelState = (eventHeaders.get("Channel-State") == null) ? "" : eventHeaders.get("Channel-State");
+
+            if ("HANGUP".equalsIgnoreCase(channelCallState) && "CS_DESTROY".equalsIgnoreCase(channelState)) {
+                String origCallerIdName = eventHeaders.get("Caller-Caller-ID-Name");
+                String origCallerDestNumber = eventHeaders.get("Caller-Destination-Number");
+                String coreuuid = eventHeaders.get("Core-UUID");
+                //System.out.println("******** uuid=" + coreuuid + " " + origCallerIdName + " is hanging up " + origCallerDestNumber);
+
+                String voiceUserId = "";
+                String callerName = origCallerIdName;
+                String clientSession = "0";
+                String callState = "CALL_ENDED";
+
+                Matcher callerListenOnly = CALLERNAME_LISTENONLY_PATTERN.matcher(origCallerIdName);
+                Matcher callWithSess = CALLERNAME_WITH_SESS_INFO_PATTERN.matcher(origCallerIdName);
+                if (callWithSess.matches()) {
+                    voiceUserId = callWithSess.group(1).trim();
+                    clientSession = callWithSess.group(2).trim();
+                    callerName = callWithSess.group(3).trim();
+                } else if (callerListenOnly.matches()) {
+                    voiceUserId = callerListenOnly.group(1).trim();
+                    clientSession = callWithSess.group(2).trim();
+                    callerName = callerListenOnly.group(3).trim();
+                }
+
+                String conf = origCallerDestNumber;
+                Matcher callerDestNumberMatcher = ECHO_TEST_DEST_PATTERN.matcher(origCallerDestNumber);
+                if (callerDestNumberMatcher.matches()) {
+                    conf = callerDestNumberMatcher.group(1).trim();
+                }
+
+                VoiceCallStateEvent csEvent = new VoiceCallStateEvent(conf,
+                        coreuuid,
+                        clientSession,
+                        voiceUserId,
+                        callerName,
+                        callState,
+                        origCallerIdName,
+                        origCallerDestNumber
+                        );
+                conferenceEventListener.handleConferenceEvent(csEvent);
+
+            } else if ("RINGING".equalsIgnoreCase(channelCallState) && "CS_EXECUTE".equalsIgnoreCase(channelState)) {
+                String origCallerIdName = eventHeaders.get("Caller-Caller-ID-Name");
+                String origCallerDestNumber = eventHeaders.get("Caller-Destination-Number");
+                String coreuuid = eventHeaders.get("Core-UUID");
+                //System.out.println("******** uuid=" + coreuuid + " " + origCallerIdName + " is ringing " + origCallerDestNumber);
+
+                String voiceUserId = "";
+                String callerName = origCallerIdName;
+                String clientSession = "0";
+                String callState = "CALL_STARTED";
+
+                Matcher callerListenOnly = CALLERNAME_LISTENONLY_PATTERN.matcher(origCallerIdName);
+                Matcher callWithSess = CALLERNAME_WITH_SESS_INFO_PATTERN.matcher(origCallerIdName);
+                if (callWithSess.matches()) {
+                    voiceUserId = callWithSess.group(1).trim();
+                    clientSession = callWithSess.group(2).trim();
+                    callerName = callWithSess.group(3).trim();
+                } else if (callerListenOnly.matches()) {
+                    voiceUserId = callerListenOnly.group(1).trim();
+                    clientSession = callWithSess.group(2).trim();
+                    callerName = callerListenOnly.group(3).trim();
+                }
+
+                String conf = origCallerDestNumber;
+                Matcher callerDestNumberMatcher = ECHO_TEST_DEST_PATTERN.matcher(origCallerDestNumber);
+                if (callerDestNumberMatcher.matches()) {
+                    conf = callerDestNumberMatcher.group(1).trim();
+                }
+
+                VoiceCallStateEvent csEvent = new VoiceCallStateEvent(conf,
+                        coreuuid,
+                        clientSession,
+                        voiceUserId,
+                        callerName,
+                        callState,
+                        origCallerIdName,
+                        origCallerDestNumber
+                        );
+                conferenceEventListener.handleConferenceEvent(csEvent);
+            }
+
         }
     }
 
diff --git a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/CheckFreeswitchStatusCommand.java b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/CheckFreeswitchStatusCommand.java
index d0d2aa67f04113bf15159a487845b929122d2996..2e8e4f912dd6c308a1f5262a715ecf1f4294e093 100755
--- a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/CheckFreeswitchStatusCommand.java
+++ b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/CheckFreeswitchStatusCommand.java
@@ -3,6 +3,7 @@ package org.bigbluebutton.freeswitch.voice.freeswitch.actions;
 import com.google.gson.Gson;
 import org.apache.commons.lang3.StringUtils;
 import org.bigbluebutton.freeswitch.voice.events.ConferenceEventListener;
+import org.bigbluebutton.freeswitch.voice.events.FreeswitchStatusReplyEvent;
 import org.freeswitch.esl.client.transport.message.EslMessage;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -26,10 +27,11 @@ public class CheckFreeswitchStatusCommand extends FreeswitchCommand {
     }
 
     public void handleResponse(EslMessage response, ConferenceEventListener eventListener) {
-
         Gson gson = new Gson();
         log.info(gson.toJson(response.getBodyLines()));
-
+        FreeswitchStatusReplyEvent statusEvent = new FreeswitchStatusReplyEvent(
+                gson.toJson(response.getBodyLines()));
+        eventListener.handleConferenceEvent(statusEvent);
     }
 
 }
diff --git a/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/freeswitch/VoiceConferenceService.scala b/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/freeswitch/VoiceConferenceService.scala
index 2e186f1990b9cc84595d487cb386fd190a6931d5..07ff1be12d2b5158582f928dfe2ff8c963ea49bc 100755
--- a/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/freeswitch/VoiceConferenceService.scala
+++ b/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/freeswitch/VoiceConferenceService.scala
@@ -273,4 +273,41 @@ class VoiceConferenceService(sender: RedisPublisher) extends IVoiceConferenceSer
     sender.publish(fromVoiceConfRedisChannel, json)
   }
 
+  def voiceCallStateEvent(
+      conf:             String,
+      callSession:      String,
+      clientSession:    String,
+      userId:           String,
+      callerName:       String,
+      callState:        String,
+      origCallerIdName: String,
+      origCalledDest:   String
+  ): Unit = {
+    val header = BbbCoreVoiceConfHeader(VoiceConfCallStateEvtMsg.NAME, conf)
+    val body = VoiceConfCallStateEvtMsgBody(
+      voiceConf = conf,
+      callSession = callSession,
+      clientSession = clientSession,
+      userId = userId,
+      callerName = callerName,
+      callState = callState,
+      origCallerIdName = origCallerIdName,
+      origCalledDest = origCalledDest
+    )
+    val envelope = BbbCoreEnvelope(VoiceConfCallStateEvtMsg.NAME, Map("voiceConf" -> conf))
+
+    val msg = new VoiceConfCallStateEvtMsg(header, body)
+    val msgEvent = BbbCommonEnvCoreMsg(envelope, msg)
+
+    val json = JsonUtil.toJson(msgEvent)
+    sender.publish(fromVoiceConfRedisChannel, json)
+  }
+
+  def freeswitchStatusReplyEvent(json: String): Unit = {
+    // Placeholder so we can add a /healthz check endpoint to
+    // monitor akka-fsesl (ralam feb 5, 2020)
+    //println("***** >>>>")
+    //println(json)
+    //println("<<<< *****")
+  }
 }
diff --git a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/VoiceConfMsgs.scala b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/VoiceConfMsgs.scala
index 83f90ead4d36f88b390aaf659140a84c57adc6c8..4d92363940c0385590b99bdfbfa52981819b17e5 100755
--- a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/VoiceConfMsgs.scala
+++ b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/VoiceConfMsgs.scala
@@ -433,4 +433,40 @@ case class UserDisconnectedFromGlobalAudioMsgBody(userId: String, name: String)
  */
 object SyncGetVoiceUsersRespMsg { val NAME = "SyncGetVoiceUsersRespMsg" }
 case class SyncGetVoiceUsersRespMsg(header: BbbClientMsgHeader, body: SyncGetVoiceUsersRespMsgBody) extends BbbCoreMsg
-case class SyncGetVoiceUsersRespMsgBody(voiceUsers: Vector[VoiceConfUser])
\ No newline at end of file
+case class SyncGetVoiceUsersRespMsgBody(voiceUsers: Vector[VoiceConfUser])
+
+/**
+ * Received from FS call state events.
+ */
+object VoiceConfCallStateEvtMsg { val NAME = "VoiceConfCallStateEvtMsg" }
+case class VoiceConfCallStateEvtMsg(
+    header: BbbCoreVoiceConfHeader,
+    body:   VoiceConfCallStateEvtMsgBody
+) extends VoiceStandardMsg
+case class VoiceConfCallStateEvtMsgBody(
+    voiceConf:        String,
+    callSession:      String,
+    clientSession:    String,
+    userId:           String,
+    callerName:       String,
+    callState:        String,
+    origCallerIdName: String,
+    origCalledDest:   String
+)
+
+/**
+ * Sent to interested parties call state events.
+ */
+object VoiceCallStateEvtMsg { val NAME = "VoiceCallStateEvtMsg" }
+case class VoiceCallStateEvtMsg(
+    header: BbbClientMsgHeader,
+    body:   VoiceCallStateEvtMsgBody
+) extends BbbCoreMsg
+case class VoiceCallStateEvtMsgBody(
+    meetingId:     String,
+    voiceConf:     String,
+    clientSession: String,
+    userId:        String,
+    callerName:    String,
+    callState:     String
+)
\ No newline at end of file
diff --git a/bbb-fsesl-client/src/main/java/org/freeswitch/esl/client/inbound/Client.java b/bbb-fsesl-client/src/main/java/org/freeswitch/esl/client/inbound/Client.java
index 482067ed8e4e2112c1945ed9316108e41029f593..dc5d0f6d46a9d83761d37a283015f96e37b94237 100755
--- a/bbb-fsesl-client/src/main/java/org/freeswitch/esl/client/inbound/Client.java
+++ b/bbb-fsesl-client/src/main/java/org/freeswitch/esl/client/inbound/Client.java
@@ -428,6 +428,7 @@ public class Client
         public void eventReceived( final EslEvent event )
         {
             log.debug( "Event received [{}]", event );
+
             /*
              *  Notify listeners in a different thread in order to:
              *    - not to block the IO threads with potentially long-running listeners
@@ -537,8 +538,10 @@ public class Client
                                         System.out.println("##### " + sb.toString());
                                          **/
                                     }
+                                } else {
+                                    listener.eventReceived( event );
                                 }
-                                listener.eventReceived( event );
+
                             } catch ( Throwable t ) {
                                 log.error( "Error caught notifying listener of event [" + event + ']', t );
                             }