Elementary/Elementary/Audio/PlaybackQueue.cs
2023-11-19 01:04:54 +09:00

108 lines
2.4 KiB
C#

using System.Collections.Concurrent;
using Discord.Audio;
using NAudio.Wave;
using NLog;
using Exception = System.Exception;
namespace Elementary.Audio;
public enum JobType
{
Audio,
Text,
// Sozai
}
public class PlaybackJob
{
public JobType Type;
public string Text;
public float Volume = 1.0f;
}
public class PlaybackQueue : IPlaybackQueue
{
// any type of job ConcurrentQueue
private ConcurrentQueue<PlaybackJob> _queue;
private AudioManager _audioManager;
private object _lock;
private bool _isPlaying;
private ILogger _logger;
public PlaybackQueue(AudioManager audioManager)
{
_queue = new();
_isPlaying = false;
_lock = new();
_audioManager = audioManager;
_logger = LogManager.GetCurrentClassLogger();
}
/// <summary>
/// Enqueue audio stream and play it
/// </summary>
/// <param name="job"></param>
public async Task Enqueue(PlaybackJob job)
{
_queue.Enqueue(job);
_logger.Info("Enqueued");
if (!_isPlaying)
{
lock (_lock)
{
if (!_isPlaying)
{
_logger.Info("Start Playing due to empty queue");
PlayNext();
}
}
}
await Task.CompletedTask;
}
public void Flush()
{
_queue.Clear();
_logger.Info("Queue Flushed");
}
private async void PlayNext()
{
try
{
if (_queue.TryDequeue(out var currentStream))
{
_logger.Info("Start Playing");
_isPlaying = true;
await (currentStream.Type switch
{
JobType.Audio => _audioManager.PlayAudio(currentStream.Text),
JobType.Text => _audioManager.PlayText(currentStream.Text),
_ => throw new ArgumentOutOfRangeException()
});
_logger.Info("Finished Playing");
await Task.Delay(200);
_isPlaying = false;
PlayNext();
}
else if (_queue.IsEmpty)
{
_logger.Info("Queue is empty");
_isPlaying = false;
}
}
catch (Exception e)
{
_logger.Error(e);
_isPlaying = false;
PlayNext();
}
}
}