public ConcurrencyTest(Variant variant, string description) : base(variant.ToString() + ": " + description) { this.variant = variant; startThreadsEvent = new ManualResetEvent(false); endTestEvent = new ManualResetEvent(false); }
public void TestDateTime() { DateTime arg = new DateTime(2010, 1, 2, 3, 4, 5, 6); Variant v1 = new Variant(arg); Assert.AreEqual(v1.Type, Variant.EnumType.DateTime); Assert.IsTrue(v1.Is(Variant.EnumType.DateTime)); Assert.IsTrue(v1.Is<DateTime>()); Assert.AreEqual(v1.As<DateTime>(), arg); Assert.AreEqual(Convert.ToDateTime(v1), arg); Assert.AreEqual(v1.ToString(), "2010-01-02T03:04:05.006"); Variant v2 = new Variant(v1); Assert.IsTrue(v1.Equals(v2)); }
public void TestBoolean() { Variant vTrue = new Variant(true); Assert.AreEqual(vTrue.Type, Variant.EnumType.Boolean); Assert.IsTrue(vTrue.Is(Variant.EnumType.Boolean)); Assert.IsTrue(vTrue.Is<bool>()); Assert.IsTrue(vTrue.As<bool>()); Assert.IsTrue(Convert.ToBoolean(vTrue)); Assert.AreEqual(vTrue.ToString(), "true"); Variant vFalse = new Variant(false); Assert.AreEqual(vFalse.Type, Variant.EnumType.Boolean); Assert.IsTrue(vFalse.Is(Variant.EnumType.Boolean)); Assert.IsTrue(vFalse.Is<bool>()); Assert.IsFalse(vFalse.As<bool>()); Assert.IsFalse(Convert.ToBoolean(vFalse)); Assert.AreEqual(vFalse.ToString(), "false"); Variant v1 = new Variant(vTrue); Assert.IsTrue(v1.Equals(vTrue)); Variant v2 = new Variant(vFalse); Assert.IsTrue(v2.Equals(vFalse)); }
public void TestUInt64() { Variant v1 = new Variant((UInt64)4); Assert.AreEqual(v1.Type, Variant.EnumType.UInt64); Assert.IsTrue(v1.Is(Variant.EnumType.UInt64)); Assert.IsTrue(v1.Is<UInt64>()); Assert.AreEqual(v1.As<UInt64>(), 4); Assert.AreEqual(Convert.ToUInt64(v1), 4); Assert.AreEqual(v1.ToString(), "4"); Variant v2 = new Variant(v1); Assert.IsTrue(v1.Equals(v2)); }
public void TestTime() { TimeSpan arg = new TimeSpan(0, 2, 3, 4, 5); Variant v1 = new Variant(arg); Assert.AreEqual(v1.Type, Variant.EnumType.Time); Assert.IsTrue(v1.Is(Variant.EnumType.Time)); Assert.IsTrue(v1.Is<TimeSpan>()); Assert.AreEqual(v1.As<TimeSpan>(), arg); Assert.AreEqual(v1.ToString(), "02:03:04.005"); Variant v2 = new Variant(v1); Assert.IsTrue(v1.Equals(v2)); }
public void TestInt64() { Variant v1 = new Variant((Int64)3); Assert.AreEqual(v1.Type, Variant.EnumType.Int64); Assert.IsTrue(v1.Is(Variant.EnumType.Int64)); Assert.IsTrue(v1.Is<Int64>()); Assert.AreEqual(v1.As<Int64>(), 3); Assert.AreEqual(Convert.ToInt64(v1), 3); Assert.AreEqual(v1.ToString(), "3"); Variant v2 = new Variant(v1); Assert.IsTrue(v1.Equals(v2)); }
public void TestInt32() { Variant v1 = new Variant((Int32)1); Assert.AreEqual(v1.Type, Variant.EnumType.Int32); Assert.IsTrue(v1.Is(Variant.EnumType.Int32)); Assert.IsTrue(v1.Is<Int32>()); Assert.AreEqual(v1.As<Int32>(), 1); Assert.AreEqual(Convert.ToInt32(v1), 1); Assert.AreEqual(v1.ToString(), "1"); Variant v2 = new Variant(v1); Assert.IsTrue(v1.Equals(v2)); }
private bool HandleRTSPResponse200Setup(RtspProtocol rtspProtocol, Variant requestHeaders, ref string requestContent, Variant responseHeaders, ref string responseContent) { if (rtspProtocol.CustomParameters["connectionType"] == "pull") { if (responseHeaders[RTSP_FIRST_LINE, RTSP_STATUS_CODE] != 200) { FATAL("request {0} failed with response {1}", (requestHeaders.ToString()), (responseHeaders.ToString())); return false; } if (rtspProtocol.CustomParameters["pendingTracks"].ArrayLength != 0) return SendSetupTrackMessages(rtspProtocol); //2. Do the play command var uri = rtspProtocol.CustomParameters["uri", "fullUri"]; //3. prepare the play command rtspProtocol.PushRequestFirstLine(RTSP_METHOD_PLAY, uri, RTSP_VERSION_1_0); return rtspProtocol.SendRequestMessage(); } else { if (responseHeaders[RTSP_HEADERS, RTSP_HEADERS_TRANSPORT] == null) { FATAL("RTSP {0} request doesn't have {1} header line", RTSP_METHOD_SETUP, RTSP_HEADERS_TRANSPORT); return false; } //3. get the transport header line var raw = responseHeaders[RTSP_HEADERS, RTSP_HEADERS_TRANSPORT]; var transport = Variant.Get(); if (!SDP.ParseTransportLine(raw, transport)) { FATAL("Unable to parse transport line {0}", (raw)); return false; } bool forceTcp; if (transport["server_port"] != null && (transport["rtp/avp/udp"] != null || transport["rtp/avp"] != null)) { forceTcp = false; }else if (transport["interleaved"] != null && transport["rtp/avp/tcp"] != null) { forceTcp = true; } else { FATAL("Invalid transport line: {0}", (transport.ToString())); return false; } if (forceTcp != (bool)rtspProtocol.CustomParameters["forceTcp"]) { FATAL("Invalid transport line: {0}", (transport.ToString())); return false; } var pConnectivity = GetOutboundConnectivity(rtspProtocol, forceTcp); if (pConnectivity == null) { FATAL("Unable to get outbound connectivity"); return false; } var param = rtspProtocol.CustomParameters; param[param["lastSetup"] == "audio" ? "audioTransport" : "videoTransport"] = transport; var variantUri = param["uri"]; string trackId = ""; bool isAudio = false; if (param["audioTrackId"] != null) { trackId = param["audioTrackId"]; param["audioTrackId"] = null; param["lastSetup"] = "audio"; isAudio = true; pConnectivity.HasAudio = true; } else { if (param["videoTrackId"] != null) { trackId = param["videoTrackId"]; param["videoTrackId"] = null; param["lastSetup"] = "video"; pConnectivity.HasVideo = true; } } if (trackId != "") { var uri = variantUri["fullUri"] + "/trackID=" + trackId; rtspProtocol.PushRequestFirstLine(RTSP_METHOD_SETUP, uri, RTSP_VERSION_1_0); transport = forceTcp ? $"RTP/AVP/TCP;unicast;interleaved={(isAudio ? pConnectivity.AudioChannels : pConnectivity.VideoChannels)};mode=record" : $"RTP/AVP;unicast;client_port={(isAudio ? pConnectivity.AudioChannels : pConnectivity.VideoChannels)};mode=record"; rtspProtocol.PushRequestHeader(RTSP_HEADERS_TRANSPORT, transport); return rtspProtocol.SendRequestMessage(); } else { rtspProtocol.PushRequestFirstLine(RTSP_METHOD_RECORD,variantUri["fullUri"],RTSP_VERSION_1_0); return rtspProtocol.SendRequestMessage(); } } }
//public void SignalONS(BaseOutNetRTMPStream pONS) //{ // if (_pSignaledRTMPOutNetStream.Contains(pONS)) return; // _pSignaledRTMPOutNetStream.AddLast(pONS); //} public InFileRTMPStream CreateIFS(Variant metadata) { var pRtmpInFileStream = InFileRTMPStream.GetInstance(this, Application.StreamsManager, metadata); if (pRtmpInFileStream == null) { WARN("Unable to get file stream. Metadata:\n{0}", metadata.ToString()); return null; } if (!pRtmpInFileStream.Initialize(metadata[CONF_APPLICATION_CLIENTSIDEBUFFER])) { WARN("Unable to initialize file inbound stream"); pRtmpInFileStream.Dispose(); return null; } // _inFileStreams.Add(pRtmpInFileStream); return pRtmpInFileStream; }
static void TestBuildVariant() { Variant v = new Variant(); string format = v.GetVariantStringFormat(); Console.WriteLine("VariantStringFormat = {0}", format); string value = v.ToString(); Console.WriteLine("VariantString = {0}", value); string options = v.GetVariantStringOptions("\t"); Console.WriteLine("VariantStringOptions = \n{0}", options); Variant v2 = new Variant(); v2.FromString("Develop.x64.NopeNotThisTime"); Console.WriteLine("FromString,ToString = {0}", v2.ToString()); }
private bool HandleRTSPResponse(RtspProtocol rtspProtocol, Variant requestHeaders,ref string requestContent, Variant responseHeaders,ref string responseContent) { switch ((uint)responseHeaders[RTSP_FIRST_LINE, RTSP_STATUS_CODE]) { case 200: switch ((string)requestHeaders[RTSP_FIRST_LINE,RTSP_METHOD]) { case RTSP_METHOD_OPTIONS: return HandleRTSPResponse200Options(rtspProtocol,requestHeaders,ref requestContent, responseHeaders,ref responseContent); case RTSP_METHOD_DESCRIBE: return HandleRTSPResponse200Describe(rtspProtocol, requestHeaders, ref requestContent, responseHeaders, ref responseContent); case RTSP_METHOD_SETUP: return HandleRTSPResponse200Setup(rtspProtocol, requestHeaders, ref requestContent, responseHeaders, ref responseContent); case RTSP_METHOD_PLAY: return HandleRTSPResponse200Play(rtspProtocol, requestHeaders, ref requestContent, responseHeaders, ref responseContent); case RTSP_METHOD_ANNOUNCE: return HandleRTSPResponse200Announce(rtspProtocol, requestHeaders, ref requestContent, responseHeaders, ref responseContent); case RTSP_METHOD_RECORD: return HandleRTSPResponse200Record(rtspProtocol, requestHeaders, ref requestContent, responseHeaders, ref responseContent); case RTSP_METHOD_TEARDOWN: return true; default: return false; } case 401: var username = rtspProtocol.CustomParameters["uri", "userName"]; var password = rtspProtocol.CustomParameters["uri", "password"]; if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password)) { FATAL("No username/password provided"); return false; } string auth = responseHeaders[RTSP_HEADERS, HTTP_HEADERS_WWWAUTHENTICATE]; if (string.IsNullOrEmpty(auth)) { FATAL("Invalid 401 response: {0}", (responseHeaders.ToString())); return false; } if (!rtspProtocol.SetAuthentication(auth, username, password)) { FATAL("Unable to authenticate: request headers:\n{0}\nresponseHeaders:\n{1}", (requestHeaders.ToString()), (responseHeaders.ToString())); return false; } return true; case 404: switch ((string)requestHeaders[RTSP_FIRST_LINE, RTSP_METHOD]) { case RTSP_METHOD_PLAY: FATAL("PLAY: Resource not found: "+(requestHeaders[RTSP_FIRST_LINE][RTSP_URL])); return false; case RTSP_METHOD_DESCRIBE: FATAL("DESCRIBE: Resource not found: "+(requestHeaders[RTSP_FIRST_LINE][RTSP_URL])); return false; default: FATAL("Response for method {0} not implemented yet\n{1}", ((string)requestHeaders[RTSP_FIRST_LINE, RTSP_METHOD]), (responseHeaders.ToString())); return false; } default: return false; } }
public bool HandleRTSPResponse(RtspProtocol rtspProtocol, Variant responseHeaders,ref string responseContent) { if (responseHeaders[RTSP_HEADERS, RTSP_HEADERS_SESSION] != null) { rtspProtocol.SessionId = responseHeaders[RTSP_HEADERS, RTSP_HEADERS_SESSION]; } if (responseHeaders[RTSP_HEADERS, RTSP_HEADERS_CSEQ] == null) { FATAL("Invalid response:\n{0}", (responseHeaders.ToString())); return false; } Variant requestHeaders = Variant.Get(); string requestContent = ""; rtspProtocol.GetRequest(responseHeaders[RTSP_HEADERS, RTSP_HEADERS_CSEQ], requestHeaders, ref requestContent); //2. Get the request, get the response and call the stack further return HandleRTSPResponse(rtspProtocol, requestHeaders, ref requestContent, responseHeaders, ref responseContent); }
private bool HandleRTSPRequestAnnounce(RtspProtocol pFrom, Variant requestHeaders, string requestContent) { //1. Make sure we ONLY handle application/sdp if ((string)requestHeaders[RTSP_HEADERS,RTSP_HEADERS_CONTENT_TYPE]!= RTSP_HEADERS_ACCEPT_APPLICATIONSDP) { FATAL("Invalid ANNOUNCE request:\n{0}", (requestHeaders.ToString())); return false; } //2. Get the SDP var sdp = pFrom.InboundSDP; //3. Parse the SDP if (!SDP.ParseSDP(sdp, requestContent)) { FATAL("Unable to parse the SDP"); return false; } //4. Get the first video track var videoTrack = sdp.GetVideoTrack(0,requestHeaders[RTSP_FIRST_LINE,RTSP_URL]); var audioTrack = sdp.GetAudioTrack(0,requestHeaders[RTSP_FIRST_LINE,RTSP_URL]); //5. Store the tracks inside the session for later use if (audioTrack != VariantType.Null) { pFrom.CustomParameters["pendingTracks",audioTrack["globalTrackIndex"]] = audioTrack; } if (videoTrack != VariantType.Null) { pFrom.CustomParameters["pendingTracks",videoTrack["globalTrackIndex"]] = videoTrack; } //6. Mark this connection as inbound connection pFrom.CustomParameters["isInbound"] = true; //7. Save the streamName string streamName = sdp.GetStreamName(); if (streamName == "") { streamName = $"rtsp_stream_{pFrom.Id}"; } pFrom.CustomParameters["sdpStreamName"] = streamName; streamName = new Uri(requestHeaders[RTSP_FIRST_LINE, RTSP_URL],UriKind.Absolute).Segments.Last(); //8. Save the bandwidth hint pFrom.CustomParameters["sdpBandwidthHint"] = sdp.GetTotalBandwidth(); //9. Get the inbound connectivity InboundConnectivity pInboundConnectivity = pFrom.GetInboundConnectivity( streamName, sdp.GetTotalBandwidth(),Application.Configuration[CONF_APPLICATION_RTCPDETECTIONINTERVAL]); if (pInboundConnectivity == null) { FATAL("Unable to create inbound connectivity"); return false; } //8. Send back the response pFrom.PushResponseFirstLine(RTSP_VERSION_1_0, 200, "OK"); return pFrom.SendResponseMessage(); }
private bool HandleRTSPResponse200Options(RtspProtocol rtspProtocol, Variant requestHeaders, ref string requestContent, Variant responseHeaders, ref string responseContent) { if (rtspProtocol.HasConnectivity) return true; if (rtspProtocol.CustomParameters["connectionType"] == null) { FATAL("Bogus connection"); rtspProtocol.EnqueueForDelete(); return false; } //1. Sanitize if (responseHeaders[RTSP_HEADERS, RTSP_HEADERS_PUBLIC] == null) { FATAL("Invalid response:\n{0}", (responseHeaders.ToString())); return false; } //2. get the raw options string raw = responseHeaders[RTSP_HEADERS, RTSP_HEADERS_PUBLIC]; //3. split and normalize the options var parts = raw.Split(',').Select(x => x.Split(':')).ToDictionary(x => x[0], x => x[1]); string url = requestHeaders[RTSP_FIRST_LINE, RTSP_URL]; switch ((string)rtspProtocol.CustomParameters["connectionType"]) { case "pull": //4. Test the presence of the wanted methods if (!parts.ContainsKey(RTSP_METHOD_DESCRIBE) || !parts.ContainsKey(RTSP_METHOD_SETUP) || !parts.ContainsKey(RTSP_METHOD_PLAY)) { FATAL("Some of the supported methods are missing: {0}", (raw)); return false; } rtspProtocol.PushRequestFirstLine(RTSP_METHOD_DESCRIBE, url, RTSP_VERSION_1_0); rtspProtocol.PushRequestHeader(RTSP_HEADERS_ACCEPT, RTSP_HEADERS_ACCEPT_APPLICATIONSDP); return rtspProtocol.SendRequestMessage(); case "push": //4. Test the presence of the wanted methods if (!parts.ContainsKey(RTSP_METHOD_ANNOUNCE) || !parts.ContainsKey(RTSP_METHOD_SETUP) || !parts.ContainsKey(RTSP_METHOD_RECORD)) { FATAL("Some of the supported methods are missing: {0}", (raw)); return false; } var parameters = rtspProtocol.CustomParameters; rtspProtocol.PushRequestFirstLine(RTSP_METHOD_ANNOUNCE,url,RTSP_VERSION_1_0); var sdp = ComputeSDP(rtspProtocol, parameters["customParameters","localStreamConfig","localStreamName"], parameters["customParameters","localStreamConfig","targetStreamName"], parameters["customParameters","localStreamConfig","targetUri","host"]); if (sdp == "") { FATAL("Unable to compute sdp"); return false; } rtspProtocol.PushRequestHeader(RTSP_HEADERS_CONTENT_TYPE, RTSP_HEADERS_ACCEPT_APPLICATIONSDP); rtspProtocol.PushRequestContent(sdp,false); return rtspProtocol.SendRequestMessage(); default: FATAL("Bogus connection"); rtspProtocol.EnqueueForDelete(); return false; } }
private bool HandleRTSPResponse200Describe(RtspProtocol rtspProtocol, Variant requestHeaders, ref string requestContent, Variant responseHeaders, ref string responseContent) { //1. Make sure we ONLY handle application/sdp if (responseHeaders[RTSP_HEADERS, RTSP_HEADERS_CONTENT_TYPE] == null) { FATAL("Invalid DESCRIBE response:\n{0}", (requestHeaders.ToString())); return false; } if (responseHeaders[RTSP_HEADERS, RTSP_HEADERS_CONTENT_TYPE] == RTSP_HEADERS_ACCEPT_APPLICATIONSDP) { FATAL("Invalid DESCRIBE response:\n{0}", (requestHeaders.ToString())); return false; } //2. Get the SDP var sdp = rtspProtocol.InboundSDP; //3. Parse the SDP if (!SDP.ParseSDP(sdp, responseContent)) { FATAL("Unable to parse the SDP"); return false; } //4. Get the first video track var videoTrack = sdp.GetVideoTrack(0,requestHeaders[RTSP_FIRST_LINE,RTSP_URL]); var audioTrack = sdp.GetAudioTrack(0,requestHeaders[RTSP_FIRST_LINE,RTSP_URL]); if ((videoTrack == VariantType.Null) && (audioTrack == VariantType.Null)) { FATAL("No compatible tracks found"); return false; } var forceTcp = rtspProtocol.CustomParameters["forceTcp"]; var rtcpDetectionInterval = Application.Configuration[CONF_APPLICATION_RTCPDETECTIONINTERVAL]; if (rtspProtocol.CustomParameters[CONF_APPLICATION_RTCPDETECTIONINTERVAL]!=null) rtcpDetectionInterval = (byte)rtspProtocol.CustomParameters[CONF_APPLICATION_RTCPDETECTIONINTERVAL]; //5. Store the tracks inside the session for later use if (audioTrack != VariantType.Null) { audioTrack["isTcp"] = (bool)forceTcp; rtspProtocol.CustomParameters["pendingTracks"][(int)audioTrack["globalTrackIndex"]] = audioTrack; } if (videoTrack != VariantType.Null) { videoTrack["isTcp"] = (bool)forceTcp; rtspProtocol.CustomParameters["pendingTracks"][(int)videoTrack["globalTrackIndex"]] = videoTrack; } //6. Save the streamName string streamName = sdp.GetStreamName(); if (streamName == "") { streamName = "rtsp_stream_"+rtspProtocol.Id; } rtspProtocol.CustomParameters["sdpStreamName"] = streamName; //7. Save the bandwidth hint rtspProtocol.CustomParameters["sdpBandwidthHint"] = sdp.GetTotalBandwidth(); //8. Get the inbound connectivity var pInboundConnectivity = rtspProtocol.GetInboundConnectivity(streamName, sdp.GetTotalBandwidth(), rtcpDetectionInterval); if (pInboundConnectivity == null) { FATAL("Unable to create inbound connectivity"); return false; } //9. Start sending the setup commands on the pending tracks; return SendSetupTrackMessages(rtspProtocol); }
public void TestDouble() { Variant v1 = new Variant((double)5.0); Assert.AreEqual(v1.Type, Variant.EnumType.Double); Assert.IsTrue(v1.Is(Variant.EnumType.Double)); Assert.IsTrue(v1.Is<double>()); Assert.AreEqual(v1.As<double>(), 5.0); Assert.AreEqual(Convert.ToDouble(v1), 5.0); Assert.AreEqual(v1.ToString(), "5"); Variant vNaN = new Variant(double.NaN); Assert.AreEqual(vNaN.ToString(), "NaN"); Variant vINF = new Variant(double.PositiveInfinity); Assert.AreEqual(vINF.ToString(), "INF"); Variant vNEGINF = new Variant(double.NegativeInfinity); Assert.AreEqual(vNEGINF.ToString(), "-INF"); Variant v2 = new Variant(v1); Assert.IsTrue(v1.Equals(v2)); }
public static bool SignalProtocolCreated(BaseProtocol protocol, Variant customParameters) { var application = ClientApplicationManager.FindAppByName(customParameters[Defines.CONF_APPLICATION_NAME]); if (application == null) { Logger.FATAL("Application {0} not found",customParameters[Defines.CONF_APPLICATION_NAME]); return false; } if (protocol == null) { Logger.FATAL("Connection failed:{0}", customParameters.ToString()); return application.OutboundConnectionFailed(customParameters); } protocol.Application = application; var outboundRTMPProtocol = protocol as OutboundRTMPProtocol; outboundRTMPProtocol.CustomParameters = customParameters; return outboundRTMPProtocol.SignalInputData(0); }
bool BindAcceptor(Variant node) { //1. Get the chain var chain = ProtocolFactoryManager.ResolveProtocolChain(node[CONF_PROTOCOL]); if (chain.Count == 0) { WARN("Invalid protocol chain: {0}",node[CONF_PROTOCOL]); } //2. Is it TCP or UDP based? if (chain[0] == ProtocolTypes.PT_TCP) { //3. This is a tcp acceptor. Instantiate it and start accepting connections var pAcceptor = new TCPAcceptor( node[CONF_IP], node[CONF_PORT], node, chain); if (!pAcceptor.Bind()) { FATAL("Unable to fire up acceptor from this config node:{0}",node.ToString()); return false; } acceptors.Add(pAcceptor); return true; } else if (chain[0] == ProtocolTypes.PT_UDP) { //4. Ok, this is an UDP acceptor. Because of that, we can instantiate //the full stack. Get the stack first var pProtocol = ProtocolFactoryManager.CreateProtocolChain(chain, node); if (pProtocol == null) { FATAL("Unable to instantiate protocol stack {0}", node[CONF_PROTOCOL]); return false; } //5. Create the carrier and bind it var pUDPCarrier = UDPCarrier.Create(node[CONF_IP], node[CONF_PORT], pProtocol); if (pUDPCarrier == null) { FATAL("Unable to instantiate UDP carrier on {0}:{1}", node[CONF_IP], node[CONF_PORT]); pProtocol.EnqueueForDelete(); return false; } pUDPCarrier.Parameters = node; acceptors.Add(pUDPCarrier); return true; } else { FATAL("Invalid carrier type"); return false; } }
public bool InboundMessageAvailable(BaseRTMPProtocol pFrom, Variant messageBody, Channel channel,out bool recycleBody) { recycleBody = true; AmfMessage message; message.Header = channel.lastInHeader; message.Body = messageBody; var parameters = pFrom.CustomParameters; if (parameters["authState"] == null) { parameters["authState"] = Variant.GetMap(new VariantMapHelper { {"stage","authenticated"}, {"canPublish",true}, {"canOverrideStreamName",false} }); } var authState = parameters["authState"]; if (pFrom.Type == ProtocolTypes.PT_INBOUND_RTMP && !string.IsNullOrEmpty(_authMethod)) { if (!AuthenticateInbound(pFrom, message, authState)) { Logger.FATAL("Unable to authenticate"); return false; } } uint size; Dictionary<uint, IStream> possibleStreams; InNetRTMPStream pInNetRTMPStream; switch (message.MessageType) { case Defines.RM_HEADER_MESSAGETYPE_WINACKSIZE: if (messageBody[Defines.RM_WINACKSIZE] != VariantType.Numberic) { Logger.FATAL("Invalid message:{0}", messageBody.ToString()); return false; } size = messageBody[Defines.RM_WINACKSIZE]; if ((size > 4 * 1024 * 1024) || size == 0) { Logger.FATAL("Invalid message:{0}", messageBody.ToString()); return false; } pFrom.SetWinAckSize(size); return true; case Defines.RM_HEADER_MESSAGETYPE_PEERBW: Logger.WARN("ProcessPeerBW"); return true; case Defines.RM_HEADER_MESSAGETYPE_ACK: return true; case Defines.RM_HEADER_MESSAGETYPE_CHUNKSIZE: if (messageBody[Defines.RM_CHUNKSIZE] != VariantType.Numberic) { Logger.FATAL("Invalid message:{0}", messageBody.ToString()); return false; } size = messageBody[Defines.RM_CHUNKSIZE]; if ((size > 4 * 1024 * 1024) || size == 0) { Logger.FATAL("Invalid message:{0}", messageBody.ToString()); return false; } if (!pFrom.SetInboundChunkSize(size)) { Logger.FATAL("Unable to set chunk size:{0}", messageBody.ToString()); return false; } return true; case Defines.RM_HEADER_MESSAGETYPE_USRCTRL: switch ((ushort)messageBody[Defines.RM_USRCTRL, Defines.RM_USRCTRL_TYPE]) { case Defines.RM_USRCTRL_TYPE_PING_REQUEST: return SendRTMPMessage(pFrom, ConnectionMessageFactory.GetPong()); case Defines.RM_USRCTRL_TYPE_STREAM_BEGIN: case Defines.RM_USRCTRL_TYPE_STREAM_SET_BUFFER_LENGTH: case Defines.RM_USRCTRL_TYPE_STREAM_IS_RECORDED: case Defines.RM_USRCTRL_TYPE_PING_RESPONSE: Logger.WARN("User control message type: {0}", messageBody[Defines.RM_USRCTRL, Defines.RM_USRCTRL_TYPE_STRING]); return true; case Defines.RM_USRCTRL_TYPE_UNKNOWN1: case Defines.RM_USRCTRL_TYPE_UNKNOWN2: return true; default: Logger.FATAL("Invalid user ctrl:\n{0}", messageBody.ToString()); return false; } case Defines.RM_HEADER_MESSAGETYPE_NOTIFY: //1. Find the corresponding inbound stream possibleStreams = Application.StreamsManager.FindByProtocolIdByType(pFrom.Id, StreamTypes.ST_IN_NET_RTMP, false); pInNetRTMPStream = possibleStreams.Select(x => x.Value as InNetRTMPStream) .SingleOrDefault( x => x.RtmpStreamId == message.StreamId); if (pInNetRTMPStream == null) { Logger.WARN("No stream found. Serached for {0}:{1}. Message was:{2}", pFrom.Id, message.StreamId, messageBody.ToString()); return true; } //2. Remove all string values starting with @ foreach (var item in messageBody[Defines.RM_NOTIFY, Defines.RM_NOTIFY_PARAMS].Children.Where( x => x.Value == VariantType.String && ((string)x.Value).StartsWith("@")).Select(x => x.Key).ToArray()) { messageBody[Defines.RM_NOTIFY, Defines.RM_NOTIFY_PARAMS].Children.Remove(item); } recycleBody = false; //3. Brodcast the message on the inbound stream pInNetRTMPStream.SendStreamMessage(new BufferWithOffset(((MemoryStream)channel.inputData.BaseStream).GetBuffer(), length: (int)message.MessageLength)); return true; case Defines.RM_HEADER_MESSAGETYPE_FLEXSTREAMSEND: recycleBody = false; //1. Find the corresponding inbound stream possibleStreams = Application.StreamsManager.FindByProtocolIdByType(pFrom.Id, StreamTypes.ST_IN_NET_RTMP, false); pInNetRTMPStream = possibleStreams.Select(x => x.Value as InNetRTMPStream) .SingleOrDefault(x => x.RtmpStreamId == message.StreamId); if (pInNetRTMPStream == null) { Logger.WARN("No stream found. Serached for {0}:{1}. Message was:{2}", pFrom.Id, message.StreamId, messageBody.ToString()); return true; } //2. Remove all string values starting with @ foreach (var item in messageBody[Defines.RM_FLEXSTREAMSEND, Defines.RM_FLEXSTREAMSEND_PARAMS].Children.Where( x => x.Value == VariantType.String && ((string)x.Value).StartsWith("@")).Select(x => x.Key).ToArray()) { messageBody[Defines.RM_FLEXSTREAMSEND, Defines.RM_FLEXSTREAMSEND_PARAMS].Children.Remove(item); } //写入文件 //pInNetRTMPStream.SendStreamMessage(channel); //3. Brodcast the message on the inbound stream pInNetRTMPStream.SendStreamMessage(new BufferWithOffset(((MemoryStream)channel.inputData.BaseStream).GetBuffer(),length: (int)message.MessageLength)); return true; case Defines.RM_HEADER_MESSAGETYPE_SHAREDOBJECT: case Defines.RM_HEADER_MESSAGETYPE_FLEXSHAREDOBJECT: return Application.SOManager.Process(pFrom, messageBody); case Defines.RM_HEADER_MESSAGETYPE_INVOKE: case Defines.RM_HEADER_MESSAGETYPE_FLEX: string functionName = messageBody[Defines.RM_INVOKE][Defines.RM_INVOKE_FUNCTION]; Logger.INFO(functionName); uint currentInvokeId = messageBody[Defines.RM_INVOKE, Defines.RM_INVOKE_ID]; if (currentInvokeId != 0 && _nextInvokeId[pFrom.Id] <= currentInvokeId) { _nextInvokeId[pFrom.Id] = currentInvokeId + 1; } string streamName; BaseOutNetRTMPStream pBaseOutNetRTMPStream = null; double timeOffset; Variant metadata; switch (functionName) { case Defines.RM_INVOKE_FUNCTION_CONNECT: return ProcessInvokeConnect(pFrom, message); case Defines.RM_INVOKE_FUNCTION_CREATESTREAM: //1. Create the neutral stream uint id = 0; if (pFrom.CreateNeutralStream(ref id) == null) { Logger.FATAL("Unable to create stream"); return false; } //2. Send the response return SendRTMPMessage(pFrom, StreamMessageFactory.GetInvokeCreateStreamResult(message, id)); case Defines.RM_INVOKE_FUNCTION_PUBLISH: //1. gather the required data from the request var param1 = messageBody[Defines.RM_INVOKE, Defines.RM_INVOKE_PARAMS][1]; if (param1 != VariantType.String && param1 != VariantType.Boolean) { Logger.FATAL("Invalid request:{0}", messageBody.ToString()); return false; } if (param1 == VariantType.Boolean) { if (param1 != false) { Logger.FATAL("Invalid request {0}", messageBody.ToString()); return false; } this.Log().Info("Closing stream via publish(false)"); return pFrom.CloseStream(message.StreamId, true); } streamName = param1; //2. Check to see if we are allowed to create inbound streams if (!pFrom.CustomParameters["authState"]["canPublish"]) { return pFrom.SendMessage(StreamMessageFactory.GetInvokeOnStatusStreamPublishBadName( message, streamName),true); } var recording = string.Equals(message.InvokeParam[2], Defines.RM_INVOKE_PARAMS_PUBLISH_TYPERECORD); var appending = string.Equals(message.InvokeParam[2], Defines.RM_INVOKE_PARAMS_PUBLISH_TYPEAPPEND); //3. Test to see if this stream name is already published somewhere if (Application.AllowDuplicateInboundNetworkStreams) { var existingStreams = Application.StreamsManager.FindByTypeByName(StreamTypes.ST_IN_NET_RTMP, streamName,false, false); if (existingStreams.Count > 0) { if (pFrom.CustomParameters["authState"]["canOverrideStreamName"]) { foreach (var existingStream in existingStreams.Values.OfType<InNetRTMPStream>().Where(existingStream => existingStream.Protocol != null)) { Logger.WARN( "Overriding stream {0}:{1} with name {2} from conneciton {3}", existingStream.RtmpStreamId, existingStream.UniqueId, existingStream.Name, existingStream.Protocol.Id); (existingStream.Protocol as BaseRTMPProtocol).CloseStream( existingStream.RtmpStreamId, true); } } else { Logger.WARN( "Unable to override stream {0} because this connection dosen't have the right", streamName); return pFrom.SendMessage( StreamMessageFactory.GetInvokeOnStatusStreamPublishBadName(message, streamName),true); } } } else if (!Application.StreamNameAvailable(streamName, pFrom)) { Logger.WARN("Stream name {0} already occupied and application doesn't allow duplicated inbound network streams", streamName); return pFrom.SendMessage( StreamMessageFactory.GetInvokeOnStatusStreamPublishBadName( message, streamName), true); } //4. Create the network inbound stream pInNetRTMPStream = pFrom.CreateINS(message.ChannelId, message.StreamId, streamName); if (pInNetRTMPStream == null) { Logger.FATAL("Unable to create inbound stream"); return false; } //7. Bind the waiting subscribers Application.OnPublish(pFrom, pInNetRTMPStream, message.InvokeParam[2]); //8. Send the streamPublished status message if (!pInNetRTMPStream.SendOnStatusStreamPublished()) { Logger.FATAL("Unable to send OnStatusStreamPublished"); return false; } //9. Start recording if necessary //if (recording || appending) //{ // var meta = GetMetaData(streamName, false); // var pOutFileStream = CreateOutFileStream(pFrom, meta, appending); // if (pOutFileStream != null && pOutFileStream.Link(pInNetRTMPStream)) return true; // Logger.FATAL("Unable to bind the recording stream"); // return false; //} return true; case Defines.RM_INVOKE_FUNCTION_PLAY: //1. Minimal validation if (message.InvokeParam[1] != VariantType.String) { Logger.FATAL("Invalid request:{0}", message.Body.ToString()); return false; } //2. Close any streams left open if (!pFrom.CloseStream(message.StreamId, true)) { Logger.FATAL("Unable to close stream {0} {1}", pFrom.Id, message.StreamId); return false; } //3. Gather required data from the request streamName = message.InvokeParam[1]; double startTime = message.InvokeParam[2] == VariantType.Double ? (double)message.InvokeParam[2] : -2000; double length = message.InvokeParam[3] == VariantType.Double ? (double)message.InvokeParam[3] : -1000; if (startTime < 0 && startTime != -2000 && startTime != -1000) startTime = -2000; if (length < 0 && length != -1) length = -1; Logger.INFO("Play request for stream name `{0}`. Start:{1}; length: {2}", streamName, startTime, length); //6. bind the network outbound stream to the inbound stream //depending on the type of the outbound stream switch ((int)startTime) { case -2000: bool linked; //7. try to link to live stream if (!TryLinkToLiveStream(pFrom, message.StreamId, streamName, out linked)) { Logger.FATAL("Unable to link streams"); return false; } if (linked) return true; metadata = GetMetaData(streamName, true); //8. try to link to file stream if (!TryLinkToFileStream(pFrom, message.StreamId, metadata, streamName, startTime, length, out linked)) { Logger.FATAL("Unable to link streams"); return false; } if (linked) return true; //9. Ok, no live/file stream. Just wait for the live stream now... Logger.WARN("We are going to wait for the live stream `{0}`", streamName); pBaseOutNetRTMPStream = pFrom.CreateONS(message.StreamId, streamName, StreamTypes.ST_IN_NET_RTMP); goto case -999; case -1000://only live if (!TryLinkToLiveStream(pFrom, message.StreamId, streamName, out linked)) { Logger.FATAL("Unable to link streams"); return false; } if (linked) return true; Logger.WARN("We are going to wait for the live stream `%s`", streamName); pBaseOutNetRTMPStream = pFrom.CreateONS( message.StreamId, streamName, StreamTypes.ST_IN_NET_RTMP); goto case -999; case -999: //Application.ClusterAppProtocolHandler.PlayStream(Application.InstanceName,streamName); if (ClientApplicationManager.ClusterApplication != null) { ClientApplicationManager.ClusterApplication.GetProtocolHandler<BaseClusterAppProtocolHandler>().PlayStream(Application.Id, streamName); } //request["waitForLiveStream"] = true; //request["streamName"] = streamName; //if (pFrom.CustomParameters["origin"] != null) //{ //if (_externalStreamProtocol == null) // Application.PullExternalStream(new Variant // { // {"uri", "rtmp://192.168.20.56/live"}, // {"localStreamName", streamName}, // {"emulateUserAgent", "MAC 10,1,82,76"}, // {"swfUrl", "my crtmpserver"}, // {"pageUrl", "linkage"} // }); //else //{ // PlayAnotherStream(_externalStreamProtocol, streamName); //} //} return pBaseOutNetRTMPStream != null; default://only recorded metadata = GetMetaData(streamName, true); //12. Perform little adjustment on metadata if ((string)metadata[Defines.META_MEDIA_TYPE] == Defines.MEDIA_TYPE_LIVE_OR_FLV) { metadata[Defines.META_MEDIA_TYPE] = Defines.MEDIA_TYPE_FLV; } //13. try to link to file stream if (!TryLinkToFileStream(pFrom, message.StreamId, metadata, streamName, startTime, length, out linked)) { Logger.FATAL("Unable to link streams"); return false; } return linked; } case Defines.RM_INVOKE_FUNCTION_PAUSERAW: case Defines.RM_INVOKE_FUNCTION_PAUSE: pBaseOutNetRTMPStream = Application.StreamsManager.FindByProtocolIdByType(pFrom.Id, StreamTypes.ST_OUT_NET_RTMP, true).Values.OfType<BaseOutNetRTMPStream>().SingleOrDefault(x => x.RTMPStreamId == message.StreamId); if (pBaseOutNetRTMPStream == null) { Logger.FATAL("No out stream"); return false; } //3. get the operation bool pause = message.InvokeParam[1]; if (pause) { //4. Pause it return pBaseOutNetRTMPStream.Pause(); } else { timeOffset = 0.0; if (message.InvokeParam[2] == VariantType.Numberic) timeOffset = message.InvokeParam[2]; //8. Perform seek if (!pBaseOutNetRTMPStream.Seek(timeOffset)) { Logger.FATAL("Unable to seek"); return false; } //9. Resume return pBaseOutNetRTMPStream.Resume(); } case Defines.RM_INVOKE_FUNCTION_CLOSESTREAM: return pFrom.CloseStream(message.StreamId, true); case Defines.RM_INVOKE_FUNCTION_SEEK: //1. Read stream index and offset in millisecond timeOffset = 0.0; if (message.InvokeParam[1] == VariantType.Numberic) timeOffset = message.InvokeParam[1]; //2. Find the corresponding outbound stream pBaseOutNetRTMPStream = Application.StreamsManager.FindByProtocolIdByType(pFrom.Id, StreamTypes.ST_OUT_NET_RTMP, true).Values.OfType<BaseOutNetRTMPStream>().SingleOrDefault(x => x.RTMPStreamId == message.StreamId); if (pBaseOutNetRTMPStream == null) { Logger.FATAL("No out stream"); return false; } return pBaseOutNetRTMPStream.Seek(timeOffset); case Defines.RM_INVOKE_FUNCTION_RELEASESTREAM: //1. Attempt to find the stream var streams = Application.StreamsManager.FindByProtocolIdByName(pFrom.Id, message.InvokeParam[1], false); uint streamId = 0; if (streams.Count > 0) { //2. Is this the correct kind? if (streams.Values.First().Type.TagKindOf(StreamTypes.ST_IN_NET_RTMP)) { //3. get the rtmp stream id pInNetRTMPStream = (InNetRTMPStream)streams.Values.First(); streamId = pInNetRTMPStream.RtmpStreamId; //4. close the stream if (!pFrom.CloseStream(streamId, true)) { Logger.FATAL("Unable to close stream"); return true; } } } if (streamId > 0) { //5. Send the response if (!pFrom.SendMessage( StreamMessageFactory.GetInvokeReleaseStreamResult(3, streamId, message.InvokeId, streamId), true)) { Logger.FATAL("Unable to send message to client"); return false; } } else { if (!pFrom.SendMessage( StreamMessageFactory.GetInvokeReleaseStreamErrorNotFound(message), true)) { Logger.FATAL("Unable to send message to client"); return false; } } //3. Done return true; case Defines.RM_INVOKE_FUNCTION_DELETESTREAM: return pFrom.CloseStream(message.InvokeParam[1], false); case Defines.RM_INVOKE_FUNCTION_RESULT: case Defines.RM_INVOKE_FUNCTION_ERROR: if (!_resultMessageTracking.ContainsKey(pFrom.Id) || !_resultMessageTracking[pFrom.Id].ContainsKey(message.InvokeId)) return true; var request0 = _resultMessageTracking[pFrom.Id][message.InvokeId]; switch (request0.InvokeFunction) { case Defines.RM_INVOKE_FUNCTION_CONNECT: return ProcessInvokeConnectResult(pFrom, request0, message); case Defines.RM_INVOKE_FUNCTION_CREATESTREAM: return ProcessInvokeCreateStreamResult(pFrom, request0, message); case Defines.RM_INVOKE_FUNCTION_FCSUBSCRIBE: return true; case Defines.RM_INVOKE_FUNCTION_ONBWCHECK: startTime = pFrom.CustomParameters["lastOnnBWCheckMessage"]; double totalTime = (DateTime.Now.Ticks - startTime) / (double)1000000; var speed = (int)(ONBWCHECK_SIZE / totalTime / 1024.0 * 8.0); return SendRTMPMessage(pFrom, GenericMessageFactory.GetInvokeOnBWDone(speed)); default: Logger.WARN("Invoke result not yet implemented: Request:{0} Response:{1}", request0.ToString(), message.ToString()); return true; } case Defines.RM_INVOKE_FUNCTION_ONSTATUS: return ProcessInvokeOnStatus(pFrom, message); case Defines.RM_INVOKE_FUNCTION_FCPUBLISH: //1. Get the stream name streamName = message.InvokeParam[1]; //2. Send the release stream response. Is identical to the one //needed by this f****r //TODO: this is a nasty hack if (!pFrom.SendMessage( StreamMessageFactory.GetInvokeReleaseStreamResult(3, 0, message.InvokeId, 0), true)) { Logger.FATAL("Unable to send message to client"); return false; } //3. send the onFCPublish message if (!SendRTMPMessage(pFrom, StreamMessageFactory.GetInvokeOnFCPublish(3, 0, 0, false, 0, Defines.RM_INVOKE_PARAMS_ONSTATUS_CODE_NETSTREAMPUBLISHSTART, streamName))) { Logger.FATAL("Unable to send message to client"); return false; } //4. Done return true; case Defines.RM_INVOKE_FUNCTION_GETSTREAMLENGTH: metadata = GetMetaData(message.InvokeParam[1], true); var _params = Variant.GetList(Variant.Get(),metadata == VariantType.Map ? metadata[Defines.META_FILE_DURATION]/1000.00 : 0.0); if (!SendRTMPMessage(pFrom, GenericMessageFactory.GetInvokeResult(message, _params))) { Logger.FATAL("Unable to send message to client"); return false; } return true; case Defines.RM_INVOKE_FUNCTION_ONBWDONE: return true; case Defines.RM_INVOKE_FUNCTION_CHECKBANDWIDTH: case "_checkbw": if (!_enableCheckBandwidth) { Logger.WARN("checkBandwidth is disabled."); return true; } if (!SendRTMPMessage(pFrom, _onBWCheckMessage,true, false)) { Logger.FATAL("Unable to send message to flash player"); return false; } pFrom.CustomParameters["lastOnnBWCheckMessage"] = DateTime.Now.Ticks; return true; case "receiveAudio": pBaseOutNetRTMPStream = Application.StreamsManager.FindByProtocolIdByType(pFrom.Id, StreamTypes.ST_OUT_NET_RTMP, true).Values.OfType<BaseOutNetRTMPStream>().SingleOrDefault(x => x.RTMPStreamId ==message.StreamId); if (pBaseOutNetRTMPStream != null) pBaseOutNetRTMPStream.ReceiveAudio = message.InvokeParam[1]; return true; case "receiveVideo": pBaseOutNetRTMPStream = Application.StreamsManager.FindByProtocolIdByType(pFrom.Id, StreamTypes.ST_OUT_NET_RTMP, true).Values.OfType<BaseOutNetRTMPStream>().SingleOrDefault(x => x.RTMPStreamId == message.StreamId); if (pBaseOutNetRTMPStream != null) pBaseOutNetRTMPStream.ReceiveVideo = message.InvokeParam[1]; return true; default: return ProcessInvokeGeneric(pFrom, message); } case Defines.RM_HEADER_MESSAGETYPE_ABORTMESSAGE: if (messageBody[Defines.RM_ABORTMESSAGE] != VariantType.Numberic) { Logger.FATAL("Invalid message {0}", messageBody.ToString()); return false; } return pFrom.ResetChannel(messageBody[Defines.RM_ABORTMESSAGE]); default: Logger.FATAL("Request type not yet implemented:{0}", messageBody.ToString()); return false; } }