Semi-working music fix, DO NOT USE YET
This commit is contained in:
parent
78da2599f1
commit
0c8934f12f
@ -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.");
|
||||||
|
lock (_voiceLock) {
|
||||||
if (SongQueue.Count == 0) {
|
if (SongQueue.Count == 0) {
|
||||||
CurrentSong = null;
|
CurrentSong = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CurrentSong = SongQueue[0];
|
CurrentSong = SongQueue[0];
|
||||||
SongQueue.RemoveAt(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,6 +63,7 @@ namespace NadekoBot.Classes.Music {
|
|||||||
Title = video.Title;
|
Title = video.Title;
|
||||||
|
|
||||||
musicStreamer = new MusicStreamer(this, video.DownloadUrl, Channel);
|
musicStreamer = new MusicStreamer(this, video.DownloadUrl, Channel);
|
||||||
|
if(OnQueued!=null)
|
||||||
OnQueued();
|
OnQueued();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -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) {
|
||||||
|
if (attempt == 2) {
|
||||||
try {
|
try {
|
||||||
p.CancelOutputRead();
|
p.CancelOutputRead();
|
||||||
p.Close();
|
p.Close();
|
||||||
} catch (Exception) { }
|
} 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) {
|
||||||
|
Console.WriteLine($"Failed to read {attempt} times. Stopping playback.");
|
||||||
break;
|
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}");
|
||||||
};
|
};
|
||||||
|
lock (player.SongQueue) {
|
||||||
player.SongQueue.Add(sr);
|
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}");
|
||||||
|
Loading…
Reference in New Issue
Block a user