/**
  * 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} */
  @Override
  protected void onPing(RTMPConnection conn, Channel channel, Header source, Ping ping) {
    log.trace("onPing");
    switch (ping.getEventType()) {
      case Ping.PING_CLIENT:
      case Ping.STREAM_BEGIN:
      case Ping.RECORDED_STREAM:
      case Ping.STREAM_PLAYBUFFER_CLEAR:
        // the server wants to measure the RTT
        Ping pong = new Ping();
        pong.setEventType(Ping.PONG_SERVER);
        pong.setValue2((int) (System.currentTimeMillis() & 0xffffffff));
        conn.ping(pong);
        break;
      case Ping.STREAM_DRY:
        log.debug("Stream indicates there is no data available");
        break;
      case Ping.CLIENT_BUFFER:
        // set the client buffer
        IClientStream stream = null;
        // get the stream id
        int streamId = ping.getValue2();
        // get requested buffer size in milliseconds
        int buffer = ping.getValue3();
        log.debug("Client sent a buffer size: {} ms for stream id: {}", buffer, streamId);
        if (streamId != 0) {
          // the client wants to set the buffer time
          stream = conn.getStreamById(streamId);
          if (stream != null) {
            stream.setClientBufferDuration(buffer);
            log.info("Setting client buffer on stream: {}", buffer);
          }
        }
        // catch-all to make sure buffer size is set
        if (stream == null) {
          // remember buffer time until stream is created
          conn.rememberStreamBufferDuration(streamId, buffer);
          log.info("Remembering client buffer on stream: {}", buffer);
        }
        break;
      case Ping.PING_SWF_VERIFY:
        log.debug("SWF verification ping");
        // TODO get the swf verification bytes from the handshake
        SWFResponse swfPong = new SWFResponse(new byte[42]);
        conn.ping(swfPong);
        break;
      case Ping.BUFFER_EMPTY:
        log.debug("Buffer empty ping");

        break;
      case Ping.BUFFER_FULL:
        log.debug("Buffer full ping");

        break;
      default:
        log.warn("Unhandled ping: {}", ping);
    }
  }
 /** {@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();
       }
     }
   }
 }
 /** {@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);
 }
Beispiel #5
0
 /** {@inheritDoc} */
 public IMessageOutput getConsumerOutput(IClientStream stream) {
   IStreamCapableConnection streamConn = stream.getConnection();
   if (streamConn == null || !(streamConn instanceof RTMPConnection)) {
     return null;
   }
   RTMPConnection conn = (RTMPConnection) streamConn;
   // TODO Better manage channels.
   // now we use OutputStream as a channel wrapper.
   OutputStream o = conn.createOutputStream(stream.getStreamId());
   IPipe pipe = new InMemoryPushPushPipe();
   pipe.subscribe(
       new ConnectionConsumer(
           conn, o.getVideo().getId(), o.getAudio().getId(), o.getData().getId()),
       null);
   return pipe;
 }
 /** {@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 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);
       }
     }
   }
 }
Beispiel #9
0
 public void addClientStream(IClientStream stream) {
   int streamId = stream.getStreamId();
   getWriteLock().lock();
   try {
     if (reservedStreams.get(streamId - 1)) {
       return;
     }
     reservedStreams.set(streamId - 1);
   } finally {
     getWriteLock().unlock();
   }
   streams.put(streamId - 1, stream);
   usedStreams.incrementAndGet();
 }
Beispiel #10
0
 /** {@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");
   }
 }
Beispiel #11
0
 /**
  * Remove a stream from the connection.
  *
  * @param stream
  */
 @SuppressWarnings("unused")
 private void unregisterStream(IClientStream stream) {
   streams.remove(stream.getStreamId());
 }
Beispiel #12
0
 /**
  * Store a stream in the connection.
  *
  * @param stream
  */
 private void registerStream(IClientStream stream) {
   streams.put(stream.getStreamId() - 1, stream);
 }
 /** {@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");
   }
 }