Пример #1
0
        bool SendSecureTokenResponse(string resp)
        {
            RTMPPacket packet = new RTMPPacket();
            packet.m_nChannel = 0x03;	/* control channel (invoke) */
            packet.HeaderType = HeaderType.Medium;
            packet.PacketType = PacketType.Invoke;

            Logger.Log(string.Format("Sending SecureTokenResponse: {0}", resp));
            List<byte> enc = new List<byte>();
            EncodeString(enc, "secureTokenResponse");
            EncodeNumber(enc, 0.0);
            enc.Add(0x05); // NULL
            EncodeString(enc, resp);

            packet.m_nBodySize = (uint)enc.Count;
            packet.m_body = enc.ToArray();

            return SendPacket(packet, false);
        }
Пример #2
0
 void HandleMetadata(RTMPPacket packet)
 {
     HandleMetadata(packet.m_body, 0, (int)packet.m_nBodySize);
 }
Пример #3
0
        bool SendPlay()
        {
            RTMPPacket packet = new RTMPPacket();
            packet.m_nChannel = 0x08;   // we make 8 our stream channel
            packet.HeaderType = HeaderType.Large;
            packet.PacketType = PacketType.Invoke;
            packet.m_nInfoField2 = m_stream_id;

            packet.AllocPacket(256); // should be enough
            List<byte> enc = new List<byte>();

            EncodeString(enc, "play");
            EncodeNumber(enc, ++m_numInvokes);
            enc.Add(0x05); // NULL

            EncodeString(enc, Link.playpath);

            /* Optional parameters start and len.
             *
             * start: -2, -1, 0, positive number
             *  -2: looks for a live stream, then a recorded stream, if not found any open a live stream
             *  -1: plays a live stream
             * >=0: plays a recorded streams from 'start' milliseconds
            */
            if (Link.bLiveStream)
            {
                EncodeNumber(enc, -1000.0d);
            }
            else
            {
                if (Link.seekTime > 0.0)
                    EncodeNumber(enc, Link.seekTime);
                else
                    EncodeNumber(enc, 0.0d);
            }
            /* len: -1, 0, positive number
             *  -1: plays live or recorded stream to the end (default)
             *   0: plays a frame 'start' ms away from the beginning
             *  >0: plays a live or recoded stream for 'len' milliseconds
             */

            packet.m_body = enc.ToArray();
            packet.m_nBodySize = (uint)enc.Count;

            Logger.Log(string.Format("Sending play: '{0}' from time: '{1}'", Link.playpath, m_channelTimestamp[m_mediaChannel]));

            return SendPacket(packet);
        }
Пример #4
0
 void HandleChangeChunkSize(RTMPPacket packet)
 {
     if (packet.m_nBodySize >= 4)
     {
         InChunkSize = ReadInt32(packet.m_body, 0);
         Logger.Log(string.Format("received: chunk size change to {0}", InChunkSize));
     }
 }
Пример #5
0
        void HandleFlvTags(RTMPPacket packet)
        {
            // go through FLV packets and handle metadata packets
            int pos = 0;
            uint nTimeStamp = packet.m_nTimeStamp;

            while (pos + 11 < packet.m_nBodySize)
            {
                int dataSize = ReadInt24(packet.m_body, pos + 1); // size without header (11) and prevTagSize (4)

                if (pos + 11 + dataSize + 4 > packet.m_nBodySize)
                {
                    Logger.Log("Stream corrupt?!");
                    break;
                }
                if (packet.m_body[pos] == 0x12)
                {
                    HandleMetadata(packet.m_body, pos + 11, dataSize);
                }
                else if (packet.m_body[pos] == 8 || packet.m_body[pos] == 9)
                {
                    nTimeStamp = (uint)ReadInt24(packet.m_body, pos + 4);
                    nTimeStamp |= (uint)(packet.m_body[pos + 7] << 24);
                }
                pos += (11 + dataSize + 4);
            }
            if (Pausing == 0) m_mediaStamp = nTimeStamp;
        }
Пример #6
0
        public bool SendCreateStream()
        {
            RTMPPacket packet = new RTMPPacket();
            packet.m_nChannel = 0x03;   // control channel (invoke)
            packet.HeaderType = HeaderType.Medium;
            packet.PacketType = PacketType.Invoke;

            Logger.Log("Sending createStream");
            packet.AllocPacket(256); // should be enough
            List<byte> enc = new List<byte>();
            EncodeString(enc, "createStream");
            EncodeNumber(enc, ++m_numInvokes);
            enc.Add(0x05); // NULL

            packet.m_nBodySize = (uint)enc.Count;
            packet.m_body = enc.ToArray();

            return SendPacket(packet);
        }
Пример #7
0
        public bool SendRequestData(string id, string request)
        {
            RTMPPacket packet = new RTMPPacket();
            packet.m_nChannel = 0x03;   // control channel (invoke)
            packet.HeaderType = HeaderType.Large;
            packet.PacketType = PacketType.Invoke_AMF3;

            List<byte> enc = new List<byte>();
            enc.Add(0x00);
            EncodeString(enc, "requestData");
            EncodeNumber(enc, 0);
            enc.Add(0x05); // NULL
            EncodeString(enc, id);
            EncodeString(enc, request);

            packet.m_body = enc.ToArray();
            packet.m_nBodySize = (uint)enc.Count;

            Logger.Log(string.Format("Sending requestData: ({0},{1})", id, request));

            return SendPacket(packet);
        }
Пример #8
0
        bool SendCheckBWResult(double txn)
        {
            RTMPPacket packet = new RTMPPacket();
            packet.m_nChannel = 0x03;   // control channel (invoke)
            packet.HeaderType = HeaderType.Medium;
            packet.PacketType = PacketType.Invoke;
            packet.m_nTimeStamp = (uint)(0x16 * m_nBWCheckCounter); // temp inc value. till we figure it out.

            packet.AllocPacket(256); // should be enough
            List<byte> enc = new List<byte>();
            EncodeString(enc, "_result");
            EncodeNumber(enc, txn);
            enc.Add(0x05); // NULL
            EncodeNumber(enc, (double)m_nBWCheckCounter++);

            packet.m_nBodySize = (uint)enc.Count;
            packet.m_body = enc.ToArray();

            return SendPacket(packet, false);
        }
Пример #9
0
        bool SendConnect()
        {
            RTMPPacket packet = new RTMPPacket();
            packet.m_nChannel = 0x03;   // control channel (invoke)
            packet.HeaderType = HeaderType.Large;
            packet.PacketType = PacketType.Invoke;
            packet.AllocPacket(4096);

            Logger.Log("Sending connect");
            List<byte> enc = new List<byte>();
            EncodeString(enc, "connect");
            EncodeNumber(enc, ++m_numInvokes);
            enc.Add(0x03); //Object Datatype
            EncodeString(enc, "app", Link.app); Logger.Log(string.Format("app : {0}", Link.app));
            if (String.IsNullOrEmpty(Link.flashVer))
                EncodeString(enc, "flashVer", "WIN 10,0,32,18");
            else
                EncodeString(enc, "flashVer", Link.flashVer);
            if (!string.IsNullOrEmpty(Link.swfUrl)) EncodeString(enc, "swfUrl", Link.swfUrl);
            EncodeString(enc, "tcUrl", Link.tcUrl); Logger.Log(string.Format("tcUrl : {0}", Link.tcUrl));
            EncodeBoolean(enc, "fpad", false);
            EncodeNumber(enc, "capabilities", 15.0);
            EncodeNumber(enc, "audioCodecs", 3191.0);
            EncodeNumber(enc, "videoCodecs", 252.0);
            EncodeNumber(enc, "videoFunction", 1.0);
            if (!string.IsNullOrEmpty(Link.pageUrl)) EncodeString(enc, "pageUrl", Link.pageUrl);
            //EncodeNumber(enc, "objectEncoding", 0.0);
            enc.Add(0); enc.Add(0); enc.Add(0x09); // end of object - 0x00 0x00 0x09

            // add auth string
            if (!string.IsNullOrEmpty(Link.auth))
            {
                EncodeBoolean(enc, true);
                EncodeString(enc, Link.auth);
            }

            // add aditional arbitrary AMF connection properties
            if (Link.extras != null)
            {
                foreach (AMFObjectProperty aProp in Link.extras.m_properties) aProp.Encode(enc);
            }

            Array.Copy(enc.ToArray(), packet.m_body, enc.Count);
            packet.m_nBodySize = (uint)enc.Count;

            return SendPacket(packet);
        }
Пример #10
0
        bool SendBytesReceived()
        {
            RTMPPacket packet = new RTMPPacket();
            packet.m_nChannel = 0x02;   // control channel (invoke)
            packet.HeaderType = HeaderType.Medium;
            packet.PacketType = PacketType.BytesRead;

            packet.AllocPacket(4);
            packet.m_nBodySize = 4;

            List<byte> enc = new List<byte>();
            EncodeInt32(enc, bytesReadTotal);
            packet.m_nBodySize = (uint)enc.Count;
            packet.m_body = enc.ToArray();

            lastSentBytesRead = bytesReadTotal;
            Logger.Log(string.Format("Send bytes report. ({0} bytes)", bytesReadTotal));
            return SendPacket(packet, false);
        }
Пример #11
0
        bool SendCheckBW()
        {
            RTMPPacket packet = new RTMPPacket();
            packet.m_nChannel = 0x03;   // control channel (invoke)

            packet.HeaderType = HeaderType.Large;
            packet.PacketType = PacketType.Invoke;
            //packet.m_nInfoField1 = System.Environment.TickCount;

            Logger.Log("Sending _checkbw");
            List<byte> enc = new List<byte>();
            EncodeString(enc, "_checkbw");
            EncodeNumber(enc, ++m_numInvokes);
            enc.Add(0x05); // NULL

            packet.m_nBodySize = (uint)enc.Count;
            packet.m_body = enc.ToArray();

            // triggers _onbwcheck and eventually results in _onbwdone
            return SendPacket(packet, false);
        }
Пример #12
0
        bool ReadPacket(out RTMPPacket packet)
        {
            // Chunk Basic Header (1, 2 or 3 bytes)
            // the two most significant bits hold the chunk type
            // value in the 6 least significant bits gives the chunk stream id (0,1,2 are reserved): 0 -> 3 byte header | 1 -> 2 byte header | 2 -> low level protocol message | 3-63 -> stream id
            byte[] singleByteToReadBuffer = new byte[1];
            if (ReadN(singleByteToReadBuffer, 0, 1) != 1)
            {
                Logger.Log("failed to read RTMP packet header");
                packet = null;
                return false;
            }

            byte type = singleByteToReadBuffer[0];

            byte headerType = (byte)((type & 0xc0) >> 6);
            int channel = (byte)(type & 0x3f);

            if (channel == 0)
            {
                if (ReadN(singleByteToReadBuffer, 0, 1) != 1)
                {
                    Logger.Log("failed to read RTMP packet header 2nd byte");
                    packet = null;
                    return false;
                }
                channel = singleByteToReadBuffer[0];
                channel += 64;
                //header++;
            }
            else if (channel == 1)
            {
                int tmp;
                byte[] hbuf = new byte[2];

                if (ReadN(hbuf, 0, 2) != 2)
                {
                    Logger.Log("failed to read RTMP packet header 3rd and 4th byte");
                    packet = null;
                    return false;
                }
                tmp = ((hbuf[2]) << 8) + hbuf[1];
                channel = tmp + 64;
                Logger.Log(string.Format("channel: {0}", channel));
                //header += 2;
            }

            uint nSize = packetSize[headerType];

            //Logger.Log(string.Format("reading RTMP packet chunk on channel {0}, headersz {1}", channel, nSize));

            if (nSize < RTMP_LARGE_HEADER_SIZE)
                packet = m_vecChannelsIn[channel]; // using values from the last message of this channel
            else
                packet = new RTMPPacket() { HeaderType = (HeaderType)headerType, m_nChannel = channel, m_hasAbsTimestamp = true }; // new packet

            nSize--;

            byte[] header = new byte[RTMP_LARGE_HEADER_SIZE];
            if (nSize > 0 && ReadN(header, 0, (int)nSize) != nSize)
            {
                Logger.Log(string.Format("failed to read RTMP packet header. type: {0}", type));
                return false;
            }

            if (nSize >= 3)
            {
                packet.m_nTimeStamp = (uint)ReadInt24(header, 0);

                if (nSize >= 6)
                {
                    packet.m_nBodySize = (uint)ReadInt24(header, 3);
                    //Logger.Log(string.Format("new packet body to read {0}", packet.m_nBodySize));
                    packet.m_nBytesRead = 0;
                    packet.Free(); // new packet body

                    if (nSize > 6)
                    {
                        if (Enum.IsDefined(typeof(PacketType), header[6])) packet.PacketType = (PacketType)header[6];
                        else Logger.Log(string.Format("Unknown packet type received: {0}", header[6]));

                        if (nSize == 11)
                            packet.m_nInfoField2 = ReadInt32LE(header, 7);
                    }
                }

                if (packet.m_nTimeStamp == 0xffffff)
                {
                    byte[] extendedTimestampDate = new byte[4];
                    if (ReadN(extendedTimestampDate, 0, 4) != 4)
                    {
                        Logger.Log("failed to read extended timestamp");
                        return false;
                    }
                    packet.m_nTimeStamp = (uint)ReadInt32(extendedTimestampDate, 0);
                }
            }

            if (packet.m_nBodySize >= 0 && packet.m_body == null && !packet.AllocPacket((int)packet.m_nBodySize))
            {
                //CLog::Log(LOGDEBUG,"%s, failed to allocate packet", __FUNCTION__);
                return false;
            }

            uint nToRead = packet.m_nBodySize - packet.m_nBytesRead;
            uint nChunk = (uint)InChunkSize;
            if (nToRead < nChunk)
                nChunk = nToRead;

            int read = ReadN(packet.m_body, (int)packet.m_nBytesRead, (int)nChunk);
            if (read != nChunk)
            {
                Logger.Log(string.Format("failed to read RTMP packet body. total:{0}/{1} chunk:{2}/{3}", packet.m_nBytesRead, packet.m_nBodySize, read, nChunk));
                packet.m_body = null; // we dont want it deleted since its pointed to from the stored packets (m_vecChannelsIn)
                return false;
            }

            packet.m_nBytesRead += nChunk;

            // keep the packet as ref for other packets on this channel
            m_vecChannelsIn[packet.m_nChannel] = packet.ShallowCopy();

            if (packet.IsReady())
            {
                //Logger.Log(string.Format("packet with {0} bytes read", packet.m_nBytesRead));

                // make packet's timestamp absolute
                if (!packet.m_hasAbsTimestamp)
                    packet.m_nTimeStamp += m_channelTimestamp[packet.m_nChannel]; // timestamps seem to be always relative!!
                m_channelTimestamp[packet.m_nChannel] = packet.m_nTimeStamp;

                // reset the data from the stored packet. we keep the header since we may use it later if a new packet for this channel
                // arrives and requests to re-use some info (small packet header)
                m_vecChannelsIn[packet.m_nChannel].m_body = null;
                m_vecChannelsIn[packet.m_nChannel].m_nBytesRead = 0;
                m_vecChannelsIn[packet.m_nChannel].m_hasAbsTimestamp = false; // can only be false if we reuse header
            }

            return true;
        }
Пример #13
0
 void HandleServerBW(RTMPPacket packet)
 {
     m_nServerBW = ReadInt32(packet.m_body, 0);
     Logger.Log(string.Format("HandleServerBW: server BW = {0}", m_nServerBW));
 }
Пример #14
0
        void HandlePing(RTMPPacket packet)
        {
            short nType = -1;
            if (packet.m_body != null && packet.m_nBodySize >= 2)
                nType = (short)ReadInt16(packet.m_body, 0);

            Logger.Log(string.Format("received: ping, type: {0}", nType));

            if (packet.m_nBodySize >= 6)
            {
                uint nTime = (uint)ReadInt32(packet.m_body, 2);
                switch (nType)
                {
                    case 0:
                        Logger.Log(string.Format("Stream Begin {0}", nTime));
                        break;
                    case 1:
                        Logger.Log(string.Format("Stream EOF {0}", nTime));
                        if (Pausing == 1) Pausing = 2;
                        break;
                    case 2:
                        Logger.Log(string.Format("Stream Dry {0}", nTime));
                        break;
                    case 4:
                        Logger.Log(string.Format("Stream IsRecorded {0}", nTime));
                        break;
                    case 6:
                        // server ping. reply with pong.
                        Logger.Log(string.Format("Ping {0}", nTime));
                        SendPing(0x07, nTime, 0);
                        break;
                    case 31:
                        Logger.Log(string.Format("Stream BufferEmpty {0}", nTime));
                        if (!Link.bLiveStream)
                        {
                            if (Pausing == 0)
                            {
                                SendPause(true);
                                Pausing = 1;
                            }
                            else if (Pausing == 2)
                            {
                                SendPause(false);
                                Pausing = 3;
                            }
                        }
                        break;
                    case 32:
                        Logger.Log(string.Format("Stream BufferReady {0}", nTime));
                        break;
                    default:
                        Logger.Log(string.Format("Stream xx {0}", nTime));
                        break;
                }
            }

            if (nType == 0x1A)
            {
                if (packet.m_nBodySize > 2 && packet.m_body[2] > 0x01)
                {
                    Logger.Log(string.Format("SWFVerification Type {0} request not supported! Patches welcome...", packet.m_body[2]));
                }
                else if (Link.SWFHash != null) // respond with HMAC SHA256 of decompressed SWF, key is the 30 byte player key, also the last 30 bytes of the server handshake are applied
                {
                    SendPing(0x1B, 0, 0);
                }
                else
                {
                    Logger.Log("Ignoring SWFVerification request, swfhash and swfsize parameters not set!");
                }
            }
        }
Пример #15
0
        bool SendServerBW()
        {
            RTMPPacket packet = new RTMPPacket();
            packet.m_nChannel = 0x02;   // control channel (invoke)
            packet.HeaderType = HeaderType.Large;
            packet.PacketType = PacketType.ServerBW;

            packet.AllocPacket(4);
            packet.m_nBodySize = 4;

            List<byte> bytesToSend = new List<byte>();
            EncodeInt32(bytesToSend, m_nServerBW); // was hard coded : 0x001312d0
            packet.m_body = bytesToSend.ToArray();
            return SendPacket(packet, false);
        }
Пример #16
0
        bool SendDeleteStream()
        {
            RTMPPacket packet = new RTMPPacket();
            packet.m_nChannel = 0x03;   // control channel (invoke)
            packet.HeaderType = HeaderType.Medium;
            packet.PacketType = PacketType.Invoke;

            Logger.Log("Sending deleteStream");
            List<byte> enc = new List<byte>();
            EncodeString(enc, "deleteStream");
            EncodeNumber(enc, ++m_numInvokes);
            enc.Add(0x05); // NULL
            EncodeNumber(enc, m_stream_id);

            packet.m_nBodySize = (uint)enc.Count;
            packet.m_body = enc.ToArray();

            /* no response expected */
            return SendPacket(packet, false);
        }
Пример #17
0
        public int GetNextMediaPacket(out RTMPPacket packet)
        {
            int bHasMediaPacket = 0;
            packet = null;

            while (bHasMediaPacket == 0 && IsConnected() && ReadPacket(out packet))
            {
                if (!packet.IsReady()) continue; // keep reading until complete package has arrived
                bHasMediaPacket = ClientPacket(packet);
                if (bHasMediaPacket > 0 && Pausing == 3) Pausing = 0;
                packet.m_nBytesRead = 0;
            }
            if (bHasMediaPacket > 0) Playing = true;
            return bHasMediaPacket;
        }
Пример #18
0
        bool SendFCSubscribe(string subscribepath)
        {
            RTMPPacket packet = new RTMPPacket();
            packet.m_nChannel = 0x03;   // control channel (invoke)
            packet.HeaderType = HeaderType.Medium;
            packet.PacketType = PacketType.Invoke;

            Logger.Log(string.Format("Sending FCSubscribe: {0}", subscribepath));
            List<byte> enc = new List<byte>();
            EncodeString(enc, "FCSubscribe");
            EncodeNumber(enc, ++m_numInvokes);
            enc.Add(0x05); // NULL
            EncodeString(enc, subscribepath);

            packet.m_nBodySize = (uint)enc.Count;
            packet.m_body = enc.ToArray();

            return SendPacket(packet);
        }
Пример #19
0
        public bool SendFlex(string name, double number)
        {
            RTMPPacket packet = new RTMPPacket();
            packet.m_nChannel = 0x03;   // control channel (invoke)
            packet.HeaderType = HeaderType.Large;
            packet.PacketType = PacketType.Invoke_AMF3;

            List<byte> enc = new List<byte>();
            enc.Add(0x00);
            EncodeString(enc, name);
            EncodeNumber(enc, 0);
            enc.Add(0x05); // NULL
            EncodeNumber(enc, number);

            packet.m_body = enc.ToArray();
            packet.m_nBodySize = (uint)enc.Count;

            Logger.Log(string.Format("Sending flex: ({0},{1})", name, number.ToString()));

            return SendPacket(packet);
        }
Пример #20
0
        bool SendPacket(RTMPPacket packet, bool queue = true)
        {
            uint last = 0;
            uint t = 0;

            RTMPPacket prevPacket = m_vecChannelsOut[packet.m_nChannel];
            if (packet.HeaderType != HeaderType.Large && prevPacket != null)
            {
                // compress a bit by using the prev packet's attributes
                if (prevPacket.m_nBodySize == packet.m_nBodySize &&
                    prevPacket.PacketType == packet.PacketType &&
                    packet.HeaderType == HeaderType.Medium)
                    packet.HeaderType = HeaderType.Small;

                if (prevPacket.m_nTimeStamp == packet.m_nTimeStamp &&
                    packet.HeaderType == HeaderType.Small)
                    packet.HeaderType = HeaderType.Minimum;

                last = prevPacket.m_nTimeStamp;
            }

            uint nSize = packetSize[(byte)packet.HeaderType];
            t = packet.m_nTimeStamp - last;
            List<byte> header = new List<byte>();//byte[RTMP_LARGE_HEADER_SIZE];
            byte c = (byte)(((byte)packet.HeaderType << 6) | packet.m_nChannel);
            header.Add(c);
            if (nSize > 1)
                EncodeInt24(header, (int)t);

            if (nSize > 4)
            {
                EncodeInt24(header, (int)packet.m_nBodySize);
                header.Add((byte)packet.PacketType);
            }

            if (nSize > 8)
                EncodeInt32LE(header, packet.m_nInfoField2);

            uint hSize = nSize;
            byte[] headerBuffer = header.ToArray();
            nSize = packet.m_nBodySize;
            byte[] buffer = packet.m_body;
            uint bufferOffset = 0;
            uint nChunkSize = (uint)outChunkSize;
            while (nSize + hSize > 0)
            {
                if (nSize < nChunkSize) nChunkSize = nSize;

                if (hSize > 0)
                {
                    byte[] combinedBuffer = new byte[headerBuffer.Length + nChunkSize];
                    Array.Copy(headerBuffer, combinedBuffer, headerBuffer.Length);
                    Array.Copy(buffer, (int)bufferOffset, combinedBuffer, headerBuffer.Length, (int)nChunkSize);
                    WriteN(combinedBuffer, 0, combinedBuffer.Length);
                    hSize = 0;
                }
                else
                {
                    WriteN(buffer, (int)bufferOffset, (int)nChunkSize);
                }

                nSize -= nChunkSize;
                bufferOffset += nChunkSize;

                if (nSize > 0)
                {
                    byte sep = (byte)(0xc0 | c);
                    hSize = 1;
                    headerBuffer = new byte[1] { sep };
                }
            }

            if (packet.PacketType == PacketType.Invoke && queue) // we invoked a remote method, keep it in call queue till result arrives
                m_methodCalls.Enqueue(ReadString(packet.m_body, 1));

            m_vecChannelsOut[packet.m_nChannel] = packet;
            //m_vecChannelsOut[packet.m_nChannel].m_body = null;

            return true;
        }
Пример #21
0
        /// <summary>
        /// Reacts corresponding to the packet.
        /// </summary>
        /// <param name="packet"></param>
        /// <returns>0 - no media packet, 1 - media packet, 2 - play complete</returns>
        int ClientPacket(RTMPPacket packet)
        {
            int bHasMediaPacket = 0;

            switch (packet.PacketType)
            {
                case PacketType.ChunkSize:
                    HandleChangeChunkSize(packet);
                    break;
                case PacketType.BytesRead:
                    //CLog::Log(LOGDEBUG,"%s, received: bytes read report", __FUNCTION__);
                    break;
                case PacketType.Control:
                    HandlePing(packet);
                    break;
                case PacketType.ServerBW:
                    HandleServerBW(packet);
                    break;
                case PacketType.ClientBW:
                    HandleClientBW(packet);
                    break;
                case PacketType.Audio:
                    //CLog::Log(LOGDEBUG,"%s, received: audio %lu bytes", __FUNCTION__, packet.m_nBodySize);
                    //HandleAudio(packet);
                    if (m_mediaChannel == 0) m_mediaChannel = packet.m_nChannel;
                    if (Pausing == 0) m_mediaStamp = packet.m_nTimeStamp;
                    bHasMediaPacket = 1;
                    break;
                case PacketType.Video:
                    //CLog::Log(LOGDEBUG,"%s, received: video %lu bytes", __FUNCTION__, packet.m_nBodySize);
                    //HandleVideo(packet);
                    if (m_mediaChannel == 0) m_mediaChannel = packet.m_nChannel;
                    if (Pausing == 0) m_mediaStamp = packet.m_nTimeStamp;
                    bHasMediaPacket = 1;
                    break;
                case PacketType.Metadata:
                    //CLog::Log(LOGDEBUG,"%s, received: notify %lu bytes", __FUNCTION__, packet.m_nBodySize);
                    HandleMetadata(packet);
                    bHasMediaPacket = 1;
                    break;
                case PacketType.Invoke:
                    //CLog::Log(LOGDEBUG,"%s, received: invoke %lu bytes", __FUNCTION__, packet.m_nBodySize);
                    if (HandleInvoke(packet) == true) bHasMediaPacket = 2;
                    break;
                case PacketType.FlvTags:
                    //Logger.Log(string.Format("received: FLV tag(s) {0} bytes", packet.m_nBodySize));
                    HandleFlvTags(packet);
                    bHasMediaPacket = 1;
                    break;
                default:
                    Logger.Log(string.Format("Ignoring packet of type {0}", packet.PacketType));
                    break;
            }

            return bHasMediaPacket;
        }
Пример #22
0
        bool SendPause(bool doPause)
        {
            RTMPPacket packet = new RTMPPacket();
            packet.m_nChannel = 0x08;   // we make 8 our stream channel
            packet.HeaderType = HeaderType.Medium;
            packet.PacketType = PacketType.Invoke;

            List<byte> enc = new List<byte>();

            EncodeString(enc, "pause");
            EncodeNumber(enc, ++m_numInvokes);
            enc.Add(0x05); // NULL
            EncodeBoolean(enc, doPause);
            EncodeNumber(enc, (double)m_channelTimestamp[m_mediaChannel]);

            packet.m_body = enc.ToArray();
            packet.m_nBodySize = (uint)enc.Count;

            Logger.Log(string.Format("Sending pause: ({0}), Time = {1}", doPause.ToString(), m_channelTimestamp[m_mediaChannel]));

            return SendPacket(packet);
        }
Пример #23
0
 void HandleClientBW(RTMPPacket packet)
 {
     m_nClientBW = ReadInt32(packet.m_body, 0);
     if (packet.m_nBodySize > 4)
         m_nClientBW2 = packet.m_body[4];
     else
         m_nClientBW2 = 0;
     Logger.Log(string.Format("HandleClientBW: client BW = {0} {1}", m_nClientBW, m_nClientBW2));
 }
Пример #24
0
        /// <summary>
        /// The type of Ping packet is 0x4 and contains two mandatory parameters and two optional parameters. 
        /// The first parameter is the type of Ping (short integer).
        /// The second parameter is the target of the ping. 
        /// As Ping is always sent in Channel 2 (control channel) and the target object in RTMP header is always 0 
        /// which means the Connection object, 
        /// it's necessary to put an extra parameter to indicate the exact target object the Ping is sent to. 
        /// The second parameter takes this responsibility. 
        /// The value has the same meaning as the target object field in RTMP header. 
        /// (The second value could also be used as other purposes, like RTT Ping/Pong. It is used as the timestamp.) 
        /// The third and fourth parameters are optional and could be looked upon as the parameter of the Ping packet. 
        /// Below is an unexhausted list of Ping messages.
        /// type 0: Clear the stream. No third and fourth parameters. The second parameter could be 0. After the connection is established, a Ping 0,0 will be sent from server to client. The message will also be sent to client on the start of Play and in response of a Seek or Pause/Resume request. This Ping tells client to re-calibrate the clock with the timestamp of the next packet server sends.
        /// type 1: Tell the stream to clear the playing buffer.
        /// type 3: Buffer time of the client. The third parameter is the buffer time in millisecond.
        /// type 4: Reset a stream. Used together with type 0 in the case of VOD. Often sent before type 0.
        /// type 6: Ping the client from server. The second parameter is the current time.
        /// type 7: Pong reply from client. The second parameter is the time the server sent with his ping request.
        /// type 26: SWFVerification request
        /// type 27: SWFVerification response
        /// type 31: Buffer empty
        /// type 32: Buffer full
        /// </summary>
        /// <param name="nType"></param>
        /// <param name="nObject"></param>
        /// <param name="nTime"></param>
        /// <returns></returns>
        bool SendPing(short nType, uint nObject, uint nTime)
        {
            Logger.Log(string.Format("Sending ping type: {0}", nType));

            RTMPPacket packet = new RTMPPacket();
            packet.m_nChannel = 0x02;   // control channel (ping)
            packet.HeaderType = HeaderType.Medium;
            packet.PacketType = PacketType.Control;
            //packet.m_nInfoField1 = System.Environment.TickCount;

            int nSize = (nType == 0x03 ? 10 : 6); // type 3 is the buffer time and requires all 3 parameters. all in all 10 bytes.
            if (nType == 0x1B) nSize = 44;
            packet.AllocPacket(nSize);
            packet.m_nBodySize = (uint)nSize;

            List<byte> buf = new List<byte>();
            EncodeInt16(buf, nType);

            if (nType == 0x1B)
            {
                buf.AddRange(Link.SWFVerificationResponse);
            }
            else
            {
                if (nSize > 2)
                    EncodeInt32(buf, (int)nObject);

                if (nSize > 6)
                    EncodeInt32(buf, (int)nTime);
            }
            packet.m_body = buf.ToArray();
            return SendPacket(packet, false);
        }
Пример #25
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;
        }
Пример #26
0
        bool WriteStream(RTMPPacket packet, Stream stream, out uint nTimeStamp)
        {
            nTimeStamp = 0;
            uint prevTagSize = 0;

            // skip video info/command packets
            if (packet.PacketType == PacketType.Video && packet.m_nBodySize == 2 && ((packet.m_body[0] & 0xf0) == 0x50))
            {
                return true;
            }

            if (packet.PacketType == PacketType.Video && packet.m_nBodySize <= 5)
            {
                Logger.Log(string.Format("ignoring too small video packet: size: {0}", packet.m_nBodySize));
                return true;
            }

            if (packet.PacketType == PacketType.Audio && packet.m_nBodySize <= 1)
            {
                Logger.Log(string.Format("ignoring too small audio packet: size: {0}", packet.m_nBodySize));
                return true;
            }

            // audio (0x08), video (0x09) or metadata (0x12) packets :
            // construct 11 byte header then add rtmp packet's data
            if (packet.PacketType == PacketType.Audio || packet.PacketType == PacketType.Video || packet.PacketType == PacketType.Metadata)
            {
                nTimeStamp = (uint)packet.m_nTimeStamp;
                prevTagSize = 11 + packet.m_nBodySize;

                stream.WriteByte((byte)packet.PacketType);

                List<byte> somebytes = new List<byte>();
                RTMP.EncodeInt24(somebytes, (int)packet.m_nBodySize);
                RTMP.EncodeInt24(somebytes, (int)nTimeStamp);
                stream.Write(somebytes.ToArray(), 0, somebytes.Count);
                somebytes.Clear();

                stream.WriteByte((byte)(((nTimeStamp) & 0xFF000000) >> 24));

                // stream id
                RTMP.EncodeInt24(somebytes, 0);
                stream.Write(somebytes.ToArray(), 0, somebytes.Count);
                somebytes.Clear();

                // body
                stream.Write(packet.m_body, 0, (int)packet.m_nBodySize);

                // prevTagSize
                RTMP.EncodeInt32(somebytes, (int)prevTagSize);
                stream.Write(somebytes.ToArray(), 0, somebytes.Count);
                somebytes.Clear();
            }
            // correct tagSize and obtain timestamp if we have an FLV stream
            else if (packet.PacketType == PacketType.FlvTags)
            {
                List<byte> data = packet.m_body.ToList();

                uint pos = 0;

                /* grab first timestamp and see if it needs fixing */
                nTimeStamp = (uint)RTMP.ReadInt24(packet.m_body, 4);
                nTimeStamp |= (uint)(packet.m_body[7] << 24);
                var delta = packet.m_nTimeStamp - nTimeStamp;

                while (pos + 11 < packet.m_nBodySize)
                {
                    uint dataSize = (uint)RTMP.ReadInt24(packet.m_body, (int)pos + 1); // size without header (11) and without prevTagSize (4)
                    nTimeStamp = (uint)RTMP.ReadInt24(packet.m_body, (int)pos + 4);
                    nTimeStamp |= (uint)(packet.m_body[pos + 7] << 24);

                    if (delta != 0)
                    {
                        nTimeStamp += delta;
                        List<byte> newTimeStampData = new List<byte>();
                        RTMP.EncodeInt24(newTimeStampData, (int)nTimeStamp);
                        data[(int)pos + 4] = newTimeStampData[0];
                        data[(int)pos + 5] = newTimeStampData[1];
                        data[(int)pos + 6] = newTimeStampData[2];
                        data[(int)pos + 7] = (byte)(nTimeStamp >> 24);
                    }

                    if (pos + 11 + dataSize + 4 > packet.m_nBodySize)
                    {
                        if (pos + 11 + dataSize > packet.m_nBodySize)
                        {
                            Logger.Log(string.Format("Wrong data size ({0}), stream corrupted, aborting!", dataSize));
                            return false;
                        }
                        // we have to append a last tagSize!
                        prevTagSize = dataSize + 11;
                        RTMP.EncodeInt32(data, (int)prevTagSize);
                    }
                    else
                    {
                        prevTagSize = (uint)RTMP.ReadInt32(packet.m_body, (int)(pos + 11 + dataSize));

                        if (prevTagSize != (dataSize + 11))
                        {
                            //Tag and data size are inconsistent, writing tag size according to dataSize+11
                            prevTagSize = dataSize + 11;
                            RTMP.EncodeInt32(data, (int)prevTagSize, pos + 11 + dataSize);
                        }
                    }

                    pos += prevTagSize + 4;//(11+dataSize+4);
                }

                stream.Write(data.ToArray(), 0, data.Count);
            }
            return true;
        }