public void Publish([FromOptionalArgument] string publishingName, [FromOptionalArgument] string publishingType) { if (string.IsNullOrEmpty(publishingName)) { throw new InvalidOperationException("empty publishing name"); } if (!PublishingHelpers.IsTypeSupported(publishingType)) { throw new InvalidOperationException($"not supported publishing type {publishingType}"); } _publishingType = PublishingHelpers.PublishingTypes[publishingType]; _publisherSessionService.RegisterPublisher(publishingName, this); RtmpSession.SendControlMessageAsync(new StreamBeginMessage() { StreamID = MessageStream.MessageStreamId }); var onStatus = RtmpSession.CreateCommandMessage <OnStatusCommandMessage>(); MessageStream.RegisterMessageHandler <DataMessage>(HandleDataMessage); MessageStream.RegisterMessageHandler <AudioMessage>(HandleAudioMessage); MessageStream.RegisterMessageHandler <VideoMessage>(HandleVideoMessage); onStatus.InfoObject = new AmfObject { { "level", "status" }, { "code", "NetStream.Publish.Start" }, { "description", "Stream is now published." }, { "details", publishingName } }; MessageStream.SendMessageAsync(ChunkStream, onStatus); }
public async Task Seek([FromOptionalArgument] double milliSeconds) { var resetData = new AmfObject { { "level", "status" }, { "code", "NetStream.Seek.Notify" }, { "description", "Seeking stream." }, { "details", "seek" } }; var resetStatus = RtmpSession.CreateCommandMessage <OnStatusCommandMessage>(); resetStatus.InfoObject = resetData; await MessageStream.SendMessageAsync(ChunkStream, resetStatus); _playCts?.Cancel(); while (_playing == 1) { await Task.Yield(); } var cts = new CancellationTokenSource(); _playCts?.Dispose(); _playCts = cts; await SeekAndPlay(milliSeconds, cts.Token); }
public async Task Play( [FromOptionalArgument] string streamName, [FromOptionalArgument] double start = -1, [FromOptionalArgument] double duration = -1, [FromOptionalArgument] bool reset = false) { _recordFile = new FileStream(_recordService.GetRecordFilename(streamName) + ".flv", FileMode.Open, FileAccess.Read); await FlvDemuxer.AttachStream(_recordFile); var resetData = new AmfObject { { "level", "status" }, { "code", "NetStream.Play.Reset" }, { "description", "Resetting and playing stream." }, { "details", streamName } }; var resetStatus = RtmpSession.CreateCommandMessage <OnStatusCommandMessage>(); resetStatus.InfoObject = resetData; await MessageStream.SendMessageAsync(ChunkStream, resetStatus); var startData = new AmfObject { { "level", "status" }, { "code", "NetStream.Play.Start" }, { "description", "Started playing." }, { "details", streamName } }; var startStatus = RtmpSession.CreateCommandMessage <OnStatusCommandMessage>(); startStatus.InfoObject = startData; await MessageStream.SendMessageAsync(ChunkStream, startStatus); var bandwidthLimit = new WindowAcknowledgementSizeMessage() { WindowSize = 500 * 1024 }; await RtmpSession.ControlMessageStream.SendMessageAsync(RtmpSession.ControlChunkStream, bandwidthLimit); VideoChunkStream = RtmpSession.CreateChunkStream(); AudioChunkStream = RtmpSession.CreateChunkStream(); var cts = new CancellationTokenSource(); _playCts?.Dispose(); _playCts = cts; start = Math.Max(start, 0); await SeekAndPlay(start / 1000, cts.Token); }
public async Task Publish([FromOptionalArgument] string streamName, [FromOptionalArgument] string publishingType) { if (string.IsNullOrEmpty(streamName)) { throw new InvalidOperationException("empty publishing name"); } if (!PublishingHelpers.IsTypeSupported(publishingType)) { throw new InvalidOperationException($"not supported publishing type {publishingType}"); } _publishingType = PublishingHelpers.PublishingTypes[publishingType]; await RtmpSession.SendControlMessageAsync(new StreamIsRecordedMessage() { StreamID = MessageStream.MessageStreamId }); await RtmpSession.SendControlMessageAsync(new StreamBeginMessage() { StreamID = MessageStream.MessageStreamId }); var onStatus = RtmpSession.CreateCommandMessage <OnStatusCommandMessage>(); MessageStream.RegisterMessageHandler <DataMessage>(HandleData); MessageStream.RegisterMessageHandler <AudioMessage>(HandleAudioMessage); MessageStream.RegisterMessageHandler <VideoMessage>(HandleVideoMessage); MessageStream.RegisterMessageHandler <UserControlMessage>(HandleUserControlMessage); onStatus.InfoObject = new AmfObject { { "level", "status" }, { "code", "NetStream.Publish.Start" }, { "description", "Stream is now published." }, { "details", streamName } }; await MessageStream.SendMessageAsync(ChunkStream, onStatus); _recordFileData = new FileStream(_recordService.GetRecordFilename(streamName) + ".data", FileMode.OpenOrCreate); _recordFileData.SetLength(0); _keyframes = new AmfObject(); _keyframeTimes = new List <object>(); _keyframeFilePositions = new List <object>(); _keyframes.Add("times", _keyframeTimes); _keyframes.Add("filepositions", _keyframeFilePositions); }
public async Task Play( [FromOptionalArgument] string streamName, [FromOptionalArgument] double start = -1, [FromOptionalArgument] double duration = -1, [FromOptionalArgument] bool reset = false) { var publisher = _publisherSessionService.FindPublisher(streamName); if (publisher == null) { throw new KeyNotFoundException(); } var resetData = new AmfObject { { "level", "status" }, { "code", "NetStream.Play.Reset" }, { "description", "Resetting and playing stream." }, { "details", streamName } }; var resetStatus = RtmpSession.CreateCommandMessage <OnStatusCommandMessage>(); resetStatus.InfoObject = resetData; await MessageStream.SendMessageAsync(ChunkStream, resetStatus); var startData = new AmfObject { { "level", "status" }, { "code", "NetStream.Play.Start" }, { "description", "Started playing." }, { "details", streamName } }; var startStatus = RtmpSession.CreateCommandMessage <OnStatusCommandMessage>(); startStatus.InfoObject = startData; await MessageStream.SendMessageAsync(ChunkStream, startStatus); var flvMetadata = RtmpSession.CreateData <DataMessage>(); flvMetadata.MessageHeader = (MessageHeader)publisher.FlvMetadata.MessageHeader.Clone(); flvMetadata.Data = publisher.FlvMetadata.Data; await MessageStream.SendMessageAsync(ChunkStream, flvMetadata); _videoChunkStream = RtmpSession.CreateChunkStream(); _audioChunkStream = RtmpSession.CreateChunkStream(); if (publisher.AACConfigureRecord != null) { await MessageStream.SendMessageAsync(_audioChunkStream, publisher.AACConfigureRecord.Clone() as AudioMessage); } if (publisher.AVCConfigureRecord != null) { await MessageStream.SendMessageAsync(_videoChunkStream, publisher.AVCConfigureRecord.Clone() as VideoMessage); } publisher.OnAudioMessage += SendAudio; publisher.OnVideoMessage += SendVideo; _cleanupActions.Add(() => { publisher.OnVideoMessage -= SendVideo; publisher.OnAudioMessage -= SendAudio; }); }