Semi-working music fix, DO NOT USE YET
This commit is contained in:
		| @@ -3,6 +3,7 @@ using Discord.Audio; | |||||||
| using System; | using System; | ||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||||
|  | using Discord.Commands; | ||||||
|  |  | ||||||
| namespace NadekoBot.Classes.Music { | namespace NadekoBot.Classes.Music { | ||||||
|     public class MusicControls { |     public class MusicControls { | ||||||
| @@ -14,6 +15,9 @@ namespace NadekoBot.Classes.Music { | |||||||
|         public StreamRequest CurrentSong; |         public StreamRequest CurrentSong; | ||||||
|  |  | ||||||
|         public bool IsPaused { get; internal set; } |         public bool IsPaused { get; internal set; } | ||||||
|  |         public IAudioClient VoiceClient; | ||||||
|  |  | ||||||
|  |         private readonly object _voiceLock = new object(); | ||||||
|  |  | ||||||
|         public MusicControls() { |         public MusicControls() { | ||||||
|             Task.Run(async () => { |             Task.Run(async () => { | ||||||
| @@ -22,6 +26,7 @@ namespace NadekoBot.Classes.Music { | |||||||
|                         if (CurrentSong == null) { |                         if (CurrentSong == null) { | ||||||
|                             if (SongQueue.Count > 0) |                             if (SongQueue.Count > 0) | ||||||
|                                 LoadNextSong(); |                                 LoadNextSong(); | ||||||
|  |  | ||||||
|                         } else if (CurrentSong.State == StreamState.Completed) { |                         } else if (CurrentSong.State == StreamState.Completed) { | ||||||
|                             LoadNextSong(); |                             LoadNextSong(); | ||||||
|                         } |                         } | ||||||
| @@ -33,25 +38,42 @@ namespace NadekoBot.Classes.Music { | |||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         public MusicControls(Channel voiceChannel) : this() { | ||||||
|  |             VoiceChannel = voiceChannel; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         public void LoadNextSong() { |         public void LoadNextSong() { | ||||||
|             Console.WriteLine("Loading next song."); |             Console.WriteLine("Loading next song."); | ||||||
|             if (SongQueue.Count == 0) { |             lock (_voiceLock) { | ||||||
|                 CurrentSong = null; |                 if (SongQueue.Count == 0) { | ||||||
|                 return; |                     CurrentSong = null; | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |                 CurrentSong = SongQueue[0]; | ||||||
|  |                 SongQueue.RemoveAt(0); | ||||||
|             } |             } | ||||||
|             CurrentSong = SongQueue[0]; |  | ||||||
|             SongQueue.RemoveAt(0); |  | ||||||
|             CurrentSong.Start(); |             CurrentSong.Start(); | ||||||
|  |  | ||||||
|             Console.WriteLine("Starting next song."); |             Console.WriteLine("Starting next song."); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         internal void RemoveAllSongs() { |         internal void RemoveAllSongs() { | ||||||
|             lock (SongQueue) { |             lock (_voiceLock) { | ||||||
|                 foreach (var kvp in SongQueue) { |                 foreach (var kvp in SongQueue) { | ||||||
|                     if(kvp != null) |                     if(kvp != null) | ||||||
|                         kvp.Cancel(); |                         kvp.Cancel(); | ||||||
|                 } |                 } | ||||||
|                 SongQueue.Clear(); |                 SongQueue.Clear(); | ||||||
|  |                 VoiceClient.Disconnect(); | ||||||
|  |                 VoiceClient = null; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         internal StreamRequest CreateStreamRequest(CommandEventArgs e, string query, Channel voiceChannel) { | ||||||
|  |             lock (_voiceLock) { | ||||||
|  |                 if (VoiceClient == null) | ||||||
|  |                     VoiceClient = NadekoBot.client.Audio().Join(VoiceChannel).Result; | ||||||
|  |                 return new StreamRequest(e, query, VoiceClient); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -29,20 +29,23 @@ namespace NadekoBot.Classes.Music { | |||||||
|         public User User { get; } |         public User User { get; } | ||||||
|         public string Query { get; } |         public string Query { get; } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         public string Title { get; internal set; } = String.Empty; | ||||||
|  |         public IAudioClient VoiceClient { get; private set; } | ||||||
|  |  | ||||||
|         private MusicStreamer musicStreamer = null; |         private MusicStreamer musicStreamer = null; | ||||||
|         public StreamState State => musicStreamer?.State ?? StreamState.Resolving; |         public StreamState State => musicStreamer?.State ?? StreamState.Resolving; | ||||||
|  |  | ||||||
|         public StreamRequest(CommandEventArgs e, string query) { |         public StreamRequest(CommandEventArgs e, string query, IAudioClient voiceClient) { | ||||||
|             if (e == null) |             if (e == null) | ||||||
|                 throw new ArgumentNullException(nameof(e)); |                 throw new ArgumentNullException(nameof(e)); | ||||||
|             if (query == null) |             if (query == null) | ||||||
|                 throw new ArgumentNullException(nameof(query)); |                 throw new ArgumentNullException(nameof(query)); | ||||||
|             if (e.User.VoiceChannel == null) |             if (voiceClient == null) | ||||||
|                 throw new NullReferenceException("Voicechannel is null."); |                 throw new NullReferenceException($"{nameof(voiceClient)} is null, bot didn't join any server."); | ||||||
|  |  | ||||||
|  |             this.VoiceClient = voiceClient; | ||||||
|             this.Server = e.Server; |             this.Server = e.Server; | ||||||
|             this.Channel = e.User.VoiceChannel; |  | ||||||
|             this.User = e.User; |  | ||||||
|             this.Query = query; |             this.Query = query; | ||||||
|             ResolveStreamLink(); |             ResolveStreamLink(); | ||||||
|         } |         } | ||||||
| @@ -60,7 +63,8 @@ namespace NadekoBot.Classes.Music { | |||||||
|                 Title = video.Title; |                 Title = video.Title; | ||||||
|  |  | ||||||
|                 musicStreamer = new MusicStreamer(this, video.DownloadUrl, Channel); |                 musicStreamer = new MusicStreamer(this, video.DownloadUrl, Channel); | ||||||
|                 OnQueued(); |                 if(OnQueued!=null) | ||||||
|  |                     OnQueued(); | ||||||
|             }); |             }); | ||||||
|  |  | ||||||
|         internal string PrintStats() => musicStreamer?.Stats(); |         internal string PrintStats() => musicStreamer?.Stats(); | ||||||
| @@ -69,8 +73,6 @@ namespace NadekoBot.Classes.Music { | |||||||
|             throw new NotImplementedException(); |             throw new NotImplementedException(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public string Title { get; internal set; } = String.Empty; |  | ||||||
|  |  | ||||||
|         public Action OnQueued = null; |         public Action OnQueued = null; | ||||||
|         public Action OnBuffering = null; |         public Action OnBuffering = null; | ||||||
|         public Action OnStarted = null; |         public Action OnStarted = null; | ||||||
| @@ -146,18 +148,35 @@ namespace NadekoBot.Classes.Music { | |||||||
|                 CreateNoWindow = true, |                 CreateNoWindow = true, | ||||||
|                 WindowStyle = ProcessWindowStyle.Hidden, |                 WindowStyle = ProcessWindowStyle.Hidden, | ||||||
|             }); |             }); | ||||||
|  |             int attempt = 0; | ||||||
|             while (true) { |             while (true) { | ||||||
|                 while (buffer.writePos - buffer.readPos > 2.MB() && State != StreamState.Completed) { |  | ||||||
|                     try { |                 while (buffer.writePos - buffer.readPos > 5.MB() && State != StreamState.Completed) { | ||||||
|                         if (bufferCancelSource.Token.CanBeCanceled && !bufferCancelSource.IsCancellationRequested) { |                         if (bufferCancelSource.Token.CanBeCanceled && !bufferCancelSource.IsCancellationRequested) { | ||||||
|                             bufferCancelSource.Cancel(); |                             bufferCancelSource.Cancel(); | ||||||
|                             Console.WriteLine("Canceling buffer token"); |                             Console.WriteLine("Canceling buffer token"); | ||||||
|                         } |                         } | ||||||
|                     } catch (Exception ex) { Console.WriteLine($"Canceling buffer token failed {ex}"); } |  | ||||||
|                     await Task.Delay(1000); |                     await Task.Delay(1000); | ||||||
|                 } |                 } | ||||||
|                  |                  | ||||||
|  |                 if (buffer.readPos > 5.MiB()) { // if buffer is over 5 MiB, create new one | ||||||
|  |                     Console.WriteLine("Buffer over 5 megs, clearing."); | ||||||
|  |  | ||||||
|  |                     var skip = 5.MB(); //remove only 5 MB, just in case | ||||||
|  |                     var newBuffer = new DualStream(); | ||||||
|  |  | ||||||
|  |                     lock (_bufferLock) { | ||||||
|  |                         byte[] data = buffer.ToArray().Skip(skip).ToArray(); | ||||||
|  |                         var newReadPos = buffer.readPos - skip; | ||||||
|  |                         var newPos = buffer.Position - skip; | ||||||
|  |                         buffer = newBuffer; | ||||||
|  |                         buffer.Write(data, 0, data.Length); | ||||||
|  |                         buffer.readPos = newReadPos; | ||||||
|  |                         buffer.Position = newPos; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |  | ||||||
|                 if (State == StreamState.Completed) { |                 if (State == StreamState.Completed) { | ||||||
|                     try { |                     try { | ||||||
|                         p.CancelOutputRead(); |                         p.CancelOutputRead(); | ||||||
| @@ -167,40 +186,28 @@ namespace NadekoBot.Classes.Music { | |||||||
|                     return; |                     return; | ||||||
|                 }                 |                 }                 | ||||||
|  |  | ||||||
|                 if (buffer.readPos > 5.MiB()) { // if buffer is over 5 MiB, create new one |  | ||||||
|                     Console.WriteLine("Buffer over 5 megs, clearing."); |  | ||||||
|  |  | ||||||
|                     var skip = 5.MB(); //remove only 10 MB, just in case |  | ||||||
|                     byte[] data = buffer.ToArray().Skip(skip).ToArray(); |  | ||||||
|  |  | ||||||
|                     var newBuffer = new DualStream(); |  | ||||||
|                     lock (_bufferLock) { |  | ||||||
|                         var newReadPos = buffer.readPos - skip; |  | ||||||
|                         var newPos = buffer.Position - skip; |  | ||||||
|                         buffer = newBuffer; |  | ||||||
|                         buffer.Write(data, 0, data.Length); |  | ||||||
|                         buffer.readPos = newReadPos; |  | ||||||
|                         buffer.Position = newPos; |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 var buf = new byte[1024]; |                 var buf = new byte[1024]; | ||||||
|                 int read = 0; |                 int read = 0; | ||||||
|                 read = await p.StandardOutput.BaseStream.ReadAsync(buf, 0, 1024); |                 read = await p.StandardOutput.BaseStream.ReadAsync(buf, 0, 1024); | ||||||
|                 //Console.WriteLine($"Read: {read}"); |                 //Console.WriteLine($"Read: {read}"); | ||||||
|                 if (read == 0) { |                 if (read == 0) { | ||||||
|                     try { |                     if (attempt == 2) { | ||||||
|                         p.CancelOutputRead(); |                         try { | ||||||
|                         p.Close(); |                             p.CancelOutputRead(); | ||||||
|                     } catch (Exception) { } |                             p.Close(); | ||||||
|  |                         } catch (Exception) { } | ||||||
|  |  | ||||||
|                     Console.WriteLine("Didn't read anything from the stream"); |                         Console.WriteLine($"Didn't read anything from the stream for {attempt} attempts. {buffer.Length/1.MB()}MB length"); | ||||||
|                     return; |                         return; | ||||||
|  |                     } else { | ||||||
|  |                         ++attempt; | ||||||
|  |                         await Task.Delay(10); | ||||||
|  |                     } | ||||||
|  |                 } else { | ||||||
|  |                     attempt = 0; | ||||||
|  |                     await buffer.WriteAsync(buf, 0, read); | ||||||
|                 } |                 } | ||||||
|                 await buffer.WriteAsync(buf, 0, read); |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         internal async Task StartPlayback() { |         internal async Task StartPlayback() { | ||||||
| @@ -225,12 +232,10 @@ namespace NadekoBot.Classes.Music { | |||||||
|             } |             } | ||||||
|             //for now wait for 3 seconds before starting playback. |             //for now wait for 3 seconds before starting playback. | ||||||
|              |              | ||||||
|             var audio = NadekoBot.client.Audio(); |  | ||||||
|  |  | ||||||
|             var voiceClient = await audio.Join(channel); |  | ||||||
|             int blockSize = 1920 * NadekoBot.client.Audio().Config.Channels; |             int blockSize = 1920 * NadekoBot.client.Audio().Config.Channels; | ||||||
|             byte[] voiceBuffer = new byte[blockSize]; |             byte[] voiceBuffer = new byte[blockSize]; | ||||||
|  |  | ||||||
|  |             int attempt = 0; | ||||||
|             while (!IsCanceled) { |             while (!IsCanceled) { | ||||||
|                 int readCount = 0; |                 int readCount = 0; | ||||||
|                 lock (_bufferLock) { |                 lock (_bufferLock) { | ||||||
| @@ -238,21 +243,24 @@ namespace NadekoBot.Classes.Music { | |||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 if (readCount == 0) { |                 if (readCount == 0) { | ||||||
|                     Console.WriteLine("Nothing else to read."); |                     if (attempt == 2) { | ||||||
|                     break; |                         Console.WriteLine($"Failed to read {attempt} times. Stopping playback."); | ||||||
|                 } |                         break; | ||||||
|  |                     } else { | ||||||
|  |                         ++attempt; | ||||||
|  |                         await Task.Delay(10); | ||||||
|  |                     } | ||||||
|  |                 } else | ||||||
|  |                     attempt = 0; | ||||||
|  |  | ||||||
|                 if (State == StreamState.Completed) { |                 if (State == StreamState.Completed) { | ||||||
|                     Console.WriteLine("Canceled"); |                     Console.WriteLine("Canceled"); | ||||||
|                     break; |                     break; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 voiceClient.Send(voiceBuffer, 0, voiceBuffer.Length); |                 parent.VoiceClient.Send(voiceBuffer, 0, voiceBuffer.Length); | ||||||
|             } |             } | ||||||
|  |             parent.VoiceClient.Wait(); | ||||||
|             voiceClient.Wait(); |  | ||||||
|             await voiceClient.Disconnect(); |  | ||||||
|  |  | ||||||
|             StopPlayback(); |             StopPlayback(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -104,11 +104,11 @@ namespace NadekoBot.Modules { | |||||||
|                                 return; |                                 return; | ||||||
|                                 }  |                                 }  | ||||||
|                             else |                             else | ||||||
|                                 musicPlayers.TryAdd(e.Server, new MusicControls()); |                                 (musicPlayers as System.Collections.IDictionary).Add(e.Server, new MusicControls(e.User.VoiceChannel)); | ||||||
|  |  | ||||||
|                         var player = musicPlayers[e.Server]; |                         var player = musicPlayers[e.Server]; | ||||||
|                         try { |                         try { | ||||||
|                             var sr = new StreamRequest(e, e.GetArg("query")); |                             var sr = player.CreateStreamRequest(e, e.GetArg("query"), player.VoiceChannel); | ||||||
|                             Message msg = null; |                             Message msg = null; | ||||||
|                             sr.OnQueued += async() => { |                             sr.OnQueued += async() => { | ||||||
|                                 msg = await e.Send($":musical_note:**Queued** {sr.Title}"); |                                 msg = await e.Send($":musical_note:**Queued** {sr.Title}"); | ||||||
| @@ -118,15 +118,17 @@ namespace NadekoBot.Modules { | |||||||
|                             }; |                             }; | ||||||
|                             sr.OnStarted += async () => { |                             sr.OnStarted += async () => { | ||||||
|                                 if (msg == null) |                                 if (msg == null) | ||||||
|                                     await e.Send($":musical_note:**Started playing** {sr.Title}"); |                                     await e.Send($":musical_note:**Starting playback of** {sr.Title}"); | ||||||
|                                 else |                                 else | ||||||
|                                     await msg.Edit($":musical_note:**Started playing** {sr.Title}"); |                                     await msg.Edit($":musical_note:**Starting playback of** {sr.Title}"); | ||||||
|                             }; |                             }; | ||||||
|                             sr.OnBuffering += async () => { |                             sr.OnBuffering += async () => { | ||||||
|                                 if (msg != null) |                                 if (msg != null) | ||||||
|                                     msg = await e.Send($":musical_note:**Buffering the song**...{sr.Title}"); |                                     msg = await e.Send($":musical_note:**Buffering the song**...{sr.Title}"); | ||||||
|                             }; |                             }; | ||||||
|                             player.SongQueue.Add(sr); |                             lock (player.SongQueue) { | ||||||
|  |                                 player.SongQueue.Add(sr); | ||||||
|  |                             } | ||||||
|                         } catch (Exception ex) { |                         } catch (Exception ex) { | ||||||
|                             Console.WriteLine(); |                             Console.WriteLine(); | ||||||
|                             await e.Send($"Error. :anger:\n{ex.Message}"); |                             await e.Send($"Error. :anger:\n{ex.Message}"); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user