public async Task ConnectAsync(string appName)
        {
            var command = new AmfCommandMessage
            {
                Name          = "connect",
                TransactionId = NextTrasactionId,
                CommandObject = new
                {
                    app      = appName,
                    flashVer = _configuration.Value.FlashVersion,
                },
            };

            _pendingTransactions.Add(command.TransactionId, (args) =>
            {
                _logger.LogInformation($"Connect to server version:{args.CommandObject.fmsVer} capabilities:{args.CommandObject.capabilities}");
                UpdateState(ClientSessionState.Conntected);
                return(Task.CompletedTask);
            });
            await _commandProcessor.SendCommandMessageAsync(0, command);
        }
        private async Task HandleDeleteStreamAsync(AmfCommandMessage command)
        {
            if (_session.IsPlaying)
            {
                _context.RemovePlayer(_session.PlayStream.Path, _session.Id);
                _logger.LogInformation($@"[rtmp play] Close stream. id ={_session.Id}
                streamPath ={_session.PlayStream.Path}
                streamId =${ _session.PlayStream.Id}");
                await SendStatusMessageAsync(_session.PlayStream.Id, "status", "NetStream.Play.Stop", "Stopped playing stream.");
            }
            if (_session.IsPublishing)
            {
                var stream = _session.PublishStream;
                _logger.LogInformation($@"[rtmp publish] Close stream. id ={_session.Id}
                streamPath ={stream.Path} streamId ={stream.Id}");
                await SendStatusMessageAsync(stream.Id, "status", "NetStream.Unpublish.Success", $"{stream.Path} is now unpublished.");

                await _session.SendStopToAllPlayersAsync();

                _session.PublishStream = null;
                _context.RemovePublisher(stream.Path);
            }
        }
        private async Task HandlePlayAsync(RtmpMessage message, AmfCommandMessage command)
        {
            var streamName = command.AdditionalArguments[0] as string;
            var streamPath = $"/{_application}/{streamName.Split("?")[0]}";
            var streamId   = message.Message.StreamId;
            var stream     = new RtmpStream(streamId, streamName, streamPath);

            if (_session.IsPlaying)
            {
                _logger.LogInformation($@"[rtmp play] NetConnection is playing.id ={_session.Id}
                streamPath ={streamPath}
                streamId ={streamId} ");
                await SendStatusMessageAsync(streamId, "error", "NetStream.Play.BadConnection", "Connection already playing");

                return;
            }
            else
            {
                _session.PlayStream = stream;
                await RespondPlayAsync(stream);
            }

            if (_context.TryGetPublishser(streamPath, out var publisher))
            {
                await OnStartPlayAsync(publisher, stream);

                _context.AddPlayer(streamPath, _session.Id);
            }
            else
            {
                _logger.LogInformation($@"[rtmp play] Stream not found.id ={_session.Id}
                streamPath ={streamPath}
                streamId ={streamId}");
                _context.AddIdlePlayer(streamPath, _session.Id);
            }
        }
 protected abstract Task ProcessCommandAsync(AmfCommandMessage command, RtmpMessage message);
 private Task HandlePauseAsync(RtmpMessage message, AmfCommandMessage command)
 {
     throw new NotImplementedException();
 }
 private Task HandleCloseStreamAsync(AmfCommandMessage command)
 {
     throw new NotImplementedException();
 }