Fixed a bug where spamming .n would crash the music player, closes #1372

This commit is contained in:
Master Kwoth 2017-07-10 21:21:45 +02:00
parent 70f0f6af44
commit 9a744172a9
2 changed files with 104 additions and 81 deletions

View File

@ -163,83 +163,86 @@ namespace NadekoBot.Services.Music
if (data.Song != null) if (data.Song != null)
{ {
_log.Info("Starting"); _log.Info("Starting");
using (var b = new SongBuffer(await data.Song.Uri(), "", data.Song.ProviderType == Database.Models.MusicType.Local)) AudioOutStream pcm = null;
SongBuffer b = null;
try
{ {
_log.Info("Created buffer, buffering..."); b = new SongBuffer(await data.Song.Uri(), "", data.Song.ProviderType == Database.Models.MusicType.Local);
AudioOutStream pcm = null; //_log.Info("Created buffer, buffering...");
try
//var bufferTask = b.StartBuffering(cancelToken);
//var timeout = Task.Delay(10000);
//if (Task.WhenAny(bufferTask, timeout) == timeout)
//{
// _log.Info("Buffering failed due to a timeout.");
// continue;
//}
//else if (!bufferTask.Result)
//{
// _log.Info("Buffering failed due to a cancel or error.");
// continue;
//}
//_log.Info("Buffered. Getting audio client...");
var ac = await GetAudioClient();
_log.Info("Got Audio client");
if (ac == null)
{ {
var bufferTask = b.StartBuffering(cancelToken); _log.Info("Can't join");
var timeout = Task.Delay(10000); await Task.Delay(900, cancelToken);
if (Task.WhenAny(bufferTask, timeout) == timeout) // just wait some time, maybe bot doesn't even have perms to join that voice channel,
{ // i don't want to spam connection attempts
_log.Info("Buffering failed due to a timeout."); continue;
continue;
}
else if (!bufferTask.Result)
{
_log.Info("Buffering failed due to a cancel or error.");
continue;
}
_log.Info("Buffered. Getting audio client...");
var ac = await GetAudioClient();
_log.Info("Got Audio client");
if (ac == null)
{
_log.Info("Can't join");
await Task.Delay(900, cancelToken);
// just wait some time, maybe bot doesn't even have perms to join that voice channel,
// i don't want to spam connection attempts
continue;
}
pcm = ac.CreatePCMStream(AudioApplication.Music, bufferMillis: 500);
_log.Info("Created pcm stream");
OnStarted?.Invoke(this, data);
byte[] buffer = new byte[3840];
int bytesRead = 0;
while ((bytesRead = b.Read(buffer, 0, buffer.Length)) > 0
&& (MaxPlaytimeSeconds <= 0 || MaxPlaytimeSeconds >= CurrentTime.TotalSeconds))
{
AdjustVolume(buffer, Volume);
await pcm.WriteAsync(buffer, 0, bytesRead, cancelToken).ConfigureAwait(false);
unchecked { _bytesSent += bytesRead; }
await (pauseTaskSource?.Task ?? Task.CompletedTask);
}
} }
catch (OperationCanceledException) pcm = ac.CreatePCMStream(AudioApplication.Music, bufferMillis: 500);
{ _log.Info("Created pcm stream");
_log.Info("Song Canceled"); OnStarted?.Invoke(this, data);
cancel = true;
}
catch (Exception ex)
{
_log.Warn(ex);
}
finally
{
if (pcm != null)
{
// flush is known to get stuck from time to time,
// just skip flushing if it takes more than 1 second
var flushCancel = new CancellationTokenSource();
var flushToken = flushCancel.Token;
var flushDelay = Task.Delay(1000, flushToken);
await Task.WhenAny(flushDelay, pcm.FlushAsync(flushToken));
flushCancel.Cancel();
pcm.Dispose();
}
OnCompleted?.Invoke(this, data.Song); byte[] buffer = new byte[3840];
int bytesRead = 0;
if (_bytesSent == 0 && !cancel) while ((bytesRead = b.Read(buffer, 0, buffer.Length)) > 0
{ && (MaxPlaytimeSeconds <= 0 || MaxPlaytimeSeconds >= CurrentTime.TotalSeconds))
lock (locker) {
Queue.RemoveSong(data.Song); AdjustVolume(buffer, Volume);
_log.Info("Song removed because it can't play"); await pcm.WriteAsync(buffer, 0, bytesRead, cancelToken).ConfigureAwait(false);
} unchecked { _bytesSent += bytesRead; }
await (pauseTaskSource?.Task ?? Task.CompletedTask);
}
}
catch (OperationCanceledException)
{
_log.Info("Song Canceled");
cancel = true;
}
catch (Exception ex)
{
_log.Warn(ex);
}
finally
{
if (pcm != null)
{
// flush is known to get stuck from time to time,
// just skip flushing if it takes more than 1 second
var flushCancel = new CancellationTokenSource();
var flushToken = flushCancel.Token;
var flushDelay = Task.Delay(1000, flushToken);
await Task.WhenAny(flushDelay, pcm.FlushAsync(flushToken));
flushCancel.Cancel();
pcm.Dispose();
}
if (b != null)
b.Dispose();
OnCompleted?.Invoke(this, data.Song);
if (_bytesSent == 0 && !cancel)
{
lock (locker)
Queue.RemoveSong(data.Song);
_log.Info("Song removed because it can't play");
} }
} }
try try

View File

@ -26,6 +26,34 @@ namespace NadekoBot.Services.Music
//_log.Warn(songUri); //_log.Warn(songUri);
this.SongUri = songUri; this.SongUri = songUri;
this._isLocal = isLocal; this._isLocal = isLocal;
try
{
this.p = StartFFmpegProcess(SongUri, 0);
var t = Task.Run(() =>
{
this.p.BeginErrorReadLine();
this.p.ErrorDataReceived += P_ErrorDataReceived;
this.p.WaitForExit();
});
this._outStream = this.p.StandardOutput.BaseStream;
}
catch (System.ComponentModel.Win32Exception)
{
_log.Error(@"You have not properly installed or configured FFMPEG.
Please install and configure FFMPEG to play music.
Check the guides for your platform on how to setup ffmpeg correctly:
Windows Guide: https://goo.gl/OjKk8F
Linux Guide: https://goo.gl/ShjCUo");
}
catch (OperationCanceledException) { }
catch (InvalidOperationException) { } // when ffmpeg is disposed
catch (Exception ex)
{
_log.Info(ex);
}
} }
private Process StartFFmpegProcess(string songUri, float skipTo = 0) private Process StartFFmpegProcess(string songUri, float skipTo = 0)
@ -65,16 +93,8 @@ namespace NadekoBot.Services.Music
var toReturn = new TaskCompletionSource<bool>(); var toReturn = new TaskCompletionSource<bool>();
var _ = Task.Run(() => var _ = Task.Run(() =>
{ {
try { try
this.p = StartFFmpegProcess(SongUri, 0);
var t = Task.Run(() =>
{ {
this.p.BeginErrorReadLine();
this.p.ErrorDataReceived += P_ErrorDataReceived;
this.p.WaitForExit();
});
this._outStream = this.p.StandardOutput.BaseStream;
////int maxLoopsPerSec = 25; ////int maxLoopsPerSec = 25;
//var sw = Stopwatch.StartNew(); //var sw = Stopwatch.StartNew();