示例#1
0
文件: Client.java 项目: Juliens/red5
 /** @return scopes on this client */
 public Collection<IScope> getScopes() {
   Set<IScope> scopes = new HashSet<IScope>();
   for (IConnection conn : connections) {
     scopes.add(conn.getScope());
   }
   return scopes;
 }
示例#2
0
文件: Client.java 项目: Juliens/red5
 /** {@inheritDoc} */
 public void setPermissions(IConnection conn, Collection<String> permissions) {
   if (permissions == null) {
     conn.removeAttribute(PERMISSIONS);
   } else {
     conn.setAttribute(PERMISSIONS, permissions);
   }
 }
示例#3
0
  /**
   * Connects client to the scope
   *
   * @param conn Client conneciton
   * @param scope Scope
   * @param params Params passed from client side with connect call
   * @return true if client was registred within scope, false otherwise
   */
  public boolean connect(IConnection conn, IScope scope, Object[] params) {

    log.debug("Connect to core handler ?");

    // Get session id
    String id = conn.getSessionId();

    // Use client registry from scope the client connected to.
    IScope connectionScope = Red5.getConnectionLocal().getScope();

    // Get client registry for connection scope
    IClientRegistry clientRegistry = connectionScope.getContext().getClientRegistry();

    // Get client from registry by id or create a new one
    IClient client =
        clientRegistry.hasClient(id)
            ? clientRegistry.lookupClient(id)
            : clientRegistry.newClient(params);

    // We have a context, and a client object.. time to init the conneciton.
    conn.initialize(client);

    // we could checked for banned clients here
    return true;
  }
示例#4
0
 /**
  * Remote method invokation
  *
  * @param conn Connection to invoke method on
  * @param call Service call context
  * @return true on success
  */
 public boolean serviceCall(IConnection conn, IServiceCall call) {
   final IContext context = conn.getScope().getContext();
   if (call.getServiceName() != null) {
     context.getServiceInvoker().invoke(call, context);
   } else {
     context.getServiceInvoker().invoke(call, conn.getScope().getHandler());
   }
   return true;
 }
示例#5
0
 /** {@inheritDoc} */
 @Override
 public void dispatchEvent(IEvent event) {
   Set<IConnection> conns = getClientConnections();
   for (IConnection conn : conns) {
     try {
       conn.dispatchEvent(event);
     } catch (RuntimeException e) {
       log.error("Exception during dispatching event: {}", event, e);
     }
   }
 }
 /** {@inheritDoc} */
 public void receiveAudio(boolean receive) {
   IConnection conn = Red5.getConnectionLocal();
   if (conn instanceof IStreamCapableConnection) {
     IStreamCapableConnection streamConn = (IStreamCapableConnection) conn;
     int streamId = conn.getStreamId();
     IClientStream stream = streamConn.getStreamById(streamId);
     if (stream != null && stream instanceof ISubscriberStream) {
       ISubscriberStream subscriberStream = (ISubscriberStream) stream;
       subscriberStream.receiveAudio(receive);
     }
   }
 }
示例#7
0
 @Override
 public boolean roomConnect(IConnection connection, Object[] params) {
   log.debug(APP + ":roomConnect");
   ISharedObject so = getSharedObject(connection.getScope(), LAYOUT_SO);
   log.debug("Setting up Listener");
   LayoutSender sender = new LayoutSender(so);
   String room = connection.getScope().getName();
   log.debug("Adding event listener to " + room);
   log.debug("Adding room listener");
   layoutApplication.addRoomListener(room, sender);
   log.debug("Done setting up listener");
   return true;
 }
示例#8
0
  /**
   * A hook to record a sample stream. A file is written in webapps/sip/streams/
   *
   * @param stream
   */
  private void recordStream(IBroadcastStream stream) {
    IConnection conn = Red5.getConnectionLocal();
    String streamName = stream.getPublishedName();

    try {
      ClientBroadcastStream cstream =
          (ClientBroadcastStream)
              this.getBroadcastStream(conn.getScope(), stream.getPublishedName());
      cstream.saveAs(streamName, false);
    } catch (Exception e) {
      System.out.println("ERROR while recording stream " + e.getMessage());
      e.printStackTrace();
    }
  }
 /** {@inheritDoc} */
 public void play(Boolean dontStop) {
   log.debug("Play called. Dont stop param: {}", dontStop);
   if (!dontStop) {
     IConnection conn = Red5.getConnectionLocal();
     if (conn instanceof IStreamCapableConnection) {
       IStreamCapableConnection streamConn = (IStreamCapableConnection) conn;
       int streamId = conn.getStreamId();
       IClientStream stream = streamConn.getStreamById(streamId);
       if (stream != null) {
         stream.stop();
       }
     }
   }
 }
示例#10
0
 /**
  * Disconnect connection from scope
  *
  * @param conn Connection object
  */
 public void disconnect(IConnection conn) {
   log.debug("Disconnect: {}", conn);
   // call disconnect handlers in reverse order of connection. ie. roomDisconnect is called before
   // appDisconnect.
   final IClient client = conn.getClient();
   if (client == null) {
     // early bail out
     removeEventListener(conn);
     connectionStats.decrement();
     if (hasParent()) {
       parent.disconnect(conn);
     }
     return;
   }
   // remove it if it exists
   if (clients.remove(client)) {
     IScopeHandler handler = getHandler();
     if (handler != null) {
       try {
         handler.disconnect(conn, this);
       } catch (Exception e) {
         log.error(
             "Error while executing \"disconnect\" for connection {} on handler {}. {}",
             new Object[] {conn, handler, e});
       }
       try {
         // there may be a timeout here ?
         handler.leave(client, this);
       } catch (Exception e) {
         log.error(
             "Error while executing \"leave\" for client {} on handler {}. {}",
             new Object[] {conn, handler, e});
       }
     }
     // remove listener
     removeEventListener(conn);
     // decrement if there was a set of connections
     connectionStats.decrement();
     if (this.equals(conn.getScope())) {
       final IServer server = getServer();
       if (server instanceof Server) {
         ((Server) server).notifyDisconnected(conn);
       }
     }
   }
   if (hasParent()) {
     parent.disconnect(conn);
   }
 }
 /**
  * Close stream. This method can close both IClientBroadcastStream (coming from Flash Player to
  * Red5) and ISubscriberStream (from Red5 to Flash Player). Corresponding application handlers
  * (streamSubscriberClose, etc.) are called as if close was initiated by Flash Player.
  *
  * <p>It is recommended to remember stream id in application handlers, ex.:
  *
  * <pre>
  * public void streamBroadcastStart(IBroadcastStream stream) {
  * 	super.streamBroadcastStart(stream);
  * 	if (stream instanceof IClientBroadcastStream) {
  * 		int publishedStreamId = ((ClientBroadcastStream)stream).getStreamId();
  * 		Red5.getConnectionLocal().setAttribute(PUBLISHED_STREAM_ID_ATTRIBUTE, publishedStreamId);
  * 	}
  * }
  * </pre>
  *
  * <pre>
  * public void streamPlaylistItemPlay(IPlaylistSubscriberStream stream, IPlayItem item, boolean isLive) {
  * 	super.streamPlaylistItemPlay(stream, item, isLive);
  * 	Red5.getConnectionLocal().setAttribute(WATCHED_STREAM_ID_ATTRIBUTE, stream.getStreamId());
  * }
  * </pre>
  *
  * When stream is closed, corresponding NetStream status will be sent to stream provider /
  * consumers. Implementation is based on Red5's StreamService.close()
  *
  * @param conn client connection
  * @param streamId stream ID (number: 1,2,...)
  */
 public void closeStream(IConnection conn, int streamId) {
   log.info("closeStream: streamId={}, connection={}", streamId, conn);
   if (conn instanceof IStreamCapableConnection) {
     IStreamCapableConnection scConn = (IStreamCapableConnection) conn;
     IClientStream stream = scConn.getStreamById(streamId);
     if (stream != null) {
       if (stream instanceof IClientBroadcastStream) {
         // this is a broadcasting stream (from Flash Player to Red5)
         IClientBroadcastStream bs = (IClientBroadcastStream) stream;
         IBroadcastScope bsScope = getBroadcastScope(conn.getScope(), bs.getPublishedName());
         if (bsScope != null && conn instanceof BaseConnection) {
           ((BaseConnection) conn).unregisterBasicScope(bsScope);
         }
       }
       stream.close();
       scConn.deleteStreamById(streamId);
       // in case of broadcasting stream, status is sent automatically by Red5
       if (!(stream instanceof IClientBroadcastStream)) {
         StreamService.sendNetStreamStatus(
             conn,
             StatusCodes.NS_PLAY_STOP,
             "Stream closed by server",
             stream.getName(),
             Status.STATUS,
             streamId);
       }
     } else {
       log.info("Stream not found: streamId={}, connection={}", streamId, conn);
     }
   } else {
     log.warn("Connection is not instance of IStreamCapableConnection: {}", conn);
   }
 }
示例#12
0
 /**
  * Connect to scope with parameters. To successfully connect to scope it must have handler that
  * will accept this connection with given set of parameters. Client associated with connection is
  * added to scope clients set, connection is registered as scope event listener.
  *
  * @param conn Connection object
  * @param params Parameters passed with connection
  * @return
  *     <pre>
  * true
  * </pre>
  *     on success,
  *     <pre>
  * false
  * </pre>
  *     otherwise
  */
 public boolean connect(IConnection conn, Object[] params) {
   log.debug("Connect - scope: {} connection: {}", this, conn);
   if (enabled) {
     if (hasParent() && !parent.connect(conn, params)) {
       log.debug("Connection to parent failed");
       return false;
     }
     if (hasHandler() && !getHandler().connect(conn, this, params)) {
       log.debug("Connection to handler failed");
       return false;
     }
     if (!conn.isConnected()) {
       log.debug("Connection is not connected");
       // timeout while connecting client
       return false;
     }
     final IClient client = conn.getClient();
     // we would not get this far if there is no handler
     if (hasHandler() && !getHandler().join(client, this)) {
       return false;
     }
     // checking the connection again? why?
     if (!conn.isConnected()) {
       // timeout while connecting client
       return false;
     }
     // add the client and event listener
     if (clients.add(client) && addEventListener(conn)) {
       log.debug("Added client");
       // increment conn stats
       connectionStats.increment();
       // get connected scope
       IScope connScope = conn.getScope();
       log.trace("Connection scope: {}", connScope);
       if (this.equals(connScope)) {
         final IServer server = getServer();
         if (server instanceof Server) {
           ((Server) server).notifyConnected(conn);
         }
       }
       return true;
     }
   } else {
     log.debug("Connection failed, scope is disabled");
   }
   return false;
 }
示例#13
0
文件: Client.java 项目: Juliens/red5
 /** {@inheritDoc} */
 @SuppressWarnings("unchecked")
 public Collection<String> getPermissions(IConnection conn) {
   Collection<String> result = (Collection<String>) conn.getAttribute(PERMISSIONS);
   if (result == null) {
     result = Collections.emptySet();
   }
   return result;
 }
示例#14
0
  @Override
  public void streamBroadcastClose(IBroadcastStream stream) {
    String clientId = Red5.getConnectionLocal().getClient().getId();
    String userid = getUserId();
    String username = getUsername();

    log.debug(
        "{} has stopped publishing stream [{}]",
        username + "[uid=" + userid + "][clientid=" + clientId + "]",
        stream.getPublishedName());
    IConnection conn = Red5.getConnectionLocal();
    String peerId = (String) conn.getAttribute("VOICE_CONF_PEER");
    if (peerId != null) {
      super.streamPublishStart(stream);
      sipPeerManager.stopTalkStream(peerId, clientId, stream, conn.getScope());
      super.streamBroadcastClose(stream);
    }
  }
示例#15
0
文件: Client.java 项目: Juliens/red5
 /** Disconnects client from Red5 application */
 public void disconnect() {
   log.debug("Disconnect - id: {}", id);
   if (connections != null && !connections.isEmpty()) {
     log.debug("Closing {} scope connections", connections.size());
     // close all connections held to Red5 by client
     for (IConnection con : getConnections()) {
       try {
         con.close();
       } catch (Exception e) {
         // closing a connection calls into application code, so exception possible
         log.error("Unexpected exception closing connection {}", e);
       }
     }
   } else {
     log.debug("Connection map is empty or null");
   }
   // unregister client
   removeInstance();
 }
示例#16
0
 @Override
 public void roomDisconnect(IConnection connection) {
   log.debug(
       "***** "
           + APP
           + " [ "
           + " roomDisconnect [ "
           + connection.getScope().getName()
           + "] *********");
 }
 /**
  * Pause at given position. Required as "pausePlayback" can be "null" if no flag is passed by the
  * client
  *
  * @param pausePlayback Pause playback or not
  * @param position Pause position
  */
 public void pause(Boolean pausePlayback, int position) {
   IConnection conn = Red5.getConnectionLocal();
   if (conn instanceof IStreamCapableConnection) {
     IStreamCapableConnection streamConn = (IStreamCapableConnection) conn;
     int streamId = conn.getStreamId();
     IClientStream stream = streamConn.getStreamById(streamId);
     if (stream != null && stream instanceof ISubscriberStream) {
       ISubscriberStream subscriberStream = (ISubscriberStream) stream;
       // pausePlayback can be "null" if "pause" is called without any parameters from flash
       if (pausePlayback == null) {
         pausePlayback = !subscriberStream.isPaused();
       }
       if (pausePlayback) {
         subscriberStream.pause(position);
       } else {
         subscriberStream.resume(position);
       }
     }
   }
 }
 /** {@inheritDoc} */
 public void close() {
   session.invalidate();
   // set a quick local ref
   final IConnection con = this;
   String threadId = String.format("RemotingCloseNotifier-%s", con.getClient().getId());
   // alert our listeners
   Thread t =
       new Thread(
           new Runnable() {
             public void run() {
               for (IConnectionListener listener : connectionListeners) {
                 listener.notifyDisconnected(con);
               }
               connectionListeners.clear();
             }
           },
           threadId);
   t.setDaemon(true);
   t.start();
 }
示例#19
0
  @Override
  public boolean roomConnect(IConnection connection, Object[] params) {
    log.debug(
        "***** "
            + APP
            + " [ "
            + " roomConnect [ "
            + connection.getScope().getName()
            + "] *********");

    return true;
  }
 /** {@inheritDoc} */
 public void initStream(int streamId) {
   IConnection conn = Red5.getConnectionLocal();
   log.info("initStream: id={} current id: {} connection={}", streamId, conn.getStreamId(), conn);
   if (conn instanceof IStreamCapableConnection) {
     ((IStreamCapableConnection) conn).reserveStreamId(streamId);
     IClientStream stream = ((IStreamCapableConnection) conn).getStreamById(streamId);
     if (stream != null) {
       if (stream instanceof IClientBroadcastStream) {
         IClientBroadcastStream bs = (IClientBroadcastStream) stream;
         IBroadcastScope bsScope = getBroadcastScope(conn.getScope(), bs.getPublishedName());
         if (bsScope != null && conn instanceof BaseConnection) {
           ((BaseConnection) conn).unregisterBasicScope(bsScope);
         }
       }
       stream.close();
     }
     ((IStreamCapableConnection) conn).deleteStreamById(streamId);
   } else {
     log.warn("ERROR in intiStream, connection is not stream capable");
   }
 }
 /** {@inheritDoc} */
 public void seek(int position) {
   log.trace("seek - position:{}", position);
   IConnection conn = Red5.getConnectionLocal();
   if (conn instanceof IStreamCapableConnection) {
     IStreamCapableConnection streamConn = (IStreamCapableConnection) conn;
     int streamId = conn.getStreamId();
     IClientStream stream = streamConn.getStreamById(streamId);
     if (stream != null && stream instanceof ISubscriberStream) {
       ISubscriberStream subscriberStream = (ISubscriberStream) stream;
       try {
         subscriberStream.seek(position);
       } catch (OperationNotSupportedException err) {
         sendNSFailed(
             streamConn,
             StatusCodes.NS_SEEK_FAILED,
             "The stream doesn't support seeking.",
             stream.getName(),
             streamId);
       }
     }
   }
 }
示例#22
0
文件: Client.java 项目: Juliens/red5
 /**
  * Associate connection with client
  *
  * @param conn Connection object
  */
 protected void register(IConnection conn) {
   log.debug("Registering connection for this client {}", id);
   if (conn != null) {
     IScope scope = conn.getScope();
     if (scope != null) {
       log.debug("Registering for scope: {}", scope);
       connections.add(conn);
     } else {
       log.warn("Clients scope is null. Id: {}", id);
     }
   } else {
     log.warn("Clients connection is null. Id: {}", id);
   }
 }
 /** {@inheritDoc} */
 public void publish(Boolean dontStop) {
   if (!dontStop) {
     IConnection conn = Red5.getConnectionLocal();
     if (conn instanceof IStreamCapableConnection) {
       IStreamCapableConnection streamConn = (IStreamCapableConnection) conn;
       int streamId = conn.getStreamId();
       IClientStream stream = streamConn.getStreamById(streamId);
       if (stream instanceof IBroadcastStream) {
         IBroadcastStream bs = (IBroadcastStream) stream;
         if (bs.getPublishedName() != null) {
           IBroadcastScope bsScope = getBroadcastScope(conn.getScope(), bs.getPublishedName());
           if (bsScope != null) {
             bsScope.unsubscribe(bs.getProvider());
             if (conn instanceof BaseConnection) {
               ((BaseConnection) conn).unregisterBasicScope(bsScope);
             }
           }
           bs.close();
           streamConn.deleteStreamById(streamId);
         }
       }
     }
   }
 }
  @Override
  public boolean roomConnect(IConnection connection, Object[] params) {
    String username = ((String) params[0]).toString();
    String role = ((String) params[1]).toString();
    String room = ((String) params[2]).toString();

    String voiceBridge = ((String) params[3]).toString();

    boolean record = (Boolean) params[4];

    String externalUserID = ((String) params[5]).toString();
    String internalUserID = ((String) params[6]).toString();

    Boolean muted = false;
    if (params.length >= 7 && ((Boolean) params[7])) {
      muted = true;
    }

    Map<String, Boolean> lsMap = null;
    if (params.length >= 8) {
      try {
        lsMap = (Map<String, Boolean>) params[8];
      } catch (Exception e) {
        lsMap = new HashMap<String, Boolean>();
      }
    }

    String userId = internalUserID;
    String sessionId = CONN + userId;
    BigBlueButtonSession bbbSession =
        new BigBlueButtonSession(
            room,
            internalUserID,
            username,
            role,
            voiceBridge,
            record,
            externalUserID,
            muted,
            sessionId);
    connection.setAttribute(Constants.SESSION, bbbSession);
    connection.setAttribute("INTERNAL_USER_ID", internalUserID);
    connection.setAttribute("USER_SESSION_ID", sessionId);
    connection.setAttribute("TIMESTAMP", System.currentTimeMillis());

    red5InGW.initLockSettings(room, lsMap);

    red5InGW.initAudioSettings(room, internalUserID, muted);

    String meetingId = bbbSession.getRoom();

    String connType = getConnectionType(Red5.getConnectionLocal().getType());
    String userFullname = bbbSession.getUsername();
    String connId = Red5.getConnectionLocal().getSessionId();

    String remoteHost = Red5.getConnectionLocal().getRemoteAddress();
    int remotePort = Red5.getConnectionLocal().getRemotePort();

    Map<String, Object> logData = new HashMap<String, Object>();
    logData.put("meetingId", meetingId);
    logData.put("connType", connType);
    logData.put("connId", connId);
    logData.put("conn", remoteHost + ":" + remotePort);
    logData.put("userId", userId);
    logData.put("externalUserId", externalUserID);
    logData.put("sessionId", sessionId);
    logData.put("username", userFullname);
    logData.put("event", "user_joining_bbb_apps");
    logData.put("description", "User joining BBB Apps.");

    Gson gson = new Gson();
    String logStr = gson.toJson(logData);

    log.info("User joining bbb-apps: data={}", logStr);

    userConnections.addUserConnection(userId, connId);

    return super.roomConnect(connection, params);
  }
 /** {@inheritDoc} */
 public void publish(String name, String mode) {
   Map<String, String> params = null;
   if (name != null && name.contains("?")) {
     // read and utilize the query string values
     params = new HashMap<String, String>();
     String tmp = name;
     // check if we start with '?' or not
     if (name.charAt(0) != '?') {
       tmp = name.split("\\?")[1];
     } else if (name.charAt(0) == '?') {
       tmp = name.substring(1);
     }
     // now break up into key/value blocks
     String[] kvs = tmp.split("&");
     // take each key/value block and break into its key value parts
     for (String kv : kvs) {
       String[] split = kv.split("=");
       params.put(split[0], split[1]);
     }
     // grab the streams name
     name = name.substring(0, name.indexOf("?"));
   }
   log.debug("publish called with name {} and mode {}", name, mode);
   IConnection conn = Red5.getConnectionLocal();
   if (conn instanceof IStreamCapableConnection) {
     IScope scope = conn.getScope();
     IStreamCapableConnection streamConn = (IStreamCapableConnection) conn;
     int streamId = conn.getStreamId();
     if (StringUtils.isEmpty(name)) {
       sendNSFailed(
           streamConn, StatusCodes.NS_FAILED, "The stream name may not be empty.", name, streamId);
       log.error("The stream name may not be empty.");
       return;
     }
     IStreamSecurityService security =
         (IStreamSecurityService) ScopeUtils.getScopeService(scope, IStreamSecurityService.class);
     if (security != null) {
       Set<IStreamPublishSecurity> handlers = security.getStreamPublishSecurity();
       for (IStreamPublishSecurity handler : handlers) {
         if (!handler.isPublishAllowed(scope, name, mode)) {
           sendNSFailed(
               streamConn,
               StatusCodes.NS_PUBLISH_BADNAME,
               "You are not allowed to publish the stream.",
               name,
               streamId);
           log.error("You are not allowed to publish the stream {}", name);
           return;
         }
       }
     }
     IBroadcastScope bsScope = getBroadcastScope(scope, name);
     if (bsScope != null && !bsScope.getProviders().isEmpty()) {
       // another stream with that name is already published
       sendNSFailed(streamConn, StatusCodes.NS_PUBLISH_BADNAME, name, name, streamId);
       log.error("Bad name {}", name);
       return;
     }
     IClientStream stream = streamConn.getStreamById(streamId);
     if (stream != null && !(stream instanceof IClientBroadcastStream)) {
       log.error(
           "Stream not found or is not instance of IClientBroadcastStream, name: {}, streamId: {}",
           name,
           streamId);
       return;
     }
     boolean created = false;
     if (stream == null) {
       stream = streamConn.newBroadcastStream(streamId);
       created = true;
     }
     IClientBroadcastStream bs = (IClientBroadcastStream) stream;
     try {
       // set publish name
       bs.setPublishedName(name);
       // set stream parameters if they exist
       if (params != null) {
         bs.setParameters(params);
       }
       IContext context = conn.getScope().getContext();
       IProviderService providerService =
           (IProviderService) context.getBean(IProviderService.BEAN_NAME);
       // TODO handle registration failure
       if (providerService.registerBroadcastStream(conn.getScope(), name, bs)) {
         bsScope = getBroadcastScope(conn.getScope(), name);
         bsScope.setClientBroadcastStream(bs);
         if (conn instanceof BaseConnection) {
           ((BaseConnection) conn).registerBasicScope(bsScope);
         }
       }
       log.debug("Mode: {}", mode);
       if (IClientStream.MODE_RECORD.equals(mode)) {
         bs.start();
         bs.saveAs(name, false);
       } else if (IClientStream.MODE_APPEND.equals(mode)) {
         bs.start();
         bs.saveAs(name, true);
       } else {
         bs.start();
       }
       bs.startPublishing();
     } catch (IOException e) {
       log.warn("Stream I/O exception", e);
       sendNSFailed(
           streamConn,
           StatusCodes.NS_RECORD_NOACCESS,
           "The file could not be created/written to.",
           name,
           streamId);
       bs.close();
       if (created) {
         streamConn.deleteStreamById(streamId);
       }
     } catch (Exception e) {
       log.warn("Exception on publish", e);
     }
   }
 }
 /**
  * Dynamic streaming play method.
  *
  * <p>The following properties are supported on the play options:
  *
  * <pre>
  * streamName: String. The name of the stream to play or the new stream to switch to.
  * oldStreamName: String. The name of the initial stream that needs to be switched out. This is not needed and ignored
  * when play2 is used for just playing the stream and not switching to a new stream.
  * start: Number. The start time of the new stream to play, just as supported by the existing play API. and it has the
  * same defaults. This is ignored when the method is called for switching (in other words, the transition
  * is either NetStreamPlayTransition.SWITCH or NetStreamPlayTransitions.SWAP)
  * len: Number. The duration of the playback, just as supported by the existing play API and has the same defaults.
  * transition: String. The transition mode for the playback command. It could be one of the following:
  * NetStreamPlayTransitions.RESET
  * NetStreamPlayTransitions.APPEND
  * NetStreamPlayTransitions.SWITCH
  * NetStreamPlayTransitions.SWAP
  * </pre>
  *
  * NetStreamPlayTransitions:
  *
  * <pre>
  * APPEND : String = "append" - Adds the stream to a playlist and begins playback with the first stream.
  * APPEND_AND_WAIT : String = "appendAndWait" - Builds a playlist without starting to play it from the first stream.
  * RESET : String = "reset" - Clears any previous play calls and plays the specified stream immediately.
  * RESUME : String = "resume" - Requests data from the new connection starting from the point at which the previous connection ended.
  * STOP : String = "stop" - Stops playing the streams in a playlist.
  * SWAP : String = "swap" - Replaces a content stream with a different content stream and maintains the rest of the playlist.
  * SWITCH : String = "switch" - Switches from playing one stream to another stream, typically with streams of the same content.
  * </pre>
  *
  * @see <a
  *     href="http://www.adobe.com/devnet/flashmediaserver/articles/dynstream_actionscript.html">ActionScript
  *     guide to dynamic streaming</a>
  * @see <a
  *     href="http://www.adobe.com/devnet/flashmediaserver/articles/dynstream_advanced_pt1.html">Dynamic
  *     streaming in Flash Media Server - Part 1: Overview of the new capabilities</a>
  * @see <a
  *     href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/NetStreamPlayTransitions.html">NetStreamPlayTransitions</a>
  * @param playOptions play options
  */
 public void play2(Map<String, ?> playOptions) {
   log.debug("play2 options: {}", playOptions.toString());
   /* { streamName=streams/new.flv, oldStreamName=streams/old.flv,
   start=0, len=-1, offset=12.195, transition=switch } */
   // get the transition type
   String transition = (String) playOptions.get("transition");
   String streamName = (String) playOptions.get("streamName");
   String oldStreamName = (String) playOptions.get("oldStreamName");
   // now initiate new playback
   int start = (Integer) playOptions.get("start");
   int length = (Integer) playOptions.get("len");
   // get the clients connection
   IConnection conn = Red5.getConnectionLocal();
   if (conn != null && conn instanceof IStreamCapableConnection) {
     // get the stream id
     int streamId = conn.getStreamId();
     IStreamCapableConnection streamConn = (IStreamCapableConnection) conn;
     if ("stop".equals(transition)) {
       play(Boolean.FALSE);
     } else if ("reset".equals(transition)) {
       // just reset the currently playing stream
       play(streamName);
     } else if ("switch".equals(transition)) {
       try {
         // set the playback type
         simplePlayback.set(Boolean.FALSE);
         // send the "start" of transition
         sendNSStatus(
             conn,
             StatusCodes.NS_PLAY_TRANSITION,
             String.format("Transitioning from %s to %s.", oldStreamName, streamName),
             streamName,
             streamId);
         // support offset?
         // playOptions.get("offset")
         play(streamName, start, length);
       } finally {
         // clean up
         simplePlayback.remove();
       }
     } else if ("append".equals(transition) || "appendAndWait".equals(transition)) {
       IPlaylistSubscriberStream playlistStream =
           (IPlaylistSubscriberStream) streamConn.getStreamById(streamId);
       IPlayItem item = SimplePlayItem.build(streamName);
       playlistStream.addItem(item);
       if ("append".equals(transition)) {
         play(streamName, start, length, false);
       }
     } else if ("swap".equals(transition)) {
       IPlaylistSubscriberStream playlistStream =
           (IPlaylistSubscriberStream) streamConn.getStreamById(streamId);
       IPlayItem item = SimplePlayItem.build(streamName);
       int itemCount = playlistStream.getItemSize();
       for (int i = 0; i < itemCount; i++) {
         IPlayItem tmpItem = playlistStream.getItem(i);
         if (tmpItem.getName().equals(oldStreamName)) {
           if (!playlistStream.replace(tmpItem, item)) {
             log.warn("Playlist item replacement failed");
             sendNSFailed(
                 streamConn,
                 StatusCodes.NS_PLAY_FAILED,
                 "Playlist swap failed.",
                 streamName,
                 streamId);
           }
           break;
         }
       }
     } else {
       log.warn("Unhandled transition: {}", transition);
       sendNSFailed(
           conn, StatusCodes.NS_FAILED, "Transition type not supported", streamName, streamId);
     }
   } else {
     log.info("Connection was null ?");
   }
 }
 @Override
 public boolean appConnect(IConnection conn, Object[] params) {
   IServiceCapableConnection service = (IServiceCapableConnection) conn;
   loginfo("Red5SIP Client connected " + conn.getClient().getId() + " service " + service);
   return true;
 }
 /** {@inheritDoc} */
 public void play(String name, int start, int length, boolean flushPlaylist) {
   log.debug(
       "Play called - name: {} start: {} length: {} flush playlist: {}",
       new Object[] {name, start, length, flushPlaylist});
   IConnection conn = Red5.getConnectionLocal();
   if (conn instanceof IStreamCapableConnection) {
     IScope scope = conn.getScope();
     IStreamCapableConnection streamConn = (IStreamCapableConnection) conn;
     int streamId = conn.getStreamId();
     if (StringUtils.isEmpty(name)) {
       sendNSFailed(
           streamConn, StatusCodes.NS_FAILED, "The stream name may not be empty.", name, streamId);
       return;
     }
     IStreamSecurityService security =
         (IStreamSecurityService) ScopeUtils.getScopeService(scope, IStreamSecurityService.class);
     if (security != null) {
       Set<IStreamPlaybackSecurity> handlers = security.getStreamPlaybackSecurity();
       for (IStreamPlaybackSecurity handler : handlers) {
         if (!handler.isPlaybackAllowed(scope, name, start, length, flushPlaylist)) {
           sendNSFailed(
               streamConn,
               StatusCodes.NS_FAILED,
               "You are not allowed to play the stream.",
               name,
               streamId);
           return;
         }
       }
     }
     boolean created = false;
     IClientStream stream = streamConn.getStreamById(streamId);
     if (stream == null) {
       if (streamId <= 0) {
         streamId = streamConn.reserveStreamId();
       }
       stream = streamConn.newPlaylistSubscriberStream(streamId);
       stream.setBroadcastStreamPublishName(name);
       stream.start();
       created = true;
     }
     if (stream != null && stream instanceof ISubscriberStream) {
       ISubscriberStream subscriberStream = (ISubscriberStream) stream;
       IPlayItem item =
           simplePlayback.get()
               ? SimplePlayItem.build(name, start, length)
               : DynamicPlayItem.build(name, start, length);
       if (subscriberStream instanceof IPlaylistSubscriberStream) {
         IPlaylistSubscriberStream playlistStream = (IPlaylistSubscriberStream) subscriberStream;
         if (flushPlaylist) {
           playlistStream.removeAllItems();
         }
         playlistStream.addItem(item);
       } else if (subscriberStream instanceof ISingleItemSubscriberStream) {
         ISingleItemSubscriberStream singleStream = (ISingleItemSubscriberStream) subscriberStream;
         singleStream.setPlayItem(item);
       } else {
         // not supported by this stream service
         log.warn(
             "Stream instance type: {} is not supported", subscriberStream.getClass().getName());
         return;
       }
       try {
         subscriberStream.play();
       } catch (IOException err) {
         if (created) {
           stream.close();
           streamConn.deleteStreamById(streamId);
         }
         sendNSFailed(streamConn, StatusCodes.NS_FAILED, err.getMessage(), name, streamId);
       }
     }
   } else {
     log.debug("Connection was not stream capable");
   }
 }
  @Override
  public boolean roomConnect(IConnection connection, Object[] params) {
    String remoteHost = Red5.getConnectionLocal().getRemoteAddress();
    int remotePort = Red5.getConnectionLocal().getRemotePort();
    String clientId = Red5.getConnectionLocal().getClient().getId();
    log.info("[clientid=" + clientId + "] connected from " + remoteHost + ":" + remotePort + ".");

    String username = ((String) params[0]).toString();
    String role = ((String) params[1]).toString();
    String conference = ((String) params[2]).toString();

    /*
     * Convert the id to Long because it gets converted to ascii decimal
     * equivalent (i.e. zero (0) becomes 48) if we don't.
     */
    long userid = Long.parseLong(Red5.getConnectionLocal().getClient().getId());
    String sessionName = connection.getScope().getName();

    String voiceBridge = ((String) params[4]).toString();
    String room = sessionName;
    assert recorderApplication != null;
    boolean record = (Boolean) params[5];
    log.debug("record value - [" + record + "]");

    String externUserID = ((String) params[6]).toString();

    if (record == true) {
      recorderApplication.createRecordSession(sessionName);
    }

    BigBlueButtonSession bbbSession =
        new BigBlueButtonSession(
            sessionName,
            userid,
            username,
            role,
            conference,
            room,
            voiceBridge,
            record,
            externUserID);
    connection.setAttribute(Constants.SESSION, bbbSession);

    String debugInfo =
        "userid="
            + userid
            + ",username="******",role="
            + role
            + ",conference="
            + conference
            + ","
            + "session="
            + sessionName
            + ",voiceConf="
            + voiceBridge
            + ",room="
            + room
            + ",externsUserid="
            + externUserID;
    log.debug("User [{}] connected to room [{}]", debugInfo, room);
    participantsApplication.createRoom(room);
    super.roomConnect(connection, params);
    return true;
  }
 /** Close stream */
 public void closeStream() {
   IConnection conn = Red5.getConnectionLocal();
   closeStream(conn, conn.getStreamId());
 }