public LivingStream GetLivingStream(string streamName)
        {
            if (publisherSessionService == null && serverTask != null)
            {
                var type            = options.GetType();
                var proInfo         = type.GetProperty("ScopedServiceProvider", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
                var serviceProvider = (IServiceProvider)proInfo.GetValue(options);
                publisherSessionService = serviceProvider.GetService <PublisherSessionService>();
            }

            var _ = publisherSessionService ?? throw new InvalidOperationException("无法获取直播流");

            return(publisherSessionService.FindPublisher(streamName));
        }
        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;
            });
        }
        public override async Task OnConnect()
        {
            var publisher = _publisherSessionService.FindPublisher(StreamName);

            if (publisher != null)
            {
                _cleanupActions.Add(() =>
                {
                    publisher.OnAudioMessage -= SendAudio;
                    publisher.OnVideoMessage -= SendVideo;
                });

                var metadata = (Dictionary <string, object>)publisher.FlvMetadata.Data.Last();
                var hasAudio = metadata.ContainsKey("audiocodecid");
                var hasVideo = metadata.ContainsKey("videocodecid");

                await Session.SendFlvHeaderAsync(hasAudio, hasVideo);

                await Session.SendMessageAsync(publisher.FlvMetadata);

                if (hasAudio)
                {
                    await Session.SendMessageAsync(publisher.AACConfigureRecord);
                }
                if (hasVideo)
                {
                    await Session.SendMessageAsync(publisher.AVCConfigureRecord);
                }

                publisher.OnAudioMessage += SendAudio;
                publisher.OnVideoMessage += SendVideo;
            }
            // play record
            else
            {
                _recordFile = new FileStream(_recordService.GetRecordFilename(StreamName) + ".flv", FileMode.Open, FileAccess.Read);
                var  fromStr = Query.Get("from");
                long from    = 0;
                if (fromStr != null)
                {
                    from = long.Parse(fromStr);
                }
                var toStr = Query.Get("to");
                _playRangeTo = -1;
                if (toStr != null)
                {
                    _playRangeTo = long.Parse(toStr);
                }

                var header = new byte[9];

                await _recordFile.ReadBytesAsync(header);

                await Session.SendRawDataAsync(header);

                from = Math.Max(from, 9);

                _recordFile.Seek(from, SeekOrigin.Begin);

                await PlayRecordFile();
            }
        }