Java tutorial
/* * 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 com.bhbsoft.videoconference; import static java.lang.System.out; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; 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.red5.server.util.ScopeUtils; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import com.bhbsoft.videoconference.record.FLVRecorderService; import com.bhbsoft.videoconference.room.BrowserStatus; import com.bhbsoft.videoconference.room.RoomStatus; import com.bhbsoft.videoconference.security.ServerAuth; import com.bhbsoft.videoconference.session.Client; import com.bhbsoft.videoconference.session.SessionManager; import com.bhbsoft.videoconference.session.util.SessionVariablesUtil; import com.bhbsoft.videoconference.util.CalendarParser; public class VideoConferenceApplicationAdapter extends ApplicationAdapter implements IPendingServiceCallback { private static final Logger log = Red5LoggerFactory.getLogger(VideoConferenceApplicationAdapter.class); private SessionManager sessionManager; private ServerAuth serverAuth; @Autowired private FLVRecorderService flvRecorderService; public static String lineSeperator = System.getProperty("line.separator"); private static long broadCastCounter = 0; public synchronized void resultReceived(IPendingServiceCall arg0) { // TODO Auto-generated method stub } @Override public synchronized boolean appStart(IScope scope) { sessionManager = SessionManager.sessionStart(); serverAuth = new ServerAuth(); flvRecorderService = new FLVRecorderService(); try { String apphome = scope.getResource("/").getFile().getAbsolutePath(); log.debug("webAppPath : " + apphome); // Only load this Class one time Initially this value might by empty, because the DB is empty yet //getCryptKey(); // init your handler here // The scheduled Jobs did go into the Spring-Managed Beans, see schedulerJobs.service.xml // Spring Definition does not work here, its too early, Instance is not set yet 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 } catch (Exception err) { log.error("[appStart]", err); } return true; } public boolean appConnect(IConnection conn, Object[] params) { log.info("appConnect " + conn.getClient().getId()); return true; } // 1 .check password - // 2. then get room to connect to from server // 3. connect user to room // 4. call service to start clock public boolean connect(IConnection conn, IScope scope, Object[] params) { // This is the master connection method called every time someone connects // to the server. // Check if the user passed valid parameters. //params = pseudo onlineStatus role sexe room world String clientRoom = "1"; if (params == null || params.length == 0) { out.println("No Username Passed"); //Reject client terminates the execution of current client rejectClient("Username required, client rejected."); return false; } else { out.println("Number of parameters passed: " + params.length + " Value: " + params[0]); //clientRoom =(String) params[0]; } // Do password Validation; //boolean valid = serverAuth.validateUser("userName","Password"); //if (!valid) { // rejectClient("Username/Password failed, client rejected."); //} //Do room validation //ID increments each connection String uid = conn.getClient().getId(); out.println("Userid: " + uid); // Call original method of parent class. if (!super.connect(conn, scope, params)) { return false; } roomConnect(true, scope); log.info("Room ScopeTxt: " + scope.getName() + clientRoom); IScope roomScope = ScopeUtils.resolveScope(scope, scope.getName()); if (roomScope == null) { if (scope.createChildScope(scope.getName() + clientRoom)) { log.info("Room {} created", scope.getName() + clientRoom); roomScope = scope.getScope(scope.getName() + clientRoom); } else { log.info("Room {} was not created", scope.getName() + clientRoom); } } else { log.info("Room scope {} was found", scope.getName() + clientRoom); } roomJoin(conn.getClient(), roomScope); //startRecording(scope); return true; } public void createRoom(String room) { IScope roomScope = ScopeUtils.resolveScope(scope, scope.getName() + room); if (roomScope == null) { if (scope.createChildScope(scope.getName() + room)) { log.info("Room {} created", scope.getName() + room); roomScope = scope.getScope(scope.getName() + room); } else { log.info("Room {} was not created", scope.getName() + room); } } else { log.info("Room scope {} was found", scope.getName() + room); } } public boolean roomStart(IScope room) { log.info("Red5First.room start " + room); if (!super.roomStart(room)) return false; return true; } public String whoami() { IConnection conn = Red5.getConnectionLocal(); IClient client = conn.getClient(); IScope scope = conn.getScope(); return client.getId(); } //@Override public void startRecording(IScope scope) { IConnection current = Red5.getConnectionLocal(); Client currentClient = sessionManager.getClientByStreamId(current.getClient().getId()); String streamId = current.getClient().getId(); boolean startRecording = true; if (currentClient != null) { currentClient.setRoom_id(scope.getName()); // Set this connection to be a RTMP-Java Client // currentClient.setIsScreenClient(true); boolean alreadyRecording = currentClient.isStartRecording(); if (startRecording) { currentClient.setStartRecording(true); } if (!alreadyRecording) { //returnMap.put("modus", "startRecording"); String recordingName = "Recording " + CalendarParser.getDateWithTimeByMiliSeconds(new Date()); // validate the deference between a meeting and a show // flvRecorderService.addRecordingByStreamId(current, scope, streamId, currentClient, currentClient.getFlvRecordingId()); //flvRecorderService.recordMeetingStream(recordingName, "", false); } else { log.warn("Recording is already started for the client id=" + currentClient.getId() + ". Second request is ignored."); } } else { log.error("Could not find Screen Sharing Client " + current.getClient().getId()); } } // check to see if room as been created from session scope if not then create. public boolean roomConnect(Boolean params, IScope scope) { log.info("roomConnect : connect to room!!"); try { IConnection conn = Red5.getConnectionLocal(); IServiceCapableConnection service = (IServiceCapableConnection) conn; String streamId = conn.getClient().getId(); boolean isAVClient = params; log.info("### Client connected to Red5 Server, register Client StreamId: " + streamId + " scope " + scope.getName() + " isAVClient " + isAVClient); log.info("params " + params); // Set StreamId in Client // service.invoke("setId", new Object[] { streamId }, this); // String swfURL = ""; // if (conn.getConnectParams().get("swfUrl") != null) { // swfURL = conn.getConnectParams().get("swfUrl").toString(); // } Client rcm = this.sessionManager.addClientListItem(streamId, scope.getName(), conn.getRemotePort(), conn.getRemoteAddress(), "swfURL", isAVClient); SessionVariablesUtil.initClient(conn.getClient(), isAVClient, rcm.getPublicSID()); } catch (Exception err) { log.error("roomJoin", err); } return true; } /** * * @param map * @return returns key,value Map with multiple return values or null in case of exception * */ @SuppressWarnings({ "rawtypes", "unchecked" }) public synchronized Map setConnectionAsSharingClient(Map map) { try { log.debug("----------- setConnectionAsSharingClient"); IConnection current = Red5.getConnectionLocal(); Client currentClient = sessionManager.getClientByStreamId(current.getClient().getId()); if (currentClient != null) { boolean startRecording = Boolean.valueOf("" + map.get("startRecording")); boolean startStreaming = Boolean.valueOf("" + map.get("startStreaming")); boolean startPublishing = Boolean.valueOf("" + map.get("startPublishing")) && (0 == sessionManager.getPublishingCount(currentClient.getRoom_id())); currentClient.setRoom_id(current.getScope().getName()); // Set this connection to be a RTMP-Java Client currentClient.setIsScreenClient(true); SessionVariablesUtil.setIsScreenClient(current.getClient()); currentClient.setUser_id(map.get("user_id").toString()); SessionVariablesUtil.setUserId(current.getClient(), map.get("user_id").toString()); boolean alreadyStreaming = currentClient.isStartStreaming(); if (startStreaming) { currentClient.setStartStreaming(true); } boolean alreadyRecording = currentClient.isStartRecording(); if (startRecording) { currentClient.setStartRecording(true); } if (startPublishing) { currentClient.setStreamPublishStarted(true); } currentClient.setOrganization_id(Long.parseLong(map.get("organization_id").toString())); sessionManager.updateClientByStreamId(current.getClient().getId(), currentClient, false); Map returnMap = new HashMap(); returnMap.put("alreadyPublished", false); // if is already started screen sharing, then there is no need // to start it again if (currentClient.isScreenPublishStarted()) { returnMap.put("alreadyPublished", true); } currentClient.setVX(Integer.parseInt(map.get("screenX").toString())); currentClient.setVY(Integer.parseInt(map.get("screenY").toString())); currentClient.setVWidth(Integer.parseInt(map.get("screenWidth").toString())); currentClient.setVHeight(Integer.parseInt(map.get("screenHeight").toString())); log.debug("screen x,y,width,height " + currentClient.getVX() + " " + currentClient.getVY() + " " + currentClient.getVWidth() + " " + currentClient.getVHeight()); log.debug("publishName :: " + map.get("publishName")); currentClient.setStreamPublishName(map.get("publishName").toString()); Client currentScreenUser = sessionManager.getClientByUserId(currentClient.getUser_id()); currentClient.setFirstname(currentScreenUser.getFirstname()); currentClient.setLastname(currentScreenUser.getLastname()); // This is duplicated, but its not sure that in the meantime // somebody requests this Client Object Info sessionManager.updateClientByStreamId(current.getClient().getId(), currentClient, false); if (startStreaming) { if (!alreadyStreaming) { returnMap.put("modus", "startStreaming"); log.debug("start streamPublishStart Is Screen Sharing "); //Send message to all users syncMessageToCurrentScope("newScreenSharing", currentClient, false); } else { log.warn("Streaming is already started for the client id=" + currentClient.getId() + ". Second request is ignored."); } } //TODO: Move method //--break not method if (startRecording) { if (!alreadyRecording) { returnMap.put("modus", "startRecording"); String recordingName = "Recording " + CalendarParser.getDateWithTimeByMiliSeconds(new Date()); // validate the deference between a meeting and a show // //flvRecorderService.recordMeetingStream(recordingName, "", false); } else { log.warn("Recording is already started for the client id=" + currentClient.getId() + ". Second request is ignored."); } } if (startPublishing) { syncMessageToCurrentScope( "startedPublishing", new Object[] { currentClient, "rtmp://" + map.get("publishingHost") + ":1935/" + map.get("publishingApp") + "/" + map.get("publishingId") }, false, true); returnMap.put("modus", "startPublishing"); } return returnMap; } else { throw new Exception("Could not find Screen Sharing Client " + current.getClient().getId()); } } catch (Exception err) { log.error("[setConnectionAsSharingClient]", err); } return null; } public synchronized List<Integer> listRoomBroadcast() { HashSet<Integer> broadcastList = new HashSet<Integer>(); IConnection current = Red5.getConnectionLocal(); String streamid = current.getClient().getId(); for (Set<IConnection> conset : current.getScope().getConnections()) { for (IConnection conn : conset) { if (conn != null) { Client rcl = this.sessionManager.getClientByStreamId(conn.getClient().getId()); if (rcl == null) { // continue; } else if (rcl.getIsScreenClient() != null && rcl.getIsScreenClient()) { // 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 (id != null && !broadcastList.contains(id)) { broadcastList.add(id.intValue()); } } } } } } return new ArrayList<Integer>(broadcastList); } /** * this function is invoked directly after initial connecting * * @return publicSID of current client */ public synchronized String getPublicSID() { log.debug("----------- getPublicSID"); IConnection current = Red5.getConnectionLocal(); Client currentClient = this.sessionManager.getClientByStreamId(current.getClient().getId()); sessionManager.updateClientByStreamId(current.getClient().getId(), currentClient, false); return currentClient.getPublicSID(); } /** * this function is invoked after a reconnect * * @param newPublicSID */ public synchronized Boolean overwritePublicSID(String newPublicSID) { try { log.debug("----------- overwritePublicSID"); IConnection current = Red5.getConnectionLocal(); IClient c = current.getClient(); Client currentClient = sessionManager.getClientByStreamId(c.getId()); if (currentClient == null) { return false; } SessionVariablesUtil.initClient(c, SessionVariablesUtil.isAVClient(c), newPublicSID); currentClient.setPublicSID(newPublicSID); sessionManager.updateClientByStreamId(c.getId(), currentClient, false); return true; } catch (Exception err) { log.error("[overwritePublicSID]", err); } return null; } /** * 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()); // 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); } } /** * 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 currentClient * @param currentScope */ public synchronized void roomLeaveByScope(Client currentClient, IScope currentScope, boolean removeUserFromSessionList) { try { log.debug("currentClient " + currentClient); String room_id = currentClient.getRoom_id(); log.debug("removing USername " + currentClient.getUsername() + " " + currentClient.getConnectedSince() + " streamid: " + currentClient.getStreamid()); // stop and save any recordings if (currentClient.getIsRecording()) { log.debug("*** roomLeave Current Client is Recording - stop that"); flvRecorderService.stopRecordAndSave(currentScope, currentClient, null); // set to true and overwrite the default one cause otherwise no // notification is send currentClient.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 " + currentScope); if (currentScope != null && currentScope.getConnections() != null) { // Notify Users of the current Scope for (Set<IConnection> conset : currentScope.getConnections()) { for (IConnection cons : conset) { if (cons != null && cons instanceof IServiceCapableConnection) { log.debug("sending roomDisconnect to {} client id {}", cons, cons.getClient().getId()); Client rcl = sessionManager.getClientByStreamId(cons.getClient().getId()); /* * 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 (!currentClient.getStreamid().equals(rcl.getStreamid())) { // add Notification if another user isrecording log.debug("###########[roomLeave]"); if (rcl.getIsRecording()) { log.debug("*** roomLeave Any Client is Recording - stop that"); flvRecorderService.stopRecordingShowForClient(cons, currentClient); } //If the user was a avclient, we do not broadcast a message about that to everybody if (currentClient.getIsAVClient()) { continue; } boolean isScreen = rcl.getIsScreenClient() != null && rcl.getIsScreenClient(); if (isScreen && currentClient.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; } else if (rcl.getIsAVClient()) { // AVClients or potential AVClients do not receive events continue; } // Send to all connected users ((IServiceCapableConnection) cons).invoke("roomDisconnect", new Object[] { currentClient }, this); log.debug("sending roomDisconnect to " + cons); } } } } } if (removeUserFromSessionList) { this.sessionManager.removeClient(currentClient.getStreamid()); } } 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 synchronized void streamPublishStart(IBroadcastStream stream) { try { log.debug("----------- streamPublishStart"); IConnection current = Red5.getConnectionLocal(); String streamid = current.getClient().getId(); Client currentClient = this.sessionManager.getClientByStreamId(streamid); //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.getIsScreenClient()) { currentClient.setScreenPublishStarted(true); this.sessionManager.updateClientByStreamId(current.getClient().getId(), currentClient, false); } **** //If its an audio/video client then send the session object with the full //data to everybody // else if (currentClient.getIsAVClient()) { clientObjectSendToSync = this.sessionManager.getClientByUserId(currentClient.getUser_id()); } 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 for (Set<IConnection> conset : current.getScope().getConnections()) { for (IConnection conn : conset) { if (conn != null) { if (conn instanceof IServiceCapableConnection) { Client rcl = this.sessionManager.getClientByStreamId(conn.getClient().getId()); if (rcl == null) { log.debug("RCL IS NULL newStream SEND"); continue; } log.debug("check send to "+rcl); if (rcl.getPublicSID() == "") { log.debug("publicSID IS NULL newStream SEND"); continue; } if (rcl.getIsRecording()) { log.debug("RCL getIsRecording newStream SEND"); flvRecorderService.addRecordingByStreamId(current, streamid, currentClient, rcl.getFlvRecordingId()); } if (rcl.getIsAVClient()) { log.debug("RCL getIsAVClient newStream SEND"); continue; } if (rcl.getIsScreenClient() == null || rcl.getIsScreenClient()) { log.debug("RCL getIsScreenClient newStream SEND"); continue; } if (rcl.getPublicSID().equals(currentClient.getPublicSID())) { log.debug("RCL publicSID is equal newStream SEND"); continue; } log.debug("RCL SEND is equal newStream SEND "+rcl.getPublicSID()+" || "+rcl.getUserport()); ((IServiceCapableConnection) conn).invoke("newStream", new Object[] { clientObjectSendToSync }, this); } } } } } 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 synchronized 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()); sendClientBroadcastNotifications(stream, "closeStream", rcl); } catch (Exception e) { log.error("[streamBroadcastClose]", e); } } /** * This method handles the notification room-based * * @return void * */ private synchronized 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); 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 (Set<IConnection> conset : current.getScope().getConnections()) { for (IConnection conn : conset) { 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()); if (clientFunction.equals("closeStream") && rcl.getIsRecording()) { log.debug( "*** stopRecordingShowForClient Any Client is Recording - stop that"); // StreamService.stopRecordingShowForClient(conn, // currentClient, // rcl.getRoomRecordingName(), false); flvRecorderService.stopRecordingShowForClient(conn, currentClient); } // Don't notify current client current.ping(); } continue; } else { Client rcl = sessionManager.getClientByStreamId(conn.getClient().getId()); if (rcl != null) { if (rcl.getIsScreenClient() != null && rcl.getIsScreenClient()) { // 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"); flvRecorderService.stopRecordingShowForClient(conn, currentClient); } } } } } } } } catch (Exception err) { log.error("[sendClientBroadcastNotifications]", err); } } /** * Adds a Moderator by its publicSID * * @param publicSID * @return -1 * public synchronized Long addModerator(String publicSID) { try { log.debug("----------- addModerator: " + publicSID); Client currentClient = this.sessionManager.getClientByPublicSID(publicSID, false); if (currentClient == null) { return -1L; } Long room_id = currentClient.getRoom_id(); currentClient.setIsMod(true); // Put the mod-flag to true for this client this.sessionManager.updateClientByStreamId(currentClient.getStreamid(), currentClient, false); List<Client> currentMods = this.sessionManager .getCurrentModeratorByRoom(room_id); //Send message to all users syncMessageToCurrentScope("setNewModeratorByList", currentMods, true); } catch (Exception err) { log.error("[addModerator]", err); } return -1L; } @SuppressWarnings("unchecked") public void setNewCursorPosition(Object item) { try { IConnection current = Red5.getConnectionLocal(); String streamid = current.getClient().getId(); Client currentClient = this.sessionManager.getClientByStreamId(streamid); @SuppressWarnings("rawtypes") Map cursor = (Map) item; cursor.put("streamPublishName", currentClient.getStreamPublishName()); // Notify all users of the same Scope for (Set<IConnection> conset : current.getScope().getConnections()) { for (IConnection conn : conset) { if (conn != null) { if (conn instanceof IServiceCapableConnection) { IClient client = conn.getClient(); if (SessionVariablesUtil.isScreenClient(client)) { // screen sharing clients do not receive events continue; } else if (SessionVariablesUtil.isAVClient(client)) { // AVClients or potential AVClients do not receive events continue; } if (client.getId().equals( current.getClient().getId())) { // don't send back to same user continue; } ((IServiceCapableConnection) conn).invoke("newRed5ScreenCursor", new Object[] { cursor }, this); } } } } } catch (Exception err) { log.error("[setNewCursorPosition]", err); } } public synchronized Long removeModerator(String publicSID) { try { log.debug("----------- removeModerator: " + publicSID); IConnection current = Red5.getConnectionLocal(); // String streamid = current.getClient().getId(); Client currentClient = this.sessionManager .getClientByPublicSID(publicSID, false, null); if (currentClient == null) { return -1L; } Long room_id = currentClient.getRoom_id(); currentClient.setIsMod(false); // Put the mod-flag to true for this client this.sessionManager.updateClientByStreamId( currentClient.getStreamid(), currentClient, false, null); List<Client> currentMods = this.sessionManager .getCurrentModeratorByRoom(room_id); // Notify all clients of the same scope (room) for (Set<IConnection> conset : current.getScope().getConnections()) { for (IConnection conn : conset) { if (conn != null) { if (conn instanceof IServiceCapableConnection) { IClient client = conn.getClient(); if (SessionVariablesUtil.isScreenClient(client)) { // screen sharing clients do not receive events continue; } else if (SessionVariablesUtil.isAVClient(client)) { // AVClients or potential AVClients do not receive events continue; } ((IServiceCapableConnection) conn).invoke( "setNewModeratorByList", new Object[] { currentMods }, this); } } } } } catch (Exception err) { log.error("[addModerator]", err); } return -1L; } */ public synchronized Long setBroadCastingFlag(String userId, boolean value, Integer interviewPodId) { try { log.debug("----------- setBroadCastingFlag: " + userId); IConnection current = Red5.getConnectionLocal(); // String streamid = current.getClient().getId(); Client currentClient = sessionManager.getClientByUserId(userId); if (currentClient == null) { return -1L; } currentClient.setIsBroadcasting(value); // Put the mod-flag to true for this client sessionManager.updateClientByStreamId(currentClient.getStreamid(), currentClient, false); // Notify all clients of the same scope (room) for (Set<IConnection> conset : current.getScope().getConnections()) { for (IConnection conn : conset) { if (conn != null) { if (conn instanceof IServiceCapableConnection) { IClient client = conn.getClient(); if (SessionVariablesUtil.isScreenClient(client)) { // screen sharing clients do not receive events continue; } else if (SessionVariablesUtil.isAVClient(client)) { // AVClients or potential AVClients do not receive events continue; } ((IServiceCapableConnection) conn).invoke("setNewBroadCastingFlag", new Object[] { currentClient }, this); } } } } } catch (Exception err) { log.error("[setBroadCastingFlag]", err); } return -1L; } public synchronized Long giveExclusiveAudio(String userId) { try { log.debug("----------- giveExclusiveAudio: " + userId); IConnection current = Red5.getConnectionLocal(); // String streamid = current.getClient().getId(); Client currentClient = this.sessionManager.getClientByUserId(userId); if (currentClient == null) { return -1L; } // Put the mod-flag to true for this client currentClient.setMicMuted(false); this.sessionManager.updateClientByStreamId(currentClient.getStreamid(), currentClient, false); // Notify all clients of the same scope (room) for (Set<IConnection> conset : current.getScope().getConnections()) { for (IConnection conn : conset) { if (conn != null) { Client rcl = this.sessionManager.getClientByStreamId(conn.getClient().getId()); if (rcl == null) { // continue; } else if (rcl.getIsScreenClient() != null && rcl.getIsScreenClient()) { // continue; } else { if (rcl != currentClient) { rcl.setMicMuted(true); this.sessionManager.updateClientByStreamId(rcl.getStreamid(), rcl, false); } log.debug("Send Flag to Client: " + rcl.getUsername()); if (conn instanceof IServiceCapableConnection) { ((IServiceCapableConnection) conn).invoke("receiveExclusiveAudioFlag", new Object[] { currentClient }, this); log.debug("sending receiveExclusiveAudioFlag to " + conn); } } } } } } catch (Exception err) { log.error("[giveExclusiveAudio]", err); } return -1L; } public synchronized Long switchMicMuted(String userId, boolean mute) { try { log.debug("----------- switchMicMuted: " + userId); Client currentClient = sessionManager.getClientByUserId(userId); if (currentClient == null) { return -1L; } currentClient.setMicMuted(mute); sessionManager.updateClientByStreamId(currentClient.getStreamid(), currentClient, false); 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 synchronized Boolean getMicMutedByUserId(String userId) { try { Client currentClient = this.sessionManager.getClientByUserId(userId); if (currentClient == null) { return true; } //Put the mod-flag to true for this client Boolean muted = currentClient.getMicMuted(); if (null == muted) { muted = true; } return muted; } 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 synchronized Long applyForModeration(String publicSID) { try { Client currentClient = this.sessionManager .getClientByPublicSID(publicSID, false, null); List<Client> currentModList = this.sessionManager .getCurrentModeratorByRoom(currentClient.getRoom_id()); if (currentModList.size() > 0) { return 2L; } else { // No moderator in this room at the moment Room room = roomDao.get(currentClient.getRoom_id()); if (room.getIsModeratedRoom()) { return 3L; } else { return 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 synchronized long getBroadCastId() { try { log.debug("----------- getBroadCastId"); IConnection current = Red5.getConnectionLocal(); String streamid = current.getClient().getId(); Client currentClient = this.sessionManager.getClientByStreamId(streamid); currentClient.setBroadCastID(broadCastCounter++); this.sessionManager.updateClientByStreamId(streamid, currentClient, false); return currentClient.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 room_id * @param publicSID * @param interviewPodId * @return RoomClient being updated in case of no errors, null otherwise */ public synchronized Client setUserAVSettings(String avsettings, Object newMessage, Integer vWidth, Integer vHeight, String room_id, String userId, Integer interviewPodId) { try { IConnection current = Red5.getConnectionLocal(); IClient c = current.getClient(); String streamid = c.getId(); log.debug("----------- setUserAVSettings {} {} {}", new Object[] { streamid, userId, avsettings, newMessage }); Client parentClient = sessionManager.getClientByUserId(userId); Client currentClient = sessionManager.getClientByStreamId(streamid); currentClient.setAvsettings(avsettings); currentClient.setRoom_id(room_id); currentClient.setVWidth(vWidth); currentClient.setVHeight(vHeight); currentClient.setUser_id(userId); currentClient.setLastname(parentClient.getLastname()); currentClient.setFirstname(parentClient.getFirstname()); currentClient.setPicture_uri(parentClient.getPicture_uri()); sessionManager.updateAVClientByStreamId(streamid, currentClient); SessionVariablesUtil.initClient(c, false, userId); HashMap<String, Object> hsm = new HashMap<String, Object>(); hsm.put("client", currentClient); hsm.put("message", newMessage); for (Set<IConnection> conset : current.getScope().getConnections()) { for (IConnection conn : conset) { if (conn != null) { if (conn instanceof IServiceCapableConnection) { IClient client = conn.getClient(); if (SessionVariablesUtil.isScreenClient(client)) { // screen sharing clients do not receive events continue; } else if (SessionVariablesUtil.isAVClient(client)) { // AVClients or potential AVClients do not receive events continue; } ((IServiceCapableConnection) conn).invoke("sendVarsToMessageWithClient", new Object[] { hsm }, this); } } } } return currentClient; } catch (Exception err) { log.error("[setUserAVSettings]", err); } return null; } /* * checks if the user is allowed to apply for Moderation * public synchronized Boolean checkRoomValues(Long room_id) { try { // appointed meeting or moderated Room? Room room = roomDao.get(room_id); // not really - default logic if (room.getAppointment() == null || room.getAppointment() == false) { if (room.getIsModeratedRoom()) { // if this is a Moderated Room then the Room can be only // locked off by the Moderator Bit List<Client> clientModeratorListRoom = this.sessionManager .getCurrentModeratorByRoom(room_id); // 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 if (clientModeratorListRoom.size() == 0) { return false; } else { return true; } } else { return true; } } 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 room_id - id of the room * @param becomeModerator - is user will become moderator * @param isSuperModerator - is user super moderator * @param organization_id - organization id of the user * @param colorObj - some color * @return RoomStatus object */ public synchronized RoomStatus setRoomValues(String room_id, Boolean becomeModerator, Boolean isSuperModerator, Long organization_id, String colorObj) { try { log.debug("----------- setRoomValues"); // Return Object RoomStatus roomStatus = new RoomStatus(); IConnection current = Red5.getConnectionLocal(); String streamid = current.getClient().getId(); Client currentClient = sessionManager.getClientByStreamId(streamid); currentClient.setRoom_id(room_id); currentClient.setRoomEnter(new Date()); currentClient.setOrganization_id(organization_id); currentClient.setUsercolor(colorObj); // This can be set without checking for Moderation Flag currentClient.setIsSuperModerator(isSuperModerator); this.sessionManager.updateClientByStreamId(streamid, currentClient, true); // Check for Moderation LogicalRoom ENTER List<Client> clientListRoom = sessionManager.getClientListByRoom(room_id); // default logic for non regular rooms // If this is a normal Room Moderator rules : first come, // first draw ;-) log.debug("setRoomValues : Room" + room_id + " not appointed! Moderator rules : first come, first draw ;-)"); if (clientListRoom.size() == 1) { log.debug("Room is empty so set this user to be moderation role"); currentClient.setIsMod(true); } else { log.debug("Room is already somebody so set this user not to be moderation role"); /* * if (becomeModerator) { currentClient.setIsMod(true); // Update the Client List this.sessionManager.updateClientByStreamId(streamid, currentClient, false); // There is a need to send an extra Event here, // cause at this moment there could be // already somebody in the Room waiting -swagner check this comment, 20.01.2012 //Sync message to everybody //syncMessageToCurrentScope("setNewModeratorByList", modRoomList, false); } else { // The current User is not a Teacher/Admin or // whatever Role that should get the Moderation currentClient.setIsMod(false); } */ currentClient.setIsMod(false); } // Update the Client List this.sessionManager.updateClientByStreamId(streamid, currentClient, false); //Sync message to everybody syncMessageToCurrentScope("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(clientListRoom); 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 synchronized Client setUsernameReconnect(String SID, String 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 = this.sessionManager.getClientByStreamId(streamid); currentClient.setUsername(username); currentClient.setUser_id(userId); SessionVariablesUtil.setUserId(current.getClient(), userId); currentClient.setPicture_uri(picture_uri); currentClient.setUserObject(userId, username, firstname, lastname); this.sessionManager.updateClientByStreamId(streamid, currentClient, false); 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 synchronized Client setUsernameAndSession(String userId, String username, String firstname, String lastname) { try { log.debug("----------- setUsernameAndSession"); IConnection current = Red5.getConnectionLocal(); String streamid = current.getClient().getId(); Client currentClient = this.sessionManager.getClientByStreamId(streamid); currentClient.setUsername(username); currentClient.setUser_id(userId); SessionVariablesUtil.setUserId(current.getClient(), userId); currentClient.setUserObject(userId, username, firstname, lastname); // Update Session Data log.debug("UDPATE SESSION " + userId); this.sessionManager.updateClientByStreamId(streamid, currentClient, false); return currentClient; } catch (Exception err) { log.error("[setUsername]", err); } return null; } /** * used by the Screen-Sharing Servlet to trigger events * * @param room_id * @param message * @return the list of room clients */ public synchronized HashMap<String, Client> sendMessageByRoomAndDomain(Long room_id, Object message) { HashMap<String, Client> roomClientList = new HashMap<String, Client>(); try { log.debug("sendMessageByRoomAndDomain " + room_id); IScope globalScope = getContext().getGlobalScope(); IScope webAppKeyScope = globalScope.getScope("/"); log.debug("webAppKeyScope " + webAppKeyScope); IScope scopeRoom = webAppKeyScope.getScope(room_id.toString()); if (scopeRoom != null) { for (Set<IConnection> conset : webAppKeyScope.getScope(room_id.toString()).getConnections()) { for (IConnection conn : conset) { if (conn != null) { if (conn instanceof IServiceCapableConnection) { IClient client = conn.getClient(); if (SessionVariablesUtil.isScreenClient(client)) { // screen sharing clients do not receive events continue; } else if (SessionVariablesUtil.isAVClient(client)) { // AVClients or potential AVClients do not receive events continue; } ((IServiceCapableConnection) conn).invoke("newMessageByRoomAndDomain", new Object[] { message }, this); } } } } } else { log.debug("sendMessageByRoomAndDomain servlet not yet started - roomID : '" + room_id + "'"); } } catch (Exception err) { log.error("[getClientListBYRoomAndDomain]", err); } return roomClientList; } public synchronized List<Client> getCurrentModeratorList() { return null; } public synchronized int sendVarsModeratorGeneral(Object vars) { log.debug("*..*sendVars: " + vars); try { IConnection current = Red5.getConnectionLocal(); Client currentClient = this.sessionManager.getClientByStreamId(current.getClient().getId()); // Long room_id = currentClient.getRoom_id(); 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 for (Set<IConnection> conset : current.getScope().getConnections()) { for (IConnection conn : conset) { if (conn != null) { if (conn instanceof IServiceCapableConnection) { IClient client = conn.getClient(); if (SessionVariablesUtil.isScreenClient(client)) { // screen sharing clients do not receive events continue; } else if (SessionVariablesUtil.isAVClient(client)) { // AVClients or potential AVClients do not receive events continue; } if (client.getId().equals(current.getClient().getId())) { // don't send back to same user continue; } ((IServiceCapableConnection) conn).invoke("sendVarsToModeratorGeneral", new Object[] { vars }, this); } } } } return 1; } else { // log.debug("*..*you are not allowed to send: "+ismod); return -1; } } catch (Exception err) { log.error("[sendVarsModeratorGeneral]", err); } return -1; } public synchronized int sendMessage(Object newMessage) { try { syncMessageToCurrentScope("sendVarsToMessage", newMessage, false); } catch (Exception err) { log.error("[sendMessage]", err); } return 1; } public synchronized int sendMessageAll(Object newMessage) { try { syncMessageToCurrentScope("sendVarsToMessage", newMessage, true); } catch (Exception err) { log.error("[sendMessage]", err); } 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); syncMessageToCurrentScope("sendVarsToMessage", newMessage, false); } catch (Exception err) { log.error("[sendMessage]", err); } return 1; } /** * wrapper method * @param newMessage */ public synchronized void sendMessageToMembers(Object newMessage) { //Sync to all users of current scope syncMessageToCurrentScope("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 synchronized void syncMessageToCurrentScope(String remoteMethodName, Object newMessage, boolean sendSelf) { syncMessageToCurrentScope(remoteMethodName, newMessage, sendSelf, false); } /** * 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 synchronized boolean loadTestSyncMessage(String remoteMethodName, Object newMessage, boolean sendSelf) { log.info(remoteMethodName, newMessage, sendSelf); syncMessageToCurrentScope(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 synchronized void syncMessageToCurrentScope(String remoteMethodName, Object newMessage, boolean sendSelf, boolean sendScreen) { try { IConnection current = Red5.getConnectionLocal(); // Send to all Clients of that Scope(Room) for (Set<IConnection> conset : current.getScope().getConnections()) { for (IConnection conn : conset) { if (conn != null) { if (conn instanceof IServiceCapableConnection) { IClient client = conn.getClient(); if (!sendScreen && SessionVariablesUtil.isScreenClient(client)) { // screen sharing clients do not receive events continue; } else if (SessionVariablesUtil.isAVClient(client)) { // AVClients or potential AVClients do not receive events continue; } else if (!sendSelf && client.getId().equals(current.getClient().getId())) { //Do not send back to self continue; } ((IServiceCapableConnection) conn).invoke(remoteMethodName, new Object[] { newMessage }, this); } } } } } catch (Exception err) { log.error("[syncMessageToCurrentScope]", err); } } /** * wrapper method * @param newMessage * @return 1 in case of success, -1 otherwise */ public synchronized 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 synchronized int sendMessageWithClientWithSyncObject(Object newMessage, boolean sync) { try { IConnection current = Red5.getConnectionLocal(); Client currentClient = this.sessionManager.getClientByStreamId(current.getClient().getId()); HashMap<String, Object> hsm = new HashMap<String, Object>(); hsm.put("client", currentClient); hsm.put("message", newMessage); //Sync to all users of current scope syncMessageToCurrentScope("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 synchronized 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 (Set<IConnection> conset : scope.getConnections()) { for (IConnection conn : conset) { 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 synchronized int sendMessageWithClientById(Object newMessage, String clientId) { try { IConnection current = Red5.getConnectionLocal(); Client currentClient = this.sessionManager.getClientByStreamId(current.getClient().getId()); 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 (Set<IConnection> conset : current.getScope().getConnections()) { for (IConnection conn : conset) { 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 synchronized void sendMessageWithClientByUserId(Object message, String userId) { try { // ApplicationContext appCtx = getContext().getApplicationContext(); IScope globalScope = getContext().getGlobalScope(); IScope webAppKeyScope = globalScope.getScope("/"); // log.debug("webAppKeyScope "+webAppKeyScope); // Get Room Id to send it to the correct Scope Client currentClient = this.sessionManager.getClientByUserId(userId); if (currentClient == null) { throw new Exception("Could not Find RoomClient on List userId: " + userId); } // default Scope Name String scopeName = "hibernate"; if (currentClient.getRoom_id() != null) { scopeName = currentClient.getRoom_id().toString(); } IScope scopeHibernate = webAppKeyScope.getScope(scopeName); // log.debug("scopeHibernate "+scopeHibernate); if (scopeHibernate != null) { // Notify the clients of the same scope (room) with user_id for (Set<IConnection> conset : webAppKeyScope.getScope(scopeName).getConnections()) { for (IConnection conn : conset) { IClient client = conn.getClient(); if (SessionVariablesUtil.isScreenClient(client)) { // screen sharing clients do not receive events continue; } else if (SessionVariablesUtil.isAVClient(client)) { // AVClients or potential AVClients do not receive events continue; } if (SessionVariablesUtil.getUserId(client).equals(userId)) { ((IServiceCapableConnection) conn).invoke("newMessageByRoomAndDomain", new Object[] { message }, this); } } } } else { // Scope not yet started } } catch (Exception err) { log.error("[sendMessageWithClient] ", err); } } public synchronized void sendMessageWithClientByPublicSIDOrUser(Object message, String user_id) { try { // ApplicationContext appCtx = getContext().getApplicationContext(); IScope globalScope = getContext().getGlobalScope(); IScope webAppKeyScope = globalScope.getScope("/"); // log.debug("webAppKeyScope "+webAppKeyScope); // Get Room Id to send it to the correct Scope Client currentClient = sessionManager.getClientByUserId(user_id); Collection<Set<IConnection>> concolset = null; if (currentClient == null) { // Must be from a previous session, search for user in current // scope IConnection current = Red5.getConnectionLocal(); // Notify all Clients of that Scope (Room) concolset = current.getScope().getConnections(); } else { // default Scope Name String scopeName = "hibernate"; if (currentClient.getRoom_id() != null) { scopeName = currentClient.getRoom_id().toString(); } IScope scopeHibernate = webAppKeyScope.getScope(scopeName); if (scopeHibernate != null) { concolset = webAppKeyScope.getScope(scopeName).getConnections(); } } // log.debug("scopeHibernate "+scopeHibernate); // Notify the clients of the same scope (room) with user_id for (Set<IConnection> conset : concolset) { for (IConnection conn : conset) { if (conn != null) { IClient client = conn.getClient(); if (SessionVariablesUtil.isScreenClient(client)) { // screen sharing clients do not receive events continue; } else if (SessionVariablesUtil.isAVClient(client)) { // AVClients or potential AVClients do not receive events continue; } if (user_id != null && SessionVariablesUtil.getUserId(client).equals(user_id)) { ((IServiceCapableConnection) conn).invoke("newMessageByRoomAndDomain", new Object[] { message }, this); log.debug("sendMessageWithClientByPublicSID RPC:newMessageByRoomAndDomain" + message); } } } } } catch (Exception err) { log.error("[sendMessageWithClient] ", err); } } @SuppressWarnings({ "rawtypes" }) public synchronized Boolean sendRemoteCursorEvent(String streamid, Map messageObj) { try { IConnection current = Red5.getConnectionLocal(); for (Set<IConnection> conset : current.getScope().getConnections()) { for (IConnection conn : conset) { if (conn != null) { IClient client = conn.getClient(); if (SessionVariablesUtil.isScreenClient(client)) { if (conn.getClient().getId().equals(streamid)) { ((IServiceCapableConnection) conn).invoke("sendRemoteCursorEvent", new Object[] { messageObj }, this); } } } } } } catch (Exception err) { log.debug("[sendRemoteCursorEvent]", err); } return null; } private Long checkRecordingClient(IConnection conn) { Long flvRecordingId = null; if (conn != null) { Client rcl = sessionManager.getClientByStreamId(conn.getClient().getId()); if (rcl != null && rcl.getIsRecording() != null && rcl.getIsRecording()) { rcl.setIsRecording(false); flvRecordingId = rcl.getFlvRecordingId(); rcl.setFlvRecordingId(null); // Reset the Recording Flag to Record all // Participants that enter later sessionManager.updateClientByStreamId(conn.getClient().getId(), rcl, false); } } return flvRecordingId; } /** * Stop the recording of the streams and send event to connected users of scope * * @return true if interview was found */ public synchronized Boolean stopInterviewRecording() { try { log.debug("----------- stopInterviewRecording"); IConnection current = Red5.getConnectionLocal(); Long flvRecordingId = checkRecordingClient(current); Collection<Set<IConnection>> concolset = current.getScope().getConnections(); for (Set<IConnection> conset : concolset) { for (IConnection conn : conset) { Long recordingId = checkRecordingClient(conn); if (recordingId != null) { flvRecordingId = recordingId; } } } if (flvRecordingId == null) { log.debug("stopInterviewRecording:: unable to find recording client"); return false; } Client currentClient = sessionManager.getClientByStreamId(current.getClient().getId()); flvRecorderService.stopRecordAndSave(scope, currentClient, flvRecordingId); Map<String, String> interviewStatus = new HashMap<String, String>(); interviewStatus.put("action", "stop"); for (Set<IConnection> conset : concolset) { for (IConnection conn : conset) { if (conn != null) { IClient client = conn.getClient(); if (SessionVariablesUtil.isScreenClient(client)) { // screen sharing clients do not receive events continue; } else if (SessionVariablesUtil.isAVClient(client)) { // AVClients or potential AVClients do not receive events continue; } ((IServiceCapableConnection) conn).invoke("interviewStatus", new Object[] { interviewStatus }, this); } } } return true; } catch (Exception err) { log.debug("[stopInterviewRecording]", err); } return null; } /** * Get all ClientList Objects of that room and domain Used in * lz.applyForModeration.lzx * * @return all ClientList Objects of that room */ public synchronized List<Client> getClientListScope() { try { IConnection current = Red5.getConnectionLocal(); Client currentClient = this.sessionManager.getClientByStreamId(current.getClient().getId()); return sessionManager.getClientListByRoom(currentClient.getRoom_id()); } catch (Exception err) { log.debug("[getClientListScope]", err); } return new ArrayList<Client>(); } public synchronized IScope getRoomScope(String room) { try { IScope globalScope = getContext().getGlobalScope(); IScope webAppKeyScope = globalScope.getScope("/"); String scopeName = "hibernate"; // If set then its a NON default Scope if (room.length() != 0) { scopeName = room; } IScope scopeHibernate = webAppKeyScope.getScope(scopeName); return scopeHibernate; } catch (Exception err) { log.error("[getRoomScope]", err); } return null; } }