private async void StartPlay(IChannelHandlerContext ctx, MediaStream stream) { try { await ctx.WriteAndFlushAsync(UserControlMessageEvent.StreamBegin(Constants.DEFAULT_STREAM_ID)); RtmpCommandMessage onStatus = OnStatus("status", "NetStream.Play.Start", "Start live"); await ctx.WriteAndFlushAsync(onStatus); var args = new List <Object>(); args.Add("|RtmpSampleAccess"); args.Add(true); args.Add(true); RtmpCommandMessage rtmpSampleAccess = new RtmpCommandMessage(args); await ctx.WriteAndFlushAsync(rtmpSampleAccess); var metadata = new List <Object>(); metadata.Add("onMetaData"); metadata.Add(stream.Metadata); RtmpDataMessage msgMetadata = new RtmpDataMessage(metadata); await ctx.WriteAndFlushAsync(msgMetadata); await stream.AddSubscriber(ctx.Channel); } catch (Exception ex) { var i = 0; } }
private void HandleCommand(IChannelHandlerContext ctx, RtmpCommandMessage msg) { var command = msg.Command; var commandName = (String)command[0].ToString(); switch (commandName) { case "connect": HandleConnect(ctx, msg); break; case "createStream": HandleCreateStream(ctx, msg); break; case "publish": HandlePublish(ctx, msg); _readAction?.Invoke(ctx, _streamName, msg); break; case "play": HandlePlay(ctx, msg); break; case "deleteStream": case "closeStream": HandleCloseStream(ctx, msg); _readAction?.Invoke(ctx, _streamName, msg); break; default: break; } }
private async void HandleCreateStream(IChannelHandlerContext ctx, RtmpCommandMessage msg) { logger.Info($"create stream received : {msg}"); var result = new List <Object>(); result.Add("_result"); result.Add(msg.Command[1]); result.Add(null); result.Add(Constants.DEFAULT_STREAM_ID); RtmpCommandMessage response = new RtmpCommandMessage(result); await ctx.WriteAndFlushAsync(response); }
public RtmpCommandMessage OnStatus(String level, String code, String description) { var result = new List <Object>(); result.Add("onStatus"); result.Add(0); result.Add(null); result.Add(new AMF0Object().AddProperty("level", level).AddProperty("code", code).AddProperty("description", description)); RtmpCommandMessage response = new RtmpCommandMessage(result); return(response); }
private async void HandleConnect(IChannelHandlerContext ctx, RtmpCommandMessage msg) { logger.Info($"client connect {msg} "); var command = ((Dictionary <string, object>)msg.Command[2]); var app = command.GetValueOrDefault("app").ToString(); var clientRequestEncode = command.GetValueOrDefault("objectEncoding"); if (!string.Equals(app, RtmpConfig.Instance.App, StringComparison.OrdinalIgnoreCase)) { await ctx.CloseAsync(); return; } if (clientRequestEncode != null && clientRequestEncode.ToString() == "3") { logger.Error($"client :{ctx} request AMF3 encoding server doesn't support"); await ctx.CloseAsync(); return; } _streamName = new StreamName(app, null, false); int ackSize = 5000000; WindowAcknowledgementSize was = new WindowAcknowledgementSize(ackSize); var spb = new SetPeerBandWidth(ackSize, Constants.SET_PEER_BANDWIDTH_TYPE_SOFT); SetChunkSize setChunkSize = new SetChunkSize(5000); await ctx.WriteAndFlushAsync(was); await ctx.WriteAndFlushAsync(spb); await ctx.WriteAndFlushAsync(setChunkSize); var result = new List <Object>(); result.Add("_result"); result.Add(msg.Command[1]); // transaction id result.Add(new AMF0Object().AddProperty("fmsVer", "FMS/3,0,1,123").AddProperty("capabilities", 31)); result.Add(new AMF0Object().AddProperty("level", "status").AddProperty("code", "NetConnection.Connect.Success") .AddProperty("description", "Connection succeeded").AddProperty("objectEncoding", 0)); RtmpCommandMessage response = new RtmpCommandMessage(result); await ctx.WriteAndFlushAsync(response); }
private async void HandlePublish(IChannelHandlerContext ctx, RtmpCommandMessage msg) { logger.Info($"publish :{msg}"); _tag = RtmpTag.Publisher; var streamType = msg.Command[4].ToString(); if (streamType != "live") { await ctx.Channel.DisconnectAsync(); } var name = msg.Command[3].ToString(); _streamName.Name = name; CreateStream(ctx); RtmpCommandMessage onStatus = OnStatus("status", "NetStream.Publish.Start", "Start publishing"); await ctx.WriteAndFlushAsync(onStatus); }
private async void HandleCloseStream(IChannelHandlerContext ctx, RtmpCommandMessage msg) { MediaStream stream = _mediaStreamDic.GetValueOrDefault(_streamName); try { if (_tag == RtmpTag.Subscriber) { logger.Info($"subscriber:{ctx.Channel.RemoteAddress} close"); return; } var onStatus = OnStatus("status", "NetStream.Unpublish.Success", "Stop publishing"); await ctx.WriteAsync(onStatus); if (stream == null) { logger.Error($"can't find stream:{nameof(_streamName)} in buffer queue"); } else { if (stream != null) { await stream.SendEofToAllSubscriberAndClose(); _mediaStreamDic.Remove(_streamName, out MediaStream mediaStream); } _normalShutdown = true; await ctx.CloseAsync(); } } catch { if (stream != null) { await stream.SendEofToAllSubscriberAndClose(); _mediaStreamDic.Remove(_streamName, out MediaStream mediaStream); } await ctx.CloseAsync(); } }
private async void HandlePlay(IChannelHandlerContext ctx, RtmpCommandMessage msg) { _tag = RtmpTag.Subscriber; var name = (String)msg.Command[3]; _streamName.Name = name; var stream = _mediaStreamDic.GetValueOrDefault(_streamName); if (stream == null) { logger.Info($"client play request for stream:{nameof(_streamName)} not exist."); RtmpCommandMessage onStatus = OnStatus("error", "NetStream.Play.StreamNotFound", "No Such Stream"); await ctx.WriteAndFlushAsync(onStatus); _normalShutdown = true; await ctx.Channel.CloseAsync(); } else { StartPlay(ctx, stream); } }
public static AbstractRtmpMessage Decode(RtmpHeader header, IByteBuffer payload) { AbstractRtmpMessage result = null; short messageTypeId = header.MessageTypeId; switch (messageTypeId) { case Constants.MSG_SET_CHUNK_SIZE: { int readInt = payload.ReadInt(); SetChunkSize setChunkSize = new SetChunkSize(); setChunkSize.ChunkSize = readInt; result = setChunkSize; } break; case Constants.MSG_ABORT_MESSAGE: { int csid = payload.ReadInt(); Abort abort = new Abort(csid); result = abort; } break; case Constants.MSG_ACKNOWLEDGEMENT: { int ack = payload.ReadInt(); result = new Acknowledgement(ack); } break; case Constants.MSG_WINDOW_ACKNOWLEDGEMENT_SIZE: { int size = payload.ReadInt(); result = new WindowAcknowledgementSize(size); } break; case Constants.MSG_SET_PEER_BANDWIDTH: { int ackSize = payload.ReadInt(); int type = payload.ReadByte(); result = new SetPeerBandWidth(ackSize, type); } break; case Constants.MSG_TYPE_COMMAND_AMF0: { List <Object> decode = AMF0.DecodeAll(payload); result = new RtmpCommandMessage(decode); } break; case Constants.MSG_USER_CONTROL_MESSAGE_EVENTS: { short readShort = payload.ReadShort(); int data = payload.ReadInt(); result = new UserControlMessageEvent(readShort, data); } break; case Constants.MSG_TYPE_AUDIO_MESSAGE: { AudioMessage am = new AudioMessage(); byte[] data = ReadAll(payload); am.AudioData = data; if (header.Fmt == Constants.CHUNK_FMT_0) { am.Timestamp = header.Timestamp; } else if (header.Fmt == Constants.CHUNK_FMT_1 || header.Fmt == Constants.CHUNK_FMT_2) { am.TimestampDelta = header.TimestampDelta; } result = am; } break; case Constants.MSG_TYPE_VIDEO_MESSAGE: { VideoMessage vm = new VideoMessage(); byte[] data = ReadAll(payload); vm.VideoData = data; if (header.Fmt == Constants.CHUNK_FMT_0) { vm.Timestamp = header.Timestamp; } else if (header.Fmt == Constants.CHUNK_FMT_1 || header.Fmt == Constants.CHUNK_FMT_2) { vm.TimestampDelta = header.TimestampDelta; } result = vm; } break; case Constants.MSG_TYPE_DATA_MESSAGE_AMF0: { result = new RtmpDataMessage(AMF0.DecodeAll(payload)); } break; default: break; } if (result != null) { result.InboundBodyLength = header.MessageLength; result.InboundHeaderLength = header.HeaderLength; return(result); } else { return(null); } }
public void Publish(ConcurrentDictionary <StreamName, MediaStream> streams, RtmpCommandMessage msg) { var streamName = new StreamName(msg.Command[4].ToString(), msg.Command[3].ToString(), false); streams.GetOrAdd(streamName, new MediaStream(streamName)); }