Exemplo n.º 1
0
        /// <summary>
        /// Analyzes and responds if required to the given <see cref="RTMPPacket"/>.
        /// </summary>
        /// <param name="packet">The <see cref="RTMPPacket"/> to inspect amnd react to.</param>
        /// <returns>0 (false) for OK/Failed/error, 1 for 'Stop or Complete' (true)</returns>
        bool HandleInvoke(RTMPPacket packet)
        {
            bool ret = false;

            if (packet.m_body[0] != 0x02) // make sure it is a string method name we start with
            {
                Logger.Log("HandleInvoke: Sanity failed. no string method in invoke packet");
                return false;
            }

            AMFObject obj = new AMFObject();
            int nRes = obj.Decode(packet.m_body, 0, (int)packet.m_nBodySize, false);
            if (nRes < 0)
            {
                Logger.Log("HandleInvoke: error decoding invoke packet");
                return false;
            }

            obj.Dump();
            string method = obj.GetProperty(0).GetString();
            double txn = obj.GetProperty(1).GetNumber();

            Logger.Log(string.Format("server invoking <{0}>", method));

            if (method == "_result")
            {
                string methodInvoked = m_methodCalls.Dequeue();

                Logger.Log(string.Format("received result for method call <{0}>", methodInvoked));

                if (methodInvoked == "connect")
                {
                    if (!string.IsNullOrEmpty(Link.token))
                    {
                        List<AMFObjectProperty> props = new List<AMFObjectProperty>();
                        obj.FindMatchingProperty("secureToken", props, int.MaxValue);
                        if (props.Count > 0)
                        {
                            string decodedToken = Tea.Decrypt(props[0].GetString(), Link.token);
                            SendSecureTokenResponse(decodedToken);
                        }
                    }
                    SendServerBW();
                    if (!SkipCreateStream)
                    {
                        SendPing(3, 0, 300);
                        SendCreateStream();
                    }
                    if (!string.IsNullOrEmpty(Link.subscribepath)) SendFCSubscribe(Link.subscribepath);
                    else if (Link.bLiveStream) SendFCSubscribe(Link.playpath);
                }
                else if (methodInvoked == "createStream")
                {
                    m_stream_id = (int)obj.GetProperty(3).GetNumber();
                    SendPlay();
                    SendPing(3, (uint)m_stream_id, (uint)m_nBufferMS);
                }
                else if (methodInvoked == "play")
                {
                    Playing = true;
                }
            }
            else if (method == "onBWDone")
            {
                if (m_nBWCheckCounter == 0) SendCheckBW();
            }
            else if (method == "_onbwcheck")
            {
                SendCheckBWResult(txn);
            }
            else if (method == "_onbwdone")
            {
                if (m_methodCalls.Contains("_checkbw"))
                {
                    string[] queue = m_methodCalls.ToArray();
                    m_methodCalls.Clear();
                    for (int i = 0; i < queue.Length; i++) if (queue[i] != "_checkbw") m_methodCalls.Enqueue(queue[i]);
                }
            }
            else if (method == "_error")
            {
                Logger.Log("rtmp server sent error");
            }
            else if (method == "close")
            {
                Logger.Log("rtmp server requested close");
                Close();
            }
            else if (method == "onStatus")
            {
                string code = obj.GetProperty(3).GetObject().GetProperty("code").GetString();
                string level = obj.GetProperty(3).GetObject().GetProperty("level").GetString();

                Logger.Log(string.Format("onStatus: code :{0}, level: {1}", code, level));

                if (code == "NetStream.Failed" || code == "NetStream.Play.Failed" || code == "NetStream.Play.StreamNotFound" || code == "NetConnection.Connect.InvalidApp")
                {
                    Close();
                }
                else if (code == "NetStream.Play.Start" || code == "NetStream.Publish.Start")
                {
                    Playing = true;
                }
                else if (code == "NetStream.Play.Complete" || code == "NetStream.Play.Stop")
                {
                    Close();
                    ret = true;
                }
                else if (code == "NetStream.Pause.Notify")
                {
                    if (Pausing == 1 || Pausing == 2)
                    {
                        SendPause(false);
                        Pausing = 3;
                    }
                }
            }
            else if (MethodHookHandler != null)
            {
                ret = MethodHookHandler(method, obj, this);
            }
            else
            {

            }

            return ret;
        }
Exemplo n.º 2
0
        public bool GetExpectedPacket(string expectedMethod, out AMFObject obj)
        {
            RTMPPacket packet = null;
            obj = null;
            bool ready = false;
            while (!ready && IsConnected() && ReadPacket(out packet))
            {
                if (!packet.IsReady()) continue; // keep reading until complete package has arrived
                if (packet.PacketType != PacketType.Invoke)
                    Logger.Log(string.Format("Ignoring packet of type {0}", packet.PacketType));
                else
                {
                    if (packet.m_body[0] != 0x02) // make sure it is a string method name we start with
                    {
                        Logger.Log("GetExpectedPacket: Sanity failed. no string method in invoke packet");
                        return false;
                    }

                    obj = new AMFObject();
                    int nRes = obj.Decode(packet.m_body, 0, (int)packet.m_nBodySize, false);
                    if (nRes < 0)
                    {
                        Logger.Log("GetExpectedPacket: error decoding invoke packet");
                        return false;
                    }

                    obj.Dump();
                    string method = obj.GetProperty(0).GetString();
                    double txn = obj.GetProperty(1).GetNumber();
                    Logger.Log(string.Format("server invoking <{0}>", method));
                    if (method == "_result" && m_methodCalls.Count > 0)
                    {
                        string methodInvoked = m_methodCalls.Dequeue();
                        Logger.Log(string.Format("received result for method call <{0}>", methodInvoked));
                    }
                    ready = method == expectedMethod;
                }
            }
            return ready;
        }
Exemplo n.º 3
0
        void HandleMetadata(byte[] buffer, int offset, int size)
        {
            AMFObject obj = new AMFObject();
            int nRes = obj.Decode(buffer, offset, size, false);
            if (nRes < 0)
            {
                //Log(LOGERROR, "%s, error decoding meta data packet", __FUNCTION__);
                return;
            }

            if (!Playing) obj.Dump();
            string metastring = obj.GetProperty(0).GetString();

            if (metastring == "onMetaData")
            {
                if (Playing) obj.Dump(); // always dump metadata for further analyzing

                List<AMFObjectProperty> props = new List<AMFObjectProperty>();
                obj.FindMatchingProperty("duration", props, 1);
                if (props.Count > 0)
                {
                    Duration = props[0].GetNumber();
                    Logger.Log(string.Format("Set duration: {0}", Duration));
                }
                props.Clear();
                obj.FindMatchingProperty("audiodatarate", props, 1);
                if (props.Count > 0)
                {
                    int audiodatarate = (int)props[0].GetNumber();
                    CombinedBitrates += audiodatarate;
                    Logger.Log(string.Format("audiodatarate: {0}", audiodatarate));
                }
                props.Clear();
                obj.FindMatchingProperty("videodatarate", props, 1);
                if (props.Count > 0)
                {
                    int videodatarate = (int)props[0].GetNumber();
                    CombinedBitrates += videodatarate;
                    Logger.Log(string.Format("videodatarate: {0}", videodatarate));
                }
                if (CombinedTracksLength == 0)
                {
                    props.Clear();
                    obj.FindMatchingProperty("filesize", props, int.MaxValue);
                    if (props.Count > 0)
                    {
                        CombinedTracksLength = (int)props[0].GetNumber();
                        Logger.Log(string.Format("Set CombinedTracksLength from filesize: {0}", CombinedTracksLength));
                    }
                }
                if (CombinedTracksLength == 0)
                {
                    props.Clear();
                    obj.FindMatchingProperty("datasize", props, int.MaxValue);
                    if (props.Count > 0)
                    {
                        CombinedTracksLength = (int)props[0].GetNumber();
                        Logger.Log(string.Format("Set CombinedTracksLength from datasize: {0}", CombinedTracksLength));
                    }
                }
            }
        }
Exemplo n.º 4
0
 public void Reset()
 {
     m_dNumVal = 0.0;
     m_strVal = "";
     m_objVal = null;
     m_type = AMFDataType.AMF_INVALID;
 }
Exemplo n.º 5
0
        public int Decode(byte[] pBuffer, int bufferOffset, int nSize, bool bDecodeName)
        {
            int nOriginalSize = nSize;

            if (nSize == 0 || pBuffer == null)
                return -1;

            if (pBuffer[bufferOffset] == 0x05)
            {
                m_type = AMFDataType.AMF_NULL;
                return 1;
            }

            if (bDecodeName && nSize < 4) // at least name (length + at least 1 byte) and 1 byte of data
                return -1;

            if (bDecodeName)
            {
                ushort nNameSize = RTMP.ReadInt16(pBuffer, bufferOffset);
                if (nNameSize > nSize - (short)sizeof(short))
                    return -1;

                m_strName = RTMP.ReadString(pBuffer, bufferOffset);
                nSize -= sizeof(short) + m_strName.Length;
                bufferOffset += sizeof(short) + m_strName.Length;
            }

            if (nSize == 0)
                return -1;

            nSize--;

            switch (pBuffer[bufferOffset])
            {
                case (byte)AMFDataType.AMF_NUMBER:
                    if (nSize < (int)sizeof(double))
                        return -1;
                    m_dNumVal = RTMP.ReadNumber(pBuffer, bufferOffset + 1);
                    nSize -= sizeof(double);
                    m_type = AMFDataType.AMF_NUMBER;
                    break;
                case (byte)AMFDataType.AMF_BOOLEAN:
                    if (nSize < 1)
                        return -1;
                    m_dNumVal = Convert.ToDouble(RTMP.ReadBool(pBuffer, bufferOffset + 1));
                    nSize--;
                    m_type = AMFDataType.AMF_BOOLEAN;
                    break;
                case (byte)AMFDataType.AMF_STRING:
                    {
                        ushort nStringSize = RTMP.ReadInt16(pBuffer, bufferOffset + 1);
                        if (nSize < nStringSize + (int)sizeof(short))
                            return -1;
                        m_strVal = RTMP.ReadString(pBuffer, bufferOffset + 1);
                        nSize -= sizeof(short) + nStringSize;
                        m_type = AMFDataType.AMF_STRING;
                        break;
                    }
                case (byte)AMFDataType.AMF_OBJECT:
                    {
                        m_objVal = new AMFObject();
                        int nRes = m_objVal.Decode(pBuffer, bufferOffset + 1, nSize, true);
                        if (nRes == -1)
                            return -1;
                        nSize -= nRes;
                        m_type = AMFDataType.AMF_OBJECT;
                        break;
                    }
                case (byte)AMFDataType.AMF_MOVIECLIP:
                    {
                        Logger.Log("AMF_MOVIECLIP reserved!");
                        return -1;
                    }
                case (byte)AMFDataType.AMF_NULL:
                case (byte)AMFDataType.AMF_UNDEFINED:
                case (byte)AMFDataType.AMF_UNSUPPORTED:
                    {
                        m_type = AMFDataType.AMF_NULL;
                        break;
                    }
                case (byte)AMFDataType.AMF_REFERENCE:
                    {
                        Logger.Log("AMF_REFERENCE not supported!");
                        return -1;
                    }
                case (byte)AMFDataType.AMF_ECMA_ARRAY:
                    {
                        //int nMaxIndex = RTMP_LIB::CRTMP::ReadInt32(pBuffer+1); // can be zero for unlimited
                        nSize -= 4;

                        // next comes the rest, mixed array has a final 0x000009 mark and names, so its an object
                        m_objVal = new AMFObject();
                        int nRes = m_objVal.Decode(pBuffer, bufferOffset + 5, nSize, true);
                        if (nRes == -1)
                            return -1;
                        nSize -= nRes;
                        m_type = AMFDataType.AMF_OBJECT;
                        break;
                    }
                case (byte)AMFDataType.AMF_OBJECT_END:
                    {
                        return -1;
                    }
                case (byte)AMFDataType.AMF_STRICT_ARRAY:
                    {
                        int nArrayLen = RTMP.ReadInt32(pBuffer, bufferOffset + 1);
                        nSize -= 4;

                        m_objVal = new AMFObject();
                        int nRes = m_objVal.DecodeArray(pBuffer, bufferOffset + 5, nSize, nArrayLen, false);
                        if (nRes == -1)
                            return -1;
                        nSize -= nRes;
                        m_type = AMFDataType.AMF_OBJECT;
                        break;
                    }
                case (byte)AMFDataType.AMF_DATE:
                    {
                        if (nSize < 10) return -1;
                        p_number = RTMP.ReadNumber(pBuffer, bufferOffset + 1);
                        p_UTCoffset = RTMP.ReadInt16(pBuffer, bufferOffset + 9);
                        nSize -= 10;
                        break;
                    }
                case (byte)AMFDataType.AMF_LONG_STRING:
                    {
                        int nStringSize = RTMP.ReadInt32(pBuffer, bufferOffset + 1);
                        if (nSize < nStringSize + 4) return -1;
                        m_strVal = RTMP.ReadLongString(pBuffer, bufferOffset + 1);
                        nSize -= (4 + nStringSize);
                        m_type = AMFDataType.AMF_STRING;
                        break;
                    }
                case (byte)AMFDataType.AMF_RECORDSET:
                    {
                        Logger.Log("AMF_RECORDSET reserved!");
                        return -1;
                    }
                case (byte)AMFDataType.AMF_XML_DOC:
                    {
                        Logger.Log("AMF_XML_DOC not supported!");
                        return -1;
                    }
                case (byte)AMFDataType.AMF_TYPED_OBJECT:
                    {
                        Logger.Log("AMF_TYPED_OBJECT not supported!");
                        return -1;
                    }
                default:
                    Logger.Log(string.Format("unknown datatype {0}", pBuffer[bufferOffset]));
                    return -1;
            }

            return nOriginalSize - nSize;
        }
Exemplo n.º 6
0
        public static AMFObject ParseAMF(string amfString)
        {
            int depth = 0;

            AMFObject obj = new AMFObject();

            string[] args = amfString.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

            foreach (string arg in args)
            {
                AMFObjectProperty prop = new AMFObjectProperty();
                string p;

                if (arg[1] == ':')
                {
                    p = arg.Substring(2);
                    switch (arg[0])
                    {
                        case 'B':
                            prop.m_type = AMFDataType.AMF_BOOLEAN;
                            prop.p_number = int.Parse(p);
                            break;
                        case 'S':
                            prop.m_type = AMFDataType.AMF_STRING;
                            prop.m_strVal = p;
                            break;
                        case 'N':
                            prop.m_type = AMFDataType.AMF_NUMBER;
                            prop.p_number = double.Parse(p);
                            break;
                        case 'Z':
                            prop.m_type = AMFDataType.AMF_NULL;
                            break;
                        case 'O':
                            int i = int.Parse(p);
                            if (i > 0)
                            {
                                prop.m_type = AMFDataType.AMF_OBJECT;
                            }
                            else
                            {
                                depth--;
                                return obj;
                            }
                            break;
                        default:
                            return null;
                    }
                }
                else if (arg[2] == ':' && arg[0] == 'N')
                {
                    int secondColonIndex = arg.IndexOf(':', 3);
                    if (secondColonIndex < 0 || depth <= 0) return null;
                    prop.m_strName = arg.Substring(3);
                    p = arg.Substring(secondColonIndex + 1);
                    switch (arg[1])
                    {
                        case 'B':
                            prop.m_type = AMFDataType.AMF_BOOLEAN;
                            prop.p_number = int.Parse(p);
                            break;
                        case 'S':
                            prop.m_type = AMFDataType.AMF_STRING;
                            prop.m_strVal = p;
                            break;
                        case 'N':
                            prop.m_type = AMFDataType.AMF_NUMBER;
                            prop.p_number = double.Parse(p);
                            break;
                        case 'O':
                            prop.m_type = AMFDataType.AMF_OBJECT;
                            break;
                        default:
                            return null;
                    }
                }
                else
                    return null;

                if (depth > 0)
                {
                    AMFObject o2;
                    for (int i = 0; i < depth; i++)
                    {
                        o2 = obj.GetProperty(obj.GetPropertyCount() - 1).GetObject();
                        obj = o2;
                    }
                }
                obj.AddProperty(prop);

                if (prop.m_type == AMFDataType.AMF_OBJECT)
                    depth++;
            }

            return obj;
        }