| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License") + you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.openmeetings.core.remote.red5; |
| |
| import static org.apache.openmeetings.util.OpenmeetingsVariables.webAppRootKey; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Date; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.UUID; |
| import java.util.concurrent.atomic.AtomicLong; |
| |
| import org.apache.openmeetings.IApplication; |
| import org.apache.openmeetings.core.data.conference.RoomManager; |
| import org.apache.openmeetings.core.data.whiteboard.WhiteboardManager; |
| import org.apache.openmeetings.core.remote.RecordingService; |
| import org.apache.openmeetings.core.remote.WhiteBoardService; |
| import org.apache.openmeetings.core.remote.util.SessionVariablesUtil; |
| import org.apache.openmeetings.db.dao.basic.ConfigurationDao; |
| import org.apache.openmeetings.db.dao.calendar.AppointmentDao; |
| import org.apache.openmeetings.db.dao.label.LabelDao; |
| import org.apache.openmeetings.db.dao.log.ConferenceLogDao; |
| import org.apache.openmeetings.db.dao.record.RecordingDao; |
| import org.apache.openmeetings.db.dao.room.RoomDao; |
| import org.apache.openmeetings.db.dao.server.ISessionManager; |
| import org.apache.openmeetings.db.dao.server.ServerDao; |
| import org.apache.openmeetings.db.dao.server.SessiondataDao; |
| import org.apache.openmeetings.db.dao.user.UserDao; |
| import org.apache.openmeetings.db.dto.room.BrowserStatus; |
| import org.apache.openmeetings.db.dto.room.RoomStatus; |
| import org.apache.openmeetings.db.entity.file.FileItem; |
| import org.apache.openmeetings.db.entity.log.ConferenceLog; |
| import org.apache.openmeetings.db.entity.room.Client; |
| import org.apache.openmeetings.db.entity.room.Room; |
| import org.apache.openmeetings.db.entity.room.Room.RoomElement; |
| import org.apache.openmeetings.db.entity.server.Server; |
| import org.apache.openmeetings.db.entity.user.User; |
| import org.apache.openmeetings.db.util.AuthLevelUtil; |
| import org.apache.openmeetings.util.CalendarPatterns; |
| import org.apache.openmeetings.util.InitializationContainer; |
| import org.apache.openmeetings.util.OmFileHelper; |
| import org.apache.openmeetings.util.OpenmeetingsVariables; |
| import org.apache.openmeetings.util.Version; |
| import org.apache.openmeetings.util.message.RoomMessage; |
| import org.apache.openmeetings.util.message.TextRoomMessage; |
| import org.apache.wicket.Application; |
| import org.apache.wicket.protocol.ws.WebSocketSettings; |
| import org.apache.wicket.protocol.ws.api.IWebSocketConnection; |
| import org.apache.wicket.protocol.ws.api.registry.IWebSocketConnectionRegistry; |
| import org.apache.wicket.util.string.StringValue; |
| import org.apache.wicket.util.string.Strings; |
| import org.red5.logging.Red5LoggerFactory; |
| import org.red5.server.adapter.ApplicationAdapter; |
| import org.red5.server.api.IClient; |
| import org.red5.server.api.IConnection; |
| import org.red5.server.api.Red5; |
| import org.red5.server.api.scope.IBasicScope; |
| import org.red5.server.api.scope.IBroadcastScope; |
| import org.red5.server.api.scope.IScope; |
| import org.red5.server.api.scope.ScopeType; |
| import org.red5.server.api.service.IPendingServiceCall; |
| import org.red5.server.api.service.IPendingServiceCallback; |
| import org.red5.server.api.service.IServiceCapableConnection; |
| import org.red5.server.api.stream.IBroadcastStream; |
| import org.slf4j.Logger; |
| import org.springframework.beans.factory.annotation.Autowired; |
| |
| public class ScopeApplicationAdapter extends ApplicationAdapter implements IPendingServiceCallback { |
| private static final Logger log = Red5LoggerFactory.getLogger(ScopeApplicationAdapter.class, webAppRootKey); |
| private static final String SECURITY_CODE_PARAM = "securityCode"; |
| |
| @Autowired |
| private ISessionManager sessionManager; |
| @Autowired |
| private WhiteBoardService whiteBoardService; |
| @Autowired |
| private WhiteboardManager whiteboardManagement; |
| @Autowired |
| private RecordingService recordingService; |
| @Autowired |
| private ConfigurationDao configurationDao; |
| @Autowired |
| private AppointmentDao appointmentDao; |
| @Autowired |
| private SessiondataDao sessiondataDao; |
| @Autowired |
| private RoomManager roomManager; |
| @Autowired |
| private ConferenceLogDao conferenceLogDao; |
| @Autowired |
| private UserDao userDao; |
| @Autowired |
| private RoomDao roomDao; |
| @Autowired |
| private RecordingDao recordingDao; |
| @Autowired |
| private ServerDao serverDao; |
| |
| private static AtomicLong broadCastCounter = new AtomicLong(0); |
| |
| @Override |
| public void resultReceived(IPendingServiceCall arg0) { |
| if (log.isTraceEnabled()) { |
| log.trace("resultReceived:: {}", arg0); |
| } |
| } |
| |
| @Override |
| public boolean appStart(IScope scope) { |
| try { |
| OmFileHelper.setOmHome(scope.getResource("/").getFile()); |
| LabelDao.initLanguageMap(); |
| |
| log.debug("webAppPath : " + OmFileHelper.getOmHome()); |
| |
| // Only load this Class one time Initially this value might by empty, because the DB is empty yet |
| getCryptKey(); |
| |
| // init your handler here |
| |
| for (String scopeName : scope.getScopeNames()) { |
| log.debug("scopeName :: " + scopeName); |
| } |
| |
| InitializationContainer.initComplete = true; |
| Version.logOMStarted(); |
| recordingDao.resetProcessingStatus(); //we are starting so all processing recordings are now errors |
| sessionManager.clearCache(); // 'sticky' clients should be cleaned up from DB |
| } catch (Exception err) { |
| log.error("[appStart]", err); |
| } |
| return true; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private static Map<String, Object> getConnParams(Object[] params) { |
| if (params != null && params.length > 0) { |
| return (Map<String, Object>)params[0]; |
| } |
| return new HashMap<>(); |
| } |
| |
| @Override |
| public boolean roomConnect(IConnection conn, Object[] params) { |
| log.debug("roomConnect : "); |
| |
| IServiceCapableConnection service = (IServiceCapableConnection) conn; |
| String streamId = conn.getClient().getId(); |
| |
| log.debug("### Client connected to OpenMeetings, register Client StreamId: " + streamId + " scope " + conn.getScope().getName()); |
| |
| // Set StreamId in Client |
| service.invoke("setId", new Object[] { streamId }, this); |
| |
| Map<String, Object> map = conn.getConnectParams(); |
| String swfURL = map.containsKey("swfUrl") ? (String)map.get("swfUrl") : ""; |
| String tcUrl = map.containsKey("tcUrl") ? (String)map.get("tcUrl") : ""; |
| Map<String, Object> connParams = getConnParams(params); |
| String uid = (String)connParams.get("uid"); |
| String securityCode = (String)connParams.get(SECURITY_CODE_PARAM); |
| if (!Strings.isEmpty(securityCode)) { |
| //FIXME TODO add better mechanism |
| Client parent = sessionManager.getClientByPublicSID(securityCode, null); |
| if (parent == null || !parent.getScope().equals(conn.getScope().getName())) { |
| return rejectClient(); |
| } |
| } |
| if (Strings.isEmpty(uid) && Strings.isEmpty(securityCode)) { |
| return rejectClient(); |
| } |
| if ("networktest".equals(uid)) { |
| return true; |
| } |
| |
| Client parentClient = null; |
| //TODO add similar code for other connections |
| if (map.containsKey("screenClient")) { |
| String parentSid = (String)map.get("parentSid"); |
| parentClient = sessionManager.getClientByPublicSID(parentSid, null); |
| if (parentClient == null) { |
| return rejectClient(); |
| } |
| } |
| Client rcm = new Client(); |
| rcm.setStreamid(conn.getClient().getId()); |
| StringValue scn = StringValue.valueOf(conn.getScope().getName()); |
| rcm.setScope(scn.toString()); |
| long roomId = scn.toLong(Long.MIN_VALUE); |
| if (Long.MIN_VALUE != roomId) { |
| rcm.setRoomId(roomId); |
| } else if (!"hibernate".equals(scn.toString())) { |
| return rejectClient(); |
| } |
| rcm.setUserport(conn.getRemotePort()); |
| rcm.setUserip(conn.getRemoteAddress()); |
| rcm.setSwfurl(swfURL); |
| rcm.setTcUrl(tcUrl); |
| rcm.setPublicSID(uid); |
| rcm.setSecurityCode(securityCode); |
| rcm = sessionManager.add(((IApplication)Application.get(OpenmeetingsVariables.wicketApplicationName)).updateClient(rcm), null); |
| if (rcm == null) { |
| log.warn("Failed to create Client on room connect"); |
| return false; |
| } |
| |
| SessionVariablesUtil.initClient(conn.getClient(), rcm.getPublicSID()); |
| //TODO add similar code for other connections, merge with above block |
| if (map.containsKey("screenClient")) { |
| //TODO add check for room rights |
| String parentSid = parentClient.getPublicSID(); |
| rcm.setRoomId(Long.valueOf(conn.getScope().getName())); |
| rcm.setScreenClient(true); |
| SessionVariablesUtil.setIsScreenClient(conn.getClient()); |
| |
| rcm.setUserId(parentClient.getUserId()); |
| Long userId = rcm.getUserId(); |
| SessionVariablesUtil.setUserId(conn.getClient(), userId); |
| |
| rcm.setStreamPublishName(parentSid); |
| User u = null; |
| if (userId != null) { |
| long _uid = userId.longValue(); |
| u = userDao.get(_uid < 0 ? -_uid : _uid); |
| } |
| if (u != null) { |
| rcm.setUsername(u.getLogin()); |
| rcm.setFirstname(u.getFirstname()); |
| rcm.setLastname(u.getLastname()); |
| } |
| log.debug("publishName :: " + rcm.getStreamPublishName()); |
| sessionManager.updateClientByStreamId(streamId, rcm, false, null); |
| } |
| |
| // Log the User |
| conferenceLogDao.add(ConferenceLog.Type.clientConnect, |
| rcm.getUserId(), streamId, null, rcm.getUserip(), |
| rcm.getScope()); |
| return true; |
| } |
| |
| public Map<String, String> screenSharerAction(Map<String, Object> map) { |
| Map<String, String> returnMap = new HashMap<String, String>(); |
| try { |
| log.debug("----------- screenSharerAction ENTER"); |
| IConnection current = Red5.getConnectionLocal(); |
| |
| Client client = sessionManager.getClientByStreamId(current.getClient().getId(), null); |
| |
| if (client != null) { |
| boolean changed = false; |
| if (Boolean.parseBoolean("" + map.get("stopStreaming")) && client.isStartStreaming()) { |
| changed = true; |
| client.setStartStreaming(false); |
| //Send message to all users |
| sendMessageToCurrentScope("stopScreenSharingMessage", client, false); |
| broadcastRoom(new TextRoomMessage(client.getRoomId(), client.getUserId(), RoomMessage.Type.sharingStoped, client.getStreamPublishName())); |
| |
| returnMap.put("result", "stopSharingOnly"); |
| } |
| if (Boolean.parseBoolean("" + map.get("stopRecording")) && client.getIsRecording()) { |
| changed = true; |
| client.setStartRecording(false); |
| client.setIsRecording(false); |
| |
| returnMap.put("result", "stopRecordingOnly"); |
| |
| recordingService.stopRecordAndSave(current.getScope(), client, null); |
| } |
| if (Boolean.parseBoolean("" + map.get("stopPublishing")) && client.isScreenPublishStarted()) { |
| changed = true; |
| client.setScreenPublishStarted(false); |
| returnMap.put("result", "stopPublishingOnly"); |
| |
| //Send message to all users |
| sendMessageToCurrentScope("stopPublishingMessage", client, false); |
| } |
| |
| if (changed) { |
| sessionManager.updateClientByStreamId(client.getStreamid(), client, false, null); |
| |
| if (!client.isStartStreaming() && !client.isStartRecording() && !client.isStreamPublishStarted()) { |
| returnMap.put("result", "stopAll"); |
| } |
| } |
| } |
| log.debug("----------- screenSharerAction, return: " + returnMap); |
| } catch (Exception err) { |
| log.error("[screenSharerAction]", err); |
| } |
| return returnMap; |
| } |
| |
| public List<Client> checkScreenSharing() { |
| try { |
| IConnection current = Red5.getConnectionLocal(); |
| String streamid = current.getClient().getId(); |
| |
| log.debug("checkScreenSharing -2- " + streamid); |
| |
| List<Client> screenSharerList = new LinkedList<Client>(); |
| |
| Client currentClient = sessionManager.getClientByStreamId(streamid, null); |
| |
| for (Client rcl : sessionManager.getClientListByRoomAll(currentClient.getRoomId())) { |
| if (rcl.isStartStreaming()) { |
| screenSharerList.add(rcl); |
| } |
| } |
| |
| return screenSharerList; |
| |
| } catch (Exception err) { |
| log.error("[checkScreenSharing]", err); |
| } |
| return null; |
| } |
| |
| /** |
| * |
| * @param map |
| * @return returns key,value Map with multiple return values or null in case of exception |
| * |
| */ |
| public Map<String, Object> setConnectionAsSharingClient(Map<String, Object> map) { |
| try { |
| log.debug("----------- setConnectionAsSharingClient"); |
| IConnection current = Red5.getConnectionLocal(); |
| |
| Client client = sessionManager.getClientByStreamId(current.getClient().getId(), null); |
| |
| if (client != null) { |
| boolean startRecording = Boolean.parseBoolean("" + map.get("startRecording")); |
| boolean startStreaming = Boolean.parseBoolean("" + map.get("startStreaming")); |
| boolean startPublishing = Boolean.parseBoolean("" + map.get("startPublishing")) && (0 == sessionManager.getPublishingCount(client.getRoomId())); |
| |
| boolean alreadyStreaming = client.isStartStreaming(); |
| if (startStreaming) { |
| client.setStartStreaming(true); |
| } |
| boolean alreadyRecording = client.isStartRecording(); |
| if (startRecording) { |
| client.setStartRecording(true); |
| } |
| if (startPublishing) { |
| client.setStreamPublishStarted(true); |
| } |
| |
| client.setVX(Double.valueOf("" + map.get("screenX")).intValue()); |
| client.setVY(Double.valueOf("" + map.get("screenY")).intValue()); |
| client.setVWidth(Double.valueOf("" + map.get("screenWidth")).intValue()); |
| client.setVHeight(Double.valueOf("" + map.get("screenHeight")).intValue()); |
| client.setStreamPublishName("" + map.get("publishName")); |
| sessionManager.updateClientByStreamId(current.getClient().getId(), client, false, null); |
| |
| Map<String, Object> returnMap = new HashMap<String, Object>(); |
| returnMap.put("alreadyPublished", false); |
| |
| // if is already started screen sharing, then there is no need |
| // to start it again |
| if (client.isScreenPublishStarted()) { |
| returnMap.put("alreadyPublished", true); |
| } |
| |
| log.debug(String.format("screen x,y,width,height %s,%s,%s,%s", client.getVX(), client.getVY(), client.getVWidth(), client.getVHeight())); |
| |
| if (startStreaming) { |
| if (!alreadyStreaming) { |
| returnMap.put("modus", "startStreaming"); |
| |
| log.debug("start streamPublishStart Is Screen Sharing "); |
| |
| //Send message to all users |
| sendMessageToCurrentScope("newScreenSharing", client, false); |
| broadcastRoom(new TextRoomMessage(client.getRoomId(), client.getUserId(), RoomMessage.Type.sharingStarted, client.getStreamPublishName())); |
| } else { |
| log.warn("Streaming is already started for the client id=" + client.getId() + ". Second request is ignored."); |
| } |
| } |
| if (startRecording) { |
| if (!alreadyRecording) { |
| returnMap.put("modus", "startRecording"); |
| |
| String recordingName = "Recording " + CalendarPatterns.getDateWithTimeByMiliSeconds(new Date()); |
| |
| recordingService.recordMeetingStream(current, client, recordingName, "", false); |
| } else { |
| log.warn("Recording is already started for the client id=" + client.getId() + ". Second request is ignored."); |
| } |
| } |
| if (startPublishing) { |
| sendMessageToCurrentScope("startedPublishing", new Object[]{client, "rtmp://" + map.get("publishingHost") + ":1935/" |
| + map.get("publishingApp") + "/" + map.get("publishingId")}, false, true); |
| returnMap.put("modus", "startPublishing"); |
| } |
| return returnMap; |
| } else { |
| log.error("[setConnectionAsSharingClient] Could not find Screen Sharing Client " + current.getClient().getId()); |
| } |
| } catch (Exception err) { |
| log.error("[setConnectionAsSharingClient]", err); |
| } |
| return null; |
| } |
| |
| public List<Long> listRoomBroadcast() { |
| Set<Long> broadcastList = new HashSet<>(); |
| IConnection current = Red5.getConnectionLocal(); |
| String streamid = current.getClient().getId(); |
| for (IConnection conn : current.getScope().getClientConnections()) { |
| if (conn != null) { |
| Client rcl = sessionManager.getClientByStreamId(conn.getClient().getId(), null); |
| if (rcl == null) { |
| // continue; |
| } else if (rcl.isScreenClient()) { |
| // continue; |
| } else { |
| if (!streamid.equals(rcl.getStreamid())) { |
| // It is not needed to send back |
| // that event to the actuall |
| // Moderator |
| // as it will be already triggered |
| // in the result of this Function |
| // in the Client |
| Long id = Long.valueOf(rcl.getBroadCastID()); |
| if (!broadcastList.contains(id)) { |
| broadcastList.add(id); |
| } |
| } |
| } |
| } |
| } |
| return new ArrayList<Long>(broadcastList); |
| } |
| |
| /** |
| * this function is invoked directly after initial connecting |
| * |
| * @return publicSID of current client |
| */ |
| public String getPublicSID() { |
| log.debug("----------- getPublicSID"); |
| IConnection current = Red5.getConnectionLocal(); |
| Client currentClient = sessionManager.getClientByStreamId(current.getClient().getId(), null); |
| sessionManager.updateClientByStreamId(current.getClient().getId(), currentClient, false, null); |
| return currentClient.getPublicSID(); |
| } |
| |
| /** |
| * this function is invoked after a reconnect |
| * |
| * @param newPublicSID |
| */ |
| public boolean overwritePublicSID(String newPublicSID) { |
| try { |
| log.debug("----------- overwritePublicSID"); |
| IConnection current = Red5.getConnectionLocal(); |
| IClient c = current.getClient(); |
| Client currentClient = sessionManager.getClientByStreamId(c.getId(), null); |
| if (currentClient == null) { |
| return false; |
| } |
| SessionVariablesUtil.initClient(c, newPublicSID); |
| currentClient.setPublicSID(newPublicSID); |
| sessionManager.updateClientByStreamId(c.getId(), currentClient, false, null); |
| return true; |
| } catch (Exception err) { |
| log.error("[overwritePublicSID]", err); |
| } |
| return false; |
| } |
| |
| /** |
| * Logic must be before roomDisconnect cause otherwise you cannot throw a |
| * message to each one |
| * |
| */ |
| @Override |
| public void roomLeave(IClient client, IScope room) { |
| try { |
| log.debug(String.format("roomLeave %s %s %s %s", client.getId(), room.getClients().size(), room.getContextPath(), room.getName())); |
| |
| Client currentClient = sessionManager.getClientByStreamId(client.getId(), null); |
| |
| // The Room Client can be null if the Client left the room by using |
| // logicalRoomLeave |
| if (currentClient != null) { |
| log.debug("currentClient IS NOT NULL"); |
| roomLeaveByScope(currentClient, room, true); |
| } |
| } catch (Exception err) { |
| log.error("[roomLeave]", err); |
| } |
| } |
| |
| /** |
| * this means a user has left a room but only logically, he didn't leave the |
| * app he just left the room |
| * |
| * FIXME: Is this really needed anymore if you re-connect to another scope? |
| * |
| * Exit Room by Application |
| * |
| */ |
| public void logicalRoomLeave() { |
| log.debug("logicalRoomLeave "); |
| try { |
| IConnection current = Red5.getConnectionLocal(); |
| String streamid = current.getClient().getId(); |
| |
| log.debug(streamid + " is leaving"); |
| |
| Client currentClient = sessionManager.getClientByStreamId(streamid, null); |
| |
| roomLeaveByScope(currentClient, current.getScope(), true); |
| } catch (Exception err) { |
| log.error("[logicalRoomLeave]", err); |
| } |
| } |
| |
| /** |
| * Removes the Client from the List, stops recording, adds the Room-Leave |
| * event to running recordings, clear Polls and removes Client from any list |
| * |
| * This function is kind of private/protected as the client won't be able |
| * to call it with proper values. |
| * |
| * @param client |
| * @param scope |
| */ |
| public void roomLeaveByScope(Client client, IScope scope, boolean removeUserFromSessionList) { |
| try { |
| log.debug("currentClient " + client); |
| Long roomId = client.getRoomId(); |
| |
| if (client.isScreenClient() && client.isStartStreaming()) { |
| //TODO check others/find better way |
| broadcastRoom(new TextRoomMessage(client.getRoomId(), client.getUserId(), RoomMessage.Type.sharingStoped, client.getStreamPublishName())); |
| } |
| |
| // Log the User |
| conferenceLogDao.add(ConferenceLog.Type.roomLeave, |
| client.getUserId(), client.getStreamid(), |
| roomId, client.getUserip(), ""); |
| |
| // Remove User from Sync List's |
| if (roomId != null) { |
| whiteBoardService.removeUserFromAllLists(scope, client); |
| } |
| |
| log.debug("removing Username " + client.getUsername() + " " |
| + client.getConnectedSince() + " streamid: " |
| + client.getStreamid()); |
| |
| // stop and save any recordings |
| if (client.getIsRecording()) { |
| log.debug("*** roomLeave Current Client is Recording - stop that"); |
| if (client.getInterviewPodId() != null) { |
| //interview, TODO need better check |
| _stopInterviewRecording(client, scope); |
| } else { |
| recordingService.stopRecordAndSave(scope, client, null); |
| |
| // set to true and overwrite the default one cause otherwise no |
| // notification is send |
| client.setIsRecording(true); |
| } |
| } |
| |
| // Notify all clients of the same currentScope (room) with domain |
| // and room except the current disconnected cause it could throw an exception |
| log.debug("currentScope " + scope); |
| |
| if (scope != null && scope.getClientConnections() != null) { |
| // Notify Users of the current Scope |
| for (IConnection cons : scope.getClientConnections()) { |
| if (cons != null && cons instanceof IServiceCapableConnection) { |
| log.debug("sending roomDisconnect to {} client id {}", cons, cons.getClient().getId()); |
| |
| Client rcl = sessionManager.getClientByStreamId(cons.getClient().getId(), null); |
| |
| // Check if the Client does still exist on the list |
| if (rcl == null) { |
| log.debug("For this StreamId: " + cons.getClient().getId() + " There is no Client in the List anymore"); |
| continue; |
| } |
| |
| //Do not send back to sender, but actually all other clients should receive this message swagner 01.10.2009 |
| if (!client.getStreamid().equals(rcl.getStreamid())) { |
| // add Notification if another user isrecording |
| log.debug("###########[roomLeaveByScope]"); |
| if (rcl.getIsRecording()) { |
| log.debug("*** roomLeave Any Client is Recording - stop that"); |
| recordingService.stopRecordingShowForClient(cons, client); |
| } |
| |
| boolean isScreen = rcl.isScreenClient(); |
| if (isScreen && client.getPublicSID().equals(rcl.getStreamPublishName())) { |
| //going to terminate screen sharing started by this client |
| ((IServiceCapableConnection) cons).invoke("stopStream", new Object[] { },this); |
| continue; |
| } else if (isScreen) { |
| // screen sharing clients do not receive events |
| continue; |
| } |
| |
| // Send to all connected users |
| ((IServiceCapableConnection) cons).invoke("roomDisconnect", new Object[] { client },this); |
| log.debug("sending roomDisconnect to " + cons); |
| } |
| } |
| } |
| } |
| |
| if (removeUserFromSessionList) { |
| sessionManager.removeClient(client.getStreamid(), null); |
| } |
| } catch (Exception err) { |
| log.error("[roomLeaveByScope]", err); |
| } |
| } |
| |
| /** |
| * This method handles the Event after a stream has been added all connected |
| * Clients in the same room will get a notification |
| * |
| */ |
| /* (non-Javadoc) |
| * @see org.red5.server.adapter.MultiThreadedApplicationAdapter#streamPublishStart(org.red5.server.api.stream.IBroadcastStream) |
| */ |
| @Override |
| public void streamPublishStart(IBroadcastStream stream) { |
| try { |
| log.debug("----------- streamPublishStart"); |
| IConnection current = Red5.getConnectionLocal(); |
| final String streamid = current.getClient().getId(); |
| final Client currentClient = sessionManager.getClientByStreamId(streamid, null); |
| |
| //We make a second object the has the reference to the object |
| //that we will use to send to all participents |
| Client clientObjectSendToSync = currentClient; |
| |
| // Notify all the clients that the stream had been started |
| log.debug("start streamPublishStart broadcast start: " + stream.getPublishedName() + " CONN " + current); |
| |
| // In case its a screen sharing we start a new Video for that |
| if (currentClient.isScreenClient()) { |
| currentClient.setScreenPublishStarted(true); |
| sessionManager.updateClientByStreamId(streamid, currentClient, false, null); |
| } |
| if (!Strings.isEmpty(currentClient.getSecurityCode())) { |
| currentClient.setBroadCastID(Long.parseLong(stream.getPublishedName())); |
| currentClient.setIsBroadcasting(true); |
| currentClient.setVWidth(320); |
| currentClient.setVHeight(240); |
| sessionManager.updateClientByStreamId(streamid, currentClient, false, null); |
| } |
| |
| log.debug("newStream SEND: " + currentClient); |
| |
| // Notify all users of the same Scope |
| // We need to iterate through the streams to catch if anybody is recording |
| new MessageSender(current, "newStream", clientObjectSendToSync) { |
| @Override |
| public boolean filter(IConnection conn) { |
| Client rcl = sessionManager.getClientByStreamId(conn.getClient().getId(), null); |
| |
| if (rcl == null) { |
| log.debug("RCL IS NULL newStream SEND"); |
| return true; |
| } |
| |
| log.debug("check send to "+rcl); |
| |
| if (rcl.getPublicSID() == "") { |
| log.debug("publicSID IS NULL newStream SEND"); |
| return true; |
| } |
| if (rcl.getIsRecording()) { |
| log.debug("RCL getIsRecording newStream SEND"); |
| recordingService.addRecordingByStreamId(current, streamid, currentClient, rcl.getRecordingId()); |
| } |
| if (rcl.isScreenClient()) { |
| log.debug("RCL getIsScreenClient newStream SEND"); |
| return true; |
| } |
| |
| if (rcl.getPublicSID().equals(currentClient.getPublicSID())) { |
| log.debug("RCL publicSID is equal newStream SEND"); |
| return true; |
| } |
| log.debug("RCL SEND is equal newStream SEND "+rcl.getPublicSID()+" || "+rcl.getUserport()); |
| return false; |
| } |
| }.start(); |
| } catch (Exception err) { |
| log.error("[streamPublishStart]", err); |
| } |
| } |
| |
| public IBroadcastScope getBroadcastScope(IScope scope, String name) { |
| IBasicScope basicScope = scope.getBasicScope(ScopeType.BROADCAST, name); |
| if (!(basicScope instanceof IBroadcastScope)) { |
| return null; |
| } else { |
| return (IBroadcastScope) basicScope; |
| } |
| } |
| |
| /** |
| * This method handles the Event after a stream has been removed all |
| * connected Clients in the same room will get a notification |
| * |
| */ |
| /* (non-Javadoc) |
| * @see org.red5.server.adapter.MultiThreadedApplicationAdapter#streamBroadcastClose(org.red5.server.api.stream.IBroadcastStream) |
| */ |
| @Override |
| public void streamBroadcastClose(IBroadcastStream stream) { |
| |
| // Notify all the clients that the stream had been closed |
| log.debug("start streamBroadcastClose broadcast close: " + stream.getPublishedName()); |
| try { |
| IConnection current = Red5.getConnectionLocal(); |
| Client rcl = sessionManager.getClientByStreamId(current.getClient().getId(), null); |
| sendClientBroadcastNotifications(stream, "closeStream", rcl); |
| } catch (Exception e) { |
| log.error("[streamBroadcastClose]", e); |
| } |
| } |
| |
| /** |
| * This method handles the notification room-based |
| * |
| * @return void |
| * |
| */ |
| private void sendClientBroadcastNotifications(IBroadcastStream stream, String clientFunction, Client rc) { |
| try { |
| // Store the local so that we do not send notification to ourself back |
| IConnection current = Red5.getConnectionLocal(); |
| String streamid = current.getClient().getId(); |
| Client currentClient = sessionManager.getClientByStreamId(streamid, null); |
| |
| if (currentClient == null) { |
| |
| // In case the client has already left(kicked) this message |
| // might be thrown later then the RoomLeave |
| // event and the currentClient is already gone |
| // The second Use-Case where the currentClient is maybe null is |
| // if we remove the client because its a Zombie/Ghost |
| |
| return; |
| |
| } |
| // Notify all the clients that the stream had been started |
| log.debug("sendClientBroadcastNotifications: " + stream.getPublishedName()); |
| log.debug("sendClientBroadcastNotifications : " + currentClient + " " + currentClient.getStreamid()); |
| |
| // Notify all clients of the same scope (room) |
| for (IConnection conn : current.getScope().getClientConnections()) { |
| if (conn != null) { |
| if (conn instanceof IServiceCapableConnection) { |
| if (conn.equals(current)) { |
| // there is a Bug in the current implementation |
| // of the appDisconnect |
| if (clientFunction.equals("closeStream")) { |
| Client rcl = sessionManager.getClientByStreamId(conn.getClient().getId(), null); |
| if (clientFunction.equals("closeStream") && rcl.getIsRecording()) { |
| log.debug("*** stopRecordingShowForClient Any Client is Recording - stop that"); |
| // StreamService.stopRecordingShowForClient(conn, |
| // currentClient, |
| // rcl.getRoomRecordingName(), false); |
| recordingService.stopRecordingShowForClient(conn, currentClient); |
| } |
| // Don't notify current client |
| current.ping(); |
| } |
| continue; |
| } else { |
| Client rcl = sessionManager.getClientByStreamId(conn.getClient().getId(), null); |
| if (rcl != null) { |
| if (rcl.isScreenClient()) { |
| // continue; |
| } else { |
| log.debug("is this users still alive? :" + rcl); |
| IServiceCapableConnection iStream = (IServiceCapableConnection) conn; |
| iStream.invoke(clientFunction, new Object[] { rc }, this); |
| } |
| |
| log.debug("sending notification to " + conn + " ID: "); |
| |
| // if this close stream event then stop the |
| // recording of this stream |
| if (clientFunction.equals("closeStream") && rcl.getIsRecording()) { |
| log.debug("*** +++++++ ######## sendClientBroadcastNotifications Any Client is Recording - stop that"); |
| recordingService.stopRecordingShowForClient(conn, currentClient); |
| } |
| } |
| } |
| } |
| } |
| } |
| } catch (Exception err) { |
| log.error("[sendClientBroadcastNotifications]", err); |
| } |
| } |
| |
| @SuppressWarnings("unchecked") |
| public void setNewCursorPosition(Object item) { |
| try { |
| IConnection current = Red5.getConnectionLocal(); |
| Client c = sessionManager.getClientByStreamId(current.getClient().getId(), null); |
| |
| @SuppressWarnings("rawtypes") |
| Map cursor = (Map) item; |
| cursor.put("streamPublishName", c.getStreamPublishName()); |
| |
| sendMessageToCurrentScope("newRed5ScreenCursor", cursor, true, false); |
| } catch (Exception err) { |
| log.error("[setNewCursorPosition]", err); |
| } |
| } |
| |
| public long removeModerator(String publicSID) { |
| try { |
| log.debug("----------- removeModerator: " + publicSID); |
| |
| Client currentClient = sessionManager.getClientByPublicSID(publicSID, null); |
| |
| if (currentClient == null) { |
| return -1L; |
| } |
| Long roomId = currentClient.getRoomId(); |
| |
| currentClient.setIsMod(false); |
| // Put the mod-flag to true for this client |
| sessionManager.updateClientByStreamId(currentClient.getStreamid(), currentClient, false, null); |
| |
| List<Client> currentMods = sessionManager.getCurrentModeratorByRoom(roomId); |
| |
| sendMessageToCurrentScope("setNewModeratorByList", currentMods, true); |
| } catch (Exception err) { |
| log.error("[removeModerator]", err); |
| } |
| return -1L; |
| } |
| |
| public long giveExclusiveAudio(String publicSID) { |
| try { |
| log.debug("----------- giveExclusiveAudio: " + publicSID); |
| |
| IConnection current = Red5.getConnectionLocal(); |
| // String streamid = current.getClient().getId(); |
| |
| final Client currentClient = sessionManager.getClientByPublicSID(publicSID, null); |
| |
| if (currentClient == null) { |
| return -1L; |
| } |
| |
| // Put the mod-flag to true for this client |
| currentClient.setMicMuted(false); |
| sessionManager.updateClientByStreamId(currentClient.getStreamid(), currentClient, false, null); |
| |
| // Notify all clients of the same scope (room) |
| new MessageSender(current, "receiveExclusiveAudioFlag", currentClient) { |
| @Override |
| public boolean filter(IConnection conn) { |
| Client rcl = sessionManager.getClientByStreamId(conn.getClient().getId(), null); |
| if (rcl == null) { |
| } else if (rcl.isScreenClient()) { |
| } else { |
| if (rcl != currentClient) { |
| rcl.setMicMuted(true); |
| sessionManager.updateClientByStreamId(rcl.getStreamid(), rcl, false, null); |
| } |
| return false; |
| } |
| return true; |
| } |
| }.start(); |
| } catch (Exception err) { |
| log.error("[giveExclusiveAudio]", err); |
| } |
| return -1L; |
| } |
| |
| public long switchMicMuted(String publicSID, boolean mute) { |
| try { |
| log.debug("----------- switchMicMuted: " + publicSID); |
| |
| Client currentClient = sessionManager.getClientByPublicSID(publicSID, null); |
| if (currentClient == null) { |
| return -1L; |
| } |
| |
| currentClient.setMicMuted(mute); |
| sessionManager.updateClientByStreamId(currentClient.getStreamid(), currentClient, false, null); |
| |
| HashMap<Integer, Object> newMessage = new HashMap<Integer, Object>(); |
| newMessage.put(0, "updateMuteStatus"); |
| newMessage.put(1, currentClient); |
| sendMessageWithClient(newMessage); |
| } catch (Exception err) { |
| log.error("[switchMicMuted]", err); |
| } |
| return 0L; |
| } |
| |
| public boolean getMicMutedByPublicSID(String publicSID) { |
| try { |
| Client currentClient = sessionManager.getClientByPublicSID(publicSID, null); |
| if (currentClient == null) { |
| return true; |
| } |
| |
| //Put the mod-flag to true for this client |
| return currentClient.getMicMuted(); |
| } catch (Exception err) { |
| log.error("[getMicMutedByPublicSID]",err); |
| } |
| return true; |
| } |
| |
| /** |
| * Invoked by a User whenever he want to become moderator this is needed, |
| * cause if the room has no moderator yet there is no-one he can ask to get |
| * the moderation, in case its a Non-Moderated Room he should then get the |
| * Moderation without any confirmation needed |
| * |
| * @return Long 1 => means get Moderation, 2 => ask Moderator for |
| * Moderation, 3 => wait for Moderator |
| */ |
| public long applyForModeration(String publicSID) { |
| try { |
| Client currentClient = sessionManager.getClientByPublicSID(publicSID, null); |
| if (currentClient == null) { |
| log.warn("Unable to find client by publicSID: {}", publicSID); |
| return -1L; |
| } |
| |
| List<Client> currentModList = sessionManager.getCurrentModeratorByRoom(currentClient.getRoomId()); |
| |
| if (currentModList.size() > 0) { |
| return 2L; |
| } else { |
| // No moderator in this room at the moment |
| Room room = roomDao.get(currentClient.getRoomId()); |
| |
| return room.isModerated() ? 3L : 1L; |
| } |
| } catch (Exception err) { |
| log.error("[applyForModeration]", err); |
| } |
| return -1L; |
| } |
| |
| /** |
| * there will be set an attribute called "broadCastCounter" this is the name |
| * this user will publish his stream |
| * |
| * @return long broadCastId |
| */ |
| public long getBroadCastId() { |
| try { |
| log.debug("----------- getBroadCastId"); |
| IConnection current = Red5.getConnectionLocal(); |
| String streamid = current.getClient().getId(); |
| Client client = sessionManager.getClientByStreamId(streamid, null); |
| client.setBroadCastID(broadCastCounter.getAndIncrement()); |
| sessionManager.updateClientByStreamId(streamid, client, false, null); |
| return client.getBroadCastID(); |
| } catch (Exception err) { |
| log.error("[getBroadCastId]", err); |
| } |
| return -1; |
| } |
| |
| /** |
| * this must be set _after_ the Video/Audio-Settings have been chosen (see |
| * editrecordstream.lzx) but _before_ anything else happens, it cannot be |
| * applied _after_ the stream has started! avsettings can be: av - video and |
| * audio a - audio only v - video only n - no a/v only static image |
| * furthermore |
| * |
| * @param avsettings |
| * @param newMessage |
| * @param vWidth |
| * @param vHeight |
| * @param roomId |
| * @param publicSID |
| * @param interviewPodId |
| * @return RoomClient being updated in case of no errors, null otherwise |
| */ |
| public Client setUserAVSettings(String avsettings, |
| Object newMessage, Integer vWidth, Integer vHeight, |
| long roomId, String publicSID, Integer interviewPodId) { |
| try { |
| IConnection current = Red5.getConnectionLocal(); |
| IClient c = current.getClient(); |
| String streamid = c.getId(); |
| log.debug("----------- setUserAVSettings {} {} {}", new Object[] {streamid, publicSID, avsettings, newMessage}); |
| Client parentClient = sessionManager.getClientByPublicSID(publicSID, null); |
| Client currentClient = sessionManager.getClientByStreamId(streamid, null); |
| if (parentClient == null || currentClient == null) { |
| log.warn("Failed to find appropriate clients"); |
| return null; |
| } |
| currentClient.setAvsettings(avsettings); |
| currentClient.setRoomId(roomId); |
| currentClient.setPublicSID(publicSID); |
| currentClient.setVWidth(vWidth); |
| currentClient.setVHeight(vHeight); |
| currentClient.setInterviewPodId(interviewPodId); |
| currentClient.setUserId(parentClient.getUserId()); |
| currentClient.setLastname(parentClient.getLastname()); |
| currentClient.setFirstname(parentClient.getFirstname()); |
| currentClient.setPicture_uri(parentClient.getPicture_uri()); |
| sessionManager.updateAVClientByStreamId(streamid, currentClient, null); |
| SessionVariablesUtil.initClient(c, publicSID); |
| |
| HashMap<String, Object> hsm = new HashMap<String, Object>(); |
| hsm.put("client", currentClient); |
| hsm.put("message", newMessage); |
| |
| sendMessageToCurrentScope("sendVarsToMessageWithClient", hsm, true); |
| return currentClient; |
| } catch (Exception err) { |
| log.error("[setUserAVSettings]", err); |
| } |
| return null; |
| } |
| |
| /* |
| * checks if the user is allowed to apply for Moderation |
| */ |
| public boolean checkRoomValues(Long roomId) { |
| try { |
| |
| // appointed meeting or moderated Room? |
| Room room = roomDao.get(roomId); |
| |
| // not really - default logic |
| if (!room.isAppointment() && room.isModerated()) { |
| // if this is a Moderated Room then the Room can be only |
| // locked off by the Moderator Bit |
| List<Client> clientModeratorListRoom = sessionManager.getCurrentModeratorByRoom(roomId); |
| |
| // If there is no Moderator yet and we are asking for it |
| // then deny it |
| // cause at this moment, the user should wait untill a |
| // Moderator enters the Room |
| return clientModeratorListRoom.size() != 0; |
| } else { |
| // FIXME: TODO: For Rooms that are created as Appointment we |
| // have to check that too |
| // but I don't know yet the Logic behind it - swagner 19.06.2009 |
| return true; |
| |
| } |
| } catch (Exception err) { |
| log.error("[checkRoomValues]", err); |
| } |
| return false; |
| } |
| |
| /** |
| * This function is called once a User enters a Room |
| * |
| * It contains several different mechanism depending on what roomtype and |
| * what options are available for the room to find out if the current user |
| * will be a moderator of that room or not<br/> |
| * <br/> |
| * Some rules:<br/> |
| * <ul> |
| * <li>If it is a room that was created through the calendar, the user that |
| * organized the room will be moderator, the param Boolean becomeModerator |
| * will be ignored then</li> |
| * <li>In regular rooms you can use the param Boolean becomeModerator to set |
| * any user to become a moderator of the room</li> |
| * </ul> |
| * <br/> |
| * If a new moderator is detected a Push Call to all current users of the |
| * room is invoked "setNewModeratorByList" to notify them of the new |
| * moderator<br/> |
| * <br/> |
| * At the end of the mechanism a push call with the new client-object |
| * and all the informations about the new user is send to every user of the |
| * current conference room<br/> |
| * <br/> |
| * |
| * @param roomId - id of the room |
| * @param becomeModerator - is user will become moderator |
| * @param isSuperModerator - is user super moderator |
| * @param groupId - group id of the user |
| * @param colorObj - some color |
| * @return RoomStatus object |
| */ |
| public RoomStatus setRoomValues(Long roomId, boolean becomeModerator, boolean isSuperModerator, String colorObj) { |
| try { |
| log.debug("----------- setRoomValues"); |
| IConnection current = Red5.getConnectionLocal(); |
| String streamid = current.getClient().getId(); |
| Client currentClient = sessionManager.getClientByStreamId(streamid, null); |
| currentClient.setRoomId(roomId); |
| currentClient.setRoomEnter(new Date()); |
| |
| currentClient.setUsercolor(colorObj); |
| |
| User u = userDao.get(currentClient.getUserId()); |
| // Inject externalUserId if nothing is set yet |
| if (currentClient.getExternalUserId() == null && u != null) { |
| currentClient.setExternalUserId(u.getExternalId()); |
| currentClient.setExternalUserType(u.getExternalType()); |
| } |
| |
| Room r = roomDao.get(roomId); |
| if (!r.isHidden(RoomElement.MicrophoneStatus)) { |
| currentClient.setCanGiveAudio(true); |
| } |
| sessionManager.updateClientByStreamId(streamid, currentClient, true, null); // first save to get valid room count |
| // Log the User |
| conferenceLogDao.add(ConferenceLog.Type.roomEnter, |
| currentClient.getUserId(), streamid, roomId, |
| currentClient.getUserip(), ""); |
| |
| // Check for Moderation LogicalRoom ENTER |
| List<Client> roomClients = sessionManager.getClientListByRoom(roomId); |
| |
| // Return Object |
| RoomStatus roomStatus = new RoomStatus(); |
| // appointed meeting or moderated Room? => Check Max Users first |
| if (isSuperModerator) { |
| // This can be set without checking for Moderation Flag |
| currentClient.setIsSuperModerator(isSuperModerator); |
| currentClient.setIsMod(isSuperModerator); |
| } else { |
| Room.Right rr = AuthLevelUtil.getRoomRight(u, r, r.isAppointment() ? appointmentDao.getByRoom(r.getId()) : null, roomClients.size()); |
| currentClient.setIsSuperModerator(rr == Room.Right.superModerator); |
| currentClient.setIsMod(becomeModerator || rr == Room.Right.moderator); |
| } |
| if (currentClient.getIsMod()) { |
| // Update the Client List |
| sessionManager.updateClientByStreamId(streamid, currentClient, false, null); |
| |
| List<Client> modRoomList = sessionManager.getCurrentModeratorByRoom(currentClient.getRoomId()); |
| |
| //Sync message to everybody |
| sendMessageToCurrentScope("setNewModeratorByList", modRoomList, false); |
| } |
| |
| //Sync message to everybody |
| sendMessageToCurrentScope("addNewUser", currentClient, false); |
| |
| //Status object for Shared Browsing |
| BrowserStatus browserStatus = (BrowserStatus)current.getScope().getAttribute("browserStatus"); |
| |
| if (browserStatus == null) { |
| browserStatus = new BrowserStatus(); |
| } |
| |
| // RoomStatus roomStatus = new RoomStatus(); |
| |
| // FIXME: Rework Client Object to DTOs |
| roomStatus.setClientList(roomClients); |
| roomStatus.setBrowserStatus(browserStatus); |
| |
| return roomStatus; |
| } catch (Exception err) { |
| log.error("[setRoomValues]", err); |
| } |
| return null; |
| } |
| |
| /** |
| * This method is invoked when the user has disconnected and reconnects to |
| * the Gateway with the new scope |
| * |
| * @param SID |
| * @param userId |
| * @param username |
| * @param firstname |
| * @param lastname |
| * @param picture_uri |
| * @return client being updated in case of success, null otherwise |
| */ |
| public Client setUsernameReconnect(String SID, Long userId, String username, String firstname, String lastname, String picture_uri) { |
| try { |
| log.debug("----------- setUsernameReconnect"); |
| IConnection current = Red5.getConnectionLocal(); |
| String streamid = current.getClient().getId(); |
| Client currentClient = sessionManager.getClientByStreamId(streamid, null); |
| |
| SessionVariablesUtil.setUserId(current.getClient(), userId); |
| currentClient.setPicture_uri(picture_uri); |
| currentClient.setUserObject(userId, username, firstname, lastname); |
| |
| // Update Session Data |
| sessiondataDao.updateUserWithoutSession(SID, userId); |
| |
| // only fill this value from User-Record |
| // cause invited users have no associated User, so |
| // you cannot set the firstname,lastname from the UserRecord |
| if (userId != null) { |
| User us = userDao.get(userId); |
| |
| if (us != null) { |
| currentClient.setExternalUserId(us.getExternalId()); |
| currentClient.setExternalUserType(us.getExternalType()); |
| if (us.getPictureuri() != null) { |
| // set Picture-URI |
| currentClient.setPicture_uri(us.getPictureuri()); |
| } |
| } |
| } |
| sessionManager.updateClientByStreamId(streamid, currentClient, false, null); |
| return currentClient; |
| } catch (Exception err) { |
| log.error("[setUsername]", err); |
| } |
| return null; |
| } |
| |
| /** |
| * this is set initial directly after login/loading language |
| * |
| * @param SID - id of the session |
| * @param userId - id of the user being set |
| * @param username - username of the user |
| * @param firstname - firstname of the user |
| * @param lastname - lastname of the user |
| * @return RoomClient in case of everything is OK, null otherwise |
| */ |
| public Client setUsernameAndSession(String SID, Long userId, String username, String firstname, String lastname) { |
| try { |
| log.debug("----------- setUsernameAndSession"); |
| IConnection current = Red5.getConnectionLocal(); |
| String streamid = current.getClient().getId(); |
| Client currentClient = sessionManager.getClientByStreamId(streamid, null); |
| |
| currentClient.setUsername(username); |
| currentClient.setUserId(userId); |
| SessionVariablesUtil.setUserId(current.getClient(), userId); |
| currentClient.setUserObject(userId, username, firstname, lastname); |
| |
| // Update Session Data |
| log.debug("UDPATE SESSION " + SID + ", " + userId); |
| sessiondataDao.updateUserWithoutSession(SID, userId); |
| |
| User user = userDao.get(userId); |
| |
| if (user != null) { |
| currentClient.setExternalUserId(user.getExternalId()); |
| currentClient.setExternalUserType(user.getExternalType()); |
| } |
| |
| // only fill this value from User-Record |
| // cause invited users have non |
| // you cannot set the firstname,lastname from the UserRecord |
| User us = userDao.get(userId); |
| if (us != null && us.getPictureuri() != null) { |
| // set Picture-URI |
| currentClient.setPicture_uri(us.getPictureuri()); |
| } |
| sessionManager.updateClientByStreamId(streamid, currentClient, false, null); |
| return currentClient; |
| } catch (Exception err) { |
| log.error("[setUsername]", err); |
| } |
| return null; |
| } |
| |
| /** |
| * used by the Screen-Sharing Servlet to trigger events |
| * |
| * @param roomId |
| * @param message |
| * @return the list of room clients |
| */ |
| public HashMap<String, Client> sendMessageByRoomAndDomain(Long roomId, Object message) { |
| HashMap<String, Client> roomClientList = new HashMap<String, Client>(); |
| try { |
| |
| log.debug("sendMessageByRoomAndDomain " + roomId); |
| |
| IScope scope = getRoomScope(roomId.toString()); |
| |
| new MessageSender(scope, "newMessageByRoomAndDomain", message) { |
| @Override |
| public boolean filter(IConnection conn) { |
| IClient client = conn.getClient(); |
| return SessionVariablesUtil.isScreenClient(client); |
| } |
| }.start(); |
| } catch (Exception err) { |
| log.error("[getClientListBYRoomAndDomain]", err); |
| } |
| return roomClientList; |
| } |
| |
| public List<Client> getCurrentModeratorList() { |
| try { |
| IConnection current = Red5.getConnectionLocal(); |
| Client client = sessionManager.getClientByStreamId(current.getClient().getId(), null); |
| Long roomId = client.getRoomId(); |
| Room r = roomDao.get(roomId); |
| if (r != null) { |
| if (Room.Type.conference == r.getType()) { |
| client.setCanVideo(!r.isAudioOnly()); |
| client.setIsBroadcasting(true); |
| sessionManager.updateClientByStreamId(client.getStreamid(), client, false, null); |
| sendToScope(roomId, "clientUpdated", client); |
| } |
| return sessionManager.getCurrentModeratorByRoom(roomId); |
| } |
| } catch (Exception err) { |
| log.error("[getCurrentModerator]", err); |
| } |
| return null; |
| } |
| |
| /** |
| * This Function is triggered from the Whiteboard |
| * |
| * @param whiteboardObjParam - array of parameters being sended to whiteboard |
| * @param whiteboardId - id of whiteboard parameters will be send to |
| * @return 1 in case of no errors, -1 otherwise |
| */ |
| public int sendVarsByWhiteboardId(List<?> whiteboardObjParam, Long whiteboardId) { |
| try { |
| IConnection current = Red5.getConnectionLocal(); |
| Client client = sessionManager.getClientByStreamId(current.getClient().getId(), null); |
| return sendToWhiteboard(client, whiteboardObjParam, whiteboardId); |
| } catch (Exception err) { |
| log.error("[sendVarsByWhiteboardId]", err); |
| return -1; |
| } |
| } |
| |
| public void sendToWhiteboard(String uid, Long wbId, FileItem fi, String url) { |
| int width = 0, height = 0; |
| if (fi.getFlvWidth() != null && fi.getFlvHeight() != null) { |
| width = fi.getFlvWidth(); |
| height = fi.getFlvHeight(); |
| } |
| String fuid = UUID.randomUUID().toString(); |
| Client client = sessionManager.getClientByPublicSIDAnyServer(uid).getRcl(); |
| |
| String type = "n/a"; |
| switch (fi.getType()) { |
| case Image: |
| type = "image"; |
| break; |
| case Presentation: |
| type = "swf"; |
| break; |
| default: |
| } |
| sendToWhiteboard(client, Arrays.asList( |
| "whiteboard" |
| , new Date() |
| , "draw" |
| , Arrays.asList( |
| type // 0 |
| , url // urlname |
| , "--dummy--" // baseurl |
| , fi.getHash() // fileName //3 |
| , "--dummy--" // moduleName //4 |
| , "--dummy--" // parentPath //5 |
| , "--dummy--" // room //6 |
| , "--dummy--" // domain //7 |
| , 1 // slideNumber //8 |
| , 0 // innerx //9 |
| , 0 // innery //10 |
| , width // innerwidth //11 |
| , height // innerheight //12 |
| , 20 // zoomlevel //13 |
| , width // initwidth //14 |
| , height // initheight //15 |
| , 100 // currentzoom //16 FIXME TODO |
| , fuid // uniquObjectSyncName //17 |
| , fi.getName() // standardFileName //18 |
| , true // fullFit //19 FIXME TODO |
| , 1 // zIndex //-8 FIXME TODO |
| , null //-7 |
| , 0 // this.counter //-6 FIXME TODO |
| , 0 // posx //-5 |
| , 0 // posy //-4 |
| , width // width //-3 |
| , height // height //-2 |
| , fuid // this.currentlayer.name //-1 |
| )), wbId); |
| } |
| |
| private int sendToWhiteboard(Client client, List<?> wbObj, Long wbId) { |
| try { |
| // Check if this User is the Mod: |
| if (client == null) { |
| return -1; |
| } |
| |
| Map<Integer, Object> whiteboardObj = new HashMap<>(); |
| int i = 0; |
| for (Object obj : wbObj) { |
| whiteboardObj.put(i++, obj); |
| } |
| |
| Long roomId = client.getRoomId(); |
| |
| // log.debug("***** sendVars: " + whiteboardObj); |
| |
| // Store event in list |
| String action = whiteboardObj.get(2).toString(); |
| |
| if (action.equals("deleteMindMapNodes")) { |
| // Simulate Single Delete Events for z-Index |
| List<?> actionObject = (List<?>) whiteboardObj.get(3); |
| |
| @SuppressWarnings("unchecked") |
| List<List<?>> itemObjects = (List<List<?>>) actionObject.get(3); |
| |
| Map<Integer, Object> whiteboardTempObj = new HashMap<>(); |
| whiteboardTempObj.put(2, "delete"); |
| |
| for (List<?> itemObject : itemObjects) { |
| List<Object> tempActionObject = new ArrayList<>(); |
| tempActionObject.add("mindmapnode"); |
| tempActionObject.add(itemObject.get(0)); // z-Index -8 |
| tempActionObject.add(null); // simulate -7 |
| tempActionObject.add(null); // simulate -6 |
| tempActionObject.add(null); // simulate -5 |
| tempActionObject.add(null); // simulate -4 |
| tempActionObject.add(null); // simulate -3 |
| tempActionObject.add(null); // simulate -2 |
| tempActionObject.add(itemObject.get(1)); // Object-Name -1 |
| |
| whiteboardTempObj.put(3, tempActionObject); |
| |
| whiteboardManagement.addWhiteBoardObjectById(roomId, whiteboardTempObj, wbId); |
| } |
| } else { |
| whiteboardManagement.addWhiteBoardObjectById(roomId, whiteboardObj, wbId); |
| } |
| |
| Map<String, Object> sendObject = new HashMap<String, Object>(); |
| sendObject.put("id", wbId); |
| sendObject.put("param", wbObj); |
| |
| boolean showDrawStatus = getWhiteboardDrawStatus(); |
| |
| sendToScope(roomId, "sendVarsToWhiteboardById", new Object[] { showDrawStatus ? client : null, sendObject }); |
| } catch (Exception err) { |
| log.error("[sendToWhiteboard]", err); |
| return -1; |
| } |
| return 1; |
| } |
| |
| public int sendVarsModeratorGeneral(Object vars) { |
| log.debug("*..*sendVars: " + vars); |
| try { |
| IConnection current = Red5.getConnectionLocal(); |
| Client currentClient = sessionManager.getClientByStreamId(current.getClient().getId(), null); |
| |
| log.debug("***** id: " + currentClient.getStreamid()); |
| |
| boolean ismod = currentClient.getIsMod(); |
| |
| if (ismod) { |
| log.debug("CurrentScope :" + current.getScope().getName()); |
| // Send to all Clients of the same Scope |
| sendMessageToCurrentScope("sendVarsToModeratorGeneral", vars, false); |
| return 1; |
| } else { |
| // log.debug("*..*you are not allowed to send: "+ismod); |
| return -1; |
| } |
| } catch (Exception err) { |
| log.error("[sendVarsModeratorGeneral]", err); |
| } |
| return -1; |
| } |
| |
| public int sendMessage(Object newMessage) { |
| sendMessageToCurrentScope("sendVarsToMessage", newMessage, false); |
| return 1; |
| } |
| |
| public int sendMessageAll(Object newMessage) { |
| sendMessageToCurrentScope("sendVarsToMessage", newMessage, true); |
| return 1; |
| } |
| |
| /** |
| * send status for shared browsing to all members except self |
| * @param newMessage |
| * @return 1 |
| */ |
| @SuppressWarnings({ "rawtypes" }) |
| public synchronized int sendBrowserMessageToMembers(Object newMessage) { |
| try { |
| IConnection current = Red5.getConnectionLocal(); |
| |
| List newMessageList = (List) newMessage; |
| |
| String action = newMessageList.get(0).toString(); |
| |
| BrowserStatus browserStatus = (BrowserStatus) current.getScope().getAttribute("browserStatus"); |
| |
| if (browserStatus == null) { |
| browserStatus = new BrowserStatus(); |
| } |
| |
| if (action.equals("initBrowser") || action.equals("newBrowserURL")) { |
| browserStatus.setBrowserInited(true); |
| browserStatus.setCurrentURL(newMessageList.get(1).toString()); |
| } else if (action.equals("closeBrowserURL")) { |
| browserStatus.setBrowserInited(false); |
| } |
| |
| current.getScope().setAttribute("browserStatus", browserStatus); |
| |
| sendMessageToCurrentScope("sendVarsToMessage", newMessage, false); |
| |
| } catch (Exception err) { |
| log.error("[sendMessage]", err); |
| } |
| return 1; |
| } |
| |
| /** |
| * wrapper method |
| * @param newMessage |
| */ |
| public void sendMessageToMembers(List<?> newMessage) { |
| //Sync to all users of current scope |
| sendMessageToCurrentScope("sendVarsToMessage", newMessage, false); |
| } |
| |
| /** |
| * General sync mechanism for all messages that are send from within the |
| * scope of the current client, but: |
| * <ul> |
| * <li>optionally do not send to self (see param: sendSelf)</li> |
| * <li>do not send to clients that are screen sharing clients</li> |
| * <li>do not send to clients that are audio/video clients (or potentially ones)</li> |
| * <li>do not send to connections where no RoomClient is registered</li> |
| * </ul> |
| * |
| * @param remoteMethodName The method to be called |
| * @param newMessage parameters |
| * @param sendSelf send to the current client as well |
| */ |
| public void sendMessageToCurrentScope(String remoteMethodName, Object newMessage, boolean sendSelf) { |
| sendMessageToCurrentScope(remoteMethodName, newMessage, sendSelf, false); |
| } |
| |
| public void sendToScope(final Long roomId, String method, Object obj) { |
| new MessageSender(getRoomScope("" + roomId), method, obj) { |
| @Override |
| public boolean filter(IConnection conn) { |
| Client rcl = sessionManager.getClientByStreamId(conn.getClient().getId(), null); |
| return rcl.isScreenClient() |
| || rcl.getRoomId() == null || !rcl.getRoomId().equals(roomId) || userDao.get(rcl.getUserId()) == null; |
| } |
| }.start(); |
| } |
| |
| /** |
| * Only temporary for load test, with return argument for the client to have a result |
| * |
| * @param remoteMethodName |
| * @param newMessage |
| * @param sendSelf |
| * @return true |
| */ |
| @Deprecated |
| public boolean loadTestSyncMessage(String remoteMethodName, Object newMessage, boolean sendSelf) { |
| sendMessageToCurrentScope(remoteMethodName, newMessage, sendSelf, false); |
| return true; |
| } |
| |
| |
| /** |
| * General sync mechanism for all messages that are send from within the |
| * scope of the current client, but: |
| * <ul> |
| * <li>optionally do not send to self (see param: sendSelf)</li> |
| * <li>send to clients that are screen sharing clients based on parameter</li> |
| * <li>do not send to clients that are audio/video clients (or potentially ones)</li> |
| * <li>do not send to connections where no RoomClient is registered</li> |
| * </ul> |
| * |
| * @param remoteMethodName The method to be called |
| * @param newMessage parameters |
| * @param sendSelf send to the current client as well |
| * @param sendScreen send to the current client as well |
| */ |
| public void sendMessageToCurrentScope(final String remoteMethodName, final Object newMessage, final boolean sendSelf, final boolean sendScreen) { |
| new MessageSender(remoteMethodName, newMessage) { |
| @Override |
| public boolean filter(IConnection conn) { |
| IClient client = conn.getClient(); |
| return (!sendScreen && SessionVariablesUtil.isScreenClient(client)) |
| || (!sendSelf && client.getId().equals(current.getClient().getId())); |
| } |
| }.start(); |
| } |
| |
| public abstract class MessageSender extends Thread { |
| final IScope scope; |
| final IConnection current; |
| final String remoteMethodName; |
| final Object newMessage; |
| |
| public MessageSender(final String remoteMethodName, final Object newMessage) { |
| this((IScope)null, remoteMethodName, newMessage); |
| } |
| |
| public MessageSender(IScope _scope, String remoteMethodName, Object newMessage) { |
| this(Red5.getConnectionLocal(), _scope, remoteMethodName, newMessage); |
| } |
| |
| public MessageSender(IConnection current, String remoteMethodName, Object newMessage) { |
| this(current, null, remoteMethodName, newMessage); |
| } |
| |
| public MessageSender(IConnection current, IScope _scope, String remoteMethodName, Object newMessage) { |
| this.current = current; |
| scope = _scope == null ? current.getScope() : _scope; |
| this.remoteMethodName = remoteMethodName; |
| this.newMessage = newMessage; |
| } |
| |
| public abstract boolean filter(IConnection conn); |
| |
| @Override |
| public void run() { |
| try { |
| if (scope == null) { |
| log.debug(String.format("[MessageSender] -> 'Unable to send message to NULL scope' %s, %s", remoteMethodName, newMessage)); |
| } else { |
| if (log.isTraceEnabled()) { |
| log.trace(String.format("[MessageSender] -> 'sending message' %s, %s", remoteMethodName, newMessage)); |
| } |
| // Send to all Clients of that Scope(Room) |
| int count = 0; |
| for (IConnection conn : scope.getClientConnections()) { |
| if (conn != null && conn instanceof IServiceCapableConnection) { |
| if (filter(conn)) { |
| continue; |
| } |
| ((IServiceCapableConnection) conn).invoke(remoteMethodName, new Object[] { newMessage }, ScopeApplicationAdapter.this); |
| count++; |
| } |
| } |
| if (log.isTraceEnabled()) { |
| log.trace(String.format("[MessageSender] -> 'sending message to %s clients, DONE' %s", count, remoteMethodName)); |
| } |
| } |
| } catch (Exception err) { |
| log.error(String.format("[MessageSender -> %s, %s]", remoteMethodName, newMessage), err); |
| } |
| } |
| } |
| |
| /** |
| * wrapper method |
| * @param newMessage |
| * @return 1 in case of success, -1 otherwise |
| */ |
| public int sendMessageWithClient(Object newMessage) { |
| try { |
| sendMessageWithClientWithSyncObject(newMessage, true); |
| |
| } catch (Exception err) { |
| log.error("[sendMessageWithClient] ", err); |
| return -1; |
| } |
| return 1; |
| } |
| |
| /** |
| * wrapper method |
| * @param newMessage |
| * @param sync |
| * @return 1 in case of success, -1 otherwise |
| */ |
| public int sendMessageWithClientWithSyncObject(Object newMessage, boolean sync) { |
| try { |
| IConnection current = Red5.getConnectionLocal(); |
| Client currentClient = sessionManager.getClientByStreamId(current.getClient().getId(), null); |
| |
| HashMap<String, Object> hsm = new HashMap<String, Object>(); |
| hsm.put("client", currentClient); |
| hsm.put("message", newMessage); |
| |
| //Sync to all users of current scope |
| sendMessageToCurrentScope("sendVarsToMessageWithClient", hsm, sync); |
| |
| } catch (Exception err) { |
| log.error("[sendMessageWithClient] ", err); |
| return -1; |
| } |
| return 1; |
| } |
| |
| /** |
| * Function is used to send the kick Trigger at the moment, |
| * it sends a general message to a specific clientId |
| * |
| * @param newMessage |
| * @param clientId |
| * @return 1 in case of success, -1 otherwise |
| */ |
| public int sendMessageById(Object newMessage, String clientId, IScope scope) { |
| try { |
| log.debug("### sendMessageById ###" + clientId); |
| |
| HashMap<String, Object> hsm = new HashMap<String, Object>(); |
| hsm.put("message", newMessage); |
| |
| // broadcast Message to specific user with id inside the same Scope |
| for (IConnection conn : scope.getClientConnections()) { |
| if (conn != null) { |
| if (conn instanceof IServiceCapableConnection) { |
| if (conn.getClient().getId().equals(clientId)) { |
| ((IServiceCapableConnection) conn).invoke("sendVarsToMessageWithClient", new Object[] { hsm }, this); |
| } |
| } |
| } |
| } |
| } catch (Exception err) { |
| log.error("[sendMessageWithClient] ", err); |
| return -1; |
| } |
| return 1; |
| } |
| |
| /** |
| * Sends a message to a user in the same room by its clientId |
| * |
| * @param newMessage |
| * @param clientId |
| * @return 1 in case of no exceptions, -1 otherwise |
| */ |
| public int sendMessageWithClientById(Object newMessage, String clientId) { |
| try { |
| IConnection current = Red5.getConnectionLocal(); |
| Client currentClient = sessionManager.getClientByStreamId(current.getClient().getId(), null); |
| |
| HashMap<String, Object> hsm = new HashMap<String, Object>(); |
| hsm.put("client", currentClient); |
| hsm.put("message", newMessage); |
| |
| // broadcast Message to specific user with id inside the same Scope |
| for (IConnection conn : current.getScope().getClientConnections()) { |
| if (conn.getClient().getId().equals(clientId)) { |
| ((IServiceCapableConnection) conn).invoke("sendVarsToMessageWithClient", new Object[] { hsm }, this); |
| } |
| } |
| } catch (Exception err) { |
| log.error("[sendMessageWithClient] ", err); |
| return -1; |
| } |
| return 1; |
| } |
| |
| public void sendMessageWithClientByPublicSID(Object message, String publicSID) { |
| try { |
| if (publicSID == null) { |
| log.warn("'null' publicSID was passed to sendMessageWithClientByPublicSID"); |
| return; |
| } |
| |
| // Get Room Id to send it to the correct Scope |
| Client currentClient = sessionManager.getClientByPublicSID(publicSID, null); |
| |
| if (currentClient == null) { |
| throw new Exception("Could not Find RoomClient on List publicSID: " + publicSID); |
| } |
| IScope scope = getRoomScope("" + currentClient.getRoomId()); |
| |
| // log.debug("scopeHibernate "+scopeHibernate); |
| |
| if (scope != null) { |
| // Notify the clients of the same scope (room) with userId |
| |
| for (IConnection conn : scope.getClientConnections()) { |
| IClient client = conn.getClient(); |
| if (SessionVariablesUtil.isScreenClient(client)) { |
| // screen sharing clients do not receive events |
| continue; |
| } |
| |
| if (publicSID.equals(SessionVariablesUtil.getPublicSID(client))) { |
| ((IServiceCapableConnection) conn).invoke("newMessageByRoomAndDomain", new Object[] { message }, this); |
| } |
| } |
| } else { |
| // Scope not yet started |
| } |
| } catch (Exception err) { |
| log.error("[sendMessageWithClientByPublicSID] ", err); |
| } |
| } |
| |
| /** |
| * @deprecated this method should be reworked to use a single SQL query in |
| * the cache to get any client in the current room that is |
| * recording instead of iterating through connections! |
| * @return true in case there is recording session, false otherwise, null if any exception happend |
| */ |
| public boolean getInterviewRecordingStatus() { |
| try { |
| IConnection current = Red5.getConnectionLocal(); |
| |
| for (IConnection conn : current.getScope().getClientConnections()) { |
| if (conn != null) { |
| Client rcl = sessionManager.getClientByStreamId(conn.getClient().getId(), null); |
| |
| if (rcl.getIsRecording()) { |
| return true; |
| } |
| } |
| } |
| } catch (Exception err) { |
| log.error("[getInterviewRecordingStatus]", err); |
| } |
| return false; |
| } |
| |
| /** |
| * @deprecated @see {@link ScopeApplicationAdapter#getInterviewRecordingStatus()} |
| * @return - false if there were existing recording, true if recording was started successfully, null if any exception happens |
| */ |
| public boolean startInterviewRecording() { |
| try { |
| log.debug("----------- startInterviewRecording"); |
| IConnection current = Red5.getConnectionLocal(); |
| |
| for (IConnection conn : current.getScope().getClientConnections()) { |
| if (conn != null) { |
| Client rcl = sessionManager.getClientByStreamId(conn.getClient().getId(), null); |
| |
| if (rcl != null && rcl.getIsRecording()) { |
| return false; |
| } |
| } |
| } |
| Client current_rcl = sessionManager.getClientByStreamId(current.getClient().getId(), null); |
| |
| // Also set the Recording Flag to Record all Participants that enter |
| // later |
| current_rcl.setIsRecording(true); |
| sessionManager.updateClientByStreamId(current.getClient().getId(), current_rcl, false, null); |
| |
| Map<String, String> interviewStatus = new HashMap<String, String>(); |
| interviewStatus.put("action", "start"); |
| |
| for (IConnection conn : current.getScope().getClientConnections()) { |
| if (conn != null) { |
| IClient client = conn.getClient(); |
| if (SessionVariablesUtil.isScreenClient(client)) { |
| // screen sharing clients do not receive events |
| continue; |
| } |
| |
| ((IServiceCapableConnection) conn).invoke("interviewStatus", new Object[] { interviewStatus }, this); |
| log.debug("-- startInterviewRecording " + interviewStatus); |
| } |
| } |
| String recordingName = "Interview " + CalendarPatterns.getDateWithTimeByMiliSeconds(new Date()); |
| |
| recordingService.recordMeetingStream(current, current_rcl, recordingName, "", true); |
| |
| return true; |
| } catch (Exception err) { |
| log.debug("[startInterviewRecording]", err); |
| } |
| return false; |
| } |
| |
| @SuppressWarnings({ "rawtypes" }) |
| public boolean sendRemoteCursorEvent(final String streamid, Map messageObj) { |
| new MessageSender("sendRemoteCursorEvent", messageObj) { |
| |
| @Override |
| public boolean filter(IConnection conn) { |
| IClient client = conn.getClient(); |
| return !SessionVariablesUtil.isScreenClient(client) || !conn.getClient().getId().equals(streamid); |
| } |
| }.start(); |
| return true; |
| } |
| |
| private Long checkRecordingClient(IConnection conn) { |
| Long recordingId = null; |
| if (conn != null) { |
| Client rcl = sessionManager.getClientByStreamId(conn.getClient().getId(), null); |
| if (rcl != null && rcl.getIsRecording()) { |
| rcl.setIsRecording(false); |
| recordingId = rcl.getRecordingId(); |
| rcl.setRecordingId(null); |
| |
| // Reset the Recording Flag to Record all |
| // Participants that enter later |
| sessionManager.updateClientByStreamId(conn.getClient().getId(), rcl, false, null); |
| } |
| } |
| return recordingId; |
| } |
| |
| /** |
| * Stop the recording of the streams and send event to connected users of scope |
| * |
| * @return true if interview was found |
| */ |
| public boolean stopInterviewRecording() { |
| IConnection current = Red5.getConnectionLocal(); |
| Client currentClient = sessionManager.getClientByStreamId(current.getClient().getId(), null); |
| return _stopInterviewRecording(currentClient, current.getScope()); |
| } |
| |
| /** |
| * Stop the recording of the streams and send event to connected users of scope |
| * |
| * @return true if interview was found |
| */ |
| private boolean _stopInterviewRecording(Client currentClient, IScope currentScope) { |
| try { |
| log.debug("----------- stopInterviewRecording"); |
| Long clientRecordingId = currentClient.getRecordingId(); |
| |
| for (IConnection conn : currentScope.getClientConnections()) { |
| Long recordingId = checkRecordingClient(conn); |
| if (recordingId != null) { |
| clientRecordingId = recordingId; |
| } |
| } |
| if (clientRecordingId == null) { |
| log.debug("stopInterviewRecording:: unable to find recording client"); |
| return false; |
| } |
| |
| recordingService.stopRecordAndSave(scope, currentClient, clientRecordingId); |
| |
| Map<String, String> interviewStatus = new HashMap<String, String>(); |
| interviewStatus.put("action", "stop"); |
| |
| sendMessageToCurrentScope("interviewStatus", interviewStatus, true); |
| return true; |
| |
| } catch (Exception err) { |
| log.debug("[stopInterviewRecording]", err); |
| } |
| return false; |
| } |
| |
| /** |
| * Get all ClientList Objects of that room and domain Used in |
| * lz.applyForModeration.lzx |
| * |
| * @return all ClientList Objects of that room |
| */ |
| public List<Client> getClientListScope() { |
| try { |
| IConnection current = Red5.getConnectionLocal(); |
| Client currentClient = sessionManager.getClientByStreamId(current.getClient().getId(), null); |
| |
| return sessionManager.getClientListByRoom(currentClient.getRoomId()); |
| } catch (Exception err) { |
| log.debug("[getClientListScope]", err); |
| } |
| return new ArrayList<Client>(); |
| } |
| |
| private boolean getWhiteboardDrawStatus() { |
| return configurationDao.getWhiteboardDrawStatus(); |
| } |
| |
| public String getCryptKey() { |
| return configurationDao.getCryptKey(); |
| } |
| |
| public IScope getRoomScope(String room) { |
| if (Strings.isEmpty(room)) { |
| return null; |
| } else { |
| IScope globalScope = getContext().getGlobalScope(); |
| IScope webAppKeyScope = globalScope.getScope(OpenmeetingsVariables.webAppRootKey); |
| |
| return webAppKeyScope.getScope(room); |
| } |
| } |
| |
| /* |
| * SIP transport methods |
| */ |
| |
| private List<Long> getVerifiedActiveRoomIds(Server s) { |
| List<Long> result = new ArrayList<Long>(sessionManager.getActiveRoomIdsByServer(s)); |
| //verify |
| for (Iterator<Long> i = result.iterator(); i.hasNext();) { |
| Long id = i.next(); |
| List<Client> rcs = sessionManager.getClientListByRoom(id); |
| if (rcs.size() == 0 || (rcs.size() == 1 && rcs.get(0).isSipTransport())) { |
| i.remove(); |
| } |
| } |
| return result.isEmpty() ? result : roomDao.getSipRooms(result); |
| } |
| |
| public List<Long> getActiveRoomIds() { |
| List<Long> result = getVerifiedActiveRoomIds(null); |
| for (Server s : serverDao.getActiveServers()) { |
| result.addAll(getVerifiedActiveRoomIds(s)); |
| } |
| return result.isEmpty() ? result : roomDao.getSipRooms(result); |
| } |
| |
| private String getSipTransportLastname(Long roomId) { |
| return getSipTransportLastname(roomManager.getSipConferenceMembersNumber(roomId)); |
| } |
| |
| private static String getSipTransportLastname(Integer c) { |
| return (c != null && c > 0) ? "(" + (c - 1) + ")" : ""; |
| } |
| |
| public synchronized int updateSipTransport() { |
| log.debug("----------- updateSipTransport"); |
| IConnection current = Red5.getConnectionLocal(); |
| String streamid = current.getClient().getId(); |
| Client client = sessionManager.getClientByStreamId(streamid, null); |
| Long roomId = client.getRoomId(); |
| Integer count = roomManager.getSipConferenceMembersNumber(roomId); |
| String newNumber = getSipTransportLastname(count); |
| log.debug("getSipConferenceMembersNumber: " + newNumber); |
| if (!newNumber.equals(client.getLastname())) { |
| client.setLastname(newNumber); |
| sessionManager.updateClientByStreamId(streamid, client, false, null); |
| log.debug("updateSipTransport: {}, {}, {}, {}, {}", new Object[] { client.getPublicSID(), client.getRoomId(), |
| client.getFirstname(), client.getLastname(), client.getAvsettings() }); |
| sendMessageWithClient(new String[] { "personal", client.getFirstname(), client.getLastname() }); |
| } |
| return count != null && count > 0 ? count - 1 : 0; |
| } |
| |
| public void setSipTransport(Long roomId, String publicSID, String broadCastId) { |
| log.debug("----------- setSipTransport"); |
| IConnection current = Red5.getConnectionLocal(); |
| IClient c = current.getClient(); |
| String streamid = c.getId(); |
| // Notify all clients of the same scope (room) |
| Client currentClient = sessionManager.getClientByStreamId(streamid, null); |
| currentClient.setSipTransport(true); |
| currentClient.setRoomId(roomId); |
| currentClient.setRoomEnter(new Date()); |
| currentClient.setFirstname("SIP Transport"); |
| currentClient.setLastname(getSipTransportLastname(roomId)); |
| currentClient.setBroadCastID(Long.parseLong(broadCastId)); |
| currentClient.setIsBroadcasting(true); |
| currentClient.setPublicSID(publicSID); |
| currentClient.setVWidth(120); |
| currentClient.setVHeight(90); |
| currentClient.setPicture_uri("phone.png"); |
| sessionManager.updateClientByStreamId(streamid, currentClient, false, null); |
| SessionVariablesUtil.initClient(c, publicSID); |
| |
| sendMessageToCurrentScope("addNewUser", currentClient, false); |
| } |
| |
| public void broadcastRoom(RoomMessage msg) { |
| log.debug("Sending WebSocket message: {} {}", msg.getType(), msg instanceof TextRoomMessage ? ((TextRoomMessage)msg).getText() : ""); |
| Application app = Application.get(OpenmeetingsVariables.wicketApplicationName); |
| WebSocketSettings settings = WebSocketSettings.Holder.get(app); |
| IWebSocketConnectionRegistry registry = settings.getConnectionRegistry(); |
| for (IWebSocketConnection wc : registry.getConnections(app)) { |
| if (wc != null && wc.isOpen()) { |
| wc.sendMessage(msg); |
| } |
| } |
| } |
| } |