Public Access
Add tray rules and identities editor
PR and Push Build/Test / build-and-test (push) Successful in 7m0s
PR and Push Build/Test / build-and-test (push) Successful in 7m0s
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
using System.Threading.Channels;
|
||||
using NAudio.Wave;
|
||||
|
||||
namespace MeetingAssistant.Workflow;
|
||||
|
||||
public interface IWorkflowRulesEditorSamplePlaybackQueue
|
||||
{
|
||||
Task<string> QueueAsync(int sampleId, byte[] wavBytes, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
public sealed class WorkflowRulesEditorSamplePlaybackQueue : IWorkflowRulesEditorSamplePlaybackQueue, IDisposable
|
||||
{
|
||||
private readonly Channel<QueuedSample> channel = Channel.CreateUnbounded<QueuedSample>();
|
||||
private readonly ILogger<WorkflowRulesEditorSamplePlaybackQueue> logger;
|
||||
private readonly CancellationTokenSource cancellation = new();
|
||||
private readonly Task playbackTask;
|
||||
|
||||
public WorkflowRulesEditorSamplePlaybackQueue(ILogger<WorkflowRulesEditorSamplePlaybackQueue> logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
playbackTask = Task.Run(PlayQueuedSamplesAsync);
|
||||
}
|
||||
|
||||
public async Task<string> QueueAsync(
|
||||
int sampleId,
|
||||
byte[] wavBytes,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (wavBytes.Length == 0)
|
||||
{
|
||||
return $"Sample {sampleId} is empty and was not queued.";
|
||||
}
|
||||
|
||||
await channel.Writer.WriteAsync(new QueuedSample(sampleId, wavBytes), cancellationToken);
|
||||
return $"Queued sample {sampleId} for playback.";
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
cancellation.Cancel();
|
||||
channel.Writer.TryComplete();
|
||||
try
|
||||
{
|
||||
playbackTask.Wait(TimeSpan.FromSeconds(2));
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
cancellation.Dispose();
|
||||
}
|
||||
|
||||
private async Task PlayQueuedSamplesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await foreach (var sample in channel.Reader.ReadAllAsync(cancellation.Token))
|
||||
{
|
||||
try
|
||||
{
|
||||
await PlayAsync(sample, cancellation.Token);
|
||||
}
|
||||
catch (OperationCanceledException) when (cancellation.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
logger.LogWarning(
|
||||
exception,
|
||||
"Could not play queued speaker identity sample {SampleId}",
|
||||
sample.SampleId);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) when (cancellation.IsCancellationRequested)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task PlayAsync(QueuedSample sample, CancellationToken cancellationToken)
|
||||
{
|
||||
await using var stream = new MemoryStream(sample.WavBytes, writable: false);
|
||||
using var reader = new WaveFileReader(stream);
|
||||
using var output = new WaveOutEvent();
|
||||
var completed = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
output.PlaybackStopped += (_, _) => completed.TrySetResult();
|
||||
output.Init(reader);
|
||||
output.Play();
|
||||
|
||||
await using var registration = cancellationToken.Register(() =>
|
||||
{
|
||||
output.Stop();
|
||||
completed.TrySetCanceled(cancellationToken);
|
||||
});
|
||||
await completed.Task;
|
||||
}
|
||||
|
||||
private sealed record QueuedSample(int SampleId, byte[] WavBytes);
|
||||
}
|
||||
Reference in New Issue
Block a user