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:
parent
842b45178d
commit
556174ec89
@ -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)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user