From 3395cdbdc0fda674047905ce5836960aa9b6db2c Mon Sep 17 00:00:00 2001 From: Richard Alam <ritzalam@gmail.com> Date: Thu, 17 Oct 2019 11:50:12 -0700 Subject: [PATCH] Make sure we record audio if meeting is recorded - We had an issue where FreeSWITCH, for some unknow reason, stopped recording the voice conference in the middle of the meeting while there are users in the voice conference. We've relied on the voice conf started event to trigger recording of wav files. This event is sent when the first user joins the voice conference. In this case, there was no voice user joined after the recording stopped as there were already users in the voice conference. TO make sure that the audio is recorded, akka-apps will send a "check if voice conf is running and recording" message to FreeSWITCH every 30sec. If akka-apps receives a "running=true recording=false" response from FreeSWITCH, akka-apps will send a start recording msg to FreeSWITCH. --- akka-bbb-apps/.gitignore | 2 + .../senders/ReceivedJsonMsgHandlerActor.scala | 2 + .../core/running/MeetingActor.scala | 39 +++++++++- .../bigbluebutton/core2/AnalyticsActor.scala | 4 + .../core2/FromAkkaAppsMsgSenderActor.scala | 2 + .../bigbluebutton/core2/MeetingStatus2x.scala | 17 +++-- .../core2/message/senders/MsgBuilder.scala | 9 +++ akka-bbb-fsesl/.gitignore | 1 + akka-bbb-fsesl/run-dev.sh | 6 ++ .../FreeswitchConferenceEventListener.java | 10 +++ .../voice/IVoiceConferenceService.java | 2 + .../VoiceConfRunningAndRecordingEvent.java | 31 ++++++++ .../freeswitch/FreeswitchApplication.java | 8 +- .../actions/CheckIfConfIsRunningCommand.java | 2 +- .../actions/ConferenceCheckRecordCommand.java | 76 ++++++++++++++++++- .../XMLResponseConferenceListParser.java | 1 - .../freeswitch/RxJsonMsgDeserializer.scala | 18 +++++ .../freeswitch/RxJsonMsgHdlrActor.scala | 2 + .../freeswitch/VoiceConferenceService.scala | 13 +++- .../common2/msgs/VoiceConfMsgs.scala | 20 +++++ 20 files changed, 245 insertions(+), 20 deletions(-) create mode 100755 akka-bbb-fsesl/run-dev.sh create mode 100755 akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/events/VoiceConfRunningAndRecordingEvent.java diff --git a/akka-bbb-apps/.gitignore b/akka-bbb-apps/.gitignore index 1c0e395724..28cb15fcec 100644 --- a/akka-bbb-apps/.gitignore +++ b/akka-bbb-apps/.gitignore @@ -47,3 +47,5 @@ akka-patterns-store/ lib_managed/ .cache bin/ +src/main/resources/ + 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 da8d9d6290..78288fbcab 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 @@ -148,6 +148,8 @@ class ReceivedJsonMsgHandlerActor( routeGenericMsg[MuteMeetingCmdMsg](envelope, jsonNode) case IsMeetingMutedReqMsg.NAME => routeGenericMsg[IsMeetingMutedReqMsg](envelope, jsonNode) + case CheckRunningAndRecordingVoiceConfEvtMsg.NAME => + routeVoiceMsg[CheckRunningAndRecordingVoiceConfEvtMsg](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 526e831e23..d31ffee053 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 @@ -376,10 +376,12 @@ class MeetingActor( case m: UserConnectedToGlobalAudioMsg => handleUserConnectedToGlobalAudioMsg(m) case m: UserDisconnectedFromGlobalAudioMsg => handleUserDisconnectedFromGlobalAudioMsg(m) case m: VoiceConfRunningEvtMsg => handleVoiceConfRunningEvtMsg(m) + case m: CheckRunningAndRecordingVoiceConfEvtMsg => + handleCheckRunningAndRecordingVoiceConfEvtMsg(m) // Layout - case m: GetCurrentLayoutReqMsg => handleGetCurrentLayoutReqMsg(m) - case m: BroadcastLayoutMsg => handleBroadcastLayoutMsg(m) + case m: GetCurrentLayoutReqMsg => handleGetCurrentLayoutReqMsg(m) + case m: BroadcastLayoutMsg => handleBroadcastLayoutMsg(m) // Lock Settings case m: ChangeLockSettingsInMeetingCmdMsg => @@ -532,12 +534,28 @@ class MeetingActor( sendRttTraceTest() setRecordingChapterBreak() + checkVoiceConfIsRunningAndRecording() processUserInactivityAudit() flagRegisteredUsersWhoHasNotJoined() checkIfNeetToEndMeetingWhenNoAuthedUsers(liveMeeting) } + var lastVoiceRecordingAndRunningCheck = System.currentTimeMillis() + def checkVoiceConfIsRunningAndRecording(): Unit = { + val now = System.currentTimeMillis() + val elapsedTime = now - lastVoiceRecordingAndRunningCheck; + val timeToCheck = elapsedTime > 30000 // 30seconds + if (props.recordProp.record && timeToCheck) { + lastVoiceRecordingAndRunningCheck = now + val event = MsgBuilder.buildCheckRunningAndRecordingToVoiceConfSysMsg( + props.meetingProp.intId, + props.voiceProp.voiceConf + ) + outGW.send(event) + } + } + var lastRecBreakSentOn = expiryTracker.startedOnInMs def setRecordingChapterBreak(): Unit = { @@ -707,4 +725,21 @@ class MeetingActor( } } } + + def handleCheckRunningAndRecordingVoiceConfEvtMsg(msg: CheckRunningAndRecordingVoiceConfEvtMsg): Unit = { + if (liveMeeting.props.recordProp.record && + msg.body.isRunning && + !msg.body.isRecording) { + // Voice conference is running but not recording. We should start recording. + // But first, see if we have recording streams and stop those. + VoiceApp.stopRecordingVoiceConference(liveMeeting, outGW) + + // Let us start recording. + val meetingId = liveMeeting.props.meetingProp.intId + val recordFile = VoiceApp.genRecordPath(voiceConfRecordPath, meetingId, TimeUtil.timeNowInMs()) + log.info("Forcing START RECORDING voice conf. meetingId=" + meetingId + " voice conf=" + liveMeeting.props.voiceProp.voiceConf) + + VoiceApp.startRecordingVoiceConference(liveMeeting, outGW, recordFile) + } + } } 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 6d3b2587fb..a975d0560a 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 @@ -123,6 +123,10 @@ class AnalyticsActor extends Actor with ActorLogging { // Recording case m: RecordingChapterBreakSysMsg => logMessage(msg) + case m: VoiceRecordingStartedEvtMsg => logMessage(msg) + case m: VoiceRecordingStoppedEvtMsgBody => logMessage(msg) + //case m: CheckRunningAndRecordingToVoiceConfSysMsg => logMessage(msg) + //case m: CheckRunningAndRecordingVoiceConfEvtMsg => logMessage(msg) case m: GetLockSettingsRespMsg => logMessage(msg) case m: ChangeLockSettingsInMeetingCmdMsg => logMessage(msg) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/FromAkkaAppsMsgSenderActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/FromAkkaAppsMsgSenderActor.scala index abb577ac35..36a4a2cdae 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/FromAkkaAppsMsgSenderActor.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/FromAkkaAppsMsgSenderActor.scala @@ -48,6 +48,8 @@ class FromAkkaAppsMsgSenderActor(msgSender: MessageSender) msgSender.send(toVoiceConfRedisChannel, json) case TransferUserToVoiceConfSysMsg.NAME => msgSender.send(toVoiceConfRedisChannel, json) + case CheckRunningAndRecordingToVoiceConfSysMsg.NAME => + msgSender.send(toVoiceConfRedisChannel, json) //================================================================== // Send chat, presentation, and whiteboard in different channels so as not to diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/MeetingStatus2x.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/MeetingStatus2x.scala index bea9bd6257..9228d659a9 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/MeetingStatus2x.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/MeetingStatus2x.scala @@ -22,13 +22,6 @@ case class MeetingExtensionProp(maxExtensions: Int = 2, numExtensions: Int = 0, object MeetingStatus2x { - def isVoiceRecording(status: MeetingStatus2x): Boolean = { - status.voiceRecordings.values.find(s => s.recording) match { - case Some(rec) => true - case None => false - } - } - def isExtensionAllowed(status: MeetingStatus2x): Boolean = status.extension.numExtensions < status.extension.maxExtensions def incNumExtension(status: MeetingStatus2x): Int = { if (status.extension.numExtensions < status.extension.maxExtensions) { @@ -56,6 +49,13 @@ object MeetingStatus2x { def getLastAuthedUserLeftOn(status: MeetingStatus2x): Long = status.lastAuthedUserLeftOn def resetLastAuthedUserLeftOn(status: MeetingStatus2x) = status.lastAuthedUserLeftOn = 0L + def isVoiceRecording(status: MeetingStatus2x): Boolean = { + status.voiceRecordings.values.find(s => s.recording) match { + case Some(rec) => true + case None => false + } + } + def voiceRecordingStart(status2x: MeetingStatus2x, stream: String): VoiceRecordingStream = { val vrs = new VoiceRecordingStream(stream, recording = false, createdOn = System.currentTimeMillis, ackedOn = None, stoppedOn = None) status2x.voiceRecordings += vrs.stream -> vrs @@ -111,7 +111,8 @@ object MeetingStatus2x { } class MeetingStatus2x { - private var voiceRecordings: collection.immutable.HashMap[String, VoiceRecordingStream] = new collection.immutable.HashMap[String, VoiceRecordingStream] + private var voiceRecordings: collection.immutable.HashMap[String, VoiceRecordingStream] = + new collection.immutable.HashMap[String, VoiceRecordingStream] private var audioSettingsInited = false private var permissionsInited = false diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/MsgBuilder.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/MsgBuilder.scala index ac693a9b1c..33839c0f27 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/MsgBuilder.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/MsgBuilder.scala @@ -289,6 +289,15 @@ object MsgBuilder { BbbCommonEnvCoreMsg(envelope, event) } + def buildCheckRunningAndRecordingToVoiceConfSysMsg(meetingId: String, voiceConf: String): BbbCommonEnvCoreMsg = { + val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka") + val envelope = BbbCoreEnvelope(CheckRunningAndRecordingToVoiceConfSysMsg.NAME, routing) + val header = BbbCoreHeaderWithMeetingId(CheckRunningAndRecordingToVoiceConfSysMsg.NAME, meetingId) + val body = CheckRunningAndRecordingToVoiceConfSysMsgBody(voiceConf, meetingId) + val event = CheckRunningAndRecordingToVoiceConfSysMsg(header, body) + BbbCommonEnvCoreMsg(envelope, event) + } + def buildStartRecordingVoiceConfSysMsg(meetingId: String, voiceConf: String, stream: String): BbbCommonEnvCoreMsg = { val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka") val envelope = BbbCoreEnvelope(StartRecordingVoiceConfSysMsg.NAME, routing) diff --git a/akka-bbb-fsesl/.gitignore b/akka-bbb-fsesl/.gitignore index 1c0e395724..446435b973 100644 --- a/akka-bbb-fsesl/.gitignore +++ b/akka-bbb-fsesl/.gitignore @@ -47,3 +47,4 @@ akka-patterns-store/ lib_managed/ .cache bin/ +src/main/resources/ diff --git a/akka-bbb-fsesl/run-dev.sh b/akka-bbb-fsesl/run-dev.sh new file mode 100755 index 0000000000..d08b052304 --- /dev/null +++ b/akka-bbb-fsesl/run-dev.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +rm -rf src/main/resources +cp -R src/universal/conf src/main/resources +sbt run + 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 445d169314..a0386f5225 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 @@ -88,7 +88,17 @@ public class FreeswitchConferenceEventListener implements ConferenceEventListene vcs.deskShareRTMPBroadcastStopped(evt.getRoom(), evt.getBroadcastingStreamUrl(), evt.getVideoWidth(), evt.getVideoHeight(), evt.getTimestamp()); } + } else if (event instanceof VoiceConfRunningAndRecordingEvent) { + VoiceConfRunningAndRecordingEvent evt = (VoiceConfRunningAndRecordingEvent) event; + if (evt.running && ! evt.recording) { + log.warn("Voice conf running but not recording. conf=" + evt.getRoom() + + ",running=" + evt.running + + ",rec=" + evt.recording); + } + + vcs.voiceConfRunningAndRecording(evt.getRoom(), evt.running, evt.recording); } + } }; 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 dd7fb1d13e..76b43997c5 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 @@ -24,4 +24,6 @@ public interface IVoiceConferenceService { void deskShareRTMPBroadcastStopped(String room, String streamname, Integer videoWidth, Integer videoHeight, String timestamp); + void voiceConfRunningAndRecording(String room, Boolean isRunning, Boolean isRecording); + } diff --git a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/events/VoiceConfRunningAndRecordingEvent.java b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/events/VoiceConfRunningAndRecordingEvent.java new file mode 100755 index 0000000000..0d3332c55c --- /dev/null +++ b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/events/VoiceConfRunningAndRecordingEvent.java @@ -0,0 +1,31 @@ +/** + * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ + * <p> + * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below). + * <p> + * This program is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation; either version 3.0 of the License, or (at your option) any later + * version. + * <p> + * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * <p> + * You should have received a copy of the GNU Lesser General Public License along + * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. + */ +package org.bigbluebutton.freeswitch.voice.events; + +public class VoiceConfRunningAndRecordingEvent extends VoiceConferenceEvent { + + public final boolean running; + public final boolean recording; + + public VoiceConfRunningAndRecordingEvent(String room, boolean running, boolean recording) { + super(room); + this.running = running; + this.recording = recording; + } + +} diff --git a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/FreeswitchApplication.java b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/FreeswitchApplication.java index e031107a3d..36af8398a3 100755 --- a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/FreeswitchApplication.java +++ b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/FreeswitchApplication.java @@ -103,12 +103,14 @@ public class FreeswitchApplication implements IDelayedCommandListener{ msgSenderExec.execute(sender); } + public void checkRunningAndRecording(String voiceConfId, String meetingId) { + ConferenceCheckRecordCommand ccrc = new ConferenceCheckRecordCommand(voiceConfId, meetingId); + queueMessage(ccrc); + } + public void getAllUsers(String voiceConfId) { GetAllUsersCommand prc = new GetAllUsersCommand(voiceConfId, USER); queueMessage(prc); - - ConferenceCheckRecordCommand ccrc = new ConferenceCheckRecordCommand(voiceConfId, USER); - queueMessage(ccrc); } public void muteUser(String voiceConfId, String voiceUserId, Boolean mute) { diff --git a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/CheckIfConfIsRunningCommand.java b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/CheckIfConfIsRunningCommand.java index 934e57826b..68df9d5922 100755 --- a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/CheckIfConfIsRunningCommand.java +++ b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/CheckIfConfIsRunningCommand.java @@ -60,7 +60,7 @@ public class CheckIfConfIsRunningCommand extends FreeswitchCommand { String firstLine = response.getBodyLines().get(0); - log.info("Check conference first line response: " + firstLine); + //log.info("Check conference first line response: " + firstLine); //E.g. Conference 85115 not found if(!firstLine.startsWith("<?xml")) { diff --git a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/ConferenceCheckRecordCommand.java b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/ConferenceCheckRecordCommand.java index 56c887d475..b9c648a743 100755 --- a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/ConferenceCheckRecordCommand.java +++ b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/actions/ConferenceCheckRecordCommand.java @@ -1,11 +1,24 @@ package org.bigbluebutton.freeswitch.voice.freeswitch.actions; +import org.apache.commons.lang3.StringUtils; import org.bigbluebutton.freeswitch.voice.events.ConferenceEventListener; +import org.bigbluebutton.freeswitch.voice.events.VoiceConfRunningAndRecordingEvent; +import org.bigbluebutton.freeswitch.voice.freeswitch.response.ConferenceMember; +import org.bigbluebutton.freeswitch.voice.freeswitch.response.XMLResponseConferenceListParser; import org.freeswitch.esl.client.transport.message.EslMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.SAXException; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import java.io.ByteArrayInputStream; +import java.io.IOException; import java.util.Iterator; public class ConferenceCheckRecordCommand extends FreeswitchCommand { + private static Logger log = LoggerFactory.getLogger(ConferenceCheckRecordCommand.class); public ConferenceCheckRecordCommand(String room, String requesterId) { super(room, requesterId); @@ -13,14 +26,69 @@ public class ConferenceCheckRecordCommand extends FreeswitchCommand { @Override public String getCommandArgs() { - return room + " chkrecord"; + //return room + " chkrecord"; + return getRoom() + SPACE + "xml_list"; } public void handleResponse(EslMessage response, ConferenceEventListener eventListener) { - Iterator iterator = response.getBodyLines().iterator(); - while(iterator.hasNext()) { - System.out.println(iterator.next()); + String firstLine = response.getBodyLines().get(0); + //log.info("Check conference first line response: " + firstLine); + + if(!firstLine.startsWith("<?xml")) { + //log.info("Conference is not running and recording {}.", room); + VoiceConfRunningAndRecordingEvent voiceConfRunningAndRecordingEvent = + new VoiceConfRunningAndRecordingEvent(getRoom(), false, false); + eventListener.handleConferenceEvent(voiceConfRunningAndRecordingEvent); + return; + } + + XMLResponseConferenceListParser confXML = new XMLResponseConferenceListParser(); + //get a factory + SAXParserFactory spf = SAXParserFactory.newInstance(); + try { + + boolean running = false; + boolean recording = false; + + //get a new instance of parser + SAXParser sp = spf.newSAXParser(); + + //Hack turning body lines back into string then to ByteStream.... BLAH! + String responseBody = StringUtils.join(response.getBodyLines(), "\n"); + //http://mark.koli.ch/2009/02/resolving-orgxmlsaxsaxparseexception-content-is-not-allowed-in-prolog.html + //This Sux! + responseBody = responseBody.trim().replaceFirst("^([\\W]+)<","<"); + + ByteArrayInputStream bs = new ByteArrayInputStream(responseBody.getBytes()); + sp.parse(bs, confXML); + + Integer numUsers = confXML.getConferenceList().size(); + if (numUsers > 0) { + //log.info("Check conference response: " + responseBody); + running = true; + + for (ConferenceMember member : confXML.getConferenceList()) { + if ("caller".equals(member.getMemberType())) { + // We don't need this. If there is at least one user in the conference, + // then it is running. (ralam Oct 16, 2019) + + } else if ("recording_node".equals(member.getMemberType())) { + recording = true; + } + } + } + + VoiceConfRunningAndRecordingEvent voiceConfRunningAndRecordingEvent = + new VoiceConfRunningAndRecordingEvent(getRoom(), running, recording); + eventListener.handleConferenceEvent(voiceConfRunningAndRecordingEvent); + + }catch(SAXException se) { + log.error("Cannot parse response. ", se); + }catch(ParserConfigurationException pce) { + log.error("ParserConfigurationException. ", pce); + }catch (IOException ie) { + log.error("Cannot parse response. IO Exception. ", ie); } } } diff --git a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/response/XMLResponseConferenceListParser.java b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/response/XMLResponseConferenceListParser.java index 48d7df3b48..7fbbd1a99d 100755 --- a/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/response/XMLResponseConferenceListParser.java +++ b/akka-bbb-fsesl/src/main/java/org/bigbluebutton/freeswitch/voice/freeswitch/response/XMLResponseConferenceListParser.java @@ -93,7 +93,6 @@ public class XMLResponseConferenceListParser extends DefaultHandler { tempVal = ""; if(qName.equalsIgnoreCase("member")) { String memberType = attributes.getValue("type"); - System.out.println("******************* Member Type = " + memberType); //create a new instance of ConferenceMember tempMember = new ConferenceMember(); diff --git a/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/freeswitch/RxJsonMsgDeserializer.scala b/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/freeswitch/RxJsonMsgDeserializer.scala index 7e69fdbdc1..1170cd5e07 100755 --- a/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/freeswitch/RxJsonMsgDeserializer.scala +++ b/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/freeswitch/RxJsonMsgDeserializer.scala @@ -9,6 +9,24 @@ trait RxJsonMsgDeserializer { object JsonDeserializer extends Deserializer + def routeCheckRunningAndRecordingToVoiceConfSysMsg(envelope: BbbCoreEnvelope, jsonNode: JsonNode): Unit = { + def deserialize(jsonNode: JsonNode): Option[CheckRunningAndRecordingToVoiceConfSysMsg] = { + val (result, error) = JsonDeserializer.toBbbCommonMsg[CheckRunningAndRecordingToVoiceConfSysMsg](jsonNode) + result match { + case Some(msg) => Some(msg.asInstanceOf[CheckRunningAndRecordingToVoiceConfSysMsg]) + case None => + log.error("Failed to deserialize message: error: {} \n msg: {}", error, jsonNode) + None + } + } + + for { + m <- deserialize(jsonNode) + } yield { + fsApp.checkRunningAndRecording(m.body.voiceConf, m.body.meetingId) + } + } + def routeDeskshareStartRtmpBroadcastVoiceConfMsg(envelope: BbbCoreEnvelope, jsonNode: JsonNode): Unit = { def deserialize(jsonNode: JsonNode): Option[ScreenshareStartRtmpBroadcastVoiceConfMsg] = { val (result, error) = JsonDeserializer.toBbbCommonMsg[ScreenshareStartRtmpBroadcastVoiceConfMsg](jsonNode) diff --git a/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/freeswitch/RxJsonMsgHdlrActor.scala b/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/freeswitch/RxJsonMsgHdlrActor.scala index 546c361cbb..0dba78515a 100755 --- a/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/freeswitch/RxJsonMsgHdlrActor.scala +++ b/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/freeswitch/RxJsonMsgHdlrActor.scala @@ -52,6 +52,8 @@ class RxJsonMsgHdlrActor(val fsApp: FreeswitchApplication) extends Actor with Ac routeDeskshareStopRtmpBroadcastVoiceConfMsg(envelope, jsonNode) case ScreenshareStartRtmpBroadcastVoiceConfMsg.NAME => routeDeskshareStartRtmpBroadcastVoiceConfMsg(envelope, jsonNode) + case CheckRunningAndRecordingToVoiceConfSysMsg.NAME => + routeCheckRunningAndRecordingToVoiceConfSysMsg(envelope, jsonNode) case _ => // do nothing } } 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 6ca12d8790..81dee9e5b8 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 @@ -10,6 +10,18 @@ class VoiceConferenceService(sender: RedisPublisher) extends IVoiceConferenceSer val FROM_VOICE_CONF_SYSTEM_CHAN = "bigbluebutton:from-voice-conf:system" + def voiceConfRunningAndRecording(voiceConfId: String, isRunning: java.lang.Boolean, isRecording: java.lang.Boolean) { + val header = BbbCoreVoiceConfHeader(CheckRunningAndRecordingVoiceConfEvtMsg.NAME, voiceConfId) + val body = CheckRunningAndRecordingVoiceConfEvtMsgBody(voiceConfId, isRunning.booleanValue(), isRecording.booleanValue()) + val envelope = BbbCoreEnvelope(CheckRunningAndRecordingVoiceConfEvtMsg.NAME, Map("voiceConf" -> voiceConfId)) + + val msg = new CheckRunningAndRecordingVoiceConfEvtMsg(header, body) + val msgEvent = BbbCommonEnvCoreMsg(envelope, msg) + + val json = JsonUtil.toJson(msgEvent) + sender.publish(fromVoiceConfRedisChannel, json) + } + def voiceConfRecordingStarted(voiceConfId: String, recordStream: String, recording: java.lang.Boolean, timestamp: String) { val header = BbbCoreVoiceConfHeader(RecordingStartedVoiceConfEvtMsg.NAME, voiceConfId) val body = RecordingStartedVoiceConfEvtMsgBody(voiceConfId, recordStream, recording.booleanValue(), timestamp) @@ -24,7 +36,6 @@ class VoiceConferenceService(sender: RedisPublisher) extends IVoiceConferenceSer } def voiceConfRunning(voiceConfId: String, running: java.lang.Boolean): Unit = { - println("*************######## Conference voiceConfId=" + voiceConfId + " running=" + running) val header = BbbCoreVoiceConfHeader(VoiceConfRunningEvtMsg.NAME, voiceConfId) val body = VoiceConfRunningEvtMsgBody(voiceConfId, running.booleanValue()) val envelope = BbbCoreEnvelope(VoiceConfRunningEvtMsg.NAME, Map("voiceConf" -> voiceConfId)) 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 c228dbae47..6e4154769d 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 @@ -253,6 +253,26 @@ case class TransferUserToVoiceConfSysMsg( ) extends BbbCoreMsg case class TransferUserToVoiceConfSysMsgBody(fromVoiceConf: String, toVoiceConf: String, voiceUserId: String) +/** + * Sent to FS to check if voice conference is running and recording. + */ +object CheckRunningAndRecordingToVoiceConfSysMsg { val NAME = "CheckRunningAndRecordingToVoiceConfSysMsg" } +case class CheckRunningAndRecordingToVoiceConfSysMsg( + header: BbbCoreHeaderWithMeetingId, + body: CheckRunningAndRecordingToVoiceConfSysMsgBody +) extends BbbCoreMsg +case class CheckRunningAndRecordingToVoiceConfSysMsgBody(voiceConf: String, meetingId: String) + +/** + * Received from FS to check if voice conference is running and recording. + */ +object CheckRunningAndRecordingVoiceConfEvtMsg { val NAME = "CheckRunningAndRecordingVoiceConfEvtMsg" } +case class CheckRunningAndRecordingVoiceConfEvtMsg( + header: BbbCoreVoiceConfHeader, + body: CheckRunningAndRecordingVoiceConfEvtMsgBody +) extends VoiceStandardMsg +case class CheckRunningAndRecordingVoiceConfEvtMsgBody(voiceConf: String, isRunning: Boolean, isRecording: Boolean) + /** * Received from FS that user joined voice conference. */ -- GitLab