public static ByteBuffer EncodeMessage(RtmpContext context, RtmpHeader header, IRtmpEvent message) { switch (header.DataType) { case Constants.TypeChunkSize: return(EncodeChunkSize(context, message as ChunkSize)); case Constants.TypeInvoke: return(EncodeInvoke(context, message as Invoke)); case Constants.TypeFlexInvoke: return(EncodeFlexInvoke(context, message as FlexInvoke)); case Constants.TypeSharedObject: return(EncodeSharedObject(context, message as ISharedObjectMessage)); case Constants.TypeFlexSharedObject: return(EncodeFlexSharedObject(context, message as ISharedObjectMessage)); case Constants.TypeNotify: if ((message as Notify).ServiceCall == null) { return(EncodeStreamMetadata(context, message as Notify)); } else { return(EncodeNotify(context, message as Notify)); } case Constants.TypePing: return(EncodePing(context, message as Ping)); case Constants.TypeBytesRead: return(EncodeBytesRead(context, message as BytesRead)); case Constants.TypeAudioData: return(EncodeAudioData(context, message as AudioData)); case Constants.TypeVideoData: return(EncodeVideoData(context, message as VideoData)); case Constants.TypeServerBandwidth: return(EncodeServerBW(context, message as ServerBW)); case Constants.TypeClientBandwidth: return(EncodeClientBW(context, message as ClientBW)); case Constants.TypeFlexStreamEnd: return(EncodeFlexStreamSend(context, message as FlexStreamSend)); default: #if !SILVERLIGHT if (_log.IsErrorEnabled) { _log.Error("Unknown object type: " + header.DataType); } #endif return(null); } }
/// <summary> /// Determine type of header to use. /// </summary> /// <param name="header">RTMP message header.</param> /// <param name="lastHeader">Previous header.</param> /// <returns>Header type to use.</returns> private static HeaderType GetHeaderType(RtmpHeader header, RtmpHeader lastHeader) { HeaderType headerType; if (lastHeader == null || header.StreamId != lastHeader.StreamId || !header.IsTimerRelative) { // New header mark if header for another stream headerType = HeaderType.HeaderNew; } else if (header.Size != lastHeader.Size || header.DataType != lastHeader.DataType) { // Same source header if last header data type or size differ headerType = HeaderType.HeaderSameSource; } else if (header.Timer != lastHeader.Timer) { // Timer change marker if there's time gap between headers timestamps headerType = HeaderType.HeaderTimerChange; } else { // Continue encoding headerType = HeaderType.HeaderContinue; } return(headerType); }
/// <summary> /// Determine type of header to use. /// </summary> /// <param name="header">RTMP message header.</param> /// <param name="lastHeader">Previous header.</param> /// <returns>Header type to use.</returns> private static HeaderType GetHeaderType(RtmpHeader header, RtmpHeader lastHeader) { HeaderType headerType; if (lastHeader == null || header.StreamId != lastHeader.StreamId || !header.IsTimerRelative) { // New header mark if header for another stream headerType = HeaderType.HeaderNew; } else if (header.Size != lastHeader.Size || header.DataType != lastHeader.DataType) { // Same source header if last header data type or size differ headerType = HeaderType.HeaderSameSource; } else if (header.Timer != lastHeader.Timer) { // Timer change marker if there's time gap between headers timestamps headerType = HeaderType.HeaderTimerChange; } else { // Continue encoding headerType = HeaderType.HeaderContinue; } return headerType; }
/// <summary> /// Encode RTMP header into given ByteBuffer /// </summary> /// <param name="header">RTMP message header</param> /// <param name="lastHeader">Previous header</param> /// <param name="buffer">Buffer to write encoded header to</param> /// <returns>Encoded header data</returns> public static ByteBuffer EncodeHeader(RtmpHeader header, RtmpHeader lastHeader, ByteBuffer buffer) { HeaderType headerType = GetHeaderType(header, lastHeader); EncodeHeaderByte(buffer, (byte)headerType, header.ChannelId); switch (headerType) { case HeaderType.HeaderNew: if (header.Timer < 0xffffff) { buffer.WriteMediumInt(header.Timer); } else { buffer.WriteMediumInt(0xffffff); } buffer.WriteMediumInt(header.Size); buffer.Put((byte)header.DataType); buffer.WriteReverseInt(header.StreamId); break; case HeaderType.HeaderSameSource: if (header.Timer < 0xffffff) { buffer.WriteMediumInt(header.Timer); } else { buffer.WriteMediumInt(0xffffff); } buffer.WriteMediumInt(header.Size); buffer.Put((byte)header.DataType); break; case HeaderType.HeaderTimerChange: if (header.Timer < 0xffffff) { buffer.WriteMediumInt(header.Timer); } else { buffer.WriteMediumInt(0xffffff); } break; case HeaderType.HeaderContinue: break; } if (header.Timer >= 0xffffff) { buffer.PutInt(header.Timer); } return(buffer); }
internal void SetLastWriteHeader(int channelId, RtmpHeader header) { try { ReaderWriterLock.AcquireWriterLock(); _lastWriteChannel = channelId; _writeHeaders[channelId] = header; } finally { ReaderWriterLock.ReleaseWriterLock(); } }
/// <summary> /// Writes packet from event data to the RTMP connection using the specified stream id. /// </summary> /// <param name="message">Event data.</param> /// <param name="streamId">Stream id.</param> private void Write(IRtmpEvent message, int streamId) { RtmpHeader header = new RtmpHeader(); RtmpPacket packet = new RtmpPacket(header, message); header.ChannelId = _channelId; header.Timer = message.Timestamp; header.StreamId = streamId; header.DataType = message.DataType; if (message.Header != null) { header.IsTimerRelative = message.Header.IsTimerRelative; } _connection.Write(packet); }
/// <summary> /// Calculate number of bytes necessary to encode the header. /// </summary> /// <param name="header">RTMP message header</param> /// <param name="lastHeader">Previous header</param> /// <returns>Calculated size</returns> private static int CalculateHeaderSize(RtmpHeader header, RtmpHeader lastHeader) { HeaderType headerType = GetHeaderType(header, lastHeader); int channelIdAdd; if (header.ChannelId > 320) { channelIdAdd = 2; } else if (header.ChannelId > 63) { channelIdAdd = 1; } else { channelIdAdd = 0; } return(RtmpHeader.GetHeaderLength(headerType) + channelIdAdd); }
/// <summary> /// This method supports the Fluorine infrastructure and is not intended to be used directly from your code. /// </summary> /// <param name="connection"></param> /// <param name="channel"></param> /// <param name="source"></param> /// <param name="ping"></param> protected abstract void OnPing(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, Ping ping);
public static ByteBuffer EncodePacket(RtmpContext context, RtmpPacket packet) { RtmpHeader header = packet.Header; int channelId = header.ChannelId; IRtmpEvent message = packet.Message; ByteBuffer data; if (message is ChunkSize) { ChunkSize chunkSizeMsg = (ChunkSize)message; context.SetWriteChunkSize(chunkSizeMsg.Size); } data = EncodeMessage(context, header, message); if (data.Position != 0) { data.Flip(); } else { data.Rewind(); } header.Size = (int)data.Limit; RtmpHeader lastHeader = context.GetLastWriteHeader(channelId); int headerSize = CalculateHeaderSize(header, lastHeader); context.SetLastWriteHeader(channelId, header); context.SetLastWritePacket(channelId, packet); int chunkSize = context.GetWriteChunkSize(); int chunkHeaderSize = 1; if (header.ChannelId > 320) { chunkHeaderSize = 3; } else if (header.ChannelId > 63) { chunkHeaderSize = 2; } int numChunks = (int)Math.Ceiling(header.Size / (float)chunkSize); int bufSize = (int)header.Size + headerSize + (numChunks > 0 ? (numChunks - 1) * chunkHeaderSize : 0); ByteBuffer output = ByteBuffer.Allocate(bufSize); EncodeHeader(header, lastHeader, output); if (numChunks == 1) { // we can do it with a single copy ByteBuffer.Put(output, data, output.Remaining); } else { for (int i = 0; i < numChunks - 1; i++) { ByteBuffer.Put(output, data, chunkSize); EncodeHeaderByte(output, (byte)HeaderType.HeaderContinue, header.ChannelId); } ByteBuffer.Put(output, data, output.Remaining); } //data.Close(); output.Flip(); return(output); }
protected override void OnSharedObject(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, SharedObjectMessage message) { ISharedObject so = null; string name = message.Name; IScope scope = connection.Scope; bool persistent = message.IsPersistent; if(scope == null) { // The scope already has been deleted. SendSOCreationFailed(connection, name, persistent); return; } ISharedObjectService sharedObjectService = ScopeUtils.GetScopeService(scope, typeof(ISharedObjectService)) as ISharedObjectService; if (!sharedObjectService.HasSharedObject(scope, name)) { ISharedObjectSecurityService securityService = ScopeUtils.GetScopeService(scope, typeof(ISharedObjectSecurityService)) as ISharedObjectSecurityService; if (securityService != null) { // Check handlers to see if creation is allowed IEnumerator enumerator = securityService.GetSharedObjectSecurity(); while(enumerator.MoveNext()) { ISharedObjectSecurity handler = enumerator.Current as ISharedObjectSecurity; if (!handler.IsCreationAllowed(scope, name, persistent)) { SendSOCreationFailed(connection, name, persistent); return; } } } if (!sharedObjectService.CreateSharedObject(scope, name, persistent)) { SendSOCreationFailed(connection, name, persistent); return; } } so = sharedObjectService.GetSharedObject(scope, name); if (so.IsPersistentObject != persistent) { log.Debug(string.Format("Shared object '{0}' persistence mismatch", name)); SendSOPersistenceMismatch(connection, name, persistent); return; } so.DispatchEvent(message); }
protected override void OnClientBW(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, ClientBW clientBW) { }
public static ByteBuffer EncodeMessage(RtmpContext context, RtmpHeader header, IRtmpEvent message) { switch(header.DataType) { case Constants.TypeChunkSize: return EncodeChunkSize(context, message as ChunkSize); case Constants.TypeInvoke: return EncodeInvoke(context, message as Invoke); case Constants.TypeFlexInvoke: return EncodeFlexInvoke(context, message as FlexInvoke); case Constants.TypeSharedObject: return EncodeSharedObject(context, message as ISharedObjectMessage); case Constants.TypeFlexSharedObject: return EncodeFlexSharedObject(context, message as ISharedObjectMessage); case Constants.TypeNotify: if ((message as Notify).ServiceCall == null) { return EncodeStreamMetadata(context, message as Notify); } else { return EncodeNotify(context, message as Notify); } case Constants.TypePing: return EncodePing(context, message as Ping); case Constants.TypeBytesRead: return EncodeBytesRead(context, message as BytesRead); case Constants.TypeAudioData: return EncodeAudioData(context, message as AudioData); case Constants.TypeVideoData: return EncodeVideoData(context, message as VideoData); case Constants.TypeServerBandwidth: return EncodeServerBW(context, message as ServerBW); case Constants.TypeClientBandwidth: return EncodeClientBW(context, message as ClientBW); case Constants.TypeFlexStreamEnd: return EncodeFlexStreamSend(context, message as FlexStreamSend); default: #if !SILVERLIGHT if( _log.IsErrorEnabled ) _log.Error("Unknown object type: " + header.DataType); #endif return null; } }
/// <summary> /// Decodes RTMP message event. /// </summary> /// <param name="context">RTMP protocol state.</param> /// <param name="header">RTMP header.</param> /// <param name="stream">Buffer to be decoded.</param> /// <returns>Decoded RTMP event.</returns> public static IRtmpEvent DecodeMessage(RtmpContext context, RtmpHeader header, ByteBuffer stream) { IRtmpEvent message = null; /* if(header.Timer == 0xffffff) { // Skip first four bytes byte[] extendedTimestamp = new byte[4]; stream.Read(extendedTimestamp, 0, 4); log.Warn("Discarding extended timestamp"); //int unknown = stream.ReadInt32(); } */ switch(header.DataType) { case Constants.TypeChunkSize: message = DecodeChunkSize(stream); break; case Constants.TypeInvoke: message = DecodeInvoke(stream); break; case Constants.TypeFlexInvoke: message = DecodeFlexInvoke(stream); break; case Constants.TypeNotify: if( header.StreamId == 0 ) message = DecodeNotify(stream, header); else message = DecodeStreamMetadata(stream); break; case Constants.TypePing: message = DecodePing(stream); break; case Constants.TypeBytesRead: message = DecodeBytesRead(stream); break; case Constants.TypeAudioData: message = DecodeAudioData(stream); break; case Constants.TypeVideoData: message = DecodeVideoData(stream); break; case Constants.TypeSharedObject: message = DecodeSharedObject(stream); break; case Constants.TypeFlexSharedObject: message = DecodeFlexSharedObject(stream); break; case Constants.TypeServerBandwidth: message = DecodeServerBW(stream); break; case Constants.TypeClientBandwidth: message = DecodeClientBW(stream); break; default: #if !SILVERLIGHT log.Warn("Unknown object type: " + header.DataType); #endif message = DecodeUnknown(stream); break; } message.Header = header; message.Timestamp = header.Timer; return message; }
/// <summary> /// This method supports the Fluorine infrastructure and is not intended to be used directly from your code. /// </summary> /// <param name="connection"></param> /// <param name="channel"></param> /// <param name="header"></param> /// <param name="invoke"></param> protected abstract void OnInvoke(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, Notify invoke);
/// <summary> /// This method supports the Fluorine infrastructure and is not intended to be used directly from your code. /// </summary> /// <param name="connection"></param> /// <param name="channel"></param> /// <param name="source"></param> /// <param name="chunkSize"></param> protected abstract void OnChunkSize(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, ChunkSize chunkSize);
/// <summary> /// This method supports the Fluorine infrastructure and is not intended to be used directly from your code. /// </summary> /// <param name="connection"></param> /// <param name="channel"></param> /// <param name="source"></param> /// <param name="streamBytesRead"></param> protected void OnStreamBytesRead(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, BytesRead streamBytesRead) { connection.ReceivedBytesRead(streamBytesRead.Bytes); }
/// <summary> /// Message recieved. /// </summary> /// <param name="connection">Connection object.</param> /// <param name="obj">Message object.</param> public void MessageReceived(RtmpConnection connection, object obj) { IRtmpEvent message = null; RtmpPacket packet = null; RtmpHeader header = null; RtmpChannel channel = null; IClientStream stream = null; try { packet = obj as RtmpPacket; message = packet.Message; header = packet.Header; channel = connection.GetChannel(header.ChannelId); if (connection is IStreamCapableConnection) { stream = (connection as IStreamCapableConnection).GetStreamById(header.StreamId); } // Support stream ids #if !SILVERLIGHT FluorineContext.ValidateContext(); FluorineContext.Current.Connection.SetAttribute(FluorineContext.FluorineStreamIdKey, header.StreamId); #endif // Increase number of received messages connection.MessageReceived(); #if !SILVERLIGHT if (log != null && log.IsDebugEnabled) { log.Debug("RtmpConnection message received, type = " + header.DataType); } #endif if (message != null) { message.Source = connection; } switch (header.DataType) { case Constants.TypeInvoke: OnInvoke(connection, channel, header, message as Invoke); if (message.Header.StreamId != 0 && (message as Invoke).ServiceCall.ServiceName == null && (message as Invoke).ServiceCall.ServiceMethodName == BaseRtmpHandler.ACTION_PUBLISH) { if (stream != null) //Dispatch if stream was created { (stream as IEventDispatcher).DispatchEvent(message); } } break; case Constants.TypeFlexInvoke: OnFlexInvoke(connection, channel, header, message as FlexInvoke); if (message.Header.StreamId != 0 && (message as Invoke).ServiceCall.ServiceName == null && (message as Invoke).ServiceCall.ServiceMethodName == BaseRtmpHandler.ACTION_PUBLISH) { if (stream != null) //Dispatch if stream was created { (stream as IEventDispatcher).DispatchEvent(message); } } break; case Constants.TypeNotify: // just like invoke, but does not return if ((message as Notify).Data != null && stream != null) { // Stream metadata (stream as IEventDispatcher).DispatchEvent(message); } else { OnInvoke(connection, channel, header, message as Notify); } break; case Constants.TypePing: OnPing(connection, channel, header, message as Ping); break; case Constants.TypeBytesRead: OnStreamBytesRead(connection, channel, header, message as BytesRead); break; case Constants.TypeSharedObject: case Constants.TypeFlexSharedObject: OnSharedObject(connection, channel, header, message as SharedObjectMessage); break; case Constants.TypeFlexStreamEnd: if (stream != null) { (stream as IEventDispatcher).DispatchEvent(message); } break; case Constants.TypeChunkSize: OnChunkSize(connection, channel, header, message as ChunkSize); break; case Constants.TypeAudioData: case Constants.TypeVideoData: // 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 Constants.TypeServerBandwidth: OnServerBW(connection, channel, header, message as ServerBW); break; case Constants.TypeClientBandwidth: OnClientBW(connection, channel, header, message as ClientBW); break; default: #if !SILVERLIGHT if (log != null && log.IsDebugEnabled) { log.Debug("RtmpService event not handled: " + header.DataType); } #endif break; } } catch (Exception ex) { #if !SILVERLIGHT if (log.IsErrorEnabled) { log.Error(__Res.GetString(__Res.Rtmp_HandlerError), ex); log.Error(__Res.GetString(__Res.Error_ContextDump)); //log.Error(Environment.NewLine); log.Error(packet); } #endif } }
/// <summary> /// This method supports the Fluorine infrastructure and is not intended to be used directly from your code. /// </summary> /// <param name="connection"></param> /// <param name="channel"></param> /// <param name="source"></param> /// <param name="clientBW"></param> protected abstract void OnClientBW(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, ClientBW clientBW);
/// <summary> /// This method supports the Fluorine infrastructure and is not intended to be used directly from your code. /// </summary> /// <param name="connection"></param> /// <param name="channel"></param> /// <param name="source"></param> /// <param name="serverBW"></param> protected abstract void OnServerBW(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, ServerBW serverBW);
/// <summary> /// This method supports the Fluorine infrastructure and is not intended to be used directly from your code. /// </summary> /// <param name="connection"></param> /// <param name="channel"></param> /// <param name="header"></param> /// <param name="message"></param> protected abstract void OnSharedObject(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, SharedObjectMessage message);
internal RtmpPacket(RtmpHeader header, IRtmpEvent message) { _header = header; _message = message; }
/// <summary> /// This method supports the Fluorine infrastructure and is not intended to be used directly from your code. /// </summary> /// <param name="connection"></param> /// <param name="channel"></param> /// <param name="header"></param> /// <param name="invoke"></param> protected abstract void OnFlexInvoke(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, FlexInvoke invoke);
static Notify DecodeNotifyOrInvoke(Notify notify, ByteBuffer stream, RtmpHeader header) { long start = stream.Position; RtmpReader reader = new RtmpReader(stream); string action = reader.ReadData() as string; if(!(notify is Invoke)) { //Don't decode "NetStream.send" requests stream.Position = start; notify.Data = ByteBuffer.Allocate(stream.Remaining); notify.Data.Put(stream); //notify.setData(in.asReadOnlyBuffer()); return notify; } if(header == null || header.StreamId == 0) { double invokeId = (double)reader.ReadData(); notify.InvokeId = (int)invokeId; } object[] parameters = Call.EmptyArguments; if(stream.HasRemaining) { #if !(NET_1_1) List<object> paramList = new List<object>(); #else ArrayList paramList = new ArrayList(); #endif object obj = reader.ReadData(); if (obj is IDictionary) { // for connect we get a map notify.ConnectionParameters = obj as IDictionary; } else if (obj != null) { paramList.Add(obj); } while(stream.HasRemaining) { paramList.Add(reader.ReadData()); } parameters = paramList.ToArray(); } int dotIndex = action.LastIndexOf("."); string serviceName = (dotIndex == -1) ? null : action.Substring(0, dotIndex); string serviceMethod = (dotIndex == -1) ? action : action.Substring(dotIndex + 1, action.Length - dotIndex - 1); if (notify is Invoke) { PendingCall call = new PendingCall(serviceName, serviceMethod, parameters); notify.ServiceCall = call; } else { Call call = new Call(serviceName, serviceMethod, parameters); notify.ServiceCall = call; } return notify; }
internal RtmpPacket(RtmpHeader header) { _header = header; _data = ByteBuffer.Allocate(header.Size + (header.Timer == 0xffffff ? 4 : 0)); }
protected override void OnInvoke(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, Notify invoke) { IServiceCall serviceCall = invoke.ServiceCall; // If it's a callback for server remote call then pass it over to callbacks handler // and return if(serviceCall.ServiceMethodName.Equals("_result") || serviceCall.ServiceMethodName.Equals("_error")) { HandlePendingCallResult(connection, invoke); return; } bool disconnectOnReturn = false; string action = null; if (serviceCall.ServiceName == null) { action = serviceCall.ServiceMethodName; switch (action) { case ACTION_CONNECT: { if (!connection.IsConnected) { IDictionary parameters = invoke.ConnectionParameters; string host = null; if( parameters.Contains("tcUrl") ) host = GetHostname(parameters["tcUrl"] as string); if (host != null && host.IndexOf(":") != -1) { // Remove default port from connection string host = host.Substring(0, host.IndexOf(":")); } string app = parameters["app"] as string; string path = parameters["app"] as string; // App name as path, but without query string if there is one if (path != null && path.IndexOf("?") != -1) { int idx = path.IndexOf("?"); parameters["queryString"] = path.Substring(idx); path = path.Substring(0, idx); } parameters["path"] = path; connection.Setup(host, path, parameters); try { //IGlobalScope global = this.Endpoint.LookupGlobal(host, path); IGlobalScope global = this.Endpoint.GetMessageBroker().GlobalScope; if (global == null) { serviceCall.Status = Call.STATUS_SERVICE_NOT_FOUND; if (serviceCall is IPendingServiceCall) { StatusASO status = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_INVALID_APPLICATION, connection.ObjectEncoding); status.description = "No global scope on this server."; (serviceCall as IPendingServiceCall).Result = status; } log.Info(string.Format("No application scope found for {0} on host {1}. Misspelled or missing application folder?", path, host)); disconnectOnReturn = true; } else { IScopeContext context = global.Context; IScope scope = null; try { scope = context.ResolveScope(global, path); } catch (ScopeNotFoundException /*exception*/) { if (log.IsErrorEnabled) log.Error(__Res.GetString(__Res.Scope_NotFound, path)); serviceCall.Status = Call.STATUS_SERVICE_NOT_FOUND; if (serviceCall is IPendingServiceCall) { StatusASO status = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_REJECTED, connection.ObjectEncoding); status.description = "No scope \"" + path + "\" on this server."; (serviceCall as IPendingServiceCall).Result = status; } disconnectOnReturn = true; } catch (ScopeShuttingDownException) { serviceCall.Status = Call.STATUS_APP_SHUTTING_DOWN; if (serviceCall is IPendingServiceCall) { StatusASO status = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_APPSHUTDOWN, connection.ObjectEncoding); status.description = "Application at \"" + path + "\" is currently shutting down."; (serviceCall as IPendingServiceCall).Result = status; } log.Info(string.Format("Application at {0} currently shutting down on {1}", path, host)); disconnectOnReturn = true; } if (scope != null) { if (log.IsInfoEnabled) log.Info(__Res.GetString(__Res.Scope_Connect, scope.Name)); bool okayToConnect; try { //The only way to differentiate NetConnection.connect() and Consumer.subscribe() seems to be the app name if (app == string.Empty) { connection.SetIsFlexClient(true); okayToConnect = connection.Connect(scope, serviceCall.Arguments); if (okayToConnect) { if (serviceCall.Arguments != null && serviceCall.Arguments.Length >= 3) { string credentials = serviceCall.Arguments[2] as string; if (credentials != null && credentials != string.Empty) { MessageBroker messageBroker = this.Endpoint.GetMessageBroker(); AuthenticationService authenticationService = messageBroker.GetService(AuthenticationService.ServiceId) as AuthenticationService; authenticationService.Authenticate(credentials); } } //FDS 2.0.1 fds.swc if (serviceCall.Arguments != null && serviceCall.Arguments.Length == 1) { string credentials = serviceCall.Arguments[0] as string; if (credentials != null && credentials != string.Empty) { MessageBroker messageBroker = this.Endpoint.GetMessageBroker(); AuthenticationService authenticationService = messageBroker.GetService(AuthenticationService.ServiceId) as AuthenticationService; authenticationService.Authenticate(credentials); } } } } else { connection.SetIsFlexClient(false); okayToConnect = connection.Connect(scope, serviceCall.Arguments); } if (okayToConnect) { if (log.IsDebugEnabled) log.Debug("Connected RtmpClient: " + connection.Client.Id); serviceCall.Status = Call.STATUS_SUCCESS_RESULT; if (serviceCall is IPendingServiceCall) { StatusASO statusASO = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_SUCCESS, connection.ObjectEncoding); statusASO.Add("id", connection.Client.Id); (serviceCall as IPendingServiceCall).Result = statusASO; } // Measure initial roundtrip time after connecting connection.GetChannel((byte)2).Write(new Ping(Ping.StreamBegin, 0, -1)); connection.StartRoundTripMeasurement(); } else { if (log.IsDebugEnabled) log.Debug("Connect failed"); serviceCall.Status = Call.STATUS_ACCESS_DENIED; if (serviceCall is IPendingServiceCall) (serviceCall as IPendingServiceCall).Result = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_REJECTED, connection.ObjectEncoding); disconnectOnReturn = true; } } catch (ClientRejectedException rejected) { if (log.IsDebugEnabled) log.Debug("Connect rejected"); serviceCall.Status = Call.STATUS_ACCESS_DENIED; if (serviceCall is IPendingServiceCall) { StatusASO statusASO = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_REJECTED, connection.ObjectEncoding); statusASO.Application = rejected.Reason; (serviceCall as IPendingServiceCall).Result = statusASO; } disconnectOnReturn = true; } } } } catch (Exception ex) { if (log.IsErrorEnabled) log.Error("Error connecting", ex); serviceCall.Status = Call.STATUS_GENERAL_EXCEPTION; if (serviceCall is IPendingServiceCall) (serviceCall as IPendingServiceCall).Result = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_FAILED, connection.ObjectEncoding); disconnectOnReturn = true; } } else { // Service calls, must be connected. InvokeCall(connection, serviceCall); } } break; case ACTION_DISCONNECT: connection.Close(); break; case ACTION_CREATE_STREAM: case ACTION_DELETE_STREAM: case ACTION_RELEASE_STREAM: case ACTION_PUBLISH: case ACTION_PLAY: case ACTION_SEEK: case ACTION_PAUSE: case ACTION_CLOSE_STREAM: case ACTION_RECEIVE_VIDEO: case ACTION_RECEIVE_AUDIO: { IStreamService streamService = ScopeUtils.GetScopeService(connection.Scope, typeof(IStreamService)) as IStreamService; StatusASO status = null; try { if (!InvokeCall(connection, serviceCall, streamService)) { status = StatusASO.GetStatusObject(StatusASO.NS_INVALID_ARGUMENT, connection.ObjectEncoding); status.description = "Failed to " + action + " (stream ID: " + header.StreamId + ")"; } } catch (Exception ex) { log.Error("Error while invoking " + action + " on stream service.", ex); status = StatusASO.GetStatusObject(StatusASO.NS_FAILED, connection.ObjectEncoding); status.description = "Error while invoking " + action + " (stream ID: " + header.StreamId + ")"; status.details = ex.Message; } if (status != null) channel.SendStatus(status); } break; default: if (connection.IsConnected) InvokeCall(connection, serviceCall); else { // Warn user attemps to call service without being connected if (log.IsWarnEnabled) log.Warn("Not connected, closing connection"); connection.Close(); } break; } } /* if(invoke is FlexInvoke) { FlexInvoke reply = new FlexInvoke(); reply.InvokeId = invoke.InvokeId; reply.SetResponseSuccess(); //TODO if( serviceCall is IPendingServiceCall ) { IPendingServiceCall pendingCall = (IPendingServiceCall)serviceCall; reply.Response = pendingCall.Result; } channel.Write(reply); } else if(invoke is Invoke) */ if (invoke is Invoke) { if((header.StreamId != 0) && (serviceCall.Status == Call.STATUS_SUCCESS_VOID || serviceCall.Status == Call.STATUS_SUCCESS_NULL)) { if (log.IsDebugEnabled) log.Debug("Method does not have return value, do not reply"); return; } // The client expects a result for the method call. Invoke reply = new Invoke(); reply.ServiceCall = serviceCall; reply.InvokeId = invoke.InvokeId; //sending reply channel.Write(reply); } if (disconnectOnReturn) { connection.Close(); } if (action == ACTION_CONNECT) { connection.Context.ObjectEncoding = connection.ObjectEncoding; } }
protected override void OnFlexInvoke(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, FlexInvoke invoke) { IMessage message = null; if (invoke.ServiceCall.Arguments != null && invoke.ServiceCall.Arguments.Length > 0) message = invoke.ServiceCall.Arguments[0] as IMessage; if( message != null ) { MessageBroker messageBroker = this.Endpoint.GetMessageBroker(); if( message.clientId == null ) { message.clientId = Guid.NewGuid().ToString("D"); /* if( !(message is CommandMessage) ) { //producer may send messages without subscribing CommandMessage commandMessageSubscribe = new CommandMessage(CommandMessage.SubscribeOperation); commandMessageSubscribe.messageId = Guid.NewGuid().ToString("D"); commandMessageSubscribe.headers = message.headers.Clone() as Hashtable; commandMessageSubscribe.messageRefType = message.GetType().FullName;//"flex.messaging.messages.AsyncMessage" commandMessageSubscribe.destination = message.destination; IMessage subscribeResponse = messageBroker.RouteMessage(commandMessageSubscribe, _endpoint, connection); message.clientId = subscribeResponse.clientId; } } */ } IMessage response = messageBroker.RouteMessage(message, this.Endpoint); invoke.ServiceCall.Status = response is ErrorMessage ? Call.STATUS_INVOCATION_EXCEPTION : Call.STATUS_SUCCESS_RESULT; if (invoke.ServiceCall is IPendingServiceCall) (invoke.ServiceCall as IPendingServiceCall).Result = response; FlexInvoke reply = new FlexInvoke(); reply.InvokeId = invoke.InvokeId; reply.ServiceCall = invoke.ServiceCall; /* if( response is ErrorMessage ) reply.SetResponseFailure(); else reply.SetResponseSuccess(); reply.Response = response; */ channel.Write(reply); } else { // If it's a callback for server remote call then pass it over to callbacks handler and return OnInvoke(connection, channel, header, invoke); } }
/// <summary> /// Writes packet from event data to the RTMP connection using the specified stream id. /// </summary> /// <param name="message">Event data.</param> /// <param name="streamId">Stream id.</param> private void Write(IRtmpEvent message, int streamId) { RtmpHeader header = new RtmpHeader(); RtmpPacket packet = new RtmpPacket(header, message); header.ChannelId = _channelId; header.Timer = message.Timestamp; header.StreamId = streamId; header.DataType = message.DataType; if( message.Header != null ) header.IsTimerRelative = message.Header.IsTimerRelative; _connection.Write(packet); }
/// <summary> /// Decodes a RTMP packet. /// </summary> /// <param name="context">RTMP protocol state.</param> /// <param name="stream">Buffer to be decoded.</param> /// <returns>The decoded RTMP packet.</returns> public static RtmpPacket DecodePacket(RtmpContext context, ByteBuffer stream) { int remaining = stream.Remaining; // We need at least one byte if (remaining < 1) { #if !SILVERLIGHT if (log.IsDebugEnabled) { log.Debug(__Res.GetString(__Res.Rtmp_DataBuffering, remaining, 1)); } #endif context.SetBufferDecoding(1); return(null); } int position = (int)stream.Position; byte headerByte = stream.Get(); int headerValue; int byteCount; if ((headerByte & 0x3f) == 0) { // Two byte header if (remaining < 2) { stream.Position = position; #if !SILVERLIGHT if (log.IsDebugEnabled) { log.Debug(__Res.GetString(__Res.Rtmp_DataBuffering, remaining, 2)); } #endif context.SetBufferDecoding(2); return(null); } headerValue = ((int)headerByte & 0xff) << 8 | ((int)stream.Get() & 0xff); byteCount = 2; } else if ((headerByte & 0x3f) == 1) { // Three byte header if (remaining < 3) { stream.Position = position; #if !SILVERLIGHT if (log.IsDebugEnabled) { log.Debug(__Res.GetString(__Res.Rtmp_DataBuffering, remaining, 3)); } #endif context.SetBufferDecoding(3); return(null); } headerValue = ((int)headerByte & 0xff) << 16 | ((int)stream.Get() & 0xff) << 8 | ((int)stream.Get() & 0xff); byteCount = 3; } else { // Single byte header headerValue = (int)headerByte & 0xff; byteCount = 1; } byte channelId = DecodeChannelId(headerValue, byteCount); if (channelId < 0) { throw new ProtocolException("Bad channel id: " + channelId); } byte headerSize = DecodeHeaderSize(headerValue, byteCount); int headerLength = GetHeaderLength(headerSize); headerLength += byteCount - 1; //if(headerLength > remaining) if (headerLength + byteCount - 1 > remaining) { #if !SILVERLIGHT if (log.IsDebugEnabled) { log.Debug(__Res.GetString(__Res.Rtmp_HeaderBuffering, remaining)); } #endif stream.Position = position; //context.SetBufferDecoding(headerLength); context.SetBufferDecoding(headerLength + byteCount - 1); return(null); } // Move the position back to the start stream.Position = position; RtmpHeader header = DecodeHeader(context, context.GetLastReadHeader(channelId), stream); #if !SILVERLIGHT log.Debug("Decoded " + header); #endif if (header == null) { throw new ProtocolException("Header is null, check for error"); } // Save the header context.SetLastReadHeader(channelId, header); // Check to see if this is a new packet or continue decoding an existing one. RtmpPacket packet = context.GetLastReadPacket(channelId); if (packet == null) { packet = new RtmpPacket(header); context.SetLastReadPacket(channelId, packet); } ByteBuffer buf = packet.Data; int addSize = (header.Timer == 0xffffff ? 4 : 0); //int addSize = 0; int readRemaining = header.Size + addSize - (int)buf.Position; int chunkSize = context.GetReadChunkSize(); int readAmount = (readRemaining > chunkSize) ? chunkSize : readRemaining; if (stream.Remaining < readAmount) { #if !SILVERLIGHT if (log.IsDebugEnabled) { log.Debug(__Res.GetString(__Res.Rtmp_ChunkSmall, stream.Remaining, readAmount)); } #endif //Skip the position back to the start stream.Position = position; context.SetBufferDecoding(headerLength + readAmount); //string path = FluorineFx.Context.FluorineContext.Current.GetFullPath(@"log\chunk.bin"); //stream.Dump(path); return(null); } //http://osflash.org/pipermail/free_osflash.org/2005-September/000261.html //http://www.acmewebworks.com/Downloads/openCS/091305-initialMeeting.txt ByteBuffer.Put(buf, stream, readAmount); if (buf.Position < header.Size + addSize) { context.ContinueDecoding(); return(null); } if (buf.Position > header.Size + addSize) { #if !SILVERLIGHT log.Warn(string.Format("Packet size expanded from {0} to {1} ({2})", header.Size + addSize, buf.Position, header)); #endif } buf.Flip(); try { IRtmpEvent message = DecodeMessage(context, packet.Header, buf); packet.Message = message; if (message is ChunkSize) { ChunkSize chunkSizeMsg = message as ChunkSize; context.SetReadChunkSize(chunkSizeMsg.Size); } } finally { context.SetLastReadPacket(channelId, null); } #if !SILVERLIGHT if (log.IsDebugEnabled) { log.Debug("Decoded " + packet.ToString()); } #endif return(packet); }
/// <summary> /// Decodes RTMP packet header. /// </summary> /// <param name="context">RTMP protocol state.</param> /// <param name="lastHeader">Previous header.</param> /// <param name="stream">Buffer to be decoded.</param> /// <returns>Decoded RTMP header.</returns> public static RtmpHeader DecodeHeader(RtmpContext context, RtmpHeader lastHeader, ByteBuffer stream) { byte headerByte = stream.Get(); int headerValue; int byteCount = 1; if ((headerByte & 0x3f) == 0) { // Two byte header headerValue = ((int)headerByte & 0xff) << 8 | ((int)stream.Get() & 0xff); byteCount = 2; } else if ((headerByte & 0x3f) == 1) { // Three byte header headerValue = ((int)headerByte & 0xff) << 16 | ((int)stream.Get() & 0xff) << 8 | ((int)stream.Get() & 0xff); byteCount = 3; } else { // Single byte header headerValue = (int)headerByte & 0xff; byteCount = 1; } byte channelId = DecodeChannelId(headerValue, byteCount); byte headerSize = DecodeHeaderSize(headerValue, byteCount); RtmpHeader header = new RtmpHeader(); header.ChannelId = channelId; header.IsTimerRelative = (HeaderType)headerSize != HeaderType.HeaderNew; if ((HeaderType)headerSize != HeaderType.HeaderNew && lastHeader == null) { #if !SILVERLIGHT if (log.IsErrorEnabled) { log.Error(string.Format("Last header null not new, headerSize: {0}, channelId {1}", headerSize, channelId)); } #endif lastHeader = new RtmpHeader(); lastHeader.ChannelId = channelId; lastHeader.IsTimerRelative = (HeaderType)headerSize != HeaderType.HeaderNew; } #if !SILVERLIGHT if (log.IsDebugEnabled) { log.Debug(__Res.GetString(__Res.Rtmp_DecodeHeader, Enum.GetName(typeof(HeaderType), (HeaderType)headerSize))); } #endif switch ((HeaderType)headerSize) { case HeaderType.HeaderNew: header.Timer = stream.ReadUInt24(); // ReadUnsignedMediumInt(); header.Size = stream.ReadUInt24(); // ReadMediumInt(); header.DataType = stream.Get(); header.StreamId = stream.ReadReverseInt(); break; case HeaderType.HeaderSameSource: header.Timer = stream.ReadUInt24(); // ReadUnsignedMediumInt(); header.Size = stream.ReadUInt24(); // ReadMediumInt(); header.DataType = stream.Get(); header.StreamId = lastHeader.StreamId; break; case HeaderType.HeaderTimerChange: header.Timer = stream.ReadUInt24(); //ReadUnsignedMediumInt(); header.Size = lastHeader.Size; header.DataType = lastHeader.DataType; header.StreamId = lastHeader.StreamId; break; case HeaderType.HeaderContinue: header.Timer = lastHeader.Timer; header.Size = lastHeader.Size; header.DataType = lastHeader.DataType; header.StreamId = lastHeader.StreamId; header.IsTimerRelative = lastHeader.IsTimerRelative; break; default: #if !SILVERLIGHT log.Error("Unexpected header size: " + headerSize); #endif return(null); } if (header.Timer >= 0xffffff) { //Extended timestamp header.Timer = stream.GetInt(); } return(header); }
/// <summary> /// Calculate number of bytes necessary to encode the header. /// </summary> /// <param name="header">RTMP message header</param> /// <param name="lastHeader">Previous header</param> /// <returns>Calculated size</returns> private static int CalculateHeaderSize(RtmpHeader header, RtmpHeader lastHeader) { HeaderType headerType = GetHeaderType(header, lastHeader); int channelIdAdd; if (header.ChannelId > 320) channelIdAdd = 2; else if (header.ChannelId > 63) channelIdAdd = 1; else channelIdAdd = 0; return RtmpHeader.GetHeaderLength(headerType) + channelIdAdd; }
/// <summary> /// Decodes RTMP packet header. /// </summary> /// <param name="context">RTMP protocol state.</param> /// <param name="lastHeader">Previous header.</param> /// <param name="stream">Buffer to be decoded.</param> /// <returns>Decoded RTMP header.</returns> public static RtmpHeader DecodeHeader(RtmpContext context, RtmpHeader lastHeader, ByteBuffer stream) { byte headerByte = stream.Get(); int headerValue; int byteCount = 1; if ((headerByte & 0x3f) == 0) { // Two byte header headerValue = ((int) headerByte & 0xff) << 8 | ((int) stream.Get() & 0xff); byteCount = 2; } else if ((headerByte & 0x3f) == 1) { // Three byte header headerValue = ((int) headerByte & 0xff) << 16 | ((int) stream.Get() & 0xff) << 8 | ((int) stream.Get() & 0xff); byteCount = 3; } else { // Single byte header headerValue = (int) headerByte & 0xff; byteCount = 1; } byte channelId = DecodeChannelId(headerValue, byteCount); byte headerSize = DecodeHeaderSize(headerValue, byteCount); RtmpHeader header = new RtmpHeader(); header.ChannelId = channelId; header.IsTimerRelative = (HeaderType)headerSize != HeaderType.HeaderNew; if ((HeaderType)headerSize != HeaderType.HeaderNew && lastHeader == null) { #if !SILVERLIGHT if(log.IsErrorEnabled) log.Error(string.Format("Last header null not new, headerSize: {0}, channelId {1}", headerSize, channelId)); #endif lastHeader = new RtmpHeader(); lastHeader.ChannelId = channelId; lastHeader.IsTimerRelative = (HeaderType)headerSize != HeaderType.HeaderNew; } #if !SILVERLIGHT if( log.IsDebugEnabled ) log.Debug(__Res.GetString(__Res.Rtmp_DecodeHeader, Enum.GetName(typeof(HeaderType), (HeaderType)headerSize))); #endif switch((HeaderType)headerSize) { case HeaderType.HeaderNew: header.Timer = stream.ReadUInt24();// ReadUnsignedMediumInt(); header.Size = stream.ReadUInt24();// ReadMediumInt(); header.DataType = stream.Get(); header.StreamId = stream.ReadReverseInt(); break; case HeaderType.HeaderSameSource: header.Timer = stream.ReadUInt24();// ReadUnsignedMediumInt(); header.Size = stream.ReadUInt24();// ReadMediumInt(); header.DataType = stream.Get(); header.StreamId = lastHeader.StreamId; break; case HeaderType.HeaderTimerChange: header.Timer = stream.ReadUInt24();//ReadUnsignedMediumInt(); header.Size = lastHeader.Size; header.DataType = lastHeader.DataType; header.StreamId = lastHeader.StreamId; break; case HeaderType.HeaderContinue: header.Timer = lastHeader.Timer; header.Size = lastHeader.Size; header.DataType = lastHeader.DataType; header.StreamId = lastHeader.StreamId; header.IsTimerRelative = lastHeader.IsTimerRelative; break; default: #if !SILVERLIGHT log.Error("Unexpected header size: " + headerSize); #endif return null; } if (header.Timer >= 0xffffff) { //Extended timestamp header.Timer = stream.GetInt(); } return header; }
protected override void OnPing(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, Ping ping) { switch (ping.PingType) { case Ping.ClientBuffer: IClientStream stream = null; // Get the stream id int streamId = ping.Value2; // Get requested buffer size in milliseconds int buffer = ping.Value3; if (streamId != 0) { // The client wants to set the buffer time stream = connection.GetStreamById(streamId); if (stream != null) { stream.SetClientBufferDuration(buffer); if (log.IsDebugEnabled) { log.Debug(string.Format("Client sent a buffer size: {0} ms for stream id: {1}", buffer, streamId)); } } } // Catch-all to make sure buffer size is set if (stream == null) { // Remember buffer time until stream is created connection.RememberStreamBufferDuration(streamId, buffer); if (log.IsDebugEnabled) { log.Debug(string.Format("Remembering client buffer size: {0} on stream id: {1} ", buffer, streamId)); } } break; case Ping.PongServer: // This is the response to an IConnection.Ping request connection.PingReceived(ping); break; default: log.Warn("Unhandled ping: " + ping); break; } }
static Notify DecodeNotify(ByteBuffer stream, RtmpHeader header) { return DecodeNotifyOrInvoke(new Notify(), stream, header); }
/// <summary> /// Encode RTMP header into given ByteBuffer /// </summary> /// <param name="header">RTMP message header</param> /// <param name="lastHeader">Previous header</param> /// <param name="buffer">Buffer to write encoded header to</param> /// <returns>Encoded header data</returns> public static ByteBuffer EncodeHeader(RtmpHeader header, RtmpHeader lastHeader, ByteBuffer buffer) { HeaderType headerType = GetHeaderType(header, lastHeader); EncodeHeaderByte(buffer, (byte)headerType, header.ChannelId); switch(headerType) { case HeaderType.HeaderNew: if (header.Timer < 0xffffff) buffer.WriteMediumInt(header.Timer); else buffer.WriteMediumInt(0xffffff); buffer.WriteMediumInt(header.Size); buffer.Put((byte)header.DataType); buffer.WriteReverseInt(header.StreamId); break; case HeaderType.HeaderSameSource: if (header.Timer < 0xffffff) buffer.WriteMediumInt(header.Timer); else buffer.WriteMediumInt(0xffffff); buffer.WriteMediumInt(header.Size); buffer.Put((byte)header.DataType); break; case HeaderType.HeaderTimerChange: if (header.Timer < 0xffffff) buffer.WriteMediumInt(header.Timer); else buffer.WriteMediumInt(0xffffff); break; case HeaderType.HeaderContinue: break; } if (header.Timer >= 0xffffff) buffer.PutInt(header.Timer); return buffer; }
protected override void OnSharedObject(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, SharedObjectMessage message) { ISharedObject so = null; string name = message.Name; IScope scope = connection.Scope; bool persistent = message.IsPersistent; if (scope == null) { // The scope already has been deleted. SendSOCreationFailed(connection, name, persistent); return; } ISharedObjectService sharedObjectService = ScopeUtils.GetScopeService(scope, typeof(ISharedObjectService)) as ISharedObjectService; if (!sharedObjectService.HasSharedObject(scope, name)) { ISharedObjectSecurityService securityService = ScopeUtils.GetScopeService(scope, typeof(ISharedObjectSecurityService)) as ISharedObjectSecurityService; if (securityService != null) { // Check handlers to see if creation is allowed IEnumerator enumerator = securityService.GetSharedObjectSecurity(); while (enumerator.MoveNext()) { ISharedObjectSecurity handler = enumerator.Current as ISharedObjectSecurity; if (!handler.IsCreationAllowed(scope, name, persistent)) { SendSOCreationFailed(connection, name, persistent); return; } } } if (!sharedObjectService.CreateSharedObject(scope, name, persistent)) { SendSOCreationFailed(connection, name, persistent); return; } } so = sharedObjectService.GetSharedObject(scope, name); if (so.IsPersistentObject != persistent) { log.Debug(string.Format("Shared object '{0}' persistence mismatch", name)); SendSOPersistenceMismatch(connection, name, persistent); return; } so.DispatchEvent(message); }
/// <summary> /// Decodes RTMP message event. /// </summary> /// <param name="context">RTMP protocol state.</param> /// <param name="header">RTMP header.</param> /// <param name="stream">Buffer to be decoded.</param> /// <returns>Decoded RTMP event.</returns> public static IRtmpEvent DecodeMessage(RtmpContext context, RtmpHeader header, ByteBuffer stream) { IRtmpEvent message = null; /* * if(header.Timer == 0xffffff) * { * // Skip first four bytes * byte[] extendedTimestamp = new byte[4]; * stream.Read(extendedTimestamp, 0, 4); * log.Warn("Discarding extended timestamp"); * //int unknown = stream.ReadInt32(); * } */ switch (header.DataType) { case Constants.TypeChunkSize: message = DecodeChunkSize(stream); break; case Constants.TypeInvoke: message = DecodeInvoke(stream); break; case Constants.TypeFlexInvoke: message = DecodeFlexInvoke(stream); break; case Constants.TypeNotify: if (header.StreamId == 0) { message = DecodeNotify(stream, header); } else { message = DecodeStreamMetadata(stream); } break; case Constants.TypePing: message = DecodePing(stream); break; case Constants.TypeBytesRead: message = DecodeBytesRead(stream); break; case Constants.TypeAudioData: message = DecodeAudioData(stream); break; case Constants.TypeVideoData: message = DecodeVideoData(stream); break; case Constants.TypeSharedObject: message = DecodeSharedObject(stream); break; case Constants.TypeFlexSharedObject: message = DecodeFlexSharedObject(stream); break; case Constants.TypeServerBandwidth: message = DecodeServerBW(stream); break; case Constants.TypeClientBandwidth: message = DecodeClientBW(stream); break; default: #if !SILVERLIGHT log.Warn("Unknown object type: " + header.DataType); #endif message = DecodeUnknown(stream); break; } message.Header = header; message.Timestamp = header.Timer; return(message); }
/* * FlexInvoke flexInvoke = new FlexInvoke(); * flexInvoke.Cmd = "onstatus"; * flexInvoke.DataType = DataType.TypeUnknown; * StatusASO statusASO = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_CLOSED, connection.ObjectEncoding); * flexInvoke.Parameters = new object[]{ statusASO }; * RtmpChannel channel = connection.GetChannel(3); * channel.Write(flexInvoke); */ protected override void OnChunkSize(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, ChunkSize chunkSize) { if (connection is IStreamCapableConnection) { IStreamCapableConnection streamCapableConnection = connection as IStreamCapableConnection; { foreach (IClientStream stream in streamCapableConnection.GetStreams()) { if (stream is IClientBroadcastStream) { IClientBroadcastStream bs = stream as IClientBroadcastStream; IBroadcastScope scope = bs.Scope.GetBasicScope(Constants.BroadcastScopeType, bs.PublishedName) as IBroadcastScope; if (scope == null) { continue; } OOBControlMessage setChunkSize = new OOBControlMessage(); setChunkSize.Target = "ClientBroadcastStream"; setChunkSize.ServiceName = "chunkSize"; setChunkSize.ServiceParameterMap.Add("chunkSize", chunkSize.Size); scope.SendOOBControlMessage((IConsumer)null, setChunkSize); if (log.IsDebugEnabled) { log.Debug("Sending chunksize " + chunkSize + " to " + bs.Provider); } } } } } }
static Notify DecodeNotify(ByteBuffer stream, RtmpHeader header) { return(DecodeNotifyOrInvoke(new Notify(), stream, header)); }
protected override void OnServerBW(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, ServerBW serverBW) { }
static Notify DecodeNotifyOrInvoke(Notify notify, ByteBuffer stream, RtmpHeader header) { long start = stream.Position; RtmpReader reader = new RtmpReader(stream); string action = reader.ReadData() as string; if (!(notify is Invoke)) { //Don't decode "NetStream.send" requests stream.Position = start; notify.Data = ByteBuffer.Allocate(stream.Remaining); notify.Data.Put(stream); //notify.setData(in.asReadOnlyBuffer()); return(notify); } if (header == null || header.StreamId == 0) { double invokeId = (double)reader.ReadData(); notify.InvokeId = (int)invokeId; } object[] parameters = Call.EmptyArguments; if (stream.HasRemaining) { #if !(NET_1_1) List <object> paramList = new List <object>(); #else ArrayList paramList = new ArrayList(); #endif object obj = reader.ReadData(); if (obj is IDictionary) { // for connect we get a map notify.ConnectionParameters = obj as IDictionary; } else if (obj != null) { paramList.Add(obj); } while (stream.HasRemaining) { paramList.Add(reader.ReadData()); } parameters = paramList.ToArray(); } int dotIndex = action.LastIndexOf("."); string serviceName = (dotIndex == -1) ? null : action.Substring(0, dotIndex); string serviceMethod = (dotIndex == -1) ? action : action.Substring(dotIndex + 1, action.Length - dotIndex - 1); if (notify is Invoke) { PendingCall call = new PendingCall(serviceName, serviceMethod, parameters); notify.ServiceCall = call; } else { Call call = new Call(serviceName, serviceMethod, parameters); notify.ServiceCall = call; } return(notify); }
protected override void OnInvoke(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, Notify invoke) { IServiceCall serviceCall = invoke.ServiceCall; // If it's a callback for server remote call then pass it over to callbacks handler // and return if (serviceCall.ServiceMethodName.Equals("_result") || serviceCall.ServiceMethodName.Equals("_error")) { HandlePendingCallResult(connection, invoke); return; } bool disconnectOnReturn = false; string action = null; if (serviceCall.ServiceName == null) { action = serviceCall.ServiceMethodName; switch (action) { case ACTION_CONNECT: { if (!connection.IsConnected) { IDictionary parameters = invoke.ConnectionParameters; string host = null; if (parameters.Contains("tcUrl")) { host = GetHostname(parameters["tcUrl"] as string); } if (host != null && host.IndexOf(":") != -1) { // Remove default port from connection string host = host.Substring(0, host.IndexOf(":")); } string app = parameters["app"] as string; string path = parameters["app"] as string; // App name as path, but without query string if there is one if (path != null && path.IndexOf("?") != -1) { int idx = path.IndexOf("?"); parameters["queryString"] = path.Substring(idx); path = path.Substring(0, idx); } parameters["path"] = path; connection.Setup(host, path, parameters); try { //IGlobalScope global = this.Endpoint.LookupGlobal(host, path); IGlobalScope global = this.Endpoint.GetMessageBroker().GlobalScope; if (global == null) { serviceCall.Status = Call.STATUS_SERVICE_NOT_FOUND; if (serviceCall is IPendingServiceCall) { StatusASO status = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_INVALID_APPLICATION, connection.ObjectEncoding); status.description = "No global scope on this server."; (serviceCall as IPendingServiceCall).Result = status; } log.Info(string.Format("No application scope found for {0} on host {1}. Misspelled or missing application folder?", path, host)); disconnectOnReturn = true; } else { IScopeContext context = global.Context; IScope scope = null; try { scope = context.ResolveScope(global, path); } catch (ScopeNotFoundException /*exception*/) { if (log.IsErrorEnabled) { log.Error(__Res.GetString(__Res.Scope_NotFound, path)); } serviceCall.Status = Call.STATUS_SERVICE_NOT_FOUND; if (serviceCall is IPendingServiceCall) { StatusASO status = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_REJECTED, connection.ObjectEncoding); status.description = "No scope \"" + path + "\" on this server."; (serviceCall as IPendingServiceCall).Result = status; } disconnectOnReturn = true; } catch (ScopeShuttingDownException) { serviceCall.Status = Call.STATUS_APP_SHUTTING_DOWN; if (serviceCall is IPendingServiceCall) { StatusASO status = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_APPSHUTDOWN, connection.ObjectEncoding); status.description = "Application at \"" + path + "\" is currently shutting down."; (serviceCall as IPendingServiceCall).Result = status; } log.Info(string.Format("Application at {0} currently shutting down on {1}", path, host)); disconnectOnReturn = true; } if (scope != null) { if (log.IsInfoEnabled) { log.Info(__Res.GetString(__Res.Scope_Connect, scope.Name)); } bool okayToConnect; try { //The only way to differentiate NetConnection.connect() and Consumer.subscribe() seems to be the app name if (app == string.Empty) { connection.SetIsFlexClient(true); okayToConnect = connection.Connect(scope, serviceCall.Arguments); if (okayToConnect) { if (serviceCall.Arguments != null && serviceCall.Arguments.Length >= 3) { string credentials = serviceCall.Arguments[2] as string; if (credentials != null && credentials != string.Empty) { MessageBroker messageBroker = this.Endpoint.GetMessageBroker(); AuthenticationService authenticationService = messageBroker.GetService(AuthenticationService.ServiceId) as AuthenticationService; authenticationService.Authenticate(credentials); } } //FDS 2.0.1 fds.swc if (serviceCall.Arguments != null && serviceCall.Arguments.Length == 1) { string credentials = serviceCall.Arguments[0] as string; if (credentials != null && credentials != string.Empty) { MessageBroker messageBroker = this.Endpoint.GetMessageBroker(); AuthenticationService authenticationService = messageBroker.GetService(AuthenticationService.ServiceId) as AuthenticationService; authenticationService.Authenticate(credentials); } } } } else { connection.SetIsFlexClient(false); okayToConnect = connection.Connect(scope, serviceCall.Arguments); } if (okayToConnect) { if (log.IsDebugEnabled) { log.Debug("Connected RtmpClient: " + connection.Client.Id); } serviceCall.Status = Call.STATUS_SUCCESS_RESULT; if (serviceCall is IPendingServiceCall) { StatusASO statusASO = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_SUCCESS, connection.ObjectEncoding); statusASO.Add("id", connection.Client.Id); (serviceCall as IPendingServiceCall).Result = statusASO; } // Measure initial roundtrip time after connecting connection.GetChannel((byte)2).Write(new Ping(Ping.StreamBegin, 0, -1)); connection.StartRoundTripMeasurement(); } else { if (log.IsDebugEnabled) { log.Debug("Connect failed"); } serviceCall.Status = Call.STATUS_ACCESS_DENIED; if (serviceCall is IPendingServiceCall) { (serviceCall as IPendingServiceCall).Result = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_REJECTED, connection.ObjectEncoding); } disconnectOnReturn = true; } } catch (ClientRejectedException rejected) { if (log.IsDebugEnabled) { log.Debug("Connect rejected"); } serviceCall.Status = Call.STATUS_ACCESS_DENIED; if (serviceCall is IPendingServiceCall) { StatusASO statusASO = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_REJECTED, connection.ObjectEncoding); statusASO.Application = rejected.Reason; (serviceCall as IPendingServiceCall).Result = statusASO; } disconnectOnReturn = true; } } } } catch (Exception ex) { if (log.IsErrorEnabled) { log.Error("Error connecting", ex); } serviceCall.Status = Call.STATUS_GENERAL_EXCEPTION; if (serviceCall is IPendingServiceCall) { (serviceCall as IPendingServiceCall).Result = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_FAILED, connection.ObjectEncoding); } disconnectOnReturn = true; } } else { // Service calls, must be connected. InvokeCall(connection, serviceCall); } } break; case ACTION_DISCONNECT: connection.Close(); break; case ACTION_CREATE_STREAM: case ACTION_DELETE_STREAM: case ACTION_RELEASE_STREAM: case ACTION_PUBLISH: case ACTION_PLAY: case ACTION_SEEK: case ACTION_PAUSE: case ACTION_CLOSE_STREAM: case ACTION_RECEIVE_VIDEO: case ACTION_RECEIVE_AUDIO: { IStreamService streamService = ScopeUtils.GetScopeService(connection.Scope, typeof(IStreamService)) as IStreamService; StatusASO status = null; try { if (!InvokeCall(connection, serviceCall, streamService)) { status = StatusASO.GetStatusObject(StatusASO.NS_INVALID_ARGUMENT, connection.ObjectEncoding); status.description = "Failed to " + action + " (stream ID: " + header.StreamId + ")"; } } catch (Exception ex) { log.Error("Error while invoking " + action + " on stream service.", ex); status = StatusASO.GetStatusObject(StatusASO.NS_FAILED, connection.ObjectEncoding); status.description = "Error while invoking " + action + " (stream ID: " + header.StreamId + ")"; status.details = ex.Message; } if (status != null) { channel.SendStatus(status); } } break; default: if (connection.IsConnected) { InvokeCall(connection, serviceCall); } else { // Warn user attemps to call service without being connected if (log.IsWarnEnabled) { log.Warn("Not connected, closing connection"); } connection.Close(); } break; } } /* * if(invoke is FlexInvoke) * { * FlexInvoke reply = new FlexInvoke(); * reply.InvokeId = invoke.InvokeId; * reply.SetResponseSuccess(); * //TODO * if( serviceCall is IPendingServiceCall ) * { * IPendingServiceCall pendingCall = (IPendingServiceCall)serviceCall; * reply.Response = pendingCall.Result; * } * channel.Write(reply); * } * else if(invoke is Invoke) */ if (invoke is Invoke) { if ((header.StreamId != 0) && (serviceCall.Status == Call.STATUS_SUCCESS_VOID || serviceCall.Status == Call.STATUS_SUCCESS_NULL)) { if (log.IsDebugEnabled) { log.Debug("Method does not have return value, do not reply"); } return; } // The client expects a result for the method call. Invoke reply = new Invoke(); reply.ServiceCall = serviceCall; reply.InvokeId = invoke.InvokeId; //sending reply channel.Write(reply); } if (disconnectOnReturn) { connection.Close(); } if (action == ACTION_CONNECT) { connection.Context.ObjectEncoding = connection.ObjectEncoding; } }
/* FlexInvoke flexInvoke = new FlexInvoke(); flexInvoke.Cmd = "onstatus"; flexInvoke.DataType = DataType.TypeUnknown; StatusASO statusASO = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_CLOSED, connection.ObjectEncoding); flexInvoke.Parameters = new object[]{ statusASO }; RtmpChannel channel = connection.GetChannel(3); channel.Write(flexInvoke); */ protected override void OnChunkSize(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, ChunkSize chunkSize) { if (connection is IStreamCapableConnection) { IStreamCapableConnection streamCapableConnection = connection as IStreamCapableConnection; { foreach (IClientStream stream in streamCapableConnection.GetStreams()) { if (stream is IClientBroadcastStream) { IClientBroadcastStream bs = stream as IClientBroadcastStream; IBroadcastScope scope = bs.Scope.GetBasicScope(Constants.BroadcastScopeType, bs.PublishedName) as IBroadcastScope; if (scope == null) continue; OOBControlMessage setChunkSize = new OOBControlMessage(); setChunkSize.Target = "ClientBroadcastStream"; setChunkSize.ServiceName = "chunkSize"; setChunkSize.ServiceParameterMap.Add("chunkSize", chunkSize.Size); scope.SendOOBControlMessage((IConsumer)null, setChunkSize); if (log.IsDebugEnabled) { log.Debug("Sending chunksize " + chunkSize + " to " + bs.Provider); } } } } } }
protected override void OnFlexInvoke(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, FlexInvoke invoke) { IMessage message = null; if (invoke.ServiceCall.Arguments != null && invoke.ServiceCall.Arguments.Length > 0) { message = invoke.ServiceCall.Arguments[0] as IMessage; } if (message != null) { MessageBroker messageBroker = this.Endpoint.GetMessageBroker(); if (message.clientId == null) { message.clientId = Guid.NewGuid().ToString("D"); /* * if( !(message is CommandMessage) ) * { * //producer may send messages without subscribing * CommandMessage commandMessageSubscribe = new CommandMessage(CommandMessage.SubscribeOperation); * commandMessageSubscribe.messageId = Guid.NewGuid().ToString("D"); * commandMessageSubscribe.headers = message.headers.Clone() as Hashtable; * commandMessageSubscribe.messageRefType = message.GetType().FullName;//"flex.messaging.messages.AsyncMessage" * commandMessageSubscribe.destination = message.destination; * * IMessage subscribeResponse = messageBroker.RouteMessage(commandMessageSubscribe, _endpoint, connection); * message.clientId = subscribeResponse.clientId; * } * } */ } IMessage response = messageBroker.RouteMessage(message, this.Endpoint); invoke.ServiceCall.Status = response is ErrorMessage ? Call.STATUS_INVOCATION_EXCEPTION : Call.STATUS_SUCCESS_RESULT; if (invoke.ServiceCall is IPendingServiceCall) { (invoke.ServiceCall as IPendingServiceCall).Result = response; } FlexInvoke reply = new FlexInvoke(); reply.InvokeId = invoke.InvokeId; reply.ServiceCall = invoke.ServiceCall; /* * if( response is ErrorMessage ) * reply.SetResponseFailure(); * else * reply.SetResponseSuccess(); * reply.Response = response; */ channel.Write(reply); } else { // If it's a callback for server remote call then pass it over to callbacks handler and return OnInvoke(connection, channel, header, invoke); } }
protected override void OnPing(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, Ping ping) { switch (ping.PingType) { case Ping.ClientBuffer: IClientStream stream = null; // Get the stream id int streamId = ping.Value2; // Get requested buffer size in milliseconds int buffer = ping.Value3; if (streamId != 0) { // The client wants to set the buffer time stream = connection.GetStreamById(streamId); if (stream != null) { stream.SetClientBufferDuration(buffer); if (log.IsDebugEnabled) log.Debug(string.Format("Client sent a buffer size: {0} ms for stream id: {1}", buffer, streamId )); } } // Catch-all to make sure buffer size is set if (stream == null) { // Remember buffer time until stream is created connection.RememberStreamBufferDuration(streamId, buffer); if (log.IsDebugEnabled) log.Debug(string.Format("Remembering client buffer size: {0} on stream id: {1} ", buffer, streamId)); } break; case Ping.PongServer: // This is the response to an IConnection.Ping request connection.PingReceived(ping); break; default: log.Warn("Unhandled ping: " + ping); break; } }