@Override public void messageReceived(Object in, IoSession session) throws Exception { RTMPConnection conn = (RTMPConnection) session.getAttribute(RTMPConnection.RTMP_CONNECTION_KEY); RTMP state = (RTMP) session.getAttribute(ProtocolState.SESSION_KEY); IRTMPEvent message = null; final Packet packet = (Packet) in; message = packet.getMessage(); final Header header = packet.getHeader(); final Channel channel = conn.getChannel(header.getChannelId()); // Increase number of received messages conn.messageReceived(); if (header.getDataType() == TYPE_BYTES_READ) { // TODO need to sync the bytes read on edge and origin onStreamBytesRead(conn, channel, header, (BytesRead) message); } if (header.getDataType() == TYPE_INVOKE) { final IServiceCall call = ((Invoke) message).getCall(); final String action = call.getServiceMethodName(); if (call.getServiceName() == null && !conn.isConnected() && StreamAction.valueOf(action).equals(StreamAction.CONNECT)) { handleConnect(conn, channel, header, (Invoke) message, (RTMP) state); return; } } switch (header.getDataType()) { case TYPE_CHUNK_SIZE: case TYPE_INVOKE: case TYPE_FLEX_MESSAGE: case TYPE_NOTIFY: case TYPE_AUDIO_DATA: case TYPE_VIDEO_DATA: case TYPE_FLEX_SHARED_OBJECT: case TYPE_FLEX_STREAM_SEND: case TYPE_SHARED_OBJECT: case TYPE_BYTES_READ: forwardPacket(conn, packet); break; case TYPE_PING: onPing(conn, channel, header, (Ping) message); break; default: if (log.isDebugEnabled()) { log.debug("Unknown type: {}", header.getDataType()); } } if (message instanceof Unknown) { log.info(message.toString()); } if (message != null) { message.release(); } }
/** * Mark message as sent. * * @param message Message to mark */ public void messageSent(Packet message) { if (message.getMessage() instanceof VideoData) { int streamId = message.getHeader().getStreamId(); AtomicInteger pending = pendingVideos.get(streamId); if (pending != null) { pending.decrementAndGet(); } } writtenMessages.incrementAndGet(); }
/** * Mark message as being written. * * @param message Message to mark */ protected void writingMessage(Packet message) { if (message.getMessage() instanceof VideoData) { int streamId = message.getHeader().getStreamId(); final AtomicInteger value = new AtomicInteger(); AtomicInteger old = pendingVideos.putIfAbsent(streamId, value); if (old == null) { old = value; } old.incrementAndGet(); } }
/** Pass through all Ping events to origin except ping/pong */ protected void onPing(RTMPConnection conn, Channel channel, Header source, Ping ping) { switch (ping.getEventType()) { case Ping.PONG_SERVER: // This is the response to an IConnection.ping request conn.pingReceived(ping); break; default: // forward other to origin Packet p = new Packet(source); p.setMessage(ping); forwardPacket(conn, p); } }
protected void handleConnect( RTMPConnection conn, Channel channel, Header header, Invoke invoke, RTMP rtmp) { final IPendingServiceCall call = invoke.getCall(); // Get parameters passed from client to NetConnection#connection final Map<String, Object> params = invoke.getConnectionParams(); // Get hostname String host = getHostname((String) params.get("tcUrl")); // App name as path, but without query string if there is one String path = (String) params.get("app"); if (path.indexOf("?") != -1) { int idx = path.indexOf("?"); params.put("queryString", path.substring(idx)); path = path.substring(0, idx); } params.put("path", path); final String sessionId = null; conn.setup(host, path, sessionId, params); // check the security constraints // send back "ConnectionRejected" if fails. if (!checkPermission(conn)) { call.setStatus(Call.STATUS_ACCESS_DENIED); call.setResult(getStatus(NC_CONNECT_REJECTED)); Invoke reply = new Invoke(); reply.setCall(call); reply.setInvokeId(invoke.getInvokeId()); channel.write(reply); conn.close(); } else { synchronized (rtmp) { // connect the origin sendConnectMessage(conn); rtmp.setState(RTMP.STATE_EDGE_CONNECT_ORIGIN_SENT); Packet packet = new Packet(header); packet.setMessage(invoke); forwardPacket(conn, packet); rtmp.setState(RTMP.STATE_ORIGIN_CONNECT_FORWARDED); // Evaluate request for AMF3 encoding if (Integer.valueOf(3).equals(params.get("objectEncoding"))) { rtmp.setEncoding(Encoding.AMF3); } } } }
/** {@inheritDoc} */ @Override public void messageReceived(IoSession session, Object in) { if (log.isDebugEnabled()) { if (in instanceof IoBuffer) { log.debug("Handskake"); return; } try { final Packet packet = (Packet) in; final Object message = packet.getMessage(); final Header source = packet.getHeader(); log.debug("{}", source); log.debug("{}", message); } catch (RuntimeException e) { log.error("Exception", e); } } }
/** {@inheritDoc} */ public void messageReceived(RTMPConnection conn, Packet packet) throws Exception { log.trace("messageReceived connection: {}", conn.getSessionId()); if (conn != null) { IRTMPEvent message = null; try { message = packet.getMessage(); final Header header = packet.getHeader(); final Number streamId = header.getStreamId(); final Channel channel = conn.getChannel(header.getChannelId()); final IClientStream stream = conn.getStreamById(streamId); if (log.isTraceEnabled()) { log.trace("Message received - header: {}", header); } // set stream id on the connection conn.setStreamId(streamId); // increase number of received messages conn.messageReceived(); // set the source of the message message.setSource(conn); // process based on data type final byte headerDataType = header.getDataType(); if (log.isTraceEnabled()) { log.trace("Header / message data type: {}", headerDataType); } switch (headerDataType) { case TYPE_AGGREGATE: log.debug( "Aggregate type data - header timer: {} size: {}", header.getTimer(), header.getSize()); case TYPE_AUDIO_DATA: case TYPE_VIDEO_DATA: // mark the event as from a live source // log.trace("Marking message as originating from a Live source"); message.setSourceType(Constants.SOURCE_TYPE_LIVE); // NOTE: If we respond to "publish" with "NetStream.Publish.BadName", // the client sends a few stream packets before stopping. We need to ignore them if (stream != null) { ((IEventDispatcher) stream).dispatchEvent(message); } break; case TYPE_FLEX_SHARED_OBJECT: case TYPE_SHARED_OBJECT: onSharedObject(conn, channel, header, (SharedObjectMessage) message); break; case TYPE_INVOKE: case TYPE_FLEX_MESSAGE: onCommand(conn, channel, header, (Invoke) message); IPendingServiceCall call = ((Invoke) message).getCall(); if (message.getHeader().getStreamId().intValue() != 0 && call.getServiceName() == null && StreamAction.PUBLISH.equals(call.getServiceMethodName())) { if (stream != null) { // Only dispatch if stream really was created ((IEventDispatcher) stream).dispatchEvent(message); } } break; case TYPE_NOTIFY: // like an invoke, but does not return // anything and has a invoke / transaction // id of 0 case TYPE_FLEX_STREAM_SEND: if (((Notify) message).getData() != null && stream != null) { // Stream metadata ((IEventDispatcher) stream).dispatchEvent(message); } else { onCommand(conn, channel, header, (Notify) message); } break; case TYPE_PING: onPing(conn, channel, header, (Ping) message); break; case TYPE_BYTES_READ: onStreamBytesRead(conn, channel, header, (BytesRead) message); break; case TYPE_CHUNK_SIZE: onChunkSize(conn, channel, header, (ChunkSize) message); break; case Constants.TYPE_CLIENT_BANDWIDTH: // onBWDone / peer bw log.debug("Client bandwidth: {}", message); onClientBandwidth(conn, channel, (ClientBW) message); break; case Constants.TYPE_SERVER_BANDWIDTH: // window ack size log.debug("Server bandwidth: {}", message); onServerBandwidth(conn, channel, (ServerBW) message); break; default: log.debug("Unknown type: {}", header.getDataType()); } if (message instanceof Unknown) { log.info("Message type unknown: {}", message); } } catch (Throwable t) { log.error("Exception", t); } // XXX this may be causing 'missing' data if previous methods are // not making copies before buffering etc.. if (message != null) { message.release(); } } }
/** * Releases a packet. * * @param packet Packet to release */ private void freePacket(Packet packet) { if (packet != null && packet.getData() != null) { packet.clearData(); } }