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) { } }
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()); }
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)); } }
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); }
public static IGit New() { var consoleOutputTarget = PipeTarget.ToStream(Console.OpenStandardOutput()); var command = Cli.Wrap("git") .WithStandardOutputPipe(consoleOutputTarget); return(new Git(command)); }
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); }
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); }
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); } } }
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); } }
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))); }