public static object Decode(RtmpContext context, ByteBuffer stream)
        {
            object obj2;
            long   position = stream.Position;

            try
            {
                switch (context.State)
                {
                case RtmpState.Connect:
                case RtmpState.Handshake:
                    return(DecodeHandshake(context, stream));

                case RtmpState.Connected:
                    return(DecodePacket(context, stream));

                case RtmpState.Error:
                    return(null);
                }
                obj2 = null;
            }
            catch (Exception exception)
            {
                throw new ProtocolException("Error during decoding", exception);
            }
            return(obj2);
        }
        static ByteBuffer EncodePing(RtmpContext context, Ping ping)
        {
            int len = 6;

            if (ping.Value3 != Ping.Undefined)
            {
                len += 4;
            }
            if (ping.Value4 != Ping.Undefined)
            {
                len += 4;
            }
            ByteBuffer output = ByteBuffer.Allocate(len);

            output.PutShort(ping.PingType);
            output.PutInt(ping.Value2);
            if (ping.Value3 != Ping.Undefined)
            {
                output.PutInt(ping.Value3);
            }
            if (ping.Value4 != Ping.Undefined)
            {
                output.PutInt(ping.Value4);
            }
            return(output);
        }
Beispiel #3
0
        private static ByteBuffer EncodeBytesRead(RtmpContext context, BytesRead bytesRead)
        {
            ByteBuffer buffer = ByteBuffer.Allocate(4);

            buffer.PutInt(bytesRead.Bytes);
            return(buffer);
        }
Beispiel #4
0
        private static ByteBuffer EncodePing(RtmpContext context, Ping ping)
        {
            int capacity = 6;

            if (ping.Value3 != -1)
            {
                capacity += 4;
            }
            if (ping.Value4 != -1)
            {
                capacity += 4;
            }
            ByteBuffer buffer = ByteBuffer.Allocate(capacity);

            buffer.PutShort(ping.Value1);
            buffer.PutInt(ping.Value2);
            if (ping.Value3 != -1)
            {
                buffer.PutInt(ping.Value3);
            }
            if (ping.Value4 != -1)
            {
                buffer.PutInt(ping.Value4);
            }
            return(buffer);
        }
        static ByteBuffer EncodeBytesRead(RtmpContext context, BytesRead bytesRead)
        {
            ByteBuffer output = ByteBuffer.Allocate(4);

            output.PutInt(bytesRead.Bytes);
            return(output);
        }
Beispiel #6
0
        private static ByteBuffer EncodeServerBW(RtmpContext context, ServerBW serverBW)
        {
            ByteBuffer buffer = ByteBuffer.Allocate(4);

            buffer.PutInt(serverBW.Bandwidth);
            return(buffer);
        }
Beispiel #7
0
        private static ByteBuffer EncodeChunkSize(RtmpContext context, ChunkSize chunkSize)
        {
            ByteBuffer buffer = ByteBuffer.Allocate(4);

            buffer.PutInt(chunkSize.Size);
            return(buffer);
        }
        static ByteBuffer EncodeChunkSize(RtmpContext context, ChunkSize chunkSize)
        {
            ByteBuffer output = ByteBuffer.Allocate(4);

            output.PutInt(chunkSize.Size);
            return(output);
        }
        /// <summary>
        /// Encode server-side bandwidth event
        /// </summary>
        /// <param name="context"></param>
        /// <param name="serverBW"></param>
        /// <returns></returns>
        static ByteBuffer EncodeServerBW(RtmpContext context, ServerBW serverBW)
        {
            ByteBuffer output = ByteBuffer.Allocate(4);

            output.PutInt(serverBW.Bandwidth);
            return(output);
        }
        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);
            }
        }
Beispiel #11
0
        public static ByteBuffer EncodePacket(RtmpContext context, RtmpPacket packet)
        {
            RtmpHeader header    = packet.Header;
            int        channelId = header.ChannelId;
            IRtmpEvent message   = packet.Message;

            if (message is ChunkSize)
            {
                ChunkSize size = (ChunkSize)message;
                context.SetWriteChunkSize(size.Size);
            }
            ByteBuffer input = EncodeMessage(context, header, message);

            if (input.Position != 0L)
            {
                input.Flip();
            }
            else
            {
                input.Rewind();
            }
            header.Size = input.Limit;
            RtmpHeader lastWriteHeader = context.GetLastWriteHeader(channelId);
            int        num2            = CalculateHeaderSize(header, lastWriteHeader);

            context.SetLastWriteHeader(channelId, header);
            context.SetLastWritePacket(channelId, packet);
            int writeChunkSize = context.GetWriteChunkSize();
            int num4           = 1;

            if (header.ChannelId > 320)
            {
                num4 = 3;
            }
            else if (header.ChannelId > 0x3f)
            {
                num4 = 2;
            }
            int        num5     = (int)Math.Ceiling((double)(((float)header.Size) / ((float)writeChunkSize)));
            int        capacity = (header.Size + num2) + ((num5 > 0) ? ((num5 - 1) * num4) : 0);
            ByteBuffer buffer   = ByteBuffer.Allocate(capacity);

            EncodeHeader(header, lastWriteHeader, buffer);
            if (num5 == 1)
            {
                ByteBuffer.Put(buffer, input, buffer.Remaining);
            }
            else
            {
                for (int i = 0; i < (num5 - 1); i++)
                {
                    ByteBuffer.Put(buffer, input, writeChunkSize);
                    EncodeHeaderByte(buffer, 3, header.ChannelId);
                }
                ByteBuffer.Put(buffer, input, buffer.Remaining);
            }
            buffer.Flip();
            return(buffer);
        }
Beispiel #12
0
        private static ByteBuffer EncodeSharedObject(RtmpContext context, ISharedObjectMessage so)
        {
            ByteBuffer output = ByteBuffer.Allocate(0x80);

            output.AutoExpand = true;
            EncodeSharedObject(context, so, output);
            return(output);
        }
        static ByteBuffer EncodeClientBW(RtmpContext context, ClientBW clientBW)
        {
            ByteBuffer output = ByteBuffer.Allocate(5);

            output.PutInt(clientBW.Bandwidth);
            output.Put(clientBW.Value2);
            return(output);
        }
Beispiel #14
0
        private static ByteBuffer EncodeClientBW(RtmpContext context, ClientBW clientBW)
        {
            ByteBuffer buffer = ByteBuffer.Allocate(5);

            buffer.PutInt(clientBW.Bandwidth);
            buffer.Put(clientBW.Value2);
            return(buffer);
        }
        static ByteBuffer EncodeFlexSharedObject(RtmpContext context, ISharedObjectMessage so)
        {
            ByteBuffer output = ByteBuffer.Allocate(128);

            output.AutoExpand = true;
            output.Put((byte)0);
            EncodeSharedObject(context, so, output);
            return(output);
        }
        static ByteBuffer EncodeNotifyOrInvoke(RtmpContext context, Notify invoke)
        {
            //MemoryStreamEx output = new MemoryStreamEx();
            ByteBuffer output = ByteBuffer.Allocate(1024);

            output.AutoExpand = true;
            RtmpWriter writer = new RtmpWriter(output);

            //Set legacy collection flag from context
            writer.UseLegacyCollection = context.UseLegacyCollection;
            writer.UseLegacyThrowable  = context.UseLegacyThrowable;

            IServiceCall serviceCall = invoke.ServiceCall;
            bool         isPending   = serviceCall.Status == Call.STATUS_PENDING;

            if (!isPending)
            {
                //log.debug("Call has been executed, send result");
                writer.WriteData(context.ObjectEncoding, serviceCall.IsSuccess ? "_result" : "_error");
            }
            else
            {
                //log.debug("This is a pending call, send request");
                string action = (serviceCall.ServiceName == null) ? serviceCall.ServiceMethodName : serviceCall.ServiceName + "." + serviceCall.ServiceMethodName;
                writer.WriteData(context.ObjectEncoding, action);
            }
            if (invoke is Invoke)
            {
                writer.WriteData(context.ObjectEncoding, invoke.InvokeId);
                writer.WriteData(context.ObjectEncoding, invoke.ConnectionParameters);
            }
            if (!isPending && (invoke is Invoke))
            {
                IPendingServiceCall pendingCall = (IPendingServiceCall)serviceCall;
                if (!serviceCall.IsSuccess && !(pendingCall.Result is StatusASO))
                {
                    StatusASO status = GenerateErrorResult(StatusASO.NC_CALL_FAILED, serviceCall.Exception);
                    pendingCall.Result = status;
                }
                writer.WriteData(context.ObjectEncoding, pendingCall.Result);
            }
            else
            {
                //log.debug("Writing params");
                object[] args = invoke.ServiceCall.Arguments;
                if (args != null)
                {
                    foreach (object element in args)
                    {
                        writer.WriteData(context.ObjectEncoding, element);
                    }
                }
            }
            return(output);
        }
        public static List <object> DecodeBuffer(RtmpContext context, ByteBuffer stream)
        {
            List <object> list = null;

            try
            {
                long num;
                bool flag;
                goto Label_0099;
Label_0009:
                num = stream.Remaining;
                if (context.CanStartDecoding(num))
                {
                    context.StartDecoding();
                    if (context.State == RtmpState.Disconnected)
                    {
                        return(list);
                    }
                    object item = Decode(context, stream);
                    if (context.HasDecodedObject)
                    {
                        if (list == null)
                        {
                            list = new List <object>();
                        }
                        list.Add(item);
                        goto Label_008A;
                    }
                    if (context.CanContinueDecoding)
                    {
                        goto Label_0099;
                    }
                }
                return(list);

Label_008A:
                if (!stream.HasRemaining)
                {
                    return(list);
                }
Label_0099:
                flag = true;
                goto Label_0009;
            }
            catch
            {
                throw;
            }
            finally
            {
                stream.Compact();
            }
            return(list);
        }
Beispiel #18
0
        public static ByteBuffer EncodeMessage(RtmpContext context, RtmpHeader header, IRtmpEvent message)
        {
            switch (header.DataType)
            {
            case 1:
                return(EncodeChunkSize(context, message as ChunkSize));

            case 3:
                return(EncodeBytesRead(context, message as BytesRead));

            case 4:
                return(EncodePing(context, message as Ping));

            case 5:
                return(EncodeServerBW(context, message as ServerBW));

            case 6:
                return(EncodeClientBW(context, message as ClientBW));

            case 8:
                return(EncodeAudioData(context, message as AudioData));

            case 9:
                return(EncodeVideoData(context, message as VideoData));

            case 15:
                return(EncodeFlexStreamSend(context, message as FlexStreamSend));

            case 0x10:
                return(EncodeFlexSharedObject(context, message as ISharedObjectMessage));

            case 0x11:
                return(EncodeFlexInvoke(context, message as FlexInvoke));

            case 0x12:
                if ((message as Notify).ServiceCall != null)
                {
                    return(EncodeNotify(context, message as Notify));
                }
                return(EncodeStreamMetadata(context, message as Notify));

            case 0x13:
                return(EncodeSharedObject(context, message as ISharedObjectMessage));

            case 20:
                return(EncodeInvoke(context, message as Invoke));
            }
            if (_log.get_IsErrorEnabled())
            {
                _log.Error("Unknown object type: " + header.DataType);
            }
            return(null);
        }
Beispiel #19
0
 internal RtmpConnection(string path, IDictionary parameters) : base(path, parameters)
 {
     this._channels          = new Dictionary <int, RtmpChannel>();
     this._clients           = new Dictionary <string, IMessageClient>();
     this._pendingCalls      = new Dictionary <int, IServiceCall>();
     this._deferredResults   = new Dictionary <DeferredResult, object>();
     this._invokeId          = new AtomicInteger(1);
     this._lastPingTime      = -1;
     this._clientBytesRead   = 0L;
     this._bytesReadInterval = 0x1e000;
     this._nextBytesRead     = 0x1e000;
     this._lastBytesRead     = 0L;
     this._context           = new RtmpContext(RtmpMode.Server);
 }
Beispiel #20
0
        private static ByteBuffer EncodeFlexInvoke(RtmpContext context, FlexInvoke invoke)
        {
            ByteBuffer stream = ByteBuffer.Allocate(0x400);

            stream.AutoExpand = true;
            RtmpWriter writer = new RtmpWriter(stream);

            writer.WriteByte(0);
            writer.WriteData(context.ObjectEncoding, invoke.Cmd);
            writer.WriteData(context.ObjectEncoding, invoke.InvokeId);
            writer.WriteData(context.ObjectEncoding, invoke.CmdData);
            object response = invoke.Response;

            writer.WriteData(context.ObjectEncoding, response);
            return(stream);
        }
Beispiel #21
0
        private static ByteBuffer EncodeNotifyOrInvoke(RtmpContext context, Notify invoke)
        {
            ByteBuffer stream = ByteBuffer.Allocate(0x400);

            stream.AutoExpand = true;
            RtmpWriter   writer      = new RtmpWriter(stream);
            IServiceCall serviceCall = invoke.ServiceCall;
            bool         flag        = serviceCall.Status == 1;

            if (!flag)
            {
                writer.WriteData(context.ObjectEncoding, "_result");
            }
            else
            {
                string data = (serviceCall.ServiceName == null) ? serviceCall.ServiceMethodName : (serviceCall.ServiceName + "." + serviceCall.ServiceMethodName);
                writer.WriteData(context.ObjectEncoding, data);
            }
            if (invoke is Invoke)
            {
                writer.WriteData(context.ObjectEncoding, invoke.InvokeId);
                writer.WriteData(context.ObjectEncoding, invoke.ConnectionParameters);
            }
            if (!flag && (invoke is Invoke))
            {
                IPendingServiceCall call2 = (IPendingServiceCall)serviceCall;
                if (!serviceCall.IsSuccess)
                {
                    StatusASO saso = GenerateErrorResult("NetConnection.Call.Failed", serviceCall.Exception);
                    call2.Result = saso;
                }
                writer.WriteData(context.ObjectEncoding, call2.Result);
                return(stream);
            }
            object[] arguments = invoke.ServiceCall.Arguments;
            if (arguments != null)
            {
                foreach (object obj2 in arguments)
                {
                    writer.WriteData(context.ObjectEncoding, obj2);
                }
            }
            return(stream);
        }
Beispiel #22
0
 public static ByteBuffer Encode(RtmpContext context, object message)
 {
     try
     {
         if (message is ByteBuffer)
         {
             return((ByteBuffer)message);
         }
         return(EncodePacket(context, message as RtmpPacket));
     }
     catch (Exception exception)
     {
         if (_log != null)
         {
             _log.Fatal("Error encoding object. ", exception);
         }
     }
     return(null);
 }
        private static object Decode(RtmpContext context, ByteBuffer stream)
        {
            //long start = stream.Position;
            switch (context.State)
            {
            case RtmpState.Connected:
                return(DecodePacket(context, stream));

            case RtmpState.Error:
                // Attempt to correct error
                return(null);

            case RtmpState.Connect:
            case RtmpState.Handshake:
                return(DecodeHandshake(context, stream));

            default:
                return(null);
            }
        }
        public static ByteBuffer Encode(RtmpContext context, object message)
        {
            try
            {
                if (message is ByteBuffer)
                {
                    return((ByteBuffer)message);
                }
                else
                {
                    return(EncodePacket(context, message as RtmpPacket));
                }
            }
            catch (Exception ex)
            {
#if !SILVERLIGHT
                if (_log != null)
                {
                    _log.Fatal("Error encoding object. ", ex);
                }
#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>
        /// 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>
        /// Decodes handshake message.
        /// </summary>
        /// <param name="context">RTMP protocol state.</param>
        /// <param name="stream">Buffer to be decoded.</param>
        /// <returns>Buffer with handshake response.</returns>
        public static object DecodeHandshake(RtmpContext context, ByteBuffer stream)
        {
            long remaining = stream.Remaining;

            if (context.Mode == RtmpMode.Server)
            {
                if (context.State == RtmpState.Connect)
                {
                    if (remaining < HandshakeSize + 1)
                    {
#if !SILVERLIGHT
                        if (log.IsDebugEnabled)
                        {
                            log.Debug(__Res.GetString(__Res.Rtmp_HSInitBuffering, remaining));
                        }
#endif
                        context.SetBufferDecoding(HandshakeSize + 1);
                        return(null);
                    }
                    else
                    {
#if !SILVERLIGHT
                        if (log.IsDebugEnabled)
                        {
                            log.Debug("Handshake 1st phase");
                        }
#endif
                        stream.Get();// skip the header byte
                        byte[] handshake = RtmpHandshake.GetHandshakeResponse(stream);
                        context.SetHandshake(handshake);
                        context.State = RtmpState.Handshake;
                        return(handshake);
                    }
                }
                if (context.State == RtmpState.Handshake)
                {
                    //if (log.IsDebugEnabled)
                    //    log.Debug("Handshake reply");

                    if (remaining < HandshakeSize)
                    {
#if !SILVERLIGHT
                        if (log.IsDebugEnabled)
                        {
                            log.Debug(__Res.GetString(__Res.Rtmp_HSReplyBuffering, remaining));
                        }
#endif
                        context.SetBufferDecoding(HandshakeSize);
                        return(null);
                    }
                    else
                    {
                        // Skip first 8 bytes when comparing the handshake, they seem to be changed when connecting from a Mac client.
                        if (!context.ValidateHandshakeReply(stream, 8, HandshakeSize - 8))
                        {
#if !SILVERLIGHT
                            if (log.IsDebugEnabled)
                            {
                                log.Debug("Handshake reply validation failed, disconnecting client.");
                            }
#endif
                            stream.Skip(HandshakeSize);
                            context.State = RtmpState.Error;
                            throw new HandshakeFailedException("Handshake validation failed");
                        }
                        stream.Skip(HandshakeSize);
                        context.State = RtmpState.Connected;
                        context.ContinueDecoding();
                        return(null);
                    }
                }
            }
            else
            {
                //Client mode
                if (context.State == RtmpState.Connect)
                {
                    int size = (2 * HandshakeSize) + 1;
                    if (remaining < size)
                    {
#if !SILVERLIGHT
                        if (log.IsDebugEnabled)
                        {
                            log.Debug(__Res.GetString(__Res.Rtmp_HSInitBuffering, remaining));
                        }
#endif
                        context.SetBufferDecoding(size);
                        return(null);
                    }
                    else
                    {
                        ByteBuffer hs = ByteBuffer.Allocate(size);
                        ByteBuffer.Put(hs, stream, size);
                        hs.Flip();
                        context.State = RtmpState.Handshake;
                        return(hs);
                    }
                }
            }
            return(null);
        }
        public static ArrayList DecodeBuffer(RtmpContext context, ByteBuffer stream)
#endif
        {
            // >> HEADER[1] + CLIENT_HANDSHAKE[1536]
            // << HEADER[1] + SERVER_HANDSHAKE[1536] + CLIENT_HANDSHAKE[1536];
            // >> SERVER_HANDSHAKE[1536] + AMF[n]
#if !(NET_1_1)
            List <object> result = null;
#else
            ArrayList result = null;
#endif
            try
            {
                while (true)
                {
                    long remaining = stream.Remaining;
                    if (context.CanStartDecoding(remaining))
                    {
                        context.StartDecoding();
                    }
                    else
                    {
                        break;
                    }

                    if (context.State == RtmpState.Disconnected)
                    {
                        break;
                    }

                    object decodedObject = Decode(context, stream);
                    if (context.HasDecodedObject)
                    {
#if !(NET_1_1)
                        if (result == null)
                        {
                            result = new List <object>();
                        }
#else
                        if (result == null)
                        {
                            result = new ArrayList();
                        }
#endif
                        result.Add(decodedObject);
                    }
                    else if (context.CanContinueDecoding)
                    {
                        continue;
                    }
                    else
                    {
                        break;
                    }

                    if (!stream.HasRemaining)
                    {
                        break;
                    }
                }
            }
            catch (HandshakeFailedException)
            {
                throw;
            }
            catch (Exception)
            {
                Dump(stream);
                throw;
            }
            finally
            {
                stream.Compact();
            }
            return(result);
        }
		static void EncodeSharedObject(RtmpContext context, ISharedObjectMessage so, ByteBuffer output)
		{
			RtmpWriter writer = new RtmpWriter(output);
            //Set legacy collection flag from context
            writer.UseLegacyCollection = context.UseLegacyCollection;
            writer.UseLegacyThrowable = context.UseLegacyThrowable;

			writer.WriteUTF(so.Name);
			// SO version
			writer.WriteInt32(so.Version);
			// Encoding (this always seems to be 2 for persistent shared objects)
			writer.WriteInt32(so.IsPersistent ? 2 : 0);
			// unknown field
			writer.WriteInt32(0);
			
			int mark, len = 0;

			foreach(ISharedObjectEvent sharedObjectEvent in so.Events)
			{
				byte type = SharedObjectTypeMapping.ToByte(sharedObjectEvent.Type);
				switch(sharedObjectEvent.Type) 
				{
                    case SharedObjectEventType.SERVER_CONNECT:
                    case SharedObjectEventType.CLIENT_INITIAL_DATA:
					case SharedObjectEventType.CLIENT_CLEAR_DATA:
						writer.WriteByte(type);
						writer.WriteInt32(0);
						break;
                    case SharedObjectEventType.SERVER_DELETE_ATTRIBUTE:
                    case SharedObjectEventType.CLIENT_DELETE_DATA:
					case SharedObjectEventType.CLIENT_UPDATE_ATTRIBUTE:
						writer.WriteByte(type);
						mark = (int)output.Position;
						output.Skip(4); // we will be back
						writer.WriteUTF(sharedObjectEvent.Key);
						len = (int)output.Position - mark - 4;
						output.PutInt(mark, len);
						break;
					case SharedObjectEventType.SERVER_SET_ATTRIBUTE:
					case SharedObjectEventType.CLIENT_UPDATE_DATA:
						if (sharedObjectEvent.Key == null) 
						{
							// Update multiple attributes in one request
							IDictionary initialData = sharedObjectEvent.Value as IDictionary;
							foreach(DictionaryEntry entry in initialData)
							{
								writer.WriteByte(type);
								mark = (int)output.Position;
								output.Skip(4); // we will be back
								string key = entry.Key as string;
								object value = entry.Value;
								writer.WriteUTF(key);
								writer.WriteData(context.ObjectEncoding, value);
								
								len = (int)output.Position - mark - 4;
								output.PutInt(mark, len);
							}
						} 
						else 
						{
							writer.WriteByte(type);
							mark = (int)output.Position;
							output.Skip(4); // we will be back
							writer.WriteUTF(sharedObjectEvent.Key);
							writer.WriteData(context.ObjectEncoding, sharedObjectEvent.Value);
							//writer.WriteData(sharedObjectEvent.Value);

							len = (int)output.Position - mark - 4;
							output.PutInt(mark, len);
						}
						break;
					case SharedObjectEventType.CLIENT_SEND_MESSAGE:
					case SharedObjectEventType.SERVER_SEND_MESSAGE:
						// Send method name and value
						writer.WriteByte(type);
						mark = (int)output.Position;
						output.Skip(4); // we will be back

						// Serialize name of the handler to call
						writer.WriteData(context.ObjectEncoding, sharedObjectEvent.Key);
						//writer.WriteUTF(sharedObjectEvent.Key);
						// Serialize the arguments
						foreach(object arg in sharedObjectEvent.Value as IList)
						{
							writer.WriteData(context.ObjectEncoding, arg);
						}
						//writer.WriteData(sharedObjectEvent.Value as IList);
						len = (int)output.Position - mark - 4;
						//output.PutInt(mark, len);
						output.PutInt(mark, len);
						break;
					case SharedObjectEventType.CLIENT_STATUS:
						writer.WriteByte(type);
						mark = (int)output.Position;
						output.Skip(4); // we will be back
						writer.WriteUTF(sharedObjectEvent.Key);
						writer.WriteUTF(sharedObjectEvent.Value as string);
						len = (int)output.Position - mark - 4;
						output.PutInt(mark, len);
						break;
                    case SharedObjectEventType.SERVER_DISCONNECT:
                        writer.WriteByte(type);
                        output.PutInt((int)output.Position, 0);
                        break;
					default:
#if !SILVERLIGHT
                        _log.Error("Unknown event " + sharedObjectEvent.Type.ToString());
#endif
						writer.WriteByte(type);
						mark = (int)output.Position;
						output.Skip(4); // we will be back
                        if (sharedObjectEvent.Key != null)
                        {
                            writer.WriteUTF(sharedObjectEvent.Key);
                            writer.WriteData(context.ObjectEncoding, sharedObjectEvent.Value);
                        }
						len = (int)output.Position - mark - 4;
						output.PutInt(mark, len);
						break;
				}
			}
		}
        /// <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;
		}
 static ByteBuffer EncodeVideoData(RtmpContext context, VideoData videoData)
 {
     ByteBuffer output = videoData.Data;
     return output;
 }
 static ByteBuffer EncodeFlexStreamSend(RtmpContext context, FlexStreamSend msg)
 {
     ByteBuffer output = msg.Data;
     return output;
 }
Beispiel #33
0
        /// <summary>
        /// Decodes handshake message.
        /// </summary>
        /// <param name="context">RTMP protocol state.</param>
        /// <param name="stream">Buffer to be decoded.</param>
        /// <returns>Buffer with handshake response.</returns>
		public static object DecodeHandshake(RtmpContext context, ByteBuffer stream) 
		{
			long remaining = stream.Remaining;
			if(context.Mode == RtmpMode.Server)
			{
				if(context.State == RtmpState.Connect)
				{
					if(remaining < HandshakeSize + 1) 
					{
#if !SILVERLIGHT
                        if( log.IsDebugEnabled )
                            log.Debug(__Res.GetString(__Res.Rtmp_HSInitBuffering, remaining));
#endif
						context.SetBufferDecoding(HandshakeSize + 1);
						return null;
					}
					else 
					{
#if !SILVERLIGHT
                        if (log.IsDebugEnabled)
                            log.Debug("Handshake 1st phase");
#endif

						ByteBuffer hs = ByteBuffer.Allocate(HandshakeSize + 1);
						ByteBuffer.Put(hs, stream, HandshakeSize + 1);
						hs.Flip();
						context.State = RtmpState.Handshake;
						return hs;
                    }
				}
				if(context.State == RtmpState.Handshake)
				{
                    //if (log.IsDebugEnabled)
                    //    log.Debug("Handshake reply");

					if(remaining < HandshakeSize)
					{
#if !SILVERLIGHT
                        if( log.IsDebugEnabled )
							log.Debug(__Res.GetString(__Res.Rtmp_HSReplyBuffering, remaining));
#endif
						context.SetBufferDecoding(HandshakeSize);
						return null;
					}				 
					else 
					{
						ByteBuffer hs = ByteBuffer.Allocate(HandshakeSize);
						ByteBuffer.Put(hs, stream, HandshakeSize);
						hs.Flip();
						context.State = RtmpState.Connected;
						return hs;
					}
				}
			}
			else
			{
				//Client mode
				if(context.State == RtmpState.Connect)
				{
					int size = (2 * HandshakeSize) + 1;
					if(remaining < size) 
					{
#if !SILVERLIGHT
                        if( log.IsDebugEnabled )
							log.Debug(__Res.GetString(__Res.Rtmp_HSInitBuffering, remaining));
#endif
						context.SetBufferDecoding(size);
						return null;
					}
					else
					{
						ByteBuffer hs = ByteBuffer.Allocate(size);
						ByteBuffer.Put(hs, stream, size);
						hs.Flip();
						context.State = RtmpState.Connected;
						return hs;
					}
				}
			}
			return null;
		}
        internal RtmpConnection(IRtmpHandler handler, RtmpMode mode, string path, IDictionary parameters)
            : base(path, parameters)
		{
            _handler = handler;
            _channels = new CopyOnWriteDictionary<int,RtmpChannel>(4);
            _streams = new CopyOnWriteDictionary<int,IClientStream>();
            _pendingVideos = new CopyOnWriteDictionary<int,AtomicInteger>();
            _streamCount = new AtomicInteger();
            _streamBuffers = new CopyOnWriteDictionary<int,int>();
            _reservedStreams = new BitArray(0);
            _pendingCalls = new CopyOnWriteDictionary<int, IServiceCall>();
            _pendingReceive = null;
			// We start with an anonymous connection without a scope.
			// These parameters will be set during the call of "connect" later.
            _context = new RtmpContext(mode);
            //Transaction id depends on server/client mode
            //When server mode is set we cannot push messages with transaction id = 1 (connect)
            _invokeId = mode == RtmpMode.Server ? new AtomicInteger(1) : new AtomicInteger(0);
		}
        /// <summary>
        /// Decodes all available objects in the buffer.
        /// </summary>
        /// <param name="context">State for the protocol.</param>
        /// <param name="stream">Buffer of data to be decoded.</param>
        /// <returns>A list of decoded objects, may be empty if nothing could be decoded.</returns>
		public static List<object> DecodeBuffer(RtmpContext context, ByteBuffer stream)
        public static ArrayList DecodeBuffer(RtmpContext context, ByteBuffer stream)
#endif
		{
			// >> HEADER[1] + CLIENT_HANDSHAKE[1536] 
			// << HEADER[1] + SERVER_HANDSHAKE[1536] + CLIENT_HANDSHAKE[1536];
			// >> SERVER_HANDSHAKE[1536] + AMF[n]
#if !(NET_1_1)
            List<object> result = null;
#else
			ArrayList result = null;
#endif
            try
            {
                while (true)
                {
                    long remaining = stream.Remaining;
                    if (context.CanStartDecoding(remaining))
                        context.StartDecoding();
                    else
                        break;

                    if (context.State == RtmpState.Disconnected)
                        break;

                    object decodedObject = Decode(context, stream);
                    if (context.HasDecodedObject)
                    {
#if !(NET_1_1)
                        if (result == null)
                            result = new List<object>();
#else
                        if (result == null)
                            result = new ArrayList();
#endif
                        result.Add(decodedObject);
                    }
                    else if (context.CanContinueDecoding)
                        continue;
                    else
                        break;

                    if (!stream.HasRemaining)
                        break;
                }
            }
            catch (HandshakeFailedException)
            {
                throw;
            }
            catch (Exception)
            {
                Dump(stream);
                throw;
            }
            finally
			{
			    stream.Compact();
			}
			return result;
		}
		private static object Decode(RtmpContext context, ByteBuffer stream)
		{
			//long start = stream.Position;
			switch(context.State)
			{					
				case RtmpState.Connected:
					return DecodePacket(context, stream);
				case RtmpState.Error:
					// Attempt to correct error 
					return null;
				case RtmpState.Connect:
				case RtmpState.Handshake:
					return DecodeHandshake(context, stream);
				default:
					return null;
			}
		}
 static ByteBuffer EncodeBytesRead(RtmpContext context, BytesRead bytesRead)
 {
     ByteBuffer output = ByteBuffer.Allocate(4);
     output.PutInt(bytesRead.Bytes);
     return output;
 }
 static ByteBuffer EncodeNotify(RtmpContext context,  Notify notify)
 {
     return EncodeNotifyOrInvoke(context, notify);
 }
 static ByteBuffer EncodeAudioData(RtmpContext context, AudioData audioData)
 {
     ByteBuffer output = audioData.Data;
     return output;
 }
		static ByteBuffer EncodeFlexInvoke(RtmpContext context, FlexInvoke invoke)
		{
			ByteBuffer output = ByteBuffer.Allocate(1024);
			output.AutoExpand = true;
			RtmpWriter writer = new RtmpWriter(output);
            //Set legacy collection flag from context
            writer.UseLegacyCollection = context.UseLegacyCollection;
            writer.UseLegacyThrowable = context.UseLegacyThrowable;
			
			writer.WriteByte(0);
			//writer.WriteData(context.ObjectEncoding, invoke.Cmd);
            IServiceCall serviceCall = invoke.ServiceCall;
            bool isPending = serviceCall.Status == Call.STATUS_PENDING;
            if (!isPending)
            {
                //log.debug("Call has been executed, send result");
                if (serviceCall.IsSuccess)
                    writer.WriteData(context.ObjectEncoding, "_result");
                else
                    writer.WriteData(context.ObjectEncoding, "_error");
            }
            else
            {
                //log.debug("This is a pending call, send request");
                writer.WriteData(context.ObjectEncoding, serviceCall.ServiceMethodName);
            }
			writer.WriteData(context.ObjectEncoding, invoke.InvokeId);
			writer.WriteData(context.ObjectEncoding, invoke.CmdData);
			//object response = invoke.Response;
			//writer.WriteData(context.ObjectEncoding, response);
            if (!isPending)
            {
                IPendingServiceCall pendingCall = (IPendingServiceCall)serviceCall;
                /*
                if (!serviceCall.IsSuccess)
                {
                    StatusASO status = GenerateErrorResult(StatusASO.NC_CALL_FAILED, serviceCall.Exception);
                    pendingCall.Result = status;
                }
                */
                writer.WriteData(context.ObjectEncoding, pendingCall.Result);
            }
            else
            {
                //log.debug("Writing params");
                object[] args = invoke.ServiceCall.Arguments;
                if (args != null)
                {
                    foreach (object element in args)
                    {
                        writer.WriteData(context.ObjectEncoding, element);
                    }
                }
            }
			return output;
		}
 static ByteBuffer EncodeStreamMetadata(RtmpContext context, Notify metaData)
 {
     ByteBuffer output = metaData.Data;
     return output;
 }
        /// <summary>
        /// Decodes handshake message.
        /// </summary>
        /// <param name="context">RTMP protocol state.</param>
        /// <param name="stream">Buffer to be decoded.</param>
        /// <returns>Buffer with handshake response.</returns>
		public static object DecodeHandshake(RtmpContext context, ByteBuffer stream) 
		{
			long remaining = stream.Remaining;
			if(context.Mode == RtmpMode.Server)
			{
				if(context.State == RtmpState.Connect)
				{
					if(remaining < HandshakeSize + 1) 
					{
#if !SILVERLIGHT
                        if( log.IsDebugEnabled )
                            log.Debug(__Res.GetString(__Res.Rtmp_HSInitBuffering, remaining));
#endif
						context.SetBufferDecoding(HandshakeSize + 1);
						return null;
					}
					else 
					{
#if !SILVERLIGHT
                        if (log.IsDebugEnabled)
                            log.Debug("Handshake 1st phase");
#endif
                        stream.Get();// skip the header byte
                        byte[] handshake = RtmpHandshake.GetHandshakeResponse(stream);
                        context.SetHandshake(handshake);
                        context.State = RtmpState.Handshake;
                        return handshake;
                    }
				}
				if(context.State == RtmpState.Handshake)
				{
                    //if (log.IsDebugEnabled)
                    //    log.Debug("Handshake reply");

					if(remaining < HandshakeSize)
					{
#if !SILVERLIGHT
                        if( log.IsDebugEnabled )
							log.Debug(__Res.GetString(__Res.Rtmp_HSReplyBuffering, remaining));
#endif
						context.SetBufferDecoding(HandshakeSize);
						return null;
					}				 
					else 
					{
					    // Skip first 8 bytes when comparing the handshake, they seem to be changed when connecting from a Mac client.
                        if (!context.ValidateHandshakeReply(stream, 8, HandshakeSize - 8))
                        {
#if !SILVERLIGHT
                            if (log.IsDebugEnabled)
                                log.Debug("Handshake reply validation failed, disconnecting client.");
#endif
                            stream.Skip(HandshakeSize);
                            context.State = RtmpState.Error;
                            throw new HandshakeFailedException("Handshake validation failed");
                        }
						stream.Skip(HandshakeSize);
						context.State = RtmpState.Connected;
						context.ContinueDecoding();
						return null;
					}
				}
			}
			else
			{
				//Client mode
				if(context.State == RtmpState.Connect)
				{
					int size = (2 * HandshakeSize) + 1;
					if(remaining < size) 
					{
#if !SILVERLIGHT
                        if( log.IsDebugEnabled )
							log.Debug(__Res.GetString(__Res.Rtmp_HSInitBuffering, remaining));
#endif
						context.SetBufferDecoding(size);
						return null;
					}
					else
					{
						ByteBuffer hs = ByteBuffer.Allocate(size);
						ByteBuffer.Put(hs, stream, size);
						hs.Flip();
						context.State = RtmpState.Handshake;
						return hs;
					}
				}
			}
			return null;
		}
		static ByteBuffer EncodeInvoke(RtmpContext context, Invoke invoke) 
		{
			return EncodeNotifyOrInvoke(context, invoke);
		}
		public static ByteBuffer Encode(RtmpContext context, object message)
		{		
			try
			{
				if (message is ByteBuffer) 
					return (ByteBuffer) message;
				else 
					return EncodePacket(context, message as RtmpPacket);
			}			 
			catch(Exception ex) 
			{
#if !SILVERLIGHT
                if( _log != null )
					_log.Fatal("Error encoding object. ", ex);
#endif
			}
			return null;
		}
		static ByteBuffer EncodeNotifyOrInvoke(RtmpContext context, Notify invoke)
		{
			//MemoryStreamEx output = new MemoryStreamEx();
			ByteBuffer output = ByteBuffer.Allocate(1024);
			output.AutoExpand = true;
			RtmpWriter writer = new RtmpWriter(output);
            //Set legacy collection flag from context
            writer.UseLegacyCollection = context.UseLegacyCollection;
            writer.UseLegacyThrowable = context.UseLegacyThrowable;

			IServiceCall serviceCall = invoke.ServiceCall;
			bool isPending = serviceCall.Status == Call.STATUS_PENDING;
			if (!isPending) 
			{
				//log.debug("Call has been executed, send result");
                writer.WriteData(context.ObjectEncoding, serviceCall.IsSuccess ? "_result" : "_error");
			}
			else
			{
				//log.debug("This is a pending call, send request");
				string action = (serviceCall.ServiceName == null) ? serviceCall.ServiceMethodName : serviceCall.ServiceName + "." + serviceCall.ServiceMethodName;
				writer.WriteData(context.ObjectEncoding, action);
			}
			if(invoke is Invoke)
			{
				writer.WriteData(context.ObjectEncoding, invoke.InvokeId);
				writer.WriteData(context.ObjectEncoding, invoke.ConnectionParameters);
			}
			if(!isPending && (invoke is Invoke)) 
			{
				IPendingServiceCall pendingCall = (IPendingServiceCall)serviceCall;
                if (!serviceCall.IsSuccess && !(pendingCall.Result is StatusASO))
                {
                    StatusASO status = GenerateErrorResult(StatusASO.NC_CALL_FAILED, serviceCall.Exception);
                    pendingCall.Result = status;
                }
				writer.WriteData(context.ObjectEncoding, pendingCall.Result);
			}
			else
			{
				//log.debug("Writing params");
				object[] args = invoke.ServiceCall.Arguments;
				if (args != null) 
				{
					foreach(object element in args)
					{
						writer.WriteData(context.ObjectEncoding, element);
					}
				}
			}
			return output;
		}
		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;
		}
		static ByteBuffer EncodeSharedObject(RtmpContext context, ISharedObjectMessage so)
		{
			ByteBuffer output = ByteBuffer.Allocate(128);
			output.AutoExpand = true;
			EncodeSharedObject(context, so, output);
			return output;
		}
		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 all available objects in the buffer.
 /// </summary>
 /// <param name="context">State for the protocol.</param>
 /// <param name="stream">Buffer of data to be decoded.</param>
 /// <returns>A list of decoded objects, may be empty if nothing could be decoded.</returns>
 public static List <object> DecodeBuffer(RtmpContext context, ByteBuffer stream)
 /// <summary>
 /// Encode server-side bandwidth event
 /// </summary>
 /// <param name="context"></param>
 /// <param name="serverBW"></param>
 /// <returns></returns>
 static ByteBuffer EncodeServerBW(RtmpContext context, ServerBW serverBW)
 {
     ByteBuffer output = ByteBuffer.Allocate(4);
     output.PutInt(serverBW.Bandwidth);
     return output;
 }
 static ByteBuffer EncodeClientBW(RtmpContext context, ClientBW clientBW)
 {
     ByteBuffer output = ByteBuffer.Allocate(5);
     output.PutInt(clientBW.Bandwidth);
     output.Put(clientBW.Value2);
     return output;
 }
        static ByteBuffer EncodeChunkSize(RtmpContext context, ChunkSize chunkSize) 
		{
			ByteBuffer output = ByteBuffer.Allocate(4);
			output.PutInt(chunkSize.Size);
			return output;
		}
        /// <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);
        }
 static ByteBuffer EncodePing(RtmpContext context, Ping ping)
 {
     int len = 6;
     if (ping.Value3 != Ping.Undefined)
     {
         len += 4;
     }
     if (ping.Value4 != Ping.Undefined)
     {
         len += 4;
     }
     ByteBuffer output = ByteBuffer.Allocate(len);
     output.PutShort(ping.PingType);
     output.PutInt(ping.Value2);
     if (ping.Value3 != Ping.Undefined)
     {
         output.PutInt(ping.Value3);
     }
     if (ping.Value4 != Ping.Undefined)
     {
         output.PutInt(ping.Value4);
     }
     return output;
 }
        /// <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>
        /// 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;
		}