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; }
/// <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; }
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)); } } } }