package org.bigbluebutton.app.screenshare.red5; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import org.bigbluebutton.app.screenshare.messaging.redis.MessageSender; import org.red5.logging.Red5LoggerFactory; import org.red5.server.api.IConnection; import org.red5.server.api.Red5; import org.slf4j.Logger; import com.google.gson.Gson; public class Red5AppService { private static Logger log = Red5LoggerFactory.getLogger(Red5AppService.class, "screenshare"); private Red5AppHandler handler; private MessageSender red5RedisSender; /** * Called from the client to pass us the userId. * * We need to do this as we can't have params on the connect call * as FFMpeg won't be able to connect. * @param userId */ public void setUserId(Map<String, Object> msg) { String meetingId = Red5.getConnectionLocal().getScope().getName(); String userId = (String) msg.get("userId"); String connType = getConnectionType(Red5.getConnectionLocal().getType()); String sessionId = Red5.getConnectionLocal().getSessionId(); /** * Find if there are any other connections owned by this user. If we find one, * that means that the connection is old and the user reconnected. Clear the * userId attribute so that messages would not be sent in the defunct connection. */ Set<IConnection> conns = Red5.getConnectionLocal().getScope().getClientConnections(); for (IConnection conn : conns) { String connUserId = (String) conn.getAttribute("USERID"); String connSessionId = conn.getSessionId(); if (connUserId != null && connUserId.equals(userId) && !connSessionId.equals(sessionId)) { conn.removeAttribute("USERID"); Map<String, Object> logData = new HashMap<String, Object>(); logData.put("meetingId", meetingId); logData.put("userId", userId); logData.put("oldConnId", connSessionId); logData.put("newConnId", sessionId); logData.put("event", "removing_defunct_connection"); logData.put("description", "Removing defunct connection BBB Screenshare."); Gson gson = new Gson(); String logStr = gson.toJson(logData); log.info("Removing defunct connection: data={}", logStr); } } Red5.getConnectionLocal().setAttribute("MEETING_ID", meetingId); Red5.getConnectionLocal().setAttribute("USERID", userId); handler.userConnected(meetingId, userId); Map<String, Object> logData = new HashMap<String, Object>(); logData.put("meetingId", meetingId); logData.put("userId", userId); logData.put("connType", connType); logData.put("connId", sessionId); logData.put("event", "user_joining_bbb_screenshare"); logData.put("description", "User joining BBB Screenshare."); Gson gson = new Gson(); String logStr = gson.toJson(logData); log.info("User joining bbb-screenshare: data={}", logStr); } private String getConnectionType(String connType) { if ("persistent".equals(connType.toLowerCase())) { return "RTMP"; } else if("polling".equals(connType.toLowerCase())) { return "RTMPT"; } else { return connType.toUpperCase(); } } public void isScreenSharing(Map<String, Object> msg) { String meetingId = Red5.getConnectionLocal().getScope().getName(); String userId = (String) Red5.getConnectionLocal().getAttribute("USERID"); if (log.isDebugEnabled()) { log.debug("Received check if publishing for meetingId=" + meetingId + " from user=" + userId); } handler.isScreenSharing(meetingId, userId); } public void pauseShareRequest(Map<String, Object> msg) { String meetingId = Red5.getConnectionLocal().getScope().getName(); log.debug("Received pauseShareRequest for meeting=[{}]", meetingId); String userId = (String) Red5.getConnectionLocal().getAttribute("USERID"); String streamId = (String) msg.get("streamId"); handler.pauseShareRequest(meetingId, userId, streamId); } public void restartShareRequest(Map<String, Object> msg) { String meetingId = Red5.getConnectionLocal().getScope().getName(); String userId = (String) Red5.getConnectionLocal().getAttribute("USERID"); if (log.isDebugEnabled()) { log.debug("Received restartShareRequest for meetingId=" + meetingId + " from user=" + userId); } handler.restartShareRequest(meetingId, userId); } public void startShareRequest(Map<String, Object> msg) { String session = (String) msg.get("session"); String meetingId = Red5.getConnectionLocal().getScope().getName(); String userId = (String) Red5.getConnectionLocal().getAttribute("USERID"); if (log.isDebugEnabled()) { log.debug("Received startShareRequest for meetingId=" + meetingId + " from user=" + userId); } handler.startShareRequest(meetingId, userId, session); } public void requestShareToken(Map<String, Object> msg) { Boolean record = (Boolean) msg.get("record"); String meetingId = Red5.getConnectionLocal().getScope().getName(); String userId = (String) Red5.getConnectionLocal().getAttribute("USERID"); Boolean tunnel = (Boolean) msg.get("tunnel"); if (log.isDebugEnabled()) { log.debug("Received startShareRequest for meetingId=" + meetingId + " from user=" + userId); } handler.requestShareToken(meetingId, userId, record, tunnel); } public void stopShareRequest(Map<String, Object> msg) { String meetingId = Red5.getConnectionLocal().getScope().getName(); String streamId = (String) msg.get("streamId"); String userId = (String) Red5.getConnectionLocal().getAttribute("USERID"); if (log.isDebugEnabled()) { log.debug("Received stopShareRequest for meetingId=" + meetingId + " from user=" + userId); } handler.stopShareRequest(meetingId, streamId); } public void screenShareClientPongMessage(Map<String, Object> msg) { String meetingId = Red5.getConnectionLocal().getScope().getName(); String streamId = (String) msg.get("streamId"); Double timestamp = (Double) msg.get("timestamp"); String userId = (String) Red5.getConnectionLocal().getAttribute("USERID"); //log.debug("Received screenShareClientPongMessage for meeting=[{}]", meetingId); handler.screenShareClientPongMessage(meetingId, userId, streamId, timestamp.longValue()); } private Long genTimestamp() { return TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); } public void setAppHandler(Red5AppHandler handler) { this.handler = handler; } public void setRed5RedisSender(MessageSender red5RedisSender) { this.red5RedisSender = red5RedisSender; } }