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