/** * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ * * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below). * * 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. * * 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. * * 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.app.screenshare.red5; import java.util.Set; import java.util.ArrayList; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import org.red5.logging.Red5LoggerFactory; import org.red5.server.api.IConnection; import org.red5.server.api.scope.IScope; import org.red5.server.api.scope.ScopeType; import org.red5.server.api.service.ServiceUtils; import org.red5.server.api.so.ISharedObject; import org.red5.server.api.so.ISharedObjectService; import org.red5.server.so.SharedObjectService; import org.red5.server.util.ScopeUtils; import org.slf4j.Logger; public class ConnectionInvokerService { private static Logger log = Red5LoggerFactory.getLogger(ConnectionInvokerService.class, "screenshare"); private static final int NTHREADS = 1; private static final Executor exec = Executors.newFixedThreadPool(NTHREADS); private static final Executor runExec = Executors.newFixedThreadPool(NTHREADS); private BlockingQueue<ClientMessage> messages; private volatile boolean sendMessages = false; private IScope bbbAppScope; public ConnectionInvokerService() { messages = new LinkedBlockingQueue<ClientMessage>(); } public void setAppScope(IScope scope) { bbbAppScope = scope; } public void start() { sendMessages = true; Runnable sender = new Runnable() { public void run() { while (sendMessages) { ClientMessage message; try { message = messages.take(); sendMessageToClient(message); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }; exec.execute(sender); } public void stop() { sendMessages = false; } public void sendMessage(final ClientMessage message) { messages.offer(message); } private void sendMessageToClient(ClientMessage message) { if (message instanceof BroadcastClientMessage) { sendBroadcastMessage((BroadcastClientMessage) message); } else if (message instanceof DirectClientMessage) { sendDirectMessage((DirectClientMessage) message); } else if (message instanceof SharedObjectClientMessage) { sendSharedObjectMessage((SharedObjectClientMessage) message); } else if (message instanceof DisconnectClientMessage) { handlDisconnectClientMessage((DisconnectClientMessage) message); } else if (message instanceof DisconnectAllClientsMessage) { handleDisconnectAllClientsMessage((DisconnectAllClientsMessage) message); } } private void handleDisconnectAllClientsMessage(DisconnectAllClientsMessage msg) { IScope meetingScope = getScope(msg.getMeetingId()); if (meetingScope != null) { Set<IConnection> conns = meetingScope.getClientConnections(); for (IConnection conn : conns) { if (conn.isConnected()) { String connId = (String) conn.getAttribute("USERID"); log.info("Disconnecting client=[{}] from meeting=[{}]", connId, msg.getMeetingId()); conn.close(); } } } } private void handlDisconnectClientMessage(DisconnectClientMessage msg) { IScope meetingScope = getScope(msg.getMeetingId()); if (meetingScope != null) { IConnection conn = getConnection(meetingScope, msg.getUserId()); if (conn != null) { if (conn.isConnected()) { log.info("Disconnecting user=[{}] from meeting=[{}]", msg.getUserId(), msg.getMeetingId()); conn.close(); } } } } private void sendSharedObjectMessage(SharedObjectClientMessage msg) { System.out.println("*********** Request to send [" + msg.getMessageName() + "] using shared object."); IScope meetingScope = getScope(msg.getMeetingID()); if (meetingScope != null) { if (meetingScope.hasChildScope(ScopeType.SHARED_OBJECT, msg.getSharedObjectName())) { ISharedObject so = getSharedObject(meetingScope, msg.getSharedObjectName()); if (so != null) { System.out.println("*********** Sending [" + msg.getMessageName() + "] using shared object."); so.sendMessage(msg.getMessageName(), msg.getMessage()); } else { System.out.println("**** Cannot get SO for [" + msg.getSharedObjectName() + "]"); } } else { System.out.println("**** No SO scope for [" + msg.getSharedObjectName() + "]"); } } else { System.out.println("**** No Meeting scope for [" + msg.getMeetingID() + "]"); } } private void sendDirectMessage(final DirectClientMessage msg) { Runnable sender = new Runnable() { public void run() { IScope meetingScope = getScope(msg.getMeetingID()); if (meetingScope != null) { log.debug("Found scope =[{}] for meeting=[{}]", meetingScope.getName(), msg.getMeetingID()); IConnection conn = getConnection(meetingScope, msg.getUserID()); if (conn != null) { if (conn.isConnected()) { List<Object> params = new ArrayList<Object>(); params.add(msg.getMessageName()); params.add(msg.getMessage()); log.debug("Sending message=[{}] to meeting=[{}]", msg.getMessageName(), msg.getMeetingID()); ServiceUtils.invokeOnConnection(conn, "onMessageFromServer", params.toArray()); } else { log.warn("Connection not connected for userid=[{}] in meeting=[{}]", msg.getUserID(), msg.getMeetingID()); } } else { log.warn("No connection for userid=[{}] in meeting=[{}]", msg.getUserID(), msg.getMeetingID()); } } else { log.error("Failed to find scope for meeting=[{}]", msg.getMeetingID()); } } }; runExec.execute(sender); } private void sendBroadcastMessage(final BroadcastClientMessage msg) { Runnable sender = new Runnable() { public void run() { IScope meetingScope = getScope(msg.getMeetingID()); if (meetingScope != null) { List<Object> params = new ArrayList<Object>(); params.add(msg.getMessageName()); params.add(msg.getMessage()); ServiceUtils.invokeOnAllScopeConnections(meetingScope, "onMessageFromServer", params.toArray(), null); } } }; runExec.execute(sender); } private IConnection getConnection(IScope scope, String userID) { Set<IConnection> conns = scope.getClientConnections(); for (IConnection conn : conns) { String connID = (String) conn.getAttribute("USERID"); if (connID != null && connID.equals(userID)) { return conn; } } return null; } public IScope getScope(String meetingID) { if (bbbAppScope != null) { return bbbAppScope.getContext().resolveScope("screenshare/" + meetingID); } else { log.error("BigBlueButton Scope not initialized. No messages are going to the Flash client!"); } return null; } private ISharedObject getSharedObject(IScope scope, String name) { ISharedObjectService service = (ISharedObjectService) ScopeUtils.getScopeService(scope, ISharedObjectService.class, SharedObjectService.class, false); return service.getSharedObject(scope, name); } }