private async Task BackgroundStream() { Console.WriteLine("Started background stream for " + Id); DataReceivedEventHandler Handler = null; var ProcessStartInfo = new ProcessStartInfo { FileName = "Includes/ffmpeg", UseShellExecute = false, RedirectStandardInput = true, RedirectStandardError = true }; while (!Stop.IsCancellationRequested) { try { await WaitAdd.WaitAsync(Stop.Token); Queue.Next(); using (Ffmpeg = new Process()) { ProcessStartInfo.Arguments = $"-re -i \"{await Queue.StreamUrl(false)}\" -vn -content_type audio/aac -f adts "; if (Queue.Playing.Type == SongType.YouTube || Queue.Playing.Type == SongType.Uploaded) { ProcessStartInfo.Arguments += "-c:a copy "; } else { ProcessStartInfo.Arguments += $"-c:a aac -b:a 128k -ac 2 -ar 48k "; } ProcessStartInfo.Arguments += $"icecast://*****:*****@localhost:80/{Id}"; ProcessWaiter = new TaskCompletionSource <bool>(); Ffmpeg.StartInfo = ProcessStartInfo; Ffmpeg.EnableRaisingEvents = true; Ffmpeg.Exited += (s, e) => { ProcessWaiter.TrySetResult(true); }; Handler = async(s, e) => { Console.WriteLine(e.Data ?? ""); if (e.Data?.StartsWith("size=") ?? false) { Ffmpeg.ErrorDataReceived -= Handler; await Task.Delay(250).ContinueWith(delegate { Chat.Home.ById(Id).Distribute(new Cloud.Json.Event { Chat = Id, Type = "start", Text = Serialize(Id) }); }); } }; Ffmpeg.ErrorDataReceived += Handler; Ffmpeg.Start(); Ffmpeg.BeginErrorReadLine(); Ffmpeg.PriorityClass = ProcessPriorityClass.BelowNormal; await ProcessWaiter.Task; Ffmpeg.CancelErrorRead(); await Ffmpeg.StandardInput.WriteAsync("q"); } } catch (Exception Ex) { Console.WriteLine(Ex.ToString()); } finally { Queue.Invalidate(); Console.WriteLine("Stopped Playing"); } if (Queue.Count == 0) { Chat.Home.ById(Id).Distribute(new Cloud.Json.Event { Chat = Id, Type = "start" }); } } }
private static async Task StreamAsync(AudioOutStream Out) { var SS = Streamer.SS.ToString(CultureInfo.InvariantCulture); var FFMpeg = Process.Start(new ProcessStartInfo { FileName = "ffmpeg", Arguments = $"-ss {SS} -re -i pipe:0 -f s16le -ar 48k -ac 2 -af \"{Filter.Tag}\" pipe:1", UseShellExecute = false, RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = true }); FFMpeg.ErrorDataReceived += async(s, e) => { var FFLog = e?.Data?.Trim(); if (FFLog != null) { if (FFLog.StartsWith("Duration: ")) { TimeSpan.TryParse(FFLog.Substring(10).Split(new[] { ',' }, 2, StringSplitOptions.RemoveEmptyEntries)[0], out Duration); } else if (FFLog.StartsWith("size=")) { var SplitTime = FFLog.Split(new[] { "time=" }, 2, StringSplitOptions.RemoveEmptyEntries)[1]; TimeSpan.TryParse(SplitTime.Split(new[] { ' ' }, 2, StringSplitOptions.RemoveEmptyEntries)[0], out Time); var SpeedSplit = SplitTime.Split('='); Logger.SetTitle($"Playback Speed {SpeedSplit[SpeedSplit.Length - 1].Trim()}"); } else { Logger.Log($"FFMpeg | {FFLog}"); } if (Duration != default(TimeSpan) && Time != default(TimeSpan) && (TicksRemaining = Duration.Ticks - Time.Ticks) <= 0) { Skip?.Cancel(); } } }; FFMpeg.BeginErrorReadLine(); BufferAsync(await GetStream(await Queue.StreamUrl()), FFMpeg.StandardInput.BaseStream, Skip.Token); using (var Pipe1 = FFMpeg.StandardOutput.BaseStream) try { int Read = await Pipe1.ReadAsync(BuffOut, Swapper *Stride, Stride, Skip.Token); while (Read != 0) { var Send = Out.WriteAsync(BuffOut, Swapper * Stride, Read, Skip.Token); Swapper = Swapper ^ 1; Read = await Pipe1.ReadAsync(BuffOut, Swapper *Stride, Stride, Skip.Token); await Send; } Streamer.SS = 0; //After full process without skip } catch (TaskCanceledException) { } catch (OperationCanceledException) { } Logger.Log("Disposed FFMpeg Pipe 1"); Logger.SetTitle($"Finished Playing"); try { FFMpeg.Kill(); } catch { } }