Exemple #1
0
        private async Task PlaySong(YoutubeExplode.Videos.Video input)
        {
            try
            {
                await audioClient.SetSpeakingAsync(true);

                var streamManifest = await youtube.Videos.Streams.GetManifestAsync(input.Id, Skip.Token);

                var streamInfo = streamManifest.GetAudioOnlyStreams().GetWithHighestBitrate();

                var stream = await youtube.Videos.Streams.GetAsync(streamInfo, Skip.Token);

                var memoryStream = new MemoryStream();
                await Cli.Wrap("ffmpeg")
                .WithArguments(" -hide_banner -loglevel panic -i pipe:0 -ac 2 -f s16le -ar 48000 pipe:1")
                .WithStandardInputPipe(PipeSource.FromStream(stream))
                .WithStandardOutputPipe(PipeTarget.ToStream(memoryStream))
                .ExecuteAsync(Skip.Token);

                using (var discord = audioClient.CreatePCMStream(AudioApplication.Music))
                {
                    try { await discord.WriteAsync(memoryStream.ToArray(), 0, (int)memoryStream.Length, Skip.Token); }
                    finally { await discord.FlushAsync(); }
                }
            }
            catch (Exception)
            {
            }
        }
Exemple #2
0
        public async Task I_can_execute_a_command_that_pipes_its_stdout_into_multiple_streams()
        {
            // Arrange
            const int expectedSize = 100_000;

            await using var stream1 = new MemoryStream();
            await using var stream2 = new MemoryStream();
            await using var stream3 = new MemoryStream();

            var pipeTarget = PipeTarget.Merge(
                PipeTarget.ToStream(stream1),
                PipeTarget.ToStream(stream2),
                PipeTarget.ToStream(stream3)
                );

            var cmd = Cli.Wrap("dotnet")
                      .WithArguments(a => a
                                     .Add(Dummy.Program.FilePath)
                                     .Add(Dummy.Program.PrintRandomBinary)
                                     .Add(expectedSize)) | pipeTarget;

            // Act
            await cmd.ExecuteAsync();

            // Assert
            stream1.Length.Should().Be(expectedSize);
            stream2.Length.Should().Be(expectedSize);
            stream3.Length.Should().Be(expectedSize);
            stream1.ToArray().Should().BeEquivalentTo(stream2.ToArray());
            stream2.ToArray().Should().BeEquivalentTo(stream3.ToArray());
        }
Exemple #3
0
        public static EsiSystem ConvertTextSchema(EsiContext ctxt, FileInfo file)
        {
            var exeDir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;

            using (var memstream = new MemoryStream())
            {
                var errorStringBuilder = new StringBuilder();
                var capnpCmd           = Cli.Wrap("capnp")
                                         .WithEnvironmentVariables(new Dictionary <string, string>()
                {
                    ["LD_LIBRARY_PATH"] = exeDir
                })
                                         .WithArguments($"compile -I{Path.Join(Esi.Utils.RootDir.FullName, "capnp.convert")} -o- {file.FullName}")
                                         .WithStandardOutputPipe(PipeTarget.ToStream(memstream))
                                         .WithStandardErrorPipe(PipeTarget.ToStringBuilder(errorStringBuilder))
                                         .WithValidation(CommandResultValidation.ZeroExitCode);

                try
                {
                    Task.Run(async() => await capnpCmd.ExecuteAsync()).Wait();
                }
                catch (AggregateException ex)
                {
                    if (ex.InnerException is CommandExecutionException cee)
                    {
                        ctxt.Log.Error($"CapNProto Error:\n{errorStringBuilder.ToString()}");
                    }
                    ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
                }
                Debug.Assert(memstream.Length > 0);

                memstream.Seek(0, SeekOrigin.Begin);
                return(ConvertFromCGRMessage(ctxt, memstream));
            }
        }
Exemple #4
0
        private async void StartStream(YoutubeClient youtube, AudioClient audioClient, AudioOnlyStreamInfo streamInfo, IMessage?message)
        {
            Stream ytStream = await youtube.Videos.Streams.GetAsync(streamInfo);

            // Convert yt stream
            MemoryStream memoryStream = new MemoryStream();
            await Cli.Wrap("ffmpeg")
            .WithArguments(" -hide_banner -loglevel panic -i pipe:0 -ac 2 -f s16le -ar 48000 pipe:1")
            .WithStandardInputPipe(PipeSource.FromStream(ytStream))
            .WithStandardOutputPipe(PipeTarget.ToStream(memoryStream))
            .ExecuteAsync();

            // Clear stream before beginning
            if (audioClient.CurrentStream != null)
            {
                audioClient.CurrentStream.Dispose();
                audioClient.CurrentStream = null;
            }

            AudioOutStream discord = audioClient.Client.CreatePCMStream(AudioApplication.Mixed);

            audioClient.CurrentStream = discord;

            // Delete calling command
            if (message != null)
            {
                await message.DeleteAsync();
            }

            // Start playing music
            await this.WriteStreamToVoiceChannel(audioClient, discord, memoryStream);
        }
Exemple #5
0
        public static IGit New()
        {
            var consoleOutputTarget = PipeTarget.ToStream(Console.OpenStandardOutput());
            var command             = Cli.Wrap("git")
                                      .WithStandardOutputPipe(consoleOutputTarget);

            return(new Git(command));
        }
Exemple #6
0
        public void I_can_create_a_new_command_from_an_existing_one_by_specifying_different_stderr_pipe()
        {
            // Arrange
            var cmd = Cli.Wrap("foo").WithStandardErrorPipe(PipeTarget.Null);

            // Act
            var cmdOther = cmd.WithStandardErrorPipe(PipeTarget.ToStream(Stream.Null));

            // Assert
            cmd.Should().BeEquivalentTo(cmdOther, o => o.Excluding(c => c.StandardErrorPipe));
            cmd.StandardErrorPipe.Should().NotBeSameAs(cmdOther.StandardErrorPipe);
        }
        public void Stderr_pipe_can_be_set()
        {
            // Arrange
            var cmd = Cli.Wrap("foo").WithStandardErrorPipe(PipeTarget.Null);

            // Act
            var cmdOther = cmd.WithStandardErrorPipe(PipeTarget.ToStream(Stream.Null));

            // Assert
            cmd.Should().BeEquivalentTo(cmdOther, o => o.Excluding(c => c.StandardErrorPipe));
            cmd.StandardErrorPipe.Should().NotBeSameAs(cmdOther.StandardErrorPipe);
        }
Exemple #8
0
        public async Task <(Stream, Stream)> ExecuteWithCliWrap_PipeToMultipleStreams()
        {
            await using var stream1 = new MemoryStream();
            await using var stream2 = new MemoryStream();

            var target = PipeTarget.Merge(
                PipeTarget.ToStream(stream1),
                PipeTarget.ToStream(stream2)
                );

            var command = Cli.Wrap(FilePath).WithArguments(Args) | target;
            await command.ExecuteAsync();

            return(stream1, stream2);
        }
    public Command ConvertToPng(string ffmpegPath, string inputFile, string outputFile)
    {
        Process process = new FFmpegProcessBuilder(ffmpegPath, false, _logger)
                          .WithThreads(1)
                          .WithQuiet()
                          .WithInput(inputFile)
                          .WithOutputFormat("apng", outputFile)
                          .Build();

        return(Cli.Wrap(process.StartInfo.FileName)
               .WithArguments(process.StartInfo.ArgumentList)
               .WithValidation(CommandResultValidation.None)
               .WithEnvironmentVariables(process.StartInfo.Environment.ToDictionary(kvp => kvp.Key, kvp => kvp.Value))
               .WithStandardErrorPipe(PipeTarget.ToStream(Stream.Null)));
    }
    public Command WrapSegmenter(string ffmpegPath, bool saveReports, Channel channel, string scheme, string host)
    {
        FFmpegPlaybackSettings playbackSettings = _playbackSettingsCalculator.ConcatSettings;

        Process process = new FFmpegProcessBuilder(ffmpegPath, saveReports, _logger)
                          .WithThreads(1)
                          .WithQuiet()
                          .WithFormatFlags(playbackSettings.FormatFlags)
                          .WithRealtimeOutput(true)
                          .WithInput($"http://localhost:{Settings.ListenPort}/iptv/channel/{channel.Number}.m3u8?mode=segmenter")
                          .WithMap("0")
                          .WithCopyCodec()
                          .WithMetadata(channel, None)
                          .WithFormat("mpegts")
                          .WithPipe()
                          .Build();

        return(Cli.Wrap(process.StartInfo.FileName)
               .WithArguments(process.StartInfo.ArgumentList)
               .WithValidation(CommandResultValidation.None)
               .WithEnvironmentVariables(process.StartInfo.Environment.ToDictionary(kvp => kvp.Key, kvp => kvp.Value))
               .WithStandardErrorPipe(PipeTarget.ToStream(Stream.Null)));
    }
        public async Task <int> ExecuteWithCliWrap()
        {
            await using var stream1 = new MemoryStream();
            await using var stream2 = new MemoryStream();

            var result = await(Cli.Wrap(FilePath).WithArguments(Args) | PipeTarget.Merge(PipeTarget.ToStream(stream1), PipeTarget.ToStream(stream2))).ExecuteAsync();

            return(result.ExitCode);
        }
Exemple #12
0
        private async Task SendAudioAsync()
        {
            if (CurrentSong == null)
            {
                await DiscordAudioClient.StopAsync();

                return;
            }

            using (var _stream = DiscordAudioClient.CreatePCMStream(AudioApplication.Music))
            {
                try
                {
                    var argument = $"-hide_banner -loglevel panic -i \"{CurrentSong.StreamUrl}\" -ac 2 -f s16le -ar 48000 pipe:1";
                    await Cli.Wrap(Helper.GetFilePath("ffmpeg")).WithArguments(argument).WithStandardOutputPipe(PipeTarget.ToStream(_stream)).ExecuteAsync();
                }
                catch (Exception ex)
                {
                    _logger.Error(ex, $"Error in {nameof(SendAudioAsync)}");
                }
                finally
                {
                    await _stream.FlushAsync();

                    Playlist.Remove(CurrentSong);
                }
            }
        }
Exemple #13
0
        public async Task SendYTAudioAsync(IGuild guild, IMessageChannel channel, IVoiceChannel target, string path, double volume = 1.0)
        {
            volume *= 0.25;


            CurrentAudioInformation client;

            if (CurrentAudioClients.TryGetValue(guild.Id, out client))
            {
                await CheckAudioClient(guild, target, client.client);

                string youtubeID = GetYouTubeVideoIdFromUrl(path);

                if (youtubeID == null)
                {
                    await channel.SendMessageAsync("That is not a valid youtube link!");

                    return;
                }

                if (!string.IsNullOrEmpty(client.playing))
                {
                    client.queue.Enqueue(path);
                    await channel.SendMessageAsync($"Added {path} to the queue.");

                    return;
                }

                client.playing = path;

                await _log.LogAsync(new LogMessage(LogSeverity.Info, "Audio", $"Starting playback of {path} in {guild.Name}"));

                if (client.currentStream == null)
                {
                    client.currentStream = client.client.CreatePCMStream(AudioApplication.Mixed, 98304, 200);
                }

                var youtube = new YoutubeClient();

                var streamManifest = await youtube.Videos.Streams.GetManifestAsync(youtubeID);

                var streamInfo = streamManifest.GetAudioOnlyStreams().GetWithHighestBitrate();

                var memoryStream = new MemoryStream();
                var video        = await youtube.Videos.Streams.GetAsync(streamInfo);

                await Cli.Wrap("ffmpeg")
                .WithArguments($"-hide_banner -loglevel panic -i pipe:0 -filter:a \"volume = {volume}\" -ac 2 -f s16le -ar 48000 pipe:1")
                .WithStandardInputPipe(PipeSource.FromStream(video))
                .WithStandardOutputPipe(PipeTarget.ToStream(memoryStream))
                .ExecuteAsync();

                try {
                    client.cancelTokenSource = new CancellationTokenSource();
                    await client.currentStream.WriteAsync(memoryStream.ToArray(), 0, (int)memoryStream.Length, client.cancelTokenSource.Token);
                } catch (OperationCanceledException e) {
                    await channel.SendMessageAsync($"Stopped http://youtu.be/{youtubeID}");
                } finally {
                    await _log.LogAsync(new LogMessage(LogSeverity.Verbose, "Audio", $"Finished playing {path}."));
                    await CheckQueue(guild, channel, target);
                }
            }
            else
            {
                await JoinAudio(guild, target);
                await SendYTAudioAsync(guild, channel, target, path, volume);
            }
        }
Exemple #14
0
        public async Task SendAudioAsync(IGuild guild, IMessageChannel channel, IVoiceChannel target, string path, double volume = 1.0)
        {
            volume *= 0.5;

            if (!Directory.Exists($"sounds/{guild.Id.ToString()}"))
            {
                Directory.CreateDirectory($"sounds/{guild.Id.ToString()}");
            }

            if (!File.Exists($"sounds/{path}.mp3") && !File.Exists($"sounds/{guild.Id.ToString()}/{path}.mp3"))
            {
                await channel.SendMessageAsync("Sound does not exist.");

                return;
            }


            CurrentAudioInformation client;

            if (CurrentAudioClients.TryGetValue(guild.Id, out client))
            {
                await CheckAudioClient(guild, target, client.client);

                await _log.LogAsync(new LogMessage(LogSeverity.Verbose, "Audio", $"Starting playback of {path} in {guild.Name}"));

                if (!string.IsNullOrEmpty(client.playing))
                {
                    client.queue.Enqueue(path);
                    await channel.SendMessageAsync($"Added {path} to the queue.");

                    return;
                }

                client.playing = path;

                if (client.currentStream == null)
                {
                    client.currentStream = client.client.CreatePCMStream(AudioApplication.Mixed, 98304, 200);
                }


                string hardpath = File.Exists($"sounds/{path}.mp3") ? $"\"sounds/{path}.mp3\"" : $"\"sounds/{guild.Id.ToString()}/{path}.mp3\"";

                var memoryStream = new MemoryStream();

                await Cli.Wrap("ffmpeg")
                .WithArguments($" -hide_banner -loglevel panic -i {hardpath} -filter:a \"volume = {volume}\" -ac 2 -f s16le -ar 48000 pipe:1")
                .WithStandardOutputPipe(PipeTarget.ToStream(memoryStream))
                .ExecuteAsync();

                try {
                    client.cancelTokenSource = new CancellationTokenSource();
                    await client.currentStream.WriteAsync(memoryStream.ToArray(), 0, (int)memoryStream.Length, client.cancelTokenSource.Token);
                } catch (OperationCanceledException e) {
                    await channel.SendMessageAsync($"Stopped {path}");
                } finally {
                    await _log.LogAsync(new LogMessage(LogSeverity.Verbose, "Audio", $"Finished playing {path}."));
                    await CheckQueue(guild, channel, target);
                }
            }
            else
            {
                await JoinAudio(guild, target);
                await SendAudioAsync(guild, channel, target, path, volume);
            }
        }
    public async Task <Command> ForError(
        string ffmpegPath,
        Channel channel,
        Option <TimeSpan> duration,
        string errorMessage,
        bool hlsRealtime,
        long ptsOffset)
    {
        FFmpegPlaybackSettings playbackSettings =
            _playbackSettingsCalculator.CalculateErrorSettings(channel.FFmpegProfile);

        IDisplaySize desiredResolution = channel.FFmpegProfile.Resolution;

        var fontSize = (int)Math.Round(channel.FFmpegProfile.Resolution.Height / 20.0);
        var margin   = (int)Math.Round(channel.FFmpegProfile.Resolution.Height * 0.05);

        string subtitleFile = await new SubtitleBuilder(_tempFilePool)
                              .WithResolution(desiredResolution)
                              .WithFontName("Roboto")
                              .WithFontSize(fontSize)
                              .WithAlignment(2)
                              .WithMarginV(margin)
                              .WithPrimaryColor("&HFFFFFF")
                              .WithFormattedContent(errorMessage.Replace(Environment.NewLine, "\\N"))
                              .BuildFile();

        var videoStream = new MediaStream {
            Index = 0
        };
        var audioStream = new MediaStream {
            Index = 0
        };

        string videoCodec = playbackSettings.VideoFormat switch
        {
            FFmpegProfileVideoFormat.Hevc => "libx265",
            FFmpegProfileVideoFormat.Mpeg2Video => "mpeg2video",
            _ => "libx264"
        };

        string audioCodec = playbackSettings.AudioFormat switch
        {
            FFmpegProfileAudioFormat.Ac3 => "ac3",
            _ => "aac"
        };

        FFmpegProcessBuilder builder = new FFmpegProcessBuilder(ffmpegPath, false, _logger)
                                       .WithThreads(1)
                                       .WithQuiet()
                                       .WithFormatFlags(playbackSettings.FormatFlags)
                                       .WithRealtimeOutput(playbackSettings.RealtimeOutput)
                                       .WithLoopedImage(Path.Combine(FileSystemLayout.ResourcesCacheFolder, "background.png"))
                                       .WithLibavfilter()
                                       .WithInput("anullsrc")
                                       .WithSubtitleFile(subtitleFile)
                                       .WithFilterComplex(
            videoStream,
            audioStream,
            Path.Combine(FileSystemLayout.ResourcesCacheFolder, "background.png"),
            "fake-audio-path",
            playbackSettings.VideoFormat)
                                       .WithPixfmt("yuv420p")
                                       .WithPlaybackArgs(playbackSettings, videoCodec, audioCodec)
                                       .WithMetadata(channel, None);

        await duration.IfSomeAsync(d => builder = builder.WithDuration(d));

        Process process = channel.StreamingMode switch
        {
            // HLS needs to segment and generate playlist
            StreamingMode.HttpLiveStreamingSegmenter =>
            builder.WithHls(
                channel.Number,
                None,
                ptsOffset,
                playbackSettings.VideoTrackTimeScale,
                playbackSettings.FrameRate)
            .Build(),
            _ => builder.WithFormat("mpegts")
            .WithPipe()
            .Build()
        };

        return(Cli.Wrap(process.StartInfo.FileName)
               .WithArguments(process.StartInfo.ArgumentList)
               .WithValidation(CommandResultValidation.None)
               .WithEnvironmentVariables(process.StartInfo.Environment.ToDictionary(kvp => kvp.Key, kvp => kvp.Value))
               .WithStandardErrorPipe(PipeTarget.ToStream(Stream.Null)));
    }