private bool MQInternal_SendBytesReceived() { RTMPPacket packet = new RTMPPacket(); packet.Channel = 0x02; // control channel (invoke) packet.HeaderType = HeaderType.Medium; packet.PacketType = PacketType.BytesReadReport; packet.AllocPacket(4); packet.BodySize = 4; List<byte> enc = new List<byte>(); lock (lockVAR) { RTMPHelper.EncodeInt32(enc, bytesReadTotal); packet.BodySize = (uint)enc.Count; packet.Body = enc.ToArray(); lastSentBytesRead = bytesReadTotal; LibRTMPLogger.Log(LibRTMPLogLevel.Trace, string.Format("[CDR.LibRTMP.NetConnection] Send bytes report. ({0} bytes)", bytesReadTotal)); } return MQInternal_SendPacket(packet, false); }
private bool MQInternal_SendCheckBWResult(double txn) { RTMPPacket packet = new RTMPPacket(); packet.Channel = 0x03; // control channel (invoke) packet.HeaderType = HeaderType.Medium; packet.PacketType = PacketType.Invoke; packet.TimeStamp = (uint)(0x16 * bwCheckCounter); // temp inc value. till we figure it out. packet.AllocPacket(256); // should be enough List<byte> enc = new List<byte>(); RTMPHelper.EncodeString(enc, "_result"); RTMPHelper.EncodeNumber(enc, txn); enc.Add(0x05); // NULL RTMPHelper.EncodeNumber(enc, (double)bwCheckCounter++); packet.BodySize = (uint)enc.Count; packet.Body = enc.ToArray(); return MQInternal_SendPacket(packet, false); }
private bool MQInternal_SendServerBW() { RTMPPacket packet = new RTMPPacket(); packet.Channel = 0x02; // control channel (invoke) packet.HeaderType = HeaderType.Large; packet.PacketType = PacketType.ServerBW; packet.AllocPacket(4); packet.BodySize = 4; List<byte> bytesToSend = new List<byte>(); RTMPHelper.EncodeInt32(bytesToSend, serverBW); // was hard coded : 0x001312d0 packet.Body = bytesToSend.ToArray(); return MQInternal_SendPacket(packet, false); }
private bool MQ_SendCreateStream(NetStream netStream) { int transactionNum = ++numInvokes; // Put netStream in transaction reference table so we can match it up when the rtmp server // give us the result back transactionIDReferenceTable[transactionNum] = netStream; RTMPPacket packet = new RTMPPacket(); packet.Channel = 0x03; // control channel (invoke) packet.HeaderType = HeaderType.Medium; packet.PacketType = PacketType.Invoke; LibRTMPLogger.Log(LibRTMPLogLevel.Trace, "[CDR.LibRTMP.NetConnection] Sending createStream"); packet.AllocPacket(256); // should be enough List<byte> enc = new List<byte>(); RTMPHelper.EncodeString(enc, "createStream"); RTMPHelper.EncodeNumber(enc, transactionNum); enc.Add(0x05); // NULL packet.BodySize = (uint)enc.Count; packet.Body = enc.ToArray(); methodCallDictionary.Add(transactionNum, "createStream"); return MQInternal_SendPacket(packet); }
/// <summary> /// Send Connect after NetConnection Handshake has finished /// </summary> private bool MQInternal_NetConnection_SendConnect(params AMFObjectProperty[] amfProperties) { // Work with copy of var so we don't have to lock to much, for to long ServerLink link; lock (lockVAR) { link = (ServerLink)serverLink.Clone(); } RTMPPacket packet = new RTMPPacket(); packet.Channel = 0x03; // control channel (invoke) packet.HeaderType = HeaderType.Large; packet.PacketType = PacketType.Invoke; packet.AllocPacket(4096); LibRTMPLogger.Log(LibRTMPLogLevel.Trace, "[CDR.LibRTMP.NetConnection] Sending connect"); List<byte> enc = new List<byte>(); RTMPHelper.EncodeString(enc, "connect"); int transactionNum = ++numInvokes; RTMPHelper.EncodeNumber(enc, transactionNum); methodCallDictionary.Add(transactionNum, "connect"); enc.Add(0x03); //Object Datatype RTMPHelper.EncodeString(enc, "app", link.Application); LibRTMPLogger.Log(LibRTMPLogLevel.Trace, string.Format("[CDR.LibRTMP.NetConnection] app : {0}", link.Application)); if (String.IsNullOrEmpty(swfFlashVer)) { RTMPHelper.EncodeString(enc, "flashVer", "WIN 10,0,32,18"); } else { RTMPHelper.EncodeString(enc, "flashVer", swfFlashVer); } if (!string.IsNullOrEmpty(swfURL)) RTMPHelper.EncodeString(enc, "swfUrl", swfURL); RTMPHelper.EncodeString(enc, "tcUrl", link.URL); LibRTMPLogger.Log(LibRTMPLogLevel.Trace, string.Format("[CDR.LibRTMP.NetConnection] tcUrl : {0}", link.URL)); RTMPHelper.EncodeBoolean(enc, "fpad", false); RTMPHelper.EncodeNumber(enc, "capabilities", 15.0); RTMPHelper.EncodeNumber(enc, "audioCodecs", 3191.0); RTMPHelper.EncodeNumber(enc, "videoCodecs", 252.0); RTMPHelper.EncodeNumber(enc, "videoFunction", 1.0); if (!string.IsNullOrEmpty(swfPageURL)) { RTMPHelper.EncodeString(enc, "pageUrl", swfPageURL); } enc.Add(0); enc.Add(0); enc.Add(0x09); // end of object - 0x00 0x00 0x09 // add auth string if (!string.IsNullOrEmpty(swfAuth)) { RTMPHelper.EncodeBoolean(enc, true); RTMPHelper.EncodeString(enc, swfAuth); } //EncodeNumber(enc, "objectEncoding", 0.0); if (amfProperties != null) { foreach (AMFObjectProperty prop in amfProperties) { prop.Encode(enc); } //foreach List<byte> objEnc = new List<byte>(); } Array.Copy(enc.ToArray(), packet.Body, enc.Count); packet.BodySize = (uint)enc.Count; return MQInternal_SendPacket(packet); }
/// <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> private bool MQ_SendPing(short nType, uint nObject, uint nTime) { LibRTMPLogger.Log(LibRTMPLogLevel.Trace, string.Format("[CDR.LibRTMP.NetConnection.MQ_SendPing] Sending ping type: {0}", nType)); RTMPPacket packet = new RTMPPacket(); packet.Channel = 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.BodySize = (uint)nSize; List<byte> buf = new List<byte>(); RTMPHelper.EncodeInt16(buf, nType); if (nType == 0x1B) { buf.AddRange(swfVerificationResponse); } else { if (nSize > 2) { RTMPHelper.EncodeInt32(buf, (int)nObject); } if (nSize > 6) { RTMPHelper.EncodeInt32(buf, (int)nTime); } } packet.Body = buf.ToArray(); return MQInternal_SendPacket(packet, false); }