fixed music up a lot, caching stats every 5 seconds.

This commit is contained in:
Master Kwoth
2016-01-29 13:28:51 +01:00
parent 0c8934f12f
commit 805c592fff
4 changed files with 139 additions and 110 deletions

View File

@@ -14,7 +14,7 @@ namespace NadekoBot.Classes.Music {
public List<StreamRequest> SongQueue = new List<StreamRequest>();
public StreamRequest CurrentSong;
public bool IsPaused { get; internal set; }
public bool IsPaused { get; internal set; } = false;
public IAudioClient VoiceClient;
private readonly object _voiceLock = new object();
@@ -23,12 +23,15 @@ namespace NadekoBot.Classes.Music {
Task.Run(async () => {
while (true) {
try {
if (CurrentSong == null) {
if (SongQueue.Count > 0)
LoadNextSong();
lock (_voiceLock) {
if (CurrentSong == null) {
if (SongQueue.Count > 0)
LoadNextSong();
} else if (CurrentSong.State == StreamState.Completed) {
LoadNextSong();
} else if (CurrentSong.State == StreamState.Completed || NextSong) {
NextSong = false;
LoadNextSong();
}
}
} catch (Exception e) {
Console.WriteLine("Bug in music task run. " + e);
@@ -43,38 +46,50 @@ namespace NadekoBot.Classes.Music {
}
public void LoadNextSong() {
Console.WriteLine("Loading next song.");
lock (_voiceLock) {
if (SongQueue.Count == 0) {
CurrentSong = null;
return;
}
CurrentSong?.Stop();
CurrentSong = null;
if (SongQueue.Count == 0) return;
CurrentSong = SongQueue[0];
SongQueue.RemoveAt(0);
}
CurrentSong.Start();
Console.WriteLine("Starting next song.");
try {
CurrentSong?.Start();
} catch (Exception ex) {
Console.WriteLine($"Starting failed: {ex}");
CurrentSong?.Stop();
CurrentSong = null;
}
}
internal void RemoveAllSongs() {
internal void Stop() {
lock (_voiceLock) {
foreach (var kvp in SongQueue) {
if(kvp != null)
kvp.Cancel();
}
SongQueue.Clear();
LoadNextSong();
VoiceClient.Disconnect();
VoiceClient = null;
}
}
internal StreamRequest CreateStreamRequest(CommandEventArgs e, string query, Channel voiceChannel) {
if (VoiceChannel == null)
throw new ArgumentNullException("Please join a voicechannel.");
StreamRequest sr = null;
lock (_voiceLock) {
if (VoiceClient == null)
if (VoiceClient == null) {
VoiceClient = NadekoBot.client.Audio().Join(VoiceChannel).Result;
return new StreamRequest(e, query, VoiceClient);
}
sr = new StreamRequest(e, query, this);
SongQueue.Add(sr);
}
return sr;
}
internal bool TogglePause() => IsPaused = !IsPaused;
}
}

View File

@@ -29,50 +29,56 @@ 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 StreamState State => musicStreamer?.State ?? privateState;
private StreamState privateState = StreamState.Resolving;
public StreamRequest(CommandEventArgs e, string query, IAudioClient voiceClient) {
public bool IsPaused => MusicControls.IsPaused;
private MusicControls MusicControls;
public StreamRequest(CommandEventArgs e, string query, MusicControls mc) {
if (e == null)
throw new ArgumentNullException(nameof(e));
if (query == null)
throw new ArgumentNullException(nameof(query));
if (voiceClient == null)
throw new NullReferenceException($"{nameof(voiceClient)} is null, bot didn't join any server.");
this.VoiceClient = voiceClient;
if (mc.VoiceClient == null)
throw new NullReferenceException($"{nameof(mc.VoiceClient)} is null, bot didn't join any server.");
this.MusicControls = mc;
this.VoiceClient = mc.VoiceClient;
this.Server = e.Server;
this.Query = query;
ResolveStreamLink();
Task.Run(() => ResolveStreamLink());
}
private Task ResolveStreamLink() =>
Task.Run(() => {
private void ResolveStreamLink() {
VideoInfo video = null;
try {
Console.WriteLine("Resolving video link");
var video = DownloadUrlResolver.GetDownloadUrls(Searches.FindYoutubeUrlByKeywords(Query))
.Where(v => v.AdaptiveType == AdaptiveType.Audio)
.OrderByDescending(v => v.AudioBitrate).FirstOrDefault();
video = DownloadUrlResolver.GetDownloadUrls(Searches.FindYoutubeUrlByKeywords(Query))
.Where(v => v.AdaptiveType == AdaptiveType.Audio)
.OrderByDescending(v => v.AudioBitrate).FirstOrDefault();
if (video == null) // do something with this error
throw new Exception("Could not load any video elements based on the query.");
Title = video.Title;
} catch (Exception ex) {
privateState = StreamState.Completed;
Console.WriteLine($"Failed resolving the link.{ex.Message}");
return;
}
musicStreamer = new MusicStreamer(this, video.DownloadUrl, Channel);
if(OnQueued!=null)
OnQueued();
});
musicStreamer = new MusicStreamer(this, video.DownloadUrl, Channel);
if (OnQueued != null)
OnQueued();
}
internal string PrintStats() => musicStreamer?.Stats();
internal void Pause() {
throw new NotImplementedException();
}
public Action OnQueued = null;
public Action OnBuffering = null;
public Action OnStarted = null;
@@ -84,24 +90,28 @@ namespace NadekoBot.Classes.Music {
musicStreamer?.Cancel();
}
internal void Stop() {
musicStreamer?.Stop();
}
internal Task Start() =>
Task.Run(async () => {
Console.WriteLine("Start called.");
int attemptsLeft = 7;
//wait for up to 7 seconds to resolve a link
int attemptsLeft = 4;
//wait for up to 4 seconds to resolve a link
while (State == StreamState.Resolving) {
await Task.Delay(1000);
Console.WriteLine("Resolving...");
if (--attemptsLeft == 0) {
Console.WriteLine("Resolving timed out.");
return;
throw new TimeoutException("Resolving timed out.");
}
}
try {
await musicStreamer.StartPlayback();
} catch (Exception ex) {
Console.WriteLine("Error in start playback." + ex);
Console.WriteLine("Error in start playback." + ex.Message);
privateState = StreamState.Completed;
}
});
}
@@ -113,6 +123,7 @@ namespace NadekoBot.Classes.Music {
public StreamState State { get; internal set; }
public string Url { get; }
private bool IsCanceled { get; set; }
public bool IsPaused => parent.IsPaused;
StreamRequest parent;
private readonly object _bufferLock = new object();
@@ -152,14 +163,23 @@ namespace NadekoBot.Classes.Music {
while (true) {
while (buffer.writePos - buffer.readPos > 5.MB() && State != StreamState.Completed) {
if (bufferCancelSource.Token.CanBeCanceled && !bufferCancelSource.IsCancellationRequested) {
bufferCancelSource.Cancel();
Console.WriteLine("Canceling buffer token");
}
if (!bufferCancelSource.IsCancellationRequested) {
Console.WriteLine("Canceling buffer token");
Task.Run(() => bufferCancelSource.Cancel());
}
await Task.Delay(1000);
await Task.Delay(50);
}
if (State == StreamState.Completed) {
try {
p.CancelOutputRead();
p.Close();
} catch (Exception) { }
Console.WriteLine("Buffering canceled, stream is completed.");
return;
}
if (buffer.readPos > 5.MiB()) { // if buffer is over 5 MiB, create new one
Console.WriteLine("Buffer over 5 megs, clearing.");
@@ -175,16 +195,7 @@ namespace NadekoBot.Classes.Music {
buffer.readPos = newReadPos;
buffer.Position = newPos;
}
}
if (State == StreamState.Completed) {
try {
p.CancelOutputRead();
p.Close();
} catch (Exception) { }
Console.WriteLine("Buffering canceled, stream is completed.");
return;
}
}
var buf = new byte[1024];
int read = 0;
@@ -212,6 +223,7 @@ namespace NadekoBot.Classes.Music {
internal async Task StartPlayback() {
Console.WriteLine("Starting playback.");
if (State == StreamState.Playing) return;
State = StreamState.Playing;
if (parent.OnBuffering != null)
parent.OnBuffering();
@@ -253,22 +265,28 @@ namespace NadekoBot.Classes.Music {
} else
attempt = 0;
if (State == StreamState.Completed) {
Console.WriteLine("Canceled");
break;
}
parent.VoiceClient.Send(voiceBuffer, 0, voiceBuffer.Length);
while (IsPaused) {
await Task.Delay(50);
}
}
parent.VoiceClient.Wait();
StopPlayback();
Stop();
}
internal void Cancel() {
IsCanceled = true;
}
internal void StopPlayback() {
internal void Stop() {
Console.WriteLine("Stopping playback");
if (State != StreamState.Completed) {
State = StreamState.Completed;