diff --git a/src/NadekoBot/Services/Music/MusicPlayer.cs b/src/NadekoBot/Services/Music/MusicPlayer.cs index 1c697e57..5c698fb3 100644 --- a/src/NadekoBot/Services/Music/MusicPlayer.cs +++ b/src/NadekoBot/Services/Music/MusicPlayer.cs @@ -163,83 +163,86 @@ namespace NadekoBot.Services.Music if (data.Song != null) { _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..."); - AudioOutStream pcm = null; - try + b = new SongBuffer(await data.Song.Uri(), "", data.Song.ProviderType == Database.Models.MusicType.Local); + //_log.Info("Created buffer, buffering..."); + + //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); - 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) - { - _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); - } + _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; } - 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(); - } + pcm = ac.CreatePCMStream(AudioApplication.Music, bufferMillis: 500); + _log.Info("Created pcm stream"); + OnStarted?.Invoke(this, data); - OnCompleted?.Invoke(this, data.Song); + byte[] buffer = new byte[3840]; + int bytesRead = 0; - if (_bytesSent == 0 && !cancel) - { - lock (locker) - Queue.RemoveSong(data.Song); - _log.Info("Song removed because it can't play"); - } + 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) + { + _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 diff --git a/src/NadekoBot/Services/Music/SongBuffer.cs b/src/NadekoBot/Services/Music/SongBuffer.cs index e7a33a64..a9d30261 100644 --- a/src/NadekoBot/Services/Music/SongBuffer.cs +++ b/src/NadekoBot/Services/Music/SongBuffer.cs @@ -26,6 +26,34 @@ namespace NadekoBot.Services.Music //_log.Warn(songUri); this.SongUri = songUri; 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) @@ -65,16 +93,8 @@ namespace NadekoBot.Services.Music var toReturn = new TaskCompletionSource(); var _ = Task.Run(() => { - try { - this.p = StartFFmpegProcess(SongUri, 0); - var t = Task.Run(() => + try { - this.p.BeginErrorReadLine(); - this.p.ErrorDataReceived += P_ErrorDataReceived; - this.p.WaitForExit(); - }); - - this._outStream = this.p.StandardOutput.BaseStream; ////int maxLoopsPerSec = 25; //var sw = Stopwatch.StartNew();