/** * 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); } }
/** {@inheritDoc} */ public void deleteStream(IStreamCapableConnection conn, int streamId) { IClientStream stream = 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(); } conn.unreserveStreamId(streamId); }
public RTMPConnection createConnection(Class<?> connCls) { log.debug("Creating connection, class: {}", connCls.getName()); if (!RTMPConnection.class.isAssignableFrom(connCls)) { throw new IllegalArgumentException("Class was not assignable"); } try { RTMPConnection conn = (RTMPConnection) connCls.newInstance(); // the id may become confused with the Object/String client id conn.setId(BaseConnection.getNextClientId()); log.debug("Connection id set {}", conn.getId()); rtmpConnections.add(conn); log.debug("Connection added to the map"); return conn; } catch (Exception e) { log.error("RTMPConnection creation failed", e); throw new RuntimeException(e); } }
/** {@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} */ @Override public void close() { getWriteLock().lock(); try { if (keepAliveJobName != null) { schedulingService.removeScheduledJob(keepAliveJobName); keepAliveJobName = null; } } finally { getWriteLock().unlock(); } Red5.setConnectionLocal(this); IStreamService streamService = (IStreamService) getScopeService(scope, IStreamService.class, StreamService.class); if (streamService != null) { for (Map.Entry<Integer, IClientStream> entry : streams.entrySet()) { IClientStream stream = entry.getValue(); if (stream != null) { log.debug("Closing stream: {}", stream.getStreamId()); streamService.deleteStream(this, stream.getStreamId()); usedStreams.decrementAndGet(); } } streams.clear(); } channels.clear(); getWriteLock().lock(); try { if (bwContext != null && getScope() != null && getScope().getContext() != null) { IBWControlService bwController = (IBWControlService) getScope().getContext().getBean(IBWControlService.KEY); bwController.unregisterBWControllable(bwContext); bwContext = null; } } finally { getWriteLock().unlock(); } super.close(); }
/** {@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); } } } } }
/** {@inheritDoc} */ @Override public void close() { getWriteLock().lock(); try { if (keepAliveJobName != null) { schedulingService.removeScheduledJob(keepAliveJobName); keepAliveJobName = null; } } finally { getWriteLock().unlock(); } Red5.setConnectionLocal(this); IStreamService streamService = (IStreamService) getScopeService(scope, IStreamService.class, StreamService.class); if (streamService != null) { for (Map.Entry<Integer, IClientStream> entry : streams.entrySet()) { IClientStream stream = entry.getValue(); if (stream != null) { log.debug("Closing stream: {}", stream.getStreamId()); streamService.deleteStream(this, stream.getStreamId()); usedStreams.decrementAndGet(); } } } // close the base connection - disconnect scopes and unregister client super.close(); // kill all the collections etc if (channels != null) { channels.clear(); channels = null; } else { log.trace("Channels collection was null"); } if (streams != null) { streams.clear(); streams = null; } else { log.trace("Streams collection was null"); } if (pendingCalls != null) { pendingCalls.clear(); pendingCalls = null; } else { log.trace("PendingCalls collection was null"); } if (deferredResults != null) { deferredResults.clear(); deferredResults = null; } else { log.trace("DeferredResults collection was null"); } if (pendingVideos != null) { pendingVideos.clear(); pendingVideos = null; } else { log.trace("PendingVideos collection was null"); } if (streamBuffers != null) { streamBuffers.clear(); streamBuffers = null; } else { log.trace("StreamBuffers collection was null"); } }
/** {@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); } } }