Restart ffmpeg if it crashes? Maybe i should reconsider file-based cache. Ffmpeg doesn't like being slowed down it seems
This commit is contained in:
		@@ -19,20 +19,14 @@ namespace NadekoBot.Services.Music
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public string SongUri { get; private set; }
 | 
					        public string SongUri { get; private set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private volatile bool restart = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public SongBuffer(string songUri, string skipTo)
 | 
					        public SongBuffer(string songUri, string skipTo)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _log = LogManager.GetCurrentClassLogger();
 | 
					            _log = LogManager.GetCurrentClassLogger();
 | 
				
			||||||
            this.SongUri = songUri;
 | 
					            this.SongUri = songUri;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.p = Process.Start(new ProcessStartInfo
 | 
					            this.p = StartFFmpegProcess(songUri, 0);
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                FileName = "ffmpeg",
 | 
					 | 
				
			||||||
                Arguments = $"-i {songUri} -f s16le -ar 48000 -vn -ac 2 pipe:1 -loglevel error -threads 0 -reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5",
 | 
					 | 
				
			||||||
                UseShellExecute = false,
 | 
					 | 
				
			||||||
                RedirectStandardOutput = true,
 | 
					 | 
				
			||||||
                RedirectStandardError = true,
 | 
					 | 
				
			||||||
                CreateNoWindow = true,
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
            var t = Task.Run(() =>
 | 
					            var t = Task.Run(() =>
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                this.p.BeginErrorReadLine();
 | 
					                this.p.BeginErrorReadLine();
 | 
				
			||||||
@@ -41,9 +35,27 @@ namespace NadekoBot.Services.Music
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private Process StartFFmpegProcess(string songUri, float skipTo = 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return Process.Start(new ProcessStartInfo
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                FileName = "ffmpeg",
 | 
				
			||||||
 | 
					                Arguments = $"-ss {skipTo:F4} -i {songUri} -f s16le -ar 48000 -vn -ac 2 pipe:1 -loglevel error -threads 0 -reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5",
 | 
				
			||||||
 | 
					                UseShellExecute = false,
 | 
				
			||||||
 | 
					                RedirectStandardOutput = true,
 | 
				
			||||||
 | 
					                RedirectStandardError = true,
 | 
				
			||||||
 | 
					                CreateNoWindow = true,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void P_ErrorDataReceived(object sender, DataReceivedEventArgs e)
 | 
					        private void P_ErrorDataReceived(object sender, DataReceivedEventArgs e)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _log.Error(">>> " + e.Data);
 | 
					            _log.Error(">>> " + e.Data);
 | 
				
			||||||
 | 
					            if (e.Data.Contains("Error in the pull function"))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _log.Info("Got error in the pull function!");
 | 
				
			||||||
 | 
					                restart = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private readonly object locker = new object();
 | 
					        private readonly object locker = new object();
 | 
				
			||||||
@@ -56,39 +68,57 @@ namespace NadekoBot.Services.Music
 | 
				
			|||||||
                var sw = Stopwatch.StartNew();
 | 
					                var sw = Stopwatch.StartNew();
 | 
				
			||||||
                var delay = 1000 / maxLoopsPerSec;
 | 
					                var delay = 1000 / maxLoopsPerSec;
 | 
				
			||||||
                int currentLoops = 0;
 | 
					                int currentLoops = 0;
 | 
				
			||||||
 | 
					                int _bytesSent = 0;
 | 
				
			||||||
                try
 | 
					                try
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    ++currentLoops;
 | 
					                    do
 | 
				
			||||||
                    byte[] buffer = new byte[readSize];
 | 
					 | 
				
			||||||
                    int bytesRead = 1;
 | 
					 | 
				
			||||||
                    while (!cancelToken.IsCancellationRequested && !this.p.HasExited)
 | 
					 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        bytesRead = await p.StandardOutput.BaseStream.ReadAsync(buffer, 0, readSize, cancelToken).ConfigureAwait(false);
 | 
					                        if (restart)
 | 
				
			||||||
                        if (bytesRead == 0)
 | 
					 | 
				
			||||||
                            break;
 | 
					 | 
				
			||||||
                        bool written;
 | 
					 | 
				
			||||||
                        do
 | 
					 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            lock (locker)
 | 
					                            var cur = _bytesSent / 3840 / (1000 / 20.0f);
 | 
				
			||||||
                                written = _outStream.Write(buffer, 0, bytesRead);
 | 
					                            _log.Info("Restarting");
 | 
				
			||||||
                            if (!written)
 | 
					                            try { this.p.StandardOutput.Dispose(); } catch { }
 | 
				
			||||||
                                await Task.Delay(2000, cancelToken);
 | 
					                            try { this.p.Dispose(); } catch { }
 | 
				
			||||||
 | 
					                            this.p = StartFFmpegProcess(SongUri, cur);
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        while (!written);
 | 
					                        restart = false;
 | 
				
			||||||
                        lock (locker)
 | 
					                        ++currentLoops;
 | 
				
			||||||
                            if (_outStream.Length > 200_000 || bytesRead == 0)
 | 
					                        byte[] buffer = new byte[readSize];
 | 
				
			||||||
                                if (toReturn.TrySetResult(true))
 | 
					                        int bytesRead = 1;
 | 
				
			||||||
                                    _log.Info("Prebuffering finished in {0}", sw.Elapsed.TotalSeconds.ToString("F2"));
 | 
					                        while (!cancelToken.IsCancellationRequested && !this.p.HasExited)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            bytesRead = await p.StandardOutput.BaseStream.ReadAsync(buffer, 0, readSize, cancelToken).ConfigureAwait(false);
 | 
				
			||||||
 | 
					                            _bytesSent += bytesRead;
 | 
				
			||||||
 | 
					                            if (bytesRead == 0)
 | 
				
			||||||
 | 
					                                break;
 | 
				
			||||||
 | 
					                            bool written;
 | 
				
			||||||
 | 
					                            do
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                lock (locker)
 | 
				
			||||||
 | 
					                                    written = _outStream.Write(buffer, 0, bytesRead);
 | 
				
			||||||
 | 
					                                if (!written)
 | 
				
			||||||
 | 
					                                    await Task.Delay(2000, cancelToken);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            while (!written);
 | 
				
			||||||
 | 
					                            lock (locker)
 | 
				
			||||||
 | 
					                                if (_outStream.Length > 200_000 || bytesRead == 0)
 | 
				
			||||||
 | 
					                                    if (toReturn.TrySetResult(true))
 | 
				
			||||||
 | 
					                                        _log.Info("Prebuffering finished in {0}", sw.Elapsed.TotalSeconds.ToString("F2"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        //_log.Info(_outStream.Length);
 | 
					                            //_log.Info(_outStream.Length);
 | 
				
			||||||
                        await Task.Delay(10);
 | 
					                            await Task.Delay(10);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        if (cancelToken.IsCancellationRequested)
 | 
				
			||||||
 | 
					                            _log.Info("Song canceled");
 | 
				
			||||||
 | 
					                        else if (p.HasExited)
 | 
				
			||||||
 | 
					                            _log.Info("Song buffered completely (FFmpeg exited)");
 | 
				
			||||||
 | 
					                        else if (bytesRead == 0)
 | 
				
			||||||
 | 
					                            _log.Info("Nothing read");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (restart)
 | 
				
			||||||
 | 
					                            _log.Info("Lets do some magix");
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (cancelToken.IsCancellationRequested)
 | 
					                    while (restart && !cancelToken.IsCancellationRequested);
 | 
				
			||||||
                        _log.Info("Song canceled");
 | 
					 | 
				
			||||||
                    else if (p.HasExited)
 | 
					 | 
				
			||||||
                        _log.Info("Song buffered completely (FFmpeg exited)");
 | 
					 | 
				
			||||||
                    else if (bytesRead == 0)
 | 
					 | 
				
			||||||
                        _log.Info("Nothing read");
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                catch (System.ComponentModel.Win32Exception)
 | 
					                catch (System.ComponentModel.Win32Exception)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user